/* * 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 #include #include #include #include #include #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; 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); } if (!(flags & FLAG_NO_DECORATE)) printf("[Split networks]\n"); 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; /* 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)) default_printf("Network:\t", "%s/%u\n", 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; } if (!(flags & FLAG_NO_DECORATE)) { dist_printf("\nTotal: \t", "%u\n", count); dist_printf("Hosts/Net:\t", "%s\n", ipv4_prefix_to_hosts(buf, sizeof(buf), split_prefix)); } } static const char *ipv6tostr(struct in6_addr *ip) { static char str[64]; return inet_ntop(AF_INET6, ip, str, sizeof(str)); } static void v6add(struct in6_addr *a, const struct in6_addr *b) { int i, j; uint32_t tmp; for (i = 15; i >= 0; i--) { tmp = (uint32_t)a->s6_addr[i] + (uint32_t)b->s6_addr[i]; if (tmp > 0xff && i > 0) { j = i - 1; for (j=i-1;j>=0;j--) { a->s6_addr[j]++; if (a->s6_addr[j] != 0) break; } } a->s6_addr[i] = tmp & 0xff; } } 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]; 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++) { if (splitmask.s6_addr) 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; v6add(&sdiff, &tmpaddr); if (!(flags & FLAG_NO_DECORATE)) printf("[Split networks]\n"); i = count = 0; while (!i) { if (!(flags & FLAG_NO_DECORATE)) default_printf("Network:\t", "%s/%u\n", ipv6tostr(&start), split_prefix); else printf("%s/%u\n", ipv6tostr(&start), split_prefix); v6add(&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)); v6add(&end, &start); v6add(&end, &ediff); count++; } if (!(flags & FLAG_NO_DECORATE)) { dist_printf("\nTotal: \t", "%u\n", count); dist_printf("Hosts/Net:\t", "%s\n", ipv6_prefix_to_hosts(buf, sizeof(buf), split_prefix)); } }