~ubuntu-branches/ubuntu/wily/rbldnsd/wily

« back to all changes in this revision

Viewing changes to rbldnsd_ip6trie.c

  • Committer: Package Import Robot
  • Author(s): Logan Rosen
  • Date: 2013-11-10 23:45:37 UTC
  • mfrom: (5.2.1 sid)
  • Revision ID: package-import@ubuntu.com-20131110234537-nfcmjceyv3f63o1a
Tags: 0.997a-1ubuntu1
* Merge from Debian unstable. Remaining changes:
  - debian/patches/as-needed.patch: Fix FTBFS with ld --as-needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ip6trie dataset type: IP6 CIDR ranges with A and TXT values.
 
2
 * Only one value per range allowed.
 
3
 */
 
4
 
 
5
#include <stdio.h>
 
6
#include <string.h>
 
7
#include <stdlib.h>
 
8
#include "rbldnsd.h"
 
9
#include "btrie.h"
 
10
 
 
11
struct dsdata {
 
12
  struct btrie *btrie;
 
13
  const char *def_rr;   /* default RR */
 
14
};
 
15
 
 
16
definedstype(ip6trie, DSTF_IP6REV, "set of (ip6cidr, value) pairs");
 
17
 
 
18
static void
 
19
ds_ip6trie_reset(struct dsdata *dsd, int UNUSED unused_freeall)
 
20
{
 
21
  memset(dsd, 0, sizeof(*dsd));
 
22
}
 
23
 
 
24
static void
 
25
ds_ip6trie_start(struct dataset *ds)
 
26
{
 
27
  struct dsdata *dsd = ds->ds_dsd;
 
28
 
 
29
  dsd->def_rr = def_rr;
 
30
  if (!dsd->btrie)
 
31
    dsd->btrie = btrie_init(ds->ds_mp);
 
32
}
 
33
 
 
34
static int
 
35
ds_ip6trie_line(struct dataset *ds, char *s, struct dsctx *dsc)
 
36
{
 
37
  struct dsdata *dsd = ds->ds_dsd;
 
38
  const char *rr;
 
39
  unsigned rrl;
 
40
  int bits, excl, non_zero_host;
 
41
  ip6oct_t addr[IP6ADDR_FULL];
 
42
 
 
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
 
45
   * (e.g. "::1")
 
46
   */
 
47
  if (*s == ':' && s[1] != ':') {
 
48
    if (!(rrl = parse_a_txt(s, &rr, def_rr, dsc)))
 
49
      return 1;
 
50
    if (!(dsd->def_rr = mp_dmemdup(ds->ds_mp, rr, rrl)))
 
51
      return 0;
 
52
    return 1;
 
53
  }
 
54
 
 
55
  excl = *s == '!';
 
56
  if (excl) {
 
57
    ++s;
 
58
    SKIPSPACE(s);
 
59
  }
 
60
 
 
61
  bits = ip6cidr(s, addr, &s);
 
62
  if (bits < 0 || (*s && !ISSPACE(*s) && !ISCOMMENT(*s) && *s != ':')) {
 
63
    dswarn(dsc, "invalid address");
 
64
    return 1;
 
65
  }
 
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)");
 
69
    return 1;
 
70
  }
 
71
 
 
72
  SKIPSPACE(s);
 
73
  if (excl)
 
74
    rr = NULL;
 
75
  else if (!*s || ISCOMMENT(*s))
 
76
    rr = dsd->def_rr;
 
77
  else if (!(rrl = parse_a_txt(s, &rr, dsd->def_rr, dsc)))
 
78
    return 1;
 
79
  else if (!(rr = mp_dmemdup(ds->ds_mp, rr, rrl)))
 
80
    return 0;
 
81
 
 
82
  switch(btrie_add_prefix(dsd->btrie, addr, bits, rr)) {
 
83
  case BTRIE_OKAY:
 
84
    return 1;
 
85
  case BTRIE_DUPLICATE_PREFIX:
 
86
    dswarn(dsc, "duplicated entry for %s/%d",
 
87
           ip6atos(addr, IP6ADDR_FULL), bits);
 
88
    return 1;
 
89
  case BTRIE_ALLOC_FAILED:
 
90
  default:
 
91
    return 0;                   /* oom */
 
92
  }
 
