// // sort a dotted quad list -- optionally discarding dups // // Copyright (c) 2003-2005, Onevista Associates // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as // published by the Free Software Foundation. // #include #include #include #include #include #include #include #include #include #define MAXMEMBERS 2500000 #define MAXLEN 256 struct INFO { uint ip; int cidr; char *line; } ptr[MAXMEMBERS]; int keep_dups = 0; int quiet = 0; char *pname = ""; int compar(struct INFO *a, struct INFO *b); char *ip_addr(uint x); void Die(char *fmt, ...); ///////////////////////////////////////////////////////////////////////////// Usage() { fprintf(stderr, "USAGE: %s [-k] [-i infile] [-o outfile] [-q]\n", pname); fprintf(stderr, "\t-k\t\tkeep duplicates\n"); fprintf(stderr, "\t-i infile\tinput filename\n"); fprintf(stderr, "\t-o outfile\toutput filename\n"); Die("\t-q\t\tkeep silent about duplicates"); } ///////////////////////////////////////////////////////////////////////////// main(argc,argv) int argc; char *argv[]; { FILE *in = stdin; FILE *out = stdout; uint lastIP = 0; int recs_read = 0; int i, x, pidx, cidr; int shft = 0; char *p, *q, ipbuf[24]; char buf[BUFSIZ]; pname = *argv; argc--; argv++; while (argc > 0) { if (*argv[0] == '-') { switch(argv[0][1]) { case 'i': if (argc < 2) Usage(); if ((in = fopen(argv[1], "r")) == NULL) Die("Can't open %s for reading (%s)", argv[1], strerror(errno)); argc--; argv++; break; case 'k': keep_dups = 1; break; case 'o': if (argc < 2) Usage(); if ((out = fopen(argv[1], "w")) == NULL) Die("Can't open %s for writing (%s)", argv[1], strerror(errno)); argc--; argv++; break; case 'q': quiet = 1; break; default: Usage(); break; } argc--; argv++; } else Usage(); } // read input file pidx = 0; while (fgets(buf, sizeof(buf), in) != NULL ) { if (*buf == '#') // ignore comment lines continue; if (++recs_read >= MAXMEMBERS) { fprintf(stderr, "Too many list elements. %u max. Ending!\n", MAXMEMBERS); exit(-1); } x = strlen(buf) + 1; ptr[pidx].line = (char *)malloc(x); if (ptr[pidx].line == NULL) { fprintf(stderr, "Can't get %u bytes of memory. Ending!\n",x); exit(-1); } memcpy(ptr[pidx].line, buf, x); p = ipbuf; q = ptr[pidx].line; while (isdigit(*q) || (*q == '.')) *p++ = *q++; *p = 0; if ((q = strchr(buf, '/')) != NULL) cidr = atoi(++q); else cidr = 32; ptr[pidx].cidr = cidr; ptr[pidx].ip = ntohl(inet_addr(ipbuf)); if (ptr[pidx].ip == -1) continue; pidx++; } // sort qsort(ptr, pidx, sizeof(struct INFO), (void *)compar); // make new output file for (i=0; i 0) { shft = 32 - ptr[i-1].cidr; lastIP = (ptr[i-1].ip >> shft) << shft; if (((ptr[i].ip >> shft) << shft) == lastIP) { if (!quiet) fprintf(stderr, "Redundant address %s covered by %s\n", ptr[i].line, ptr[i-1].line); if (!keep_dups) continue; } } if (fputs(ptr[i].line, out) < 0) fprintf(stderr, "Error writing stdout\n"); } fclose(in); fclose(out); exit(0); } ///////////////////////////////////////////////////////////////////////////// char *ip_addr(uint x) { static char str[20]; sprintf(str, "%d.%d.%d.%d", ((x>>24) & 0xff), ((x>>16) & 0xff),((x>>8) & 0xff),(x & 0xff)); return str; } ///////////////////////////////////////////////////////////////////////////// int compar(struct INFO *a, struct INFO *b) { int compar; compar = (b->ip) - (a->ip); if (compar != 0) { if (b->ip > a->ip) return -1; else return 1; } compar = (b->cidr) - (a->cidr); if (compar != 0) { if (b->cidr > a->cidr) return -1; else return 1; } return 0; } ///////////////////////////////////////////////////////////////////////////// void Die(char *fmt, ...) { va_list ap; char errmsg[MAXLEN]; va_start(ap, fmt); vsnprintf(errmsg, MAXLEN-1, fmt, ap); va_end(ap); fprintf(stderr, "%s\n", errmsg); exit(1); } /////////////////////////////////////////////////////////////////////////////