]>
Commit | Line | Data |
---|---|---|
add80afd EM |
1 | /* |
2 | * charybdis: A slightly useful ircd. | |
3 | * blacklist.c: Manages DNS blacklist entries and lookups | |
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 | ||
34 | /* Originally written for charybdis circa 2006 (by nenolod?). | |
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 | ||
731d1289 EM |
47 | #define SELF_PID (blacklist_provider.id) |
48 | ||
add80afd EM |
49 | typedef enum filter_t |
50 | { | |
51 | FILTER_ALL = 1, | |
52 | FILTER_LAST = 2, | |
53 | } filter_t; | |
54 | ||
55 | /* Blacklist accepted IP types */ | |
56 | #define IPTYPE_IPV4 1 | |
57 | #define IPTYPE_IPV6 2 | |
58 | ||
59 | /* A configured DNSBL */ | |
60 | struct blacklist | |
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 */ | |
68 | int refcount; /* When 0 and delete is set, remove this blacklist */ | |
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 */ | |
75 | struct blacklist_lookup | |
76 | { | |
77 | struct blacklist *bl; /* Blacklist we're checking */ | |
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 | ||
84 | /* A blacklist filter */ | |
85 | struct blacklist_filter | |
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 | ||
93 | /* Blacklist user data attached to auth_client instance */ | |
94 | struct blacklist_user | |
95 | { | |
bfd95f01 | 96 | bool started; |
add80afd | 97 | rb_dlink_list queries; /* Blacklist queries in flight */ |
add80afd EM |
98 | }; |
99 | ||
100 | /* public interfaces */ | |
add80afd EM |
101 | static void blacklists_destroy(void); |
102 | ||
103 | static bool blacklists_start(struct auth_client *); | |
8b0392ca | 104 | static inline void blacklists_generic_cancel(struct auth_client *, const char *); |
02e46740 | 105 | static void blacklists_timeout(struct auth_client *); |
add80afd | 106 | static void blacklists_cancel(struct auth_client *); |
cec81c79 | 107 | static void blacklists_cancel_none(struct auth_client *); |
add80afd EM |
108 | |
109 | /* private interfaces */ | |
110 | static void unref_blacklist(struct blacklist *); | |
eccc44ed | 111 | static struct blacklist *new_blacklist(const char *, const char *, uint8_t, rb_dlink_list *); |
3f2695ac | 112 | static struct blacklist *find_blacklist(const char *); |
add80afd EM |
113 | static bool blacklist_check_reply(struct blacklist_lookup *, const char *); |
114 | static void blacklist_dns_callback(const char *, bool, query_type, void *); | |
115 | static void initiate_blacklist_dnsquery(struct blacklist *, struct auth_client *); | |
add80afd EM |
116 | |
117 | /* Variables */ | |
118 | static rb_dlink_list blacklist_list = { NULL, NULL, 0 }; | |
9057170c | 119 | static int blacklist_timeout = BLACKLIST_TIMEOUT_DEFAULT; |
add80afd EM |
120 | |
121 | /* private interfaces */ | |
122 | ||
123 | static void | |
124 | unref_blacklist(struct blacklist *bl) | |
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 | ||
137 | rb_dlinkFindDestroy(bl, &blacklist_list); | |
138 | rb_free(bl); | |
139 | } | |
140 | } | |
141 | ||
142 | static struct blacklist * | |
eccc44ed | 143 | new_blacklist(const char *name, const char *reason, uint8_t iptype, rb_dlink_list *filters) |
add80afd EM |
144 | { |
145 | struct blacklist *bl; | |
146 | ||
3f2695ac | 147 | if (name == NULL || reason == NULL || iptype == 0) |
add80afd EM |
148 | return NULL; |
149 | ||
150 | if((bl = find_blacklist(name)) == NULL) | |
151 | { | |
152 | bl = rb_malloc(sizeof(struct blacklist)); | |
153 | rb_dlinkAddAlloc(bl, &blacklist_list); | |
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 | ||
169 | static struct blacklist * | |
3f2695ac | 170 | find_blacklist(const char *name) |
add80afd EM |
171 | { |
172 | rb_dlink_node *ptr; | |
173 | ||
174 | RB_DLINK_FOREACH(ptr, blacklist_list.head) | |
175 | { | |
176 | struct blacklist *bl = (struct blacklist *)ptr->data; | |
177 | ||
178 | if (!strcasecmp(bl->host, name)) | |
179 | return bl; | |
180 | } | |
181 | ||
182 | return NULL; | |
183 | } | |
184 | ||
185 | static inline bool | |
186 | blacklist_check_reply(struct blacklist_lookup *bllookup, const char *ipaddr) | |
187 | { | |
188 | struct blacklist *bl = bllookup->bl; | |
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 | { | |
202 | struct blacklist_filter *filter = ptr->data; | |
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 | { | |
34b96d7f | 211 | warn_opers(L_CRIT, "Blacklist: Unknown blacklist 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 | { | |
225 | warn_opers(L_WARN, "Garbage/undecipherable reply received from blacklist %s (reply %s)", | |
226 | bl->host, ipaddr); | |
227 | bl->lastwarning = rb_current_time(); | |
228 | } | |
72463470 | 229 | |
add80afd EM |
230 | return false; |
231 | } | |
232 | ||
233 | static void | |
234 | blacklist_dns_callback(const char *result, bool status, query_type type, void *data) | |
235 | { | |
236 | struct blacklist_lookup *bllookup = (struct blacklist_lookup *)data; | |
237 | struct blacklist_user *bluser; | |
e43e61f7 | 238 | struct blacklist *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 | ||
250 | if (result != NULL && status && blacklist_check_reply(bllookup, result)) | |
251 | { | |
252 | /* Match found, so proceed no further */ | |
a90465f7 | 253 | bl->hits++; |
731d1289 | 254 | reject_client(auth, SELF_PID, bl->host, bl->reason); |
7c003d84 | 255 | blacklists_cancel(auth); |
add80afd EM |
256 | return; |
257 | } | |
258 | ||
e43e61f7 EM |
259 | unref_blacklist(bl); |
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 */ | |
72463470 | 267 | notice_client(auth->cid, "*** IP not found in DNS blacklist%s", |
3257f9d6 | 268 | rb_dlink_list_length(&blacklist_list) > 1 ? "s" : ""); |
add80afd | 269 | rb_free(bluser); |
731d1289 EM |
270 | set_provider_data(auth, SELF_PID, NULL); |
271 | set_provider_timeout_absolute(auth, SELF_PID, 0); | |
272 | provider_done(auth, SELF_PID); | |
a5f52774 SA |
273 | |
274 | auth_client_unref(auth); | |
add80afd EM |
275 | } |
276 | } | |
277 | ||
278 | static void | |
279 | initiate_blacklist_dnsquery(struct blacklist *bl, struct auth_client *auth) | |
280 | { | |
281 | struct blacklist_lookup *bllookup = rb_malloc(sizeof(struct blacklist_lookup)); | |
731d1289 | 282 | struct blacklist_user *bluser = get_provider_data(auth, SELF_PID); |
add80afd EM |
283 | char buf[IRCD_RES_HOSTLEN + 1]; |
284 | int aftype; | |
285 | ||
286 | bllookup->bl = bl; | |
287 | bllookup->auth = auth; | |
288 | ||
289 | aftype = GET_SS_FAMILY(&auth->c_addr); | |
290 | if((aftype == AF_INET && (bl->iptype & IPTYPE_IPV4) == 0) || | |
291 | (aftype == AF_INET6 && (bl->iptype & IPTYPE_IPV6) == 0)) | |
292 | /* Incorrect blacklist type for this IP... */ | |
e78a87f3 EM |
293 | { |
294 | rb_free(bllookup); | |
add80afd | 295 | return; |
e78a87f3 | 296 | } |
add80afd EM |
297 | |
298 | build_rdns(buf, sizeof(buf), &auth->c_addr, bl->host); | |
add80afd EM |
299 | bllookup->query = lookup_ip(buf, AF_INET, blacklist_dns_callback, bllookup); |
300 | ||
301 | rb_dlinkAdd(bllookup, &bllookup->node, &bluser->queries); | |
302 | bl->refcount++; | |
303 | } | |
304 | ||
02e46740 | 305 | static inline bool |
a7d5aea1 EM |
306 | lookup_all_blacklists(struct auth_client *auth) |
307 | { | |
731d1289 | 308 | struct blacklist_user *bluser = get_provider_data(auth, SELF_PID); |
a7d5aea1 | 309 | rb_dlink_node *ptr; |
02e46740 EM |
310 | int iptype; |
311 | ||
312 | if(GET_SS_FAMILY(&auth->c_addr) == AF_INET) | |
8b0392ca | 313 | iptype = IPTYPE_IPV4; |
02e46740 EM |
314 | else if(GET_SS_FAMILY(&auth->c_addr) == AF_INET6) |
315 | iptype = IPTYPE_IPV6; | |
02e46740 EM |
316 | else |
317 | return false; | |
318 | ||
bfd95f01 | 319 | bluser->started = true; |
72463470 | 320 | notice_client(auth->cid, "*** Checking your IP against DNS blacklist%s", |
ccb5c37d | 321 | rb_dlink_list_length(&blacklist_list) > 1 ? "s" : ""); |
72463470 | 322 | |
a7d5aea1 EM |
323 | RB_DLINK_FOREACH(ptr, blacklist_list.head) |
324 | { | |
325 | struct blacklist *bl = (struct blacklist *)ptr->data; | |
326 | ||
c47e4958 | 327 | if (!bl->delete && (bl->iptype & iptype)) |
a7d5aea1 EM |
328 | initiate_blacklist_dnsquery(bl, auth); |
329 | } | |
330 | ||
02e46740 EM |
331 | if(!rb_dlink_list_length(&bluser->queries)) |
332 | /* None checked. */ | |
333 | return false; | |
334 | ||
731d1289 | 335 | set_provider_timeout_relative(auth, SELF_PID, blacklist_timeout); |
1db45f31 EM |
336 | |
337 | return true; | |
a7d5aea1 EM |
338 | } |
339 | ||
a0a218ba EM |
340 | static inline void |
341 | delete_blacklist(struct blacklist *bl) | |
342 | { | |
343 | if (bl->refcount > 0) | |
344 | bl->delete = true; | |
345 | else | |
346 | { | |
347 | rb_dlinkFindDestroy(bl, &blacklist_list); | |
348 | rb_free(bl); | |
349 | } | |
350 | } | |
351 | ||
352 | static void | |
353 | delete_all_blacklists(void) | |
354 | { | |
355 | rb_dlink_node *ptr, *nptr; | |
356 | ||
357 | RB_DLINK_FOREACH_SAFE(ptr, nptr, blacklist_list.head) | |
358 | { | |
359 | delete_blacklist(ptr->data); | |
360 | } | |
361 | } | |
362 | ||
add80afd EM |
363 | /* public interfaces */ |
364 | static bool | |
365 | blacklists_start(struct auth_client *auth) | |
366 | { | |
731d1289 | 367 | lrb_assert(get_provider_data(auth, SELF_PID) == NULL); |
add80afd | 368 | |
bfd95f01 | 369 | if (!rb_dlink_list_length(&blacklist_list)) { |
add80afd | 370 | /* Nothing to do... */ |
f21ef0ce | 371 | provider_done(auth, SELF_PID); |
add80afd | 372 | return true; |
f21ef0ce | 373 | } |
add80afd | 374 | |
a5f52774 SA |
375 | auth_client_ref(auth); |
376 | ||
731d1289 | 377 | set_provider_data(auth, SELF_PID, rb_malloc(sizeof(struct blacklist_user))); |
add80afd | 378 | |
bfd95f01 | 379 | if (run_after_provider(auth, "rdns") && run_after_provider(auth, "ident")) { |
731d1289 | 380 | /* Start the lookup if ident and rdns are finished, or not loaded. */ |
bfd95f01 | 381 | if (!lookup_all_blacklists(auth)) { |
cec81c79 | 382 | blacklists_cancel_none(auth); |
02e46740 EM |
383 | return true; |
384 | } | |
731d1289 | 385 | } |
add80afd | 386 | |
a7d5aea1 EM |
387 | return true; |
388 | } | |
add80afd | 389 | |
6c88869f | 390 | /* This is called every time a provider is completed as long as we are marked not done */ |
a7d5aea1 | 391 | static void |
731d1289 | 392 | blacklists_initiate(struct auth_client *auth, uint32_t provider) |
a7d5aea1 | 393 | { |
731d1289 | 394 | struct blacklist_user *bluser = get_provider_data(auth, SELF_PID); |
add80afd | 395 | |
731d1289 EM |
396 | lrb_assert(provider != SELF_PID); |
397 | lrb_assert(!is_provider_done(auth, SELF_PID)); | |
6c88869f EM |
398 | lrb_assert(rb_dlink_list_length(&blacklist_list) > 0); |
399 | ||
bfd95f01 | 400 | if (bluser == NULL || bluser->started) { |
a7d5aea1 EM |
401 | /* Nothing to do */ |
402 | return; | |
bfd95f01 SA |
403 | } else if (run_after_provider(auth, "rdns") && run_after_provider(auth, "ident")) { |
404 | /* Start the lookup if ident and rdns are finished, or not loaded. */ | |
405 | if (!lookup_all_blacklists(auth)) { | |
cec81c79 | 406 | blacklists_cancel_none(auth); |
bfd95f01 | 407 | } |
02e46740 | 408 | } |
add80afd EM |
409 | } |
410 | ||
cec81c79 | 411 | static inline void |
f16493f4 | 412 | blacklists_generic_cancel(struct auth_client *auth, const char *message) |
add80afd EM |
413 | { |
414 | rb_dlink_node *ptr, *nptr; | |
731d1289 | 415 | struct blacklist_user *bluser = get_provider_data(auth, SELF_PID); |
add80afd EM |
416 | |
417 | if(bluser == NULL) | |
418 | return; | |
419 | ||
ccb5c37d | 420 | if(rb_dlink_list_length(&bluser->queries)) |
add80afd | 421 | { |
f16493f4 | 422 | notice_client(auth->cid, message); |
e43e61f7 | 423 | |
72463470 EM |
424 | RB_DLINK_FOREACH_SAFE(ptr, nptr, bluser->queries.head) |
425 | { | |
426 | struct blacklist_lookup *bllookup = ptr->data; | |
427 | ||
428 | cancel_query(bllookup->query); | |
429 | unref_blacklist(bllookup->bl); | |
e43e61f7 | 430 | |
72463470 EM |
431 | rb_dlinkDelete(&bllookup->node, &bluser->queries); |
432 | rb_free(bllookup); | |
433 | } | |
add80afd EM |
434 | } |
435 | ||
436 | rb_free(bluser); | |
731d1289 EM |
437 | set_provider_data(auth, SELF_PID, NULL); |
438 | set_provider_timeout_absolute(auth, SELF_PID, 0); | |
439 | provider_done(auth, SELF_PID); | |
a5f52774 SA |
440 | |
441 | auth_client_unref(auth); | |
add80afd EM |
442 | } |
443 | ||
cec81c79 EM |
444 | static void |
445 | blacklists_timeout(struct auth_client *auth) | |
446 | { | |
447 | blacklists_generic_cancel(auth, "*** No response from DNS blacklists"); | |
448 | } | |
449 | ||
f16493f4 EM |
450 | static void |
451 | blacklists_cancel(struct auth_client *auth) | |
452 | { | |
453 | blacklists_generic_cancel(auth, "*** Aborting DNS blacklist checks"); | |
454 | } | |
455 | ||
456 | static void | |
cec81c79 | 457 | blacklists_cancel_none(struct auth_client *auth) |
f16493f4 | 458 | { |
cec81c79 | 459 | blacklists_generic_cancel(auth, "*** Could not check DNS blacklists"); |
f16493f4 EM |
460 | } |
461 | ||
add80afd EM |
462 | static void |
463 | blacklists_destroy(void) | |
464 | { | |
a71b65b1 AC |
465 | rb_dictionary_iter iter; |
466 | struct auth_client *auth; | |
add80afd | 467 | |
a71b65b1 | 468 | RB_DICTIONARY_FOREACH(auth, &iter, auth_clients) |
add80afd EM |
469 | { |
470 | blacklists_cancel(auth); | |
a5f52774 | 471 | /* auth is now invalid as we have no reference */ |
add80afd EM |
472 | } |
473 | ||
a0a218ba | 474 | delete_all_blacklists(); |
add80afd EM |
475 | } |
476 | ||
3f2695ac EM |
477 | static void |
478 | add_conf_blacklist(const char *key, int parc, const char **parv) | |
479 | { | |
f5586c3a | 480 | rb_dlink_list filters = { NULL, NULL, 0 }; |
3f2695ac | 481 | char *tmp, *elemlist = rb_strdup(parv[2]); |
eccc44ed | 482 | uint8_t iptype; |
3f2695ac | 483 | |
f5586c3a EM |
484 | if(*elemlist == '*') |
485 | goto end; | |
486 | ||
3f2695ac EM |
487 | for(char *elem = rb_strtok_r(elemlist, ",", &tmp); elem; elem = rb_strtok_r(NULL, ",", &tmp)) |
488 | { | |
489 | struct blacklist_filter *filter = rb_malloc(sizeof(struct blacklist_filter)); | |
490 | int dot_c = 0; | |
491 | filter_t type = FILTER_LAST; | |
3f2695ac EM |
492 | |
493 | /* Check blacklist filter type and for validity */ | |
494 | for(char *c = elem; *c != '\0'; c++) | |
495 | { | |
496 | if(*c == '.') | |
497 | { | |
498 | if(++dot_c > 3) | |
499 | { | |
34b96d7f EM |
500 | warn_opers(L_CRIT, "Blacklist: addr_conf_blacklist got a bad filter (too many octets)"); |
501 | exit(EX_PROVIDER_ERROR); | |
3f2695ac EM |
502 | } |
503 | ||
504 | type = FILTER_ALL; | |
505 | } | |
506 | else if(!isdigit(*c)) | |
507 | { | |
34b96d7f EM |
508 | warn_opers(L_CRIT, "Blacklist: addr_conf_blacklist got a bad filter (invalid character in blacklist filter: %c)", |
509 | *c); | |
510 | exit(EX_PROVIDER_ERROR); | |
3f2695ac EM |
511 | } |
512 | } | |
513 | ||
34b96d7f | 514 | if(dot_c > 0 && dot_c < 3) |
3f2695ac | 515 | { |
34b96d7f EM |
516 | warn_opers(L_CRIT, "Blacklist: addr_conf_blacklist got a bad filter (insufficient octets)"); |
517 | exit(EX_PROVIDER_ERROR); | |
3f2695ac EM |
518 | } |
519 | ||
520 | filter->type = type; | |
521 | rb_strlcpy(filter->filter, elem, sizeof(filter->filter)); | |
522 | rb_dlinkAdd(filter, &filter->node, &filters); | |
523 | } | |
524 | ||
f5586c3a | 525 | end: |
3f2695ac EM |
526 | rb_free(elemlist); |
527 | ||
528 | iptype = atoi(parv[1]) & 0x3; | |
529 | if(new_blacklist(parv[0], parv[3], iptype, &filters) == NULL) | |
530 | { | |
34b96d7f EM |
531 | warn_opers(L_CRIT, "Blacklist: addr_conf_blacklist got a malformed blacklist"); |
532 | exit(EX_PROVIDER_ERROR); | |
3f2695ac EM |
533 | } |
534 | } | |
535 | ||
a0a218ba EM |
536 | static void |
537 | del_conf_blacklist(const char *key, int parc, const char **parv) | |
538 | { | |
539 | struct blacklist *bl = find_blacklist(parv[0]); | |
540 | if(bl == NULL) | |
541 | { | |
34b96d7f EM |
542 | /* Not fatal for now... */ |
543 | warn_opers(L_WARN, "Blacklist: tried to remove nonexistent blacklist %s", parv[0]); | |
a0a218ba EM |
544 | return; |
545 | } | |
546 | ||
547 | delete_blacklist(bl); | |
548 | } | |
549 | ||
550 | static void | |
551 | del_conf_blacklist_all(const char *key, int parc, const char **parv) | |
552 | { | |
553 | delete_all_blacklists(); | |
554 | } | |
555 | ||
3f2695ac EM |
556 | static void |
557 | add_conf_blacklist_timeout(const char *key, int parc, const char **parv) | |
558 | { | |
559 | int timeout = atoi(parv[0]); | |
560 | ||
561 | if(timeout < 0) | |
562 | { | |
34b96d7f EM |
563 | warn_opers(L_CRIT, "Blacklist: blacklist timeout < 0 (value: %d)", timeout); |
564 | exit(EX_PROVIDER_ERROR); | |
3f2695ac EM |
565 | } |
566 | ||
567 | blacklist_timeout = timeout; | |
568 | } | |
569 | ||
1bebedd6 | 570 | #if 0 |
a90465f7 EM |
571 | static void |
572 | blacklist_stats(uint32_t rid, char letter) | |
573 | { | |
574 | rb_dlink_node *ptr; | |
575 | ||
576 | RB_DLINK_FOREACH(ptr, blacklist_list.head) | |
577 | { | |
578 | struct blacklist *bl = ptr->data; | |
579 | ||
580 | if(bl->delete) | |
581 | continue; | |
582 | ||
583 | stats_result(rid, letter, "%s %hhu %u", bl->host, bl->iptype, bl->hits); | |
584 | } | |
585 | ||
586 | stats_done(rid, letter); | |
587 | } | |
1bebedd6 | 588 | #endif |
a90465f7 | 589 | |
3f2695ac EM |
590 | struct auth_opts_handler blacklist_options[] = |
591 | { | |
592 | { "rbl", 4, add_conf_blacklist }, | |
a0a218ba EM |
593 | { "rbl_del", 1, del_conf_blacklist }, |
594 | { "rbl_del_all", 0, del_conf_blacklist_all }, | |
3f2695ac EM |
595 | { "rbl_timeout", 1, add_conf_blacklist_timeout }, |
596 | { NULL, 0, NULL }, | |
597 | }; | |
598 | ||
add80afd EM |
599 | struct auth_provider blacklist_provider = |
600 | { | |
731d1289 EM |
601 | .name = "blacklist", |
602 | .letter = 'B', | |
add80afd EM |
603 | .destroy = blacklists_destroy, |
604 | .start = blacklists_start, | |
605 | .cancel = blacklists_cancel, | |
f16493f4 | 606 | .timeout = blacklists_timeout, |
a7d5aea1 | 607 | .completed = blacklists_initiate, |
3f2695ac | 608 | .opt_handlers = blacklist_options, |
1bebedd6 | 609 | /* .stats_handler = { 'B', blacklist_stats }, */ |
add80afd | 610 | }; |