93
}
 
94
 
 
95
static void
 
96
ds_ip6trie_finish(struct dataset *ds, struct dsctx *dsc)
 
97
{
 
98
  dsloaded(dsc, "%s", btrie_stats(ds->ds_dsd->btrie));
 
99
}
 
100
 
 
101
static int
 
102
ds_ip6trie_query(const struct dataset *ds, const struct dnsqinfo *qi,
 
103
                 struct dnspacket *pkt)
 
104
{
 
105
  const char *subst = NULL;
 
106
  const char *rr;
 
107
 
 
108
  if (!qi->qi_ip6valid) return 0;
 
109
  check_query_overwrites(qi);
 
110
 
 
111
  rr = btrie_lookup(ds->ds_dsd->btrie, qi->qi_ip6, 8 * IP6ADDR_FULL);
 
112
 
 
113
  if (!rr)
 
114
    return 0;
 
115
 
 
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;
 
120
}
 
121
 
 
122
#ifndef NO_MASTER_DUMP
 
123
 
 
124
/* routines to increment individual bits in ip6 addr: returns carry */
 
125
static inline int
 
126
increment_bit(ip6oct_t *addr, int bit)
 
127
{
 
128
  ip6oct_t mask = 1 << (7 - bit % 8);
 
129
  if (addr[bit / 8] & mask) {
 
130
    addr[bit / 8] &= ~mask;
 
131
    return 1;
 
132
  } else {
 
133
    addr[bit / 8] |= mask;
 
134
    return 0;
 
135
  }
 
136
}
 
137
 
 
138
struct dump_context {
 
139
  const struct dataset *ds;
 
140
  FILE *f;
 
141
 
 
142
  ip6oct_t prev_addr[IP6ADDR_FULL];
 
143
  const char *prev_rr;
 
144
 
 
145
  /* Keep stack of data inherited from parent prefixes */
 
146
  const void *parent_data[IP6ADDR_FULL * 8 + 1];
 
147
  unsigned depth;
 
148
};
 
149
 
 
150
static void
 
151
dump_cb(const btrie_oct_t *prefix, unsigned len, const void *data, int post,
 
152
        void *user_data)
 
153
{
 
154
  struct dump_context *ctx = user_data;
 
155
  unsigned nb = (len + 7) / 8;
 
156
  ip6oct_t addr[IP6ADDR_FULL];
 
157
 
 
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);
 
163
 
 
164
  if (post == 0) {
 
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;
 
170
  }
 
171
  else {
 
172
    /* post order - restore RR at end of prefix */
 
173
    unsigned carry_bits;
 
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];
 
184
  }
 
185
 
 
186
  if (data != ctx->prev_rr) {
 
187
    if (memcmp(addr, ctx->prev_addr, IP6ADDR_FULL) != 0) {
 
188
      if (ctx->prev_rr)
 
189
        dump_ip6range(ctx->prev_addr, addr, ctx->prev_rr, ctx->ds, ctx->f);
 
190
      memcpy(ctx->prev_addr, addr, IP6ADDR_FULL);
 
191
    }
 
192
    /* else addr unchanged => zero-length range, ignore */
 
193
    ctx->prev_rr = data;
 
194
  }
 
195
  /* else rr unchanged => merge current range with previous */
 
196
}
 
197
 
 
198
static void
 
199
ds_ip6trie_dump(const struct dataset *ds,
 
200
                const unsigned char UNUSED *unused_odn,
 
201
                FILE *f)
 
202
{
 
203
  struct dump_context ctx;
 
204
 
 
205
  memset(&ctx, 0, sizeof(ctx));
 
206
  ctx.ds = ds;
 
207
  ctx.f = f;
 
208
  btrie_walk(ds->ds_dsd->btrie, dump_cb, &ctx);
 
209
 
 
210
  /* flush final range */
 
211
  if (ctx.prev_rr)
 
212
    dump_ip6range(ctx.prev_addr, NULL, ctx.prev_rr, ds, f);
 
213
}
 
214
 
 
215
#endif