forked from rspamd/rbldnsd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rbldnsd_ip4tset.c
143 lines (118 loc) · 3.15 KB
/
rbldnsd_ip4tset.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/* ip4tset dataset type: IP4 addresses (ranges), with A and TXT
* values for every individual entry.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "rbldnsd.h"
struct dsdata {
unsigned n; /* count */
unsigned a; /* allocated (only for loading) */
unsigned h; /* hint: how much to allocate next time */
ip4addr_t *e; /* array of entries */
const char *def_rr; /* default A and TXT RRs */
};
definedstype(ip4tset, DSTF_IP4REV, "(trivial) set of ip4 addresses");
static void ds_ip4tset_reset(struct dsdata *dsd, int UNUSED unused_freeall) {
if (dsd->e) {
free(dsd->e);
dsd->e = NULL;
dsd->n = dsd->a = 0;
}
dsd->def_rr = NULL;
}
static void ds_ip4tset_start(struct dataset UNUSED *unused_ds) {
}
static int
ds_ip4tset_line(struct dataset *ds, char *s, struct dsctx *dsc) {
struct dsdata *dsd = ds->ds_dsd;
ip4addr_t a;
if (*s == ':') {
if (!dsd->def_rr) {
unsigned rrl;
const char *rr;
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 (ip4prefix(s, &a, &s) != 32 ||
(*s && !ISSPACE(*s) && !ISCOMMENT(*s) && *s != ':')) {
dswarn(dsc, "invalid address");
return 1;
}
if (dsd->n >= dsd->a) {
ip4addr_t *e = dsd->e;
if (!dsd->a)
dsd->a = dsd->h ? dsd->h : 64;
else
dsd->a <<= 1;
e = trealloc(ip4addr_t, e, dsd->a);
if (!e)
return 0;
dsd->e = e;
}
dsd->e[dsd->n++] = a;
return 1;
}
static void ds_ip4tset_finish(struct dataset *ds, struct dsctx *dsc) {
struct dsdata *dsd = ds->ds_dsd;
ip4addr_t *e = dsd->e;
unsigned n = dsd->n;
if (!n)
dsd->h = 0;
else {
dsd->h = dsd->a;
while((dsd->h >> 1) >= n)
dsd->h >>= 1;
# define QSORT_TYPE ip4addr_t
# define QSORT_BASE e
# define QSORT_NELT n
# define QSORT_LT(a,b) *a < *b
# include "qsort.c"
#define ip4tset_eeq(a,b) a == b
REMOVE_DUPS(ip4addr_t, e, n, ip4tset_eeq);
SHRINK_ARRAY(ip4addr_t, e, n, dsd->a);
dsd->e = e;
dsd->n = n;
}
if (!dsd->def_rr) dsd->def_rr = def_rr;
dsloaded(dsc, "cnt=%u", n);
}
static int
ds_ip4tset_find(const ip4addr_t *e, int b, ip4addr_t q) {
int a = 0, m;
--b;
while(a <= b) {
if (e[(m = (a + b) >> 1)] == q) return 1;
else if (e[m] < q) a = m + 1;
else b = m - 1;
}
return 0;
}
static int
ds_ip4tset_query(const struct dataset *ds, const struct dnsqinfo *qi,
struct dnspacket *pkt) {
const struct dsdata *dsd = ds->ds_dsd;
const char *ipsubst;
if (!qi->qi_ip4valid) return 0;
check_query_overwrites(qi);
if (!dsd->n || !ds_ip4tset_find(dsd->e, dsd->n, qi->qi_ip4))
return 0;
ipsubst = (qi->qi_tflag & NSQUERY_TXT) ? ip4atos(qi->qi_ip4) : NULL;
addrr_a_txt(pkt, qi->qi_tflag, dsd->def_rr, ipsubst, ds);
return NSQUERY_FOUND;
}
#ifndef NO_MASTER_DUMP
static void
ds_ip4tset_dump(const struct dataset *ds,
const unsigned char UNUSED *unused_odn,
FILE *f) {
const struct dsdata *dsd = ds->ds_dsd;
const ip4addr_t *e = dsd->e, *t = e + dsd->n;
while(e < t)
dump_ip4(*e++, dsd->def_rr, ds, f);
}
#endif