Blame netsplit.c

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