#ident "%Z%%Y%:%M% %I% %E% %U% (%Q%)" /* * Copyright (c) by Greg A. Woods * * Years of publication: 2003 * * Redistribution of this software in both source and binary forms, with * or without modification, is permitted provided that all of the * following conditions are met: * * 1. Redistributions of source code, either alone or as part of a * collective work, must retain this entire copyright notice, and the * following disclaimer, without alteration, in each file that * contains part of this software. * * 2. Redistributions of this software in binary form, either alone or * as part of a collective work, must reproduce this entire copyright * notice, and the following disclaimer, without alteration, in * either the documentation (as text files in electronic media, or in * printed matter), and/or any original header files from this * software as per the previous term, and/or other materials provided * as part of the distribution. * * 3. Collective works including this software must also include the * following acknowledgement, either alone or as part of this entire * copyright license, in any printed documentation accompanying a * physical distribution (if there is printed documentation), and in * a plain text file separate from the archive files (but perhaps * along with other similar acknowledgments) on any electronic * medium: * * This product includes software developed by Greg A. Woods. * * 4. The name of the author may NOT be used to endorse or promote * products derived from this software without specific prior written * permission. The use of the author's name strictly to meet the * requirements of the previous terms is not to be considered * promotion or endorsement under this term. * * 5. Altered versions (derivative works) must be plainly marked as * such, and must not be misrepresented as being the original * software. This copyright notice, and the following disclaimer, * must not be removed from any derivative work and must not be * changed in any way. * * All other rights are reserved. * * DISCLAIMER: * * THIS SOFTWARE IS PROVIDED BY GREG A. WOODS ``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 #include #include #define MAX_AGG_NETS 10000 char *argv0 = "netagg"; extern int main __P((int, char **, char **)); /* ARGSUSED */ int main(argc, argv, environ) int argc; /* UNUSED */ char *argv[]; char *environ[]; /* UNUSED */ { char *networks[MAX_AGG_NETS]; /* XXX should be dynamic and realloc()ed as needed */ char *nextline; char *ipaddr; size_t linelen; unsigned int i; FILE *sp; argv0 = (argv0 = strrchr(argv[0], '/')) ? argv0 + 1 : argv[0]; for (i = 0; i < MAX_AGG_NETS; i++) { networks[i] = NULL; } /* * read in netblock specs (in CIDR form) * * WARNING: this is far less than optimal since 'sort' breaks when * there's more than one decimal point in a numeric field. * * If it were not for the '/BC' part the following would properly sort * a list of IP numbers. * * sed 's/\./ /g' ${1} | sort -b -n -k 1 -n -k 2 -n -k 3 -n -k 4 | sed 's/ /./g' * * In the mean time the Public Domain "cidr-convert.c" program, which * uses a tree structure to sort and merge ajacent netblocks, works * much better than this hack. Sigh. */ if (!(sp = popen("sort -n -k 2 -t /", "r"))) { fprintf(stderr, "%s: error opening pipe to sort command: %s\n", argv0, strerror(errno)); exit(1); /* NOTREACHED */ } while ((nextline = fgetln(sp, &linelen))) { in_addr_t net; in_addr_t mask; int bits; char *netspec; int matched; if (netspec[linelen - 1] != '\n') /* the last line might not have a newline */ linelen++; /* * we are saving unique netspecs in networks[], so we will * always allocate new memory, and it will be free()ed if it * was not saved, i.e. if it already matched an existing * aggregation in networks[]. */ if (!(netspec = malloc(linelen))) { fprintf(stderr, "%s: malloc(%ld) failed: %s\n", argv0, (long) linelen, strerror(errno)); exit(1); /* NOTREACHED */ } strncpy(netspec, nextline, linelen); netspec[linelen - 1] = '\0'; if ((bits = inet_net_pton(AF_INET, netspec, (void *) &net, sizeof(net))) == -1) { fprintf(stderr, "%s: [%s] is invalid: %s\n", argv0, netspec, strerror(errno)); continue; } if (bits > 32 || bits < 0) { fprintf(stderr, "%s: [%s] has invalid number of bits: %d\n", argv0, netspec, bits); continue; } net = ntohl(net); mask = (bits == 0) ? 0 : (0xffffffffL << (32 - bits)); if (mask && (net & ~mask)) { fprintf(stderr, "%s: warning: [%s] has non-zero bits in host part (0x%x).\n", argv0, netspec, net & ~mask); } matched = 0; i = 0; for (; networks[i] && i < MAX_AGG_NETS; i++) { in_addr_t dest; in_addr_t widermask; int widerbits; ipaddr = networks[i]; dest = 0; if ((widerbits = inet_net_pton(AF_INET, ipaddr, (void *) &dest, sizeof(dest))) == -1) { /* XXX this "cannot" happen... we've already done this once! :-) */ fprintf(stderr, "%s: [%s] is invalid: %s\n", argv0, netspec, strerror(errno)); continue; } widermask = (widerbits == 0) ? 0 : (0xffffffffL << (32 - widerbits)); dest = ntohl(dest); if ((dest & widermask) == (net & widermask)) { #if 0 fprintf(stderr, "%s: [%s] matched [%s].\n", argv0, netspec, ipaddr); #endif matched++; break; } } if (!matched) { if (i >= MAX_AGG_NETS) { fprintf(stderr, "%s: too many nets! Increase MAX_AGG_NETS (currently %d) and recompile\n", argv0, MAX_AGG_NETS); exit(1); /* NOTREACHED */ } networks[i] = netspec; } else { free(netspec); } } if (pclose(sp) == -1) { fprintf(stderr, "%s: error closing pipe to sort command: %s\n", argv0, strerror(errno)); } /* * print the resulting list */ for (i = 0; networks[i] && i < MAX_AGG_NETS; i++) { printf("%s\n", networks[i]); } exit(0); /* NOTREACHED */ }