struct ip4trie_node * ip4trie_addnode(struct ip4trie *trie, ip4addr_t prefix, unsigned bits, struct mempool *mp) { struct ip4trie_node *node, **last; for(last = &trie->ip4t_root; (node = *last) != NULL; last = bitset(prefix, node->ip4t_bits) ? &node->ip4t_right : &node->ip4t_left) { if (node->ip4t_bits > bits || !prefixmatch(node->ip4t_prefix, prefix, node->ip4t_bits)) { /* new node should be inserted before the given node */ struct ip4trie_node *newnode; /* Find number of common (equal) bits */ ip4addr_t diff = (prefix ^ node->ip4t_prefix) & ip4mask(bits); unsigned cbits; if (!diff) /* no difference, all bits are the same */ cbits = bits; else { cbits = 0; while((diff & ip4mask(cbits+1)) == 0) ++cbits; } ++trie->ip4t_nnodes; if (!(newnode = createnode(prefix & ip4mask(cbits), cbits, mp))) return NULL; linknode(newnode, node); *last = newnode; if (cbits == bits) return newnode; /* so we just inserted a glue node, now insert real one */ ++trie->ip4t_nnodes; if (!(node = createnode(prefix, bits, mp))) return NULL; linknode(newnode, node); return node; } /* node's prefix matches */ if (node->ip4t_bits == bits)/* if number of bits are the same too, */ return node; /* ..we're found exactly the same prefix */ } /* no more nodes, create simple new node */ ++trie->ip4t_nnodes; if (!(node = createnode(prefix, bits, mp))) return NULL; *last = node; return node; }
int ip4range(const char *s, ip4addr_t *ap, ip4addr_t *bp, char **np) { int bits = ip4prefix(s, ap, (char**)&s); if (bits < 0) return eret(np, s); else if (*s == '-') { /* a-z */ int bbits = ip4prefix(s + 1, bp, (char**)&s); if (bbits < 0) return eret(np, s); if (bbits == 8) { /* treat 127.0.0.1-2 as 127.0.0.1-127.0.0.2 */ *bp = (*bp >> (bits - 8)) | (*ap & ip4mask(bits - 8)); bbits = bits; }
static int ds_ip4set_line(struct dataset *ds, char *s, struct dsctx *dsc) { struct dsdata *dsd = ds->ds_dsd; ip4addr_t a, b; const char *rr; unsigned rrl; int not; int bits; if (*s == ':') { if (!(rrl = parse_a_txt(s, &rr, def_rr, dsc))) return 1; if (!(dsd->def_rr = mp_dmemdup(ds->ds_mp, rr, rrl))) return 0; return 1; } if (*s == '!') { not = 1; ++s; SKIPSPACE(s); } else not = 0; if ((bits = ip4range(s, &a, &b, &s)) <= 0 || (*s && !ISSPACE(*s) && !ISCOMMENT(*s) && *s != ':')) { dswarn(dsc, "invalid address"); return 1; } if (accept_in_cidr) a &= ip4mask(bits); else if (a & ~ip4mask(bits)) { dswarn(dsc, "invalid range (non-zero host part)"); return 1; } if (dsc->dsc_ip4maxrange && dsc->dsc_ip4maxrange <= (b - a)) { dswarn(dsc, "too large range (%u) ignored (%u max)", b - a + 1, dsc->dsc_ip4maxrange); return 1; } if (not) rr = NULL; else { SKIPSPACE(s); if (!*s || ISCOMMENT(*s)) rr = dsd->def_rr; else if (!(rrl = parse_a_txt(s, &rr, dsd->def_rr, dsc))) return 1; else if (!(rr = mp_dmemdup(ds->ds_mp, rr, rrl))) return 0; } /*XXX some comments about funny ip4range_expand et al */ #define fn(idx,start,count) ds_ip4set_addent(dsd, idx, start, count, rr) /* helper macro for ip4range_expand: * deal with last octet, shifting a and b when done */ #define ip4range_expand_octet(bits) \ if ((a | 255u) >= b) { \ if (b - a == 255u) \ return fn((bits>>3)+1, a<<bits, 1); \ else \ return fn(bits>>3, a<<bits, b - a + 1); \ } \ if (a & 255u) { \ if (!fn(bits>>3, a<<bits, 256u - (a & 255u))) \ return 0; \ a = (a >> 8) + 1; \ } \ else \ a >>= 8; \ if ((b & 255u) != 255u) { \ if (!fn((bits>>3), (b & ~255u)<<bits, (b&255u)+1)) \ return 0; \ b = (b >> 8) - 1; \ } \ else \ b >>= 8 ip4range_expand_octet(0); ip4range_expand_octet(8); ip4range_expand_octet(16); return fn(3, a << 24, b - a + 1); }