summaryrefslogtreecommitdiffstats
path: root/netsplit.c
diff options
context:
space:
mode:
Diffstat (limited to 'netsplit.c')
-rw-r--r--netsplit.c253
1 files changed, 253 insertions, 0 deletions
diff --git a/netsplit.c b/netsplit.c
new file mode 100644
index 0000000..05fb1fb
--- /dev/null
+++ b/netsplit.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2003-2016 Simon Ekstrand
+ * Copyright (c) 2010-2016 Joachim Nilsson
+ * Copyright (c) 2016 Nikos Mavrogiannopoulos
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdint.h>
+
+#include "ipv6.h"
+#include "ipcalc.h"
+
+static const char *numtoquad(uint32_t num)
+{
+ static char quad[64];
+
+ num = htonl(num);
+ return inet_ntop(AF_INET, &num, quad, sizeof(quad));
+}
+
+void show_split_networks_v4(unsigned split_prefix, const struct ip_info_st *info, unsigned flags)
+{
+ char buf[64];
+ uint32_t diff, start, end;
+ size_t maxlen = 0;
+ unsigned count;
+ uint32_t splitmask = ntohl(prefix2mask(split_prefix));
+ uint32_t nmask = ntohl(prefix2mask(info->prefix));
+ struct in_addr net, broadcast;
+ unsigned jsonchain = JSON_FIRST;
+
+ if (splitmask < nmask) {
+ if (!beSilent)
+ fprintf(stderr, "Cannot subnet to /%d with this base network, use a prefix > /%d\n",
+ split_prefix, info->prefix);
+ exit(1);
+ }
+
+ output_start(&jsonchain);
+ array_start(&jsonchain, "Split networks", "SPLITNETWORK");
+
+ if (inet_pton(AF_INET, info->network, &net) <= 0) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad IPv4 address: %s\n", info->network);
+ exit(1);
+ }
+ net.s_addr = ntohl(net.s_addr);
+
+ if (inet_pton(AF_INET, info->broadcast, &broadcast) <= 0) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad broadcast address: %s\n", info->broadcast);
+ exit(1);
+ }
+ broadcast.s_addr = ntohl(broadcast.s_addr);
+
+ diff = 0xffffffff - splitmask + 1;
+ start = net.s_addr;
+ end = net.s_addr + diff - 1;
+
+ /* broadcast here is used to get maximum hosts in network. Set it to start + 1 for /31. */
+ if (info->prefix == 31)
+ broadcast.s_addr = start + 1;
+
+ /* Figure out max width of a network string. */
+ while (1) {
+ size_t len;
+
+ len = snprintf(buf, sizeof(buf), "%s", numtoquad(start));
+ if (len > maxlen)
+ maxlen = len;
+
+ start += diff;
+ if (end == 0xffffffff || end >= broadcast.s_addr)
+ break;
+ end += diff;
+ }
+
+ start = net.s_addr;
+ end = net.s_addr + diff - 1;
+ count = 0;
+ while (1) {
+ if (!(flags & FLAG_NO_DECORATE) || (flags & FLAG_JSON)) {
+ default_printf(&jsonchain, "Network:\t", NULL, "%s/%u", numtoquad(start), split_prefix);
+ } else {
+ printf("%s/%u\n", numtoquad(start), split_prefix);
+ }
+
+ count++;
+ start += diff;
+ if (end == 0xffffffff || end >= broadcast.s_addr)
+ break;
+ end += diff;
+ }
+
+ array_stop(&jsonchain);
+
+ if ((!(flags & FLAG_NO_DECORATE)) || (flags & FLAG_JSON)) {
+ dist_printf(&jsonchain, "\nTotal: \t", "NETS", "%u", count);
+ dist_printf(&jsonchain, "Hosts/Net:\t", "ADDRESSES", "%s", ipv4_prefix_to_hosts(buf, sizeof(buf), split_prefix));
+ }
+
+ output_stop(&jsonchain);
+}
+
+static const char *ipv6tostr(struct in6_addr *ip)
+{
+ static char str[64];
+
+ return inet_ntop(AF_INET6, ip, str, sizeof(str));
+}
+
+void show_split_networks_v6(unsigned split_prefix, const struct ip_info_st *info, unsigned flags)
+{
+ int i, j, k;
+ unsigned count;
+ struct in6_addr splitmask, net, netmask, sdiff, ediff, start, end, tmpaddr, netlast;
+ char buf[32];
+ unsigned jsonchain = JSON_FIRST;
+
+ if (inet_pton(AF_INET6, info->network, &net) <= 0) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad IPv6 address: %s\n", info->network);
+ exit(1);
+ }
+
+ if (inet_pton(AF_INET6, info->hostmax, &netlast) <= 0) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad IPv6 address: %s\n", info->hostmax);
+ exit(1);
+ }
+
+ if (inet_pton(AF_INET6, info->netmask, &netmask) <= 0) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad IPv6 mask: %s\n", info->netmask);
+ exit(1);
+ }
+
+ if (ipv6_prefix_to_mask(split_prefix, &splitmask) < 0) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: IPv6 prefix: %d\n", split_prefix);
+ exit(1);
+ }
+
+ i = 0;
+ j = 0;
+ do {
+ if (splitmask.s6_addr[i] > netmask.s6_addr[i])
+ j = 1;
+ if (netmask.s6_addr[i] > splitmask.s6_addr[i])
+ j = 2;
+ i++;
+ } while (i < 16 && !j);
+
+ if (j == 2) {
+ if (!beSilent)
+ fprintf(stderr, "Cannot subnet to /%d with this base network, use a prefix > /%d\n",
+ split_prefix, info->prefix);
+ exit(1);
+ }
+
+ memset(&sdiff, 0, sizeof(sdiff));
+ memset(&ediff, 0, sizeof(ediff));
+
+ for (i = 0; i < 16; i++) {
+ sdiff.s6_addr[i] = 0xff - splitmask.s6_addr[i];
+ end.s6_addr[i] = net.s6_addr[i] + sdiff.s6_addr[i];
+ }
+
+ memcpy(&start, &net, sizeof(net));
+ memcpy(&ediff, &sdiff, sizeof(sdiff));
+
+ memset(&tmpaddr, 0, sizeof(tmpaddr));
+ tmpaddr.s6_addr[15] = 1;
+ ipv6_add(&sdiff, &tmpaddr);
+
+ output_start(&jsonchain);
+
+ array_start(&jsonchain, "Split networks", "SPLITNETWORK");
+
+ i = count = 0;
+ while (!i) {
+ if (!(flags & FLAG_NO_DECORATE) || (flags & FLAG_JSON)) {
+ default_printf(&jsonchain, "Network:\t", NULL, "%s/%u", ipv6tostr(&start), split_prefix);
+ } else {
+ printf("%s/%u\n", ipv6tostr(&start), split_prefix);
+ }
+
+ ipv6_add(&start, &sdiff);
+
+ j = 0;
+ for (k = 0; k < 16; k+=2)
+ if (end.s6_addr[k] != 0xff && end.s6_addr[k+1] != 0xff)
+ j = 1;
+ if (!j)
+ i = 1;
+
+ j = 0;
+ k = 0;
+ do {
+ if (end.s6_addr[k] > netlast.s6_addr[k])
+ j = 1;
+ if (netlast.s6_addr[k] > end.s6_addr[k])
+ j = 2;
+ k++;
+ } while (k < 16 && !j);
+
+ if (!j || j == 1)
+ i = 1;
+
+ memset(&end, 0, sizeof(end));
+
+ ipv6_add(&end, &start);
+ ipv6_add(&end, &ediff);
+ count++;
+ }
+
+ array_stop(&jsonchain);
+
+ if ((!(flags & FLAG_NO_DECORATE)) || (flags & FLAG_JSON)) {
+ dist_printf(&jsonchain, "\nTotal: \t", "NETS", "%u", count);
+ dist_printf(&jsonchain, "Hosts/Net:\t", "ADDRESSES", "%s", ipv6_prefix_to_hosts(buf, sizeof(buf), split_prefix));
+ }
+
+ output_stop(&jsonchain);
+
+}
+