#include #include #include #include #include #include "config.h" #include "lib.h" struct node { pos_t a[2]; }; typedef struct node *iptree; typedef void (*bitsfun)(bits, mask_t); pos_t maxpos = 0; iptree iptree_new(pos_t size) { iptree t = malloc(size * sizeof(struct node)); if (t == 0) error(1, errno, "iptree_new: malloc failed"); pos_t i; for(i = 0; i < size; ++i) { t[i].a[0] = i + 1; t[i].a[1] = 0; } t[i].a[0] = 0; return t; } pos_t iptree_popfree(iptree t) { pos_t f = t[0].a[0]; if (f > maxpos) maxpos = f; if (!f) error(1, 0, "iptree_popfree: no free nodes left"); t[0].a[0] = t[f].a[0]; t[f].a[0] = 0; return f; } void iptree_pushfree(iptree t, pos_t f) { t[f].a[0] = t[0].a[0]; t[f].a[1] = 0; t[0].a[0] = f; } int iptree_is_term(iptree t, pos_t h) { return (h && !t[h].a[0] && !t[h].a[1]); } void iptree_sub_del(iptree t, pos_t h) { for (int i = 0; i < 2; ++i) { int j = t[h].a[i]; if (j) iptree_sub_del(t, j); } iptree_pushfree(t, h); } void iptree_add_new(iptree t, pos_t h, bits b, mask_t m) { if (m) { // there are bits left int l = b[0]; // our bit is left int r = 1 - l; // sibling bit is right // allocate next node element pos_t jl = iptree_popfree(t); // fill current node t[h].a[l] = jl; // recurse to add other bits iptree_add_new(t, jl, b + 1, m - 1); } else { // no bits left, this node is terminal t[h].a[0] = 0; t[h].a[1] = 0; } } void iptree_add_rec(iptree t, pos_t h, bits b, mask_t m) { if (m) { // bits to check are left int l = b[0]; // our bit is left int r = 1 - l; // sibling bit is right pos_t jl = t[h].a[l]; // left subtree head pos_t jr = t[h].a[r]; // right subtree head if (jl) { // tree for our bit is not empty, recurse iptree_add_rec(t, jl, b + 1, m - 1); } else { // tree for our bit is missing // check if this element is terminal (less specific here) if (!jr) return; // otherwise fill new subtree iptree_add_new(t, h, b, m); } // check if we can fold if (iptree_is_term(t, t[h].a[0]) && iptree_is_term(t, t[h].a[1])) { for (int i = 0; i < 2; ++i) { iptree_pushfree(t, t[h].a[i]); t[h].a[i] = 0; } } } else { // no bits left, this node must be terminal for (int i = 0; i < 2; ++i) { pos_t j = t[h].a[i]; // subtree head // delete subtree if exist if (j) { iptree_sub_del(t, j); t[h].a[i] = 0; } } } } void iptree_add(iptree t, pos_t h, bits b, mask_t m) { if (t[h].a[0]) { // tree is not empty already iptree_add_rec(t, t[h].a[0], b, m); } else { // tree is empty, initialize it t[h].a[0] = iptree_popfree(t); iptree_add_new(t, t[h].a[0], b, m); } } void iptree_traverse_rec(iptree t, bitsfun f, pos_t h, bits b, mask_t m) { int flag = 1; for (int i = 0; i < 2; ++i) { pos_t j = t[h].a[i]; // if subtree exists if (j) { flag = 0; // node is not terminal b[m] = i; // set bit // recurse iptree_traverse_rec(t, f, j, b, m + 1); } } if (flag) { // terminal node f(b, m); } } void iptree_traverse(iptree t, pos_t h, bitsfun f) { bit_t b[IPMAXLEN]; if (t[h].a[0]) { // tree is not empty iptree_traverse_rec(t, f, t[h].a[0], b, 0); } } void print4(bits b, mask_t m) { char s_ip[BUFLEN]; bits2ip4(b, m, s_ip, BUFLEN); puts(s_ip); } void print6(bits b, mask_t m) { char s_ip[BUFLEN]; bits2ip6(b, m, s_ip, BUFLEN); puts(s_ip); } double nodes2mb(pos_t n) { return sizeof(struct node) * (double)n / (double)(1 << 20); } int main(void) { bit_t b[IPMAXLEN]; mask_t m; char s[BUFLEN]; iptree t = iptree_new(SIZE); pos_t ip4 = iptree_popfree(t); pos_t ip6 = iptree_popfree(t); while (1) { if (!fgets(s, BUFLEN, stdin)) { if (!feof(stdin)) error(1, errno, "input"); break; } int l = strlen(s); if (l && s[l - 1] == '\n') s[--l] = 0; if (!l) continue; if (!strchr(s, ':')) { // ipv4 ip42bits(s, b, &m); iptree_add(t, ip4, b, m); } else { // ipv6 ip62bits(s, b, &m); iptree_add(t, ip6, b, m); } } iptree_traverse(t, ip4, print4); iptree_traverse(t, ip6, print6); double mb_used = nodes2mb(maxpos); double mb_all = nodes2mb(SIZE); fprintf(stderr, "max nodes: %.2f%%, %d / %d, %.2fMB / %.2fMB\n", maxpos / (double)SIZE * 100.0, maxpos, SIZE, mb_used, mb_all); return 0; }