1
/* ip6trie dataset type: IP6 CIDR ranges with A and TXT values.
2
* Only one value per range allowed.
13
const char *def_rr; /* default RR */
16
definedstype(ip6trie, DSTF_IP6REV, "set of (ip6cidr, value) pairs");
19
ds_ip6trie_reset(struct dsdata *dsd, int UNUSED unused_freeall)
21
memset(dsd, 0, sizeof(*dsd));
25
ds_ip6trie_start(struct dataset *ds)
27
struct dsdata *dsd = ds->ds_dsd;
31
dsd->btrie = btrie_init(ds->ds_mp);
35
ds_ip6trie_line(struct dataset *ds, char *s, struct dsctx *dsc)
37
struct dsdata *dsd = ds->ds_dsd;
40
int bits, excl, non_zero_host;
41
ip6oct_t addr[IP6ADDR_FULL];
43
/* "::" can not be a valid start to a default RR setting ("invalid A
44
* RR") but it can be a valid beginning to an ip6 address
47
if (*s == ':' && s[1] != ':') {
48
if (!(rrl = parse_a_txt(s, &rr, def_rr, dsc)))
50
if (!(dsd->def_rr = mp_dmemdup(ds->ds_mp, rr, rrl)))
61
bits = ip6cidr(s, addr, &s);
62
if (bits < 0 || (*s && !ISSPACE(*s) && !ISCOMMENT(*s) && *s != ':')) {
63
dswarn(dsc, "invalid address");
66
non_zero_host = ip6mask(addr, addr, IP6ADDR_FULL, bits);
67
if (non_zero_host && !accept_in_cidr) {
68
dswarn(dsc, "invalid range (non-zero host part)");
75
else if (!*s || ISCOMMENT(*s))
77
else if (!(rrl = parse_a_txt(s, &rr, dsd->def_rr, dsc)))
79
else if (!(rr = mp_dmemdup(ds->ds_mp, rr, rrl)))
82
switch(btrie_add_prefix(dsd->btrie, addr, bits, rr)) {
85
case BTRIE_DUPLICATE_PREFIX:
86
dswarn(dsc, "duplicated entry for %s/%d",
87
ip6atos(addr, IP6ADDR_FULL), bits);
89
case BTRIE_ALLOC_FAILED:
96
ds_ip6trie_finish(struct dataset *ds, struct dsctx *dsc)
98
dsloaded(dsc, "%s", btrie_stats(ds->ds_dsd->btrie));
102
ds_ip6trie_query(const struct dataset *ds, const struct dnsqinfo *qi,
103
struct dnspacket *pkt)
105
const char *subst = NULL;
108
if (!qi->qi_ip6valid) return 0;
109
check_query_overwrites(qi);
111
rr = btrie_lookup(ds->ds_dsd->btrie, qi->qi_ip6, 8 * IP6ADDR_FULL);
116
if (qi->qi_tflag & NSQUERY_TXT)
117
subst = ip6atos(qi->qi_ip6, IP6ADDR_FULL);
118
addrr_a_txt(pkt, qi->qi_tflag, rr, subst, ds);
119
return NSQUERY_FOUND;
122
#ifndef NO_MASTER_DUMP
124
/* routines to increment individual bits in ip6 addr: returns carry */
126
increment_bit(ip6oct_t *addr, int bit)
128
ip6oct_t mask = 1 << (7 - bit % 8);
129
if (addr[bit / 8] & mask) {
130
addr[bit / 8] &= ~mask;
133
addr[bit / 8] |= mask;
138
struct dump_context {
139
const struct dataset *ds;
142
ip6oct_t prev_addr[IP6ADDR_FULL];
145
/* Keep stack of data inherited from parent prefixes */
146
const void *parent_data[IP6ADDR_FULL * 8 + 1];
151
dump_cb(const btrie_oct_t *prefix, unsigned len, const void *data, int post,
154
struct dump_context *ctx = user_data;
155
unsigned nb = (len + 7) / 8;
156
ip6oct_t addr[IP6ADDR_FULL];
158
if (nb > IP6ADDR_FULL)
159
return; /* paranoia */
160
/* pad prefix to full ip6 length */
161
memcpy(addr, prefix, nb);
162
memset(addr + nb, 0, IP6ADDR_FULL - nb);
165
/* pre order visit (before child nodes are visited) */
166
/* push the inherited data stack down to our level */
167
for (; ctx->depth < len; ctx->depth++)
168
ctx->parent_data[ctx->depth + 1] = ctx->parent_data[ctx->depth];
169
ctx->parent_data[len] = data;
172
/* post order - restore RR at end of prefix */
174
/* increment address to one past the end of the current prefix */
175
for (carry_bits = 0; carry_bits < len; carry_bits++)
176
if (increment_bit(addr, len - 1 - carry_bits) == 0)
177
break; /* no carry */
178
if (carry_bits == len)
179
return; /* wrapped - all done */
180
/* look up the stack one level for each bit of carry to get
181
* the inherited data value at the incremented address */
182
ctx->depth = len - 1 - carry_bits;
183
data = ctx->parent_data[ctx->depth];
186
if (data != ctx->prev_rr) {
187
if (memcmp(addr, ctx->prev_addr, IP6ADDR_FULL) != 0) {
189
dump_ip6range(ctx->prev_addr, addr, ctx->prev_rr, ctx->ds, ctx->f);
190
memcpy(ctx->prev_addr, addr, IP6ADDR_FULL);
192
/* else addr unchanged => zero-length range, ignore */
195
/* else rr unchanged => merge current range with previous */
199
ds_ip6trie_dump(const struct dataset *ds,
200
const unsigned char UNUSED *unused_odn,
203
struct dump_context ctx;
205
memset(&ctx, 0, sizeof(ctx));
208
btrie_walk(ds->ds_dsd->btrie, dump_cb, &ctx);
210
/* flush final range */
212
dump_ip6range(ctx.prev_addr, NULL, ctx.prev_rr, ds, f);