]>
Commit | Line | Data |
---|---|---|
add80afd | 1 | /* |
a6f63a82 | 2 | * Solanum: a slightly advanced ircd |
a389de2a | 3 | * dnsbl.c: Manages DNSBL entries and lookups |
add80afd EM |
4 | * |
5 | * Copyright (C) 2006-2011 charybdis development team | |
6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions are | |
9 | * met: | |
10 | * | |
11 | * 1. Redistributions of source code must retain the above copyright notice, | |
12 | * this list of conditions and the following disclaimer. | |
13 | * | |
14 | * 2. Redistributions in binary form must reproduce the above copyright | |
15 | * notice, this list of conditions and the following disclaimer in the | |
16 | * documentation and/or other materials provided with the distribution. | |
17 | * | |
18 | * 3. The name of the author may not be used to endorse or promote products | |
19 | * derived from this software without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
22 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
23 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
24 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | |
25 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
29 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
30 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
31 | * POSSIBILITY OF SUCH DAMAGE. | |
32 | */ | |
33 | ||
6ee7c05c | 34 | /* Originally written for charybdis circa 2006 (by nenolod?). |
add80afd EM |
35 | * Tweaked for authd. Some functions and structs renamed. Public/private |
36 | * interfaces have been shifted around. Some code has been cleaned up too. | |
37 | * -- Elizafox 24 March 2016 | |
38 | */ | |
39 | ||
40 | #include "authd.h" | |
9057170c | 41 | #include "defaults.h" |
add80afd | 42 | #include "provider.h" |
db821ee9 | 43 | #include "notice.h" |
add80afd EM |
44 | #include "stdinc.h" |
45 | #include "dns.h" | |
46 | ||
a389de2a | 47 | #define SELF_PID (dnsbl_provider.id) |
731d1289 | 48 | |
add80afd EM |
49 | typedef enum filter_t |
50 | { | |
51 | FILTER_ALL = 1, | |
52 | FILTER_LAST = 2, | |
53 | } filter_t; | |
54 | ||
a389de2a | 55 | /* dnsbl accepted IP types */ |
add80afd EM |
56 | #define IPTYPE_IPV4 1 |
57 | #define IPTYPE_IPV6 2 | |
58 | ||
59 | /* A configured DNSBL */ | |
a389de2a | 60 | struct dnsbl |
add80afd EM |
61 | { |
62 | char host[IRCD_RES_HOSTLEN + 1]; | |
63 | char reason[BUFSIZE]; /* Reason template (ircd fills in the blanks) */ | |
eccc44ed | 64 | uint8_t iptype; /* IP types supported */ |
add80afd EM |
65 | rb_dlink_list filters; /* Filters for queries */ |
66 | ||
67 | bool delete; /* If true delete when no clients */ | |
a389de2a | 68 | int refcount; /* When 0 and delete is set, remove this dnsbl */ |
a90465f7 | 69 | unsigned int hits; |
add80afd EM |
70 | |
71 | time_t lastwarning; /* Last warning about garbage replies sent */ | |
72 | }; | |
73 | ||
74 | /* A lookup in progress for a particular DNSBL for a particular client */ | |
a389de2a | 75 | struct dnsbl_lookup |
add80afd | 76 | { |
a389de2a | 77 | struct dnsbl *bl; /* dnsbl we're checking */ |
add80afd EM |
78 | struct auth_client *auth; /* Client */ |
79 | struct dns_query *query; /* DNS query pointer */ | |
e43e61f7 | 80 | |
add80afd EM |
81 | rb_dlink_node node; |
82 | }; | |
83 | ||
a389de2a AC |
84 | /* A dnsbl filter */ |
85 | struct dnsbl_filter | |
add80afd EM |
86 | { |
87 | filter_t type; /* Type of filter */ | |
a90465f7 | 88 | char filter[HOSTIPLEN]; /* The filter itself */ |
add80afd EM |
89 | |
90 | rb_dlink_node node; | |
91 | }; | |
92 | ||
a389de2a AC |
93 | /* dnsbl user data attached to auth_client instance */ |
94 | struct dnsbl_user | |
add80afd | 95 | { |
bfd95f01 | 96 | bool started; |
a389de2a | 97 | rb_dlink_list queries; /* dnsbl queries in flight */ |
add80afd EM |
98 | }; |
99 | ||
100 | /* public interfaces */ | |
a389de2a | 101 | static void dnsbls_destroy(void); |
add80afd | 102 | |
a389de2a AC |
103 | static bool dnsbls_start(struct auth_client *); |
104 | static inline void dnsbls_generic_cancel(struct auth_client *, const char *); | |
105 | static void dnsbls_timeout(struct auth_client *); | |
106 | static void dnsbls_cancel(struct auth_client *); | |
107 | static void dnsbls_cancel_none(struct auth_client *); | |
add80afd EM |
108 | |
109 | /* private interfaces */ | |
a389de2a AC |
110 | static void unref_dnsbl(struct dnsbl *); |
111 | static struct dnsbl *new_dnsbl(const char *, const char *, uint8_t, rb_dlink_list *); | |
112 | static struct dnsbl *find_dnsbl(const char *); | |
113 | static bool dnsbl_check_reply(struct dnsbl_lookup *, const char *); | |
114 | static void dnsbl_dns_callback(const char *, bool, query_type, void *); | |
115 | static void initiate_dnsbl_dnsquery(struct dnsbl *, struct auth_client *); | |
add80afd EM |
116 | |
117 | /* Variables */ | |
a389de2a AC |
118 | static rb_dlink_list dnsbl_list = { NULL, NULL, 0 }; |
119 | static int dnsbl_timeout = DNSBL_TIMEOUT_DEFAULT; | |
add80afd EM |
120 | |
121 | /* private interfaces */ | |
122 | ||
123 | static void | |
a389de2a | 124 | unref_dnsbl(struct dnsbl *bl) |
add80afd EM |
125 | { |
126 | rb_dlink_node *ptr, *nptr; | |
127 | ||
128 | bl->refcount--; | |
129 | if (bl->delete && bl->refcount <= 0) | |
130 | { | |
131 | RB_DLINK_FOREACH_SAFE(ptr, nptr, bl->filters.head) | |
132 | { | |
133 | rb_dlinkDelete(ptr, &bl->filters); | |
134 | rb_free(ptr); | |
135 | } | |
136 | ||
a389de2a | 137 | rb_dlinkFindDestroy(bl, &dnsbl_list); |
add80afd EM |
138 | rb_free(bl); |
139 | } | |
140 | } | |
141 | ||
a389de2a AC |
142 | static struct dnsbl * |
143 | new_dnsbl(const char *name, const char *reason, uint8_t iptype, rb_dlink_list *filters) | |
add80afd | 144 | { |
a389de2a | 145 | struct dnsbl *bl; |
add80afd | 146 | |
3f2695ac | 147 | if (name == NULL || reason == NULL || iptype == 0) |
add80afd EM |
148 | return NULL; |
149 | ||
a389de2a | 150 | if((bl = find_dnsbl(name)) == NULL) |
add80afd | 151 | { |
a389de2a AC |
152 | bl = rb_malloc(sizeof(struct dnsbl)); |
153 | rb_dlinkAddAlloc(bl, &dnsbl_list); | |
add80afd EM |
154 | } |
155 | else | |
156 | bl->delete = false; | |
157 | ||
158 | rb_strlcpy(bl->host, name, IRCD_RES_HOSTLEN + 1); | |
159 | rb_strlcpy(bl->reason, reason, BUFSIZE); | |
3f2695ac | 160 | bl->iptype = iptype; |
add80afd EM |
161 | |
162 | rb_dlinkMoveList(filters, &bl->filters); | |
163 | ||
164 | bl->lastwarning = 0; | |
165 | ||
166 | return bl; | |
167 | } | |
168 | ||
a389de2a AC |
169 | static struct dnsbl * |
170 | find_dnsbl(const char *name) | |
add80afd EM |
171 | { |
172 | rb_dlink_node *ptr; | |
173 | ||
a389de2a | 174 | RB_DLINK_FOREACH(ptr, dnsbl_list.head) |
add80afd | 175 | { |
a389de2a | 176 | struct dnsbl *bl = (struct dnsbl *)ptr->data; |
add80afd EM |
177 | |
178 | if (!strcasecmp(bl->host, name)) | |
179 | return bl; | |
180 | } | |
181 | ||
182 | return NULL; | |
183 | } | |
184 | ||
185 | static inline bool | |
a389de2a | 186 | dnsbl_check_reply(struct dnsbl_lookup *bllookup, const char *ipaddr) |
add80afd | 187 | { |
a389de2a | 188 | struct dnsbl *bl = bllookup->bl; |
add80afd EM |
189 | const char *lastoctet; |
190 | rb_dlink_node *ptr; | |
191 | ||
192 | /* No filters and entry found - thus positive match */ | |
193 | if (!rb_dlink_list_length(&bl->filters)) | |
194 | return true; | |
195 | ||
196 | /* Below will prolly have to change if IPv6 address replies are sent back */ | |
197 | if ((lastoctet = strrchr(ipaddr, '.')) == NULL || *(++lastoctet) == '\0') | |
198 | goto blwarn; | |
199 | ||
200 | RB_DLINK_FOREACH(ptr, bl->filters.head) | |
201 | { | |
a389de2a | 202 | struct dnsbl_filter *filter = ptr->data; |
add80afd EM |
203 | const char *cmpstr; |
204 | ||
205 | if (filter->type == FILTER_ALL) | |
206 | cmpstr = ipaddr; | |
207 | else if (filter->type == FILTER_LAST) | |
208 | cmpstr = lastoctet; | |
209 | else | |
210 | { | |
a389de2a | 211 | warn_opers(L_CRIT, "dnsbl: Unknown dnsbl filter type (host %s): %d", |
add80afd | 212 | bl->host, filter->type); |
34b96d7f | 213 | exit(EX_PROVIDER_ERROR); |
add80afd EM |
214 | } |
215 | ||
3f2695ac | 216 | if (strcmp(cmpstr, filter->filter) == 0) |
add80afd EM |
217 | /* Match! */ |
218 | return true; | |
219 | } | |
220 | ||
221 | return false; | |
222 | blwarn: | |
223 | if (bl->lastwarning + 3600 < rb_current_time()) | |
224 | { | |
a389de2a | 225 | warn_opers(L_WARN, "Garbage/undecipherable reply received from dnsbl %s (reply %s)", |
add80afd EM |
226 | bl->host, ipaddr); |
227 | bl->lastwarning = rb_current_time(); | |
228 | } | |
72463470 | 229 | |
add80afd EM |
230 | return false; |
231 | } | |
232 | ||
233 | static void | |
a389de2a | 234 | dnsbl_dns_callback(const char *result, bool status, query_type type, void *data) |
add80afd | 235 | { |
a389de2a AC |
236 | struct dnsbl_lookup *bllookup = (struct dnsbl_lookup *)data; |
237 | struct dnsbl_user *bluser; | |
238 | struct dnsbl *bl; | |
add80afd EM |
239 | struct auth_client *auth; |
240 | ||
e78a87f3 EM |
241 | lrb_assert(bllookup != NULL); |
242 | lrb_assert(bllookup->auth != NULL); | |
add80afd | 243 | |
e43e61f7 | 244 | bl = bllookup->bl; |
add80afd | 245 | auth = bllookup->auth; |
e78a87f3 | 246 | |
731d1289 | 247 | if((bluser = get_provider_data(auth, SELF_PID)) == NULL) |
add80afd EM |
248 | return; |
249 | ||
a389de2a | 250 | if (result != NULL && status && dnsbl_check_reply(bllookup, result)) |
add80afd EM |
251 | { |
252 | /* Match found, so proceed no further */ | |
a90465f7 | 253 | bl->hits++; |
731d1289 | 254 | reject_client(auth, SELF_PID, bl->host, bl->reason); |
a389de2a | 255 | dnsbls_cancel(auth); |
add80afd EM |
256 | return; |
257 | } | |
258 | ||
a389de2a | 259 | unref_dnsbl(bl); |
e43e61f7 | 260 | cancel_query(bllookup->query); /* Ignore future responses */ |
add80afd EM |
261 | rb_dlinkDelete(&bllookup->node, &bluser->queries); |
262 | rb_free(bllookup); | |
263 | ||
264 | if(!rb_dlink_list_length(&bluser->queries)) | |
265 | { | |
266 | /* Done here */ | |
bc89b788 | 267 | notice_client(auth->cid, "*** No DNSBL entry found for this IP"); |
add80afd | 268 | rb_free(bluser); |
731d1289 EM |
269 | set_provider_data(auth, SELF_PID, NULL); |
270 | set_provider_timeout_absolute(auth, SELF_PID, 0); | |
271 | provider_done(auth, SELF_PID); | |
a5f52774 SA |
272 | |
273 | auth_client_unref(auth); | |
add80afd EM |
274 | } |
275 | } | |
276 | ||
277 | static void | |
a389de2a | 278 | initiate_dnsbl_dnsquery(struct dnsbl *bl, struct auth_client *auth) |
add80afd | 279 | { |
a389de2a AC |
280 | struct dnsbl_lookup *bllookup = rb_malloc(sizeof(struct dnsbl_lookup)); |
281 | struct dnsbl_user *bluser = get_provider_data(auth, SELF_PID); | |
add80afd EM |
282 | char buf[IRCD_RES_HOSTLEN + 1]; |
283 | int aftype; | |
284 | ||
285 | bllookup->bl = bl; | |
286 | bllookup->auth = auth; | |
287 | ||
288 | aftype = GET_SS_FAMILY(&auth->c_addr); | |
289 | if((aftype == AF_INET && (bl->iptype & IPTYPE_IPV4) == 0) || | |
290 | (aftype == AF_INET6 && (bl->iptype & IPTYPE_IPV6) == 0)) | |
a389de2a | 291 | /* Incorrect dnsbl type for this IP... */ |
e78a87f3 EM |
292 | { |
293 | rb_free(bllookup); | |
add80afd | 294 | return; |
e78a87f3 | 295 | } |
add80afd EM |
296 | |
297 | build_rdns(buf, sizeof(buf), &auth->c_addr, bl->host); | |
a389de2a | 298 | bllookup->query = lookup_ip(buf, AF_INET, dnsbl_dns_callback, bllookup); |
add80afd EM |
299 | |
300 | rb_dlinkAdd(bllookup, &bllookup->node, &bluser->queries); | |
301 | bl->refcount++; | |
302 | } | |
303 | ||
02e46740 | 304 | static inline bool |
a389de2a | 305 | lookup_all_dnsbls(struct auth_client *auth) |
a7d5aea1 | 306 | { |
a389de2a | 307 | struct dnsbl_user *bluser = get_provider_data(auth, SELF_PID); |
a7d5aea1 | 308 | rb_dlink_node *ptr; |
02e46740 EM |
309 | int iptype; |
310 | ||
311 | if(GET_SS_FAMILY(&auth->c_addr) == AF_INET) | |
8b0392ca | 312 | iptype = IPTYPE_IPV4; |
02e46740 EM |
313 | else if(GET_SS_FAMILY(&auth->c_addr) == AF_INET6) |
314 | iptype = IPTYPE_IPV6; | |
02e46740 EM |
315 | else |
316 | return false; | |
317 | ||
bfd95f01 | 318 | bluser->started = true; |
bc89b788 | 319 | notice_client(auth->cid, "*** Checking your IP against DNSBLs"); |
72463470 | 320 | |
a389de2a | 321 | RB_DLINK_FOREACH(ptr, dnsbl_list.head) |
a7d5aea1 | 322 | { |
a389de2a | 323 | struct dnsbl *bl = (struct dnsbl *)ptr->data; |
a7d5aea1 | 324 | |
c47e4958 | 325 | if (!bl->delete && (bl->iptype & iptype)) |
a389de2a | 326 | initiate_dnsbl_dnsquery(bl, auth); |
a7d5aea1 EM |
327 | } |
328 | ||
02e46740 EM |
329 | if(!rb_dlink_list_length(&bluser->queries)) |
330 | /* None checked. */ | |
331 | return false; | |
332 | ||
a389de2a | 333 | set_provider_timeout_relative(auth, SELF_PID, dnsbl_timeout); |
1db45f31 EM |
334 | |
335 | return true; | |
a7d5aea1 EM |
336 | } |
337 | ||
a0a218ba | 338 | static inline void |
a389de2a | 339 | delete_dnsbl(struct dnsbl *bl) |
a0a218ba EM |
340 | { |
341 | if (bl->refcount > 0) | |
342 | bl->delete = true; | |
343 | else | |
344 | { | |
a389de2a | 345 | rb_dlinkFindDestroy(bl, &dnsbl_list); |
a0a218ba EM |
346 | rb_free(bl); |
347 | } | |
348 | } | |
349 | ||
350 | static void | |
a389de2a | 351 | delete_all_dnsbls(void) |
a0a218ba EM |
352 | { |
353 | rb_dlink_node *ptr, *nptr; | |
354 | ||
a389de2a | 355 | RB_DLINK_FOREACH_SAFE(ptr, nptr, dnsbl_list.head) |
a0a218ba | 356 | { |
a389de2a | 357 | delete_dnsbl(ptr->data); |
a0a218ba EM |
358 | } |
359 | } | |
360 | ||
add80afd EM |
361 | /* public interfaces */ |
362 | static bool | |
a389de2a | 363 | dnsbls_start(struct auth_client *auth) |
add80afd | 364 | { |
731d1289 | 365 | lrb_assert(get_provider_data(auth, SELF_PID) == NULL); |
add80afd | 366 | |
a389de2a | 367 | if (!rb_dlink_list_length(&dnsbl_list)) { |
add80afd | 368 | /* Nothing to do... */ |
f21ef0ce | 369 | provider_done(auth, SELF_PID); |
add80afd | 370 | return true; |
f21ef0ce | 371 | } |
add80afd | 372 | |
a5f52774 SA |
373 | auth_client_ref(auth); |
374 | ||
a389de2a | 375 | set_provider_data(auth, SELF_PID, rb_malloc(sizeof(struct dnsbl_user))); |
add80afd | 376 | |
bfd95f01 | 377 | if (run_after_provider(auth, "rdns") && run_after_provider(auth, "ident")) { |
731d1289 | 378 | /* Start the lookup if ident and rdns are finished, or not loaded. */ |
a389de2a AC |
379 | if (!lookup_all_dnsbls(auth)) { |
380 | dnsbls_cancel_none(auth); | |
02e46740 EM |
381 | return true; |
382 | } | |
731d1289 | 383 | } |
add80afd | 384 | |
a7d5aea1 EM |
385 | return true; |
386 | } | |
add80afd | 387 | |
6c88869f | 388 | /* This is called every time a provider is completed as long as we are marked not done */ |
a7d5aea1 | 389 | static void |
a389de2a | 390 | dnsbls_initiate(struct auth_client *auth, uint32_t provider) |
a7d5aea1 | 391 | { |
a389de2a | 392 | struct dnsbl_user *bluser = get_provider_data(auth, SELF_PID); |
add80afd | 393 | |
731d1289 EM |
394 | lrb_assert(provider != SELF_PID); |
395 | lrb_assert(!is_provider_done(auth, SELF_PID)); | |
a389de2a | 396 | lrb_assert(rb_dlink_list_length(&dnsbl_list) > 0); |
6c88869f | 397 | |
bfd95f01 | 398 | if (bluser == NULL || bluser->started) { |
a7d5aea1 EM |
399 | /* Nothing to do */ |
400 | return; | |
bfd95f01 SA |
401 | } else if (run_after_provider(auth, "rdns") && run_after_provider(auth, "ident")) { |
402 | /* Start the lookup if ident and rdns are finished, or not loaded. */ | |
a389de2a AC |
403 | if (!lookup_all_dnsbls(auth)) { |
404 | dnsbls_cancel_none(auth); | |
bfd95f01 | 405 | } |
02e46740 | 406 | } |
add80afd EM |
407 | } |
408 | ||
cec81c79 | 409 | static inline void |
a389de2a | 410 | dnsbls_generic_cancel(struct auth_client *auth, const char *message) |
add80afd EM |
411 | { |
412 | rb_dlink_node *ptr, *nptr; | |
a389de2a | 413 | struct dnsbl_user *bluser = get_provider_data(auth, SELF_PID); |
add80afd EM |
414 | |
415 | if(bluser == NULL) | |
416 | return; | |
417 | ||
ccb5c37d | 418 | if(rb_dlink_list_length(&bluser->queries)) |
add80afd | 419 | { |
f16493f4 | 420 | notice_client(auth->cid, message); |
e43e61f7 | 421 | |
72463470 EM |
422 | RB_DLINK_FOREACH_SAFE(ptr, nptr, bluser->queries.head) |
423 | { | |
a389de2a | 424 | struct dnsbl_lookup *bllookup = ptr->data; |
72463470 EM |
425 | |
426 | cancel_query(bllookup->query); | |
a389de2a | 427 | unref_dnsbl(bllookup->bl); |
e43e61f7 | 428 | |
72463470 EM |
429 | rb_dlinkDelete(&bllookup->node, &bluser->queries); |
430 | rb_free(bllookup); | |
431 | } | |
add80afd EM |
432 | } |
433 | ||
434 | rb_free(bluser); | |
731d1289 EM |
435 | set_provider_data(auth, SELF_PID, NULL); |
436 | set_provider_timeout_absolute(auth, SELF_PID, 0); | |
437 | provider_done(auth, SELF_PID); | |
a5f52774 SA |
438 | |
439 | auth_client_unref(auth); | |
add80afd EM |
440 | } |
441 | ||
cec81c79 | 442 | static void |
a389de2a | 443 | dnsbls_timeout(struct auth_client *auth) |
cec81c79 | 444 | { |
e658268b | 445 | dnsbls_generic_cancel(auth, "*** No response from DNSBLs"); |
cec81c79 EM |
446 | } |
447 | ||
f16493f4 | 448 | static void |
a389de2a | 449 | dnsbls_cancel(struct auth_client *auth) |
f16493f4 | 450 | { |
e658268b | 451 | dnsbls_generic_cancel(auth, "*** Aborting DNSBL checks"); |
f16493f4 EM |
452 | } |
453 | ||
454 | static void | |
a389de2a | 455 | dnsbls_cancel_none(struct auth_client *auth) |
f16493f4 | 456 | { |
e658268b | 457 | dnsbls_generic_cancel(auth, "*** Could not check DNSBLs"); |
f16493f4 EM |
458 | } |
459 | ||
add80afd | 460 | static void |
a389de2a | 461 | dnsbls_destroy(void) |
add80afd | 462 | { |
a71b65b1 AC |
463 | rb_dictionary_iter iter; |
464 | struct auth_client *auth; | |
add80afd | 465 | |
a71b65b1 | 466 | RB_DICTIONARY_FOREACH(auth, &iter, auth_clients) |
add80afd | 467 | { |
a389de2a | 468 | dnsbls_cancel(auth); |
a5f52774 | 469 | /* auth is now invalid as we have no reference */ |
add80afd EM |
470 | } |
471 | ||
a389de2a | 472 | delete_all_dnsbls(); |
add80afd EM |
473 | } |
474 | ||
3f2695ac | 475 | static void |
a389de2a | 476 | add_conf_dnsbl(const char *key, int parc, const char **parv) |
3f2695ac | 477 | { |
f5586c3a | 478 | rb_dlink_list filters = { NULL, NULL, 0 }; |
3f2695ac | 479 | char *tmp, *elemlist = rb_strdup(parv[2]); |
eccc44ed | 480 | uint8_t iptype; |
3f2695ac | 481 | |
f5586c3a EM |
482 | if(*elemlist == '*') |
483 | goto end; | |
484 | ||
3f2695ac EM |
485 | for(char *elem = rb_strtok_r(elemlist, ",", &tmp); elem; elem = rb_strtok_r(NULL, ",", &tmp)) |
486 | { | |
a389de2a | 487 | struct dnsbl_filter *filter = rb_malloc(sizeof(struct dnsbl_filter)); |
3f2695ac EM |
488 | int dot_c = 0; |
489 | filter_t type = FILTER_LAST; | |
3f2695ac | 490 | |
a389de2a | 491 | /* Check dnsbl filter type and for validity */ |
3f2695ac EM |
492 | for(char *c = elem; *c != '\0'; c++) |
493 | { | |
494 | if(*c == '.') | |
495 | { | |
496 | if(++dot_c > 3) | |
497 | { | |
a389de2a | 498 | warn_opers(L_CRIT, "dnsbl: addr_conf_dnsbl got a bad filter (too many octets)"); |
34b96d7f | 499 | exit(EX_PROVIDER_ERROR); |
3f2695ac EM |
500 | } |
501 | ||
502 | type = FILTER_ALL; | |
503 | } | |
504 | else if(!isdigit(*c)) | |
505 | { | |
a389de2a | 506 | warn_opers(L_CRIT, "dnsbl: addr_conf_dnsbl got a bad filter (invalid character in dnsbl filter: %c)", |
34b96d7f EM |
507 | *c); |
508 | exit(EX_PROVIDER_ERROR); | |
3f2695ac EM |
509 | } |
510 | } | |
511 | ||
34b96d7f | 512 | if(dot_c > 0 && dot_c < 3) |
3f2695ac | 513 | { |
a389de2a | 514 | warn_opers(L_CRIT, "dnsbl: addr_conf_dnsbl got a bad filter (insufficient octets)"); |
34b96d7f | 515 | exit(EX_PROVIDER_ERROR); |
3f2695ac EM |
516 | } |
517 | ||
518 | filter->type = type; | |
519 | rb_strlcpy(filter->filter, elem, sizeof(filter->filter)); | |
520 | rb_dlinkAdd(filter, &filter->node, &filters); | |
521 | } | |
522 | ||
f5586c3a | 523 | end: |
3f2695ac EM |
524 | rb_free(elemlist); |
525 | ||
526 | iptype = atoi(parv[1]) & 0x3; | |
a389de2a | 527 | if(new_dnsbl(parv[0], parv[3], iptype, &filters) == NULL) |
3f2695ac | 528 | { |
a389de2a | 529 | warn_opers(L_CRIT, "dnsbl: addr_conf_dnsbl got a malformed dnsbl"); |
34b96d7f | 530 | exit(EX_PROVIDER_ERROR); |
3f2695ac EM |
531 | } |
532 | } | |
533 | ||
a0a218ba | 534 | static void |
a389de2a | 535 | del_conf_dnsbl(const char *key, int parc, const char **parv) |
a0a218ba | 536 | { |
a389de2a | 537 | struct dnsbl *bl = find_dnsbl(parv[0]); |
a0a218ba EM |
538 | if(bl == NULL) |
539 | { | |
34b96d7f | 540 | /* Not fatal for now... */ |
a389de2a | 541 | warn_opers(L_WARN, "dnsbl: tried to remove nonexistent dnsbl %s", parv[0]); |
a0a218ba EM |
542 | return; |
543 | } | |
544 | ||
a389de2a | 545 | delete_dnsbl(bl); |
a0a218ba EM |
546 | } |
547 | ||
548 | static void | |
a389de2a | 549 | del_conf_dnsbl_all(const char *key, int parc, const char **parv) |
a0a218ba | 550 | { |
a389de2a | 551 | delete_all_dnsbls(); |
a0a218ba EM |
552 | } |
553 | ||
3f2695ac | 554 | static void |
a389de2a | 555 | add_conf_dnsbl_timeout(const char *key, int parc, const char **parv) |
3f2695ac EM |
556 | { |
557 | int timeout = atoi(parv[0]); | |
558 | ||
559 | if(timeout < 0) | |
560 | { | |
a389de2a | 561 | warn_opers(L_CRIT, "dnsbl: dnsbl timeout < 0 (value: %d)", timeout); |
34b96d7f | 562 | exit(EX_PROVIDER_ERROR); |
3f2695ac EM |
563 | } |
564 | ||
a389de2a | 565 | dnsbl_timeout = timeout; |
3f2695ac EM |
566 | } |
567 | ||
1bebedd6 | 568 | #if 0 |
a90465f7 | 569 | static void |
a389de2a | 570 | dnsbl_stats(uint32_t rid, char letter) |
a90465f7 EM |
571 | { |
572 | rb_dlink_node *ptr; | |
573 | ||
a389de2a | 574 | RB_DLINK_FOREACH(ptr, dnsbl_list.head) |
a90465f7 | 575 | { |
a389de2a | 576 | struct dnsbl *bl = ptr->data; |
a90465f7 EM |
577 | |
578 | if(bl->delete) | |
579 | continue; | |
580 | ||
581 | stats_result(rid, letter, "%s %hhu %u", bl->host, bl->iptype, bl->hits); | |
582 | } | |
583 | ||
584 | stats_done(rid, letter); | |
585 | } | |
1bebedd6 | 586 | #endif |
a90465f7 | 587 | |
a389de2a | 588 | struct auth_opts_handler dnsbl_options[] = |
3f2695ac | 589 | { |
a389de2a AC |
590 | { "rbl", 4, add_conf_dnsbl }, |
591 | { "rbl_del", 1, del_conf_dnsbl }, | |
592 | { "rbl_del_all", 0, del_conf_dnsbl_all }, | |
593 | { "rbl_timeout", 1, add_conf_dnsbl_timeout }, | |
3f2695ac EM |
594 | { NULL, 0, NULL }, |
595 | }; | |
596 | ||
a389de2a | 597 | struct auth_provider dnsbl_provider = |
add80afd | 598 | { |
a389de2a | 599 | .name = "dnsbl", |
731d1289 | 600 | .letter = 'B', |
a389de2a AC |
601 | .destroy = dnsbls_destroy, |
602 | .start = dnsbls_start, | |
603 | .cancel = dnsbls_cancel, | |
604 | .timeout = dnsbls_timeout, | |
605 | .completed = dnsbls_initiate, | |
606 | .opt_handlers = dnsbl_options, | |
607 | /* .stats_handler = { 'B', dnsbl_stats }, */ | |
add80afd | 608 | }; |