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