From: Tobias Brunner Date: Tue, 21 Feb 2012 13:35:07 +0000 (+0100) Subject: Script added to split an IP address range into subnets. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=15798b5bc667d36b0e4d2b636e3af69a48dd0c3f;p=thirdparty%2Fstrongswan.git Script added to split an IP address range into subnets. --- diff --git a/scripts/Makefile.am b/scripts/Makefile.am index ea399e84c1..d214f33d7d 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -3,7 +3,8 @@ AM_CFLAGS = \ -DPLUGINS="\"${scripts_plugins}\"" noinst_PROGRAMS = bin2array bin2sql id2sql key2keyid keyid2sql oid2der \ - thread_analysis dh_speed pubkey_speed crypt_burn hash_burn fetch + thread_analysis dh_speed pubkey_speed crypt_burn hash_burn fetch \ + range2subnets if USE_TLS noinst_PROGRAMS += tls_test @@ -24,6 +25,7 @@ pubkey_speed_SOURCES = pubkey_speed.c crypt_burn_SOURCES = crypt_burn.c hash_burn_SOURCES = hash_burn.c fetch_SOURCES = fetch.c +range2subnets_SOURCES = range2subnets.c id2sql_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la key2keyid_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la keyid2sql_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la @@ -33,6 +35,7 @@ pubkey_speed_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lrt crypt_burn_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la hash_burn_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la fetch_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la +range2subnets_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la key2keyid.o : $(top_builddir)/config.status diff --git a/scripts/range2subnets.c b/scripts/range2subnets.c new file mode 100644 index 0000000000..678a15299a --- /dev/null +++ b/scripts/range2subnets.c @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include + +#include +#include +#include +#include + +#define swap(a, b) ({ typeof(a) _tmp = a; a = b; b = _tmp; }) + +typedef struct { + host_t *net; + int netmask; +} subnet_t; + +static linked_list_t *nets; + +static void subnet_destroy(subnet_t *this) +{ + this->net->destroy(this->net); + free(this); +} + +/** + * Insert a subnet into the list of subnets sorted by increasing address. + * The address is not masked, i.e. host bits are expected to be 0. + */ +static void add_subnet(int family, chunk_t addr, int netmask) +{ + enumerator_t *enumerator; + subnet_t *subnet, *current; + + INIT(subnet, + .net = host_create_from_chunk(family, addr, 0), + .netmask = netmask, + ); + + enumerator = nets->create_enumerator(nets); + while (enumerator->enumerate(enumerator, ¤t)) + { + int cmp = chunk_compare(current->net->get_address(current->net), addr); + if (cmp > 0 || + (cmp == 0 && current->netmask > subnet->netmask)) + { + break; + } + } + nets->insert_before(nets, enumerator, subnet); + enumerator->destroy(enumerator); +} + +static void split_range(int family, chunk_t from, chunk_t to) +{ + static const u_char bitmask[] = { 0x80, 0x40, 0x20, 0x10, + 0x08, 0x04, 0x02, 0x01 }; + int byte = 0, bit = 0, prefix, netmask, common_byte, common_bit, + from_cur, from_prev, to_cur, to_prev; + bool from_full = TRUE, to_full = TRUE; + + /* find a common prefix */ + while ((from.ptr[byte] & bitmask[bit]) == (to.ptr[byte] & bitmask[bit]) && + byte < from.len) + { + if (++bit == 8) + { + bit = 0; + byte++; + } + } + prefix = byte * 8 + bit; + + /* at this point we know that the current bit is 0 for the from and 1 for + * the to address. we skip this bit and analyze the remaining bits from the + * back, looking at them as two binary trees (0=left, 1=right). in that + * process the host bits get zeroed out. if the range is a single address + * we don't enter the loops below. */ + if (++bit == 8) + { + bit = 0; + byte++; + } + common_byte = byte; + common_bit = bit; + netmask = from.len * 8; + from_prev = 0, to_prev = 1; + for (byte = from.len - 1; byte >= common_byte; byte--) + { + int bit_min = (byte == common_byte) ? common_bit : 0; + for (bit = 7; bit >= bit_min; bit--) + { + u_char mask = bitmask[bit]; + + from_cur = from.ptr[byte] & mask; + if (!from_prev && from_cur) + { /* 0 -> 1: subnet includes the whole current (right) subtree */ + add_subnet(family, from, netmask); + from_full = FALSE; + } + else if (from_prev && !from_cur) + { /* 1 -> 0: invert bit and add subnet (right subtree) */ + from.ptr[byte] ^= mask; + add_subnet(family, from, netmask); + from_cur = 1; + } + from.ptr[byte] &= ~mask; + from_prev = from_cur; + + to_cur = to.ptr[byte] & mask; + if (to_prev && !to_cur) + { /* 1 -> 0: subnet includes the whole current (left) subtree */ + add_subnet(family, to, netmask); + to_full = FALSE; + } + else if (!to_prev && to_cur) + { /* 0 -> 1: invert bit and add subnet (left subtree) */ + to.ptr[byte] ^= mask; + add_subnet(family, to, netmask); + to_cur = 0; + } + to.ptr[byte] &= ~mask; + to_prev = to_cur; + netmask--; + } + } + + if (from_full && to_full) + { /* full subnet (i.e. from=to or from=0 and to=1 after common prefix) */ + add_subnet(family, from, prefix); + } + else if (from_full) + { /* full left subnet */ + add_subnet(family, from, prefix + 1); + } + else if (to_full) + { /* full right subnet */ + add_subnet(family, to, prefix + 1); + } +} + +/** + * Split an IP address range into multiple distinct subnets. + */ +int main(int argc, char *argv[]) +{ + enumerator_t *enumerator; + host_t *from = NULL, *to = NULL; + chunk_t from_addr, to_addr; + subnet_t *subnet; + char *token; + int family; + + library_init(NULL); + atexit(library_deinit); + + if (argc != 2) + { + printf("Usage: %s -\n", argv[0]); + return -1; + } + + enumerator = enumerator_create_token(argv[1], "-", " "); + while (enumerator->enumerate(enumerator, &token)) + { + host_t **host; + host = !from ? &from : &to; + *host = host_create_from_string(token, 0); + if (*host == NULL) + { + printf("Unable to parse IP address: %s\n", token); + enumerator->destroy(enumerator); + DESTROY_IF(from); + return -2; + } + } + enumerator->destroy(enumerator); + + if (!to) + { + to = from->clone(from); + } + + if (from->get_family(from) != to->get_family(to)) + { + printf("Address family does not match!"); + from->destroy(from); + to->destroy(to); + return -3; + } + + family = from->get_family(from); + from_addr = from->get_address(from); + to_addr = to->get_address(to); + nets = linked_list_create(); + + if (chunk_compare(from_addr, to_addr) > 0) + { + swap(from_addr, to_addr); + swap(from, to); + } + + printf("Splitting range %H-%H...\n", from, to); + split_range(family, from_addr, to_addr); + + enumerator = nets->create_enumerator(nets); + while (enumerator->enumerate(enumerator, &subnet)) + { + printf(" %H/%d\n", subnet->net, subnet->netmask); + } + enumerator->destroy(enumerator); + + nets->destroy_function(nets, (void*)subnet_destroy); + from->destroy(from); + to->destroy(to); + return 0; +} +