2 * charybdis: A slightly useful ircd.
3 * blacklist.c: Manages DNS blacklist entries and lookups
5 * Copyright (C) 2006-2011 charybdis development team
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
11 * 1. Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
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.
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.
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.
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
51 /* Blacklist accepted IP types */
55 /* A configured DNSBL */
58 char host
[IRCD_RES_HOSTLEN
+ 1];
59 char reason
[BUFSIZE
]; /* Reason template (ircd fills in the blanks) */
60 unsigned char iptype
; /* IP types supported */
61 rb_dlink_list filters
; /* Filters for queries */
63 bool delete; /* If true delete when no clients */
64 int refcount
; /* When 0 and delete is set, remove this blacklist */
66 time_t lastwarning
; /* Last warning about garbage replies sent */
69 /* A lookup in progress for a particular DNSBL for a particular client */
70 struct blacklist_lookup
72 struct blacklist
*bl
; /* Blacklist we're checking */
73 struct auth_client
*auth
; /* Client */
74 struct dns_query
*query
; /* DNS query pointer */
79 /* A blacklist filter */
80 struct blacklist_filter
82 filter_t type
; /* Type of filter */
83 char filterstr
[HOSTIPLEN
]; /* The filter itself */
88 /* Blacklist user data attached to auth_client instance */
91 rb_dlink_list queries
; /* Blacklist queries in flight */
92 time_t timeout
; /* When this times out */
95 /* public interfaces */
96 static bool blacklists_init(void);
97 static void blacklists_destroy(void);
99 static bool blacklists_start(struct auth_client
*);
100 static void blacklists_cancel(struct auth_client
*);
102 /* private interfaces */
103 static void unref_blacklist(struct blacklist
*);
104 static struct blacklist
*new_blacklist(char *, char *, bool, bool, rb_dlink_list
*);
105 static struct blacklist
*find_blacklist(char *);
106 static bool blacklist_check_reply(struct blacklist_lookup
*, const char *);
107 static void blacklist_dns_callback(const char *, bool, query_type
, void *);
108 static void initiate_blacklist_dnsquery(struct blacklist
*, struct auth_client
*);
109 static void timeout_blacklist_queries_event(void *);
112 static rb_dlink_list blacklist_list
= { NULL
, NULL
, 0 };
113 static struct ev_entry
*timeout_ev
;
114 static EVH timeout_blacklists
;
115 static int blacklist_timeout
= 15;
117 /* private interfaces */
120 unref_blacklist(struct blacklist
*bl
)
122 rb_dlink_node
*ptr
, *nptr
;
125 if (bl
->delete && bl
->refcount
<= 0)
127 RB_DLINK_FOREACH_SAFE(ptr
, nptr
, bl
->filters
.head
)
129 rb_dlinkDelete(ptr
, &bl
->filters
);
133 rb_dlinkFindDestroy(bl
, &blacklist_list
);
138 static struct blacklist
*
139 new_blacklist(char *name
, char *reason
, bool ipv4
, bool ipv6
, rb_dlink_list
*filters
)
141 struct blacklist
*bl
;
143 if (name
== NULL
|| reason
== NULL
|| !(ipv4
|| ipv6
))
146 if((bl
= find_blacklist(name
)) == NULL
)
148 bl
= rb_malloc(sizeof(struct blacklist
));
149 rb_dlinkAddAlloc(bl
, &blacklist_list
);
154 rb_strlcpy(bl
->host
, name
, IRCD_RES_HOSTLEN
+ 1);
155 rb_strlcpy(bl
->reason
, reason
, BUFSIZE
);
157 bl
->iptype
|= IPTYPE_IPV4
;
159 bl
->iptype
|= IPTYPE_IPV6
;
161 rb_dlinkMoveList(filters
, &bl
->filters
);
168 static struct blacklist
*
169 find_blacklist(char *name
)
173 RB_DLINK_FOREACH(ptr
, blacklist_list
.head
)
175 struct blacklist
*bl
= (struct blacklist
*)ptr
->data
;
177 if (!strcasecmp(bl
->host
, name
))
185 blacklist_check_reply(struct blacklist_lookup
*bllookup
, const char *ipaddr
)
187 struct blacklist
*bl
= bllookup
->bl
;
188 const char *lastoctet
;
191 /* No filters and entry found - thus positive match */
192 if (!rb_dlink_list_length(&bl
->filters
))
195 /* Below will prolly have to change if IPv6 address replies are sent back */
196 if ((lastoctet
= strrchr(ipaddr
, '.')) == NULL
|| *(++lastoctet
) == '\0')
199 RB_DLINK_FOREACH(ptr
, bl
->filters
.head
)
201 struct blacklist_filter
*filter
= ptr
->data
;
204 if (filter
->type
== FILTER_ALL
)
206 else if (filter
->type
== FILTER_LAST
)
210 warn_opers(L_CRIT
, "BUG: Unknown blacklist filter type on blacklist %s: %d",
211 bl
->host
, filter
->type
);
215 if (strcmp(cmpstr
, filter
->filterstr
) == 0)
222 if (bl
->lastwarning
+ 3600 < rb_current_time())
224 warn_opers(L_WARN
, "Garbage/undecipherable reply received from blacklist %s (reply %s)",
226 bl
->lastwarning
= rb_current_time();
232 blacklist_dns_callback(const char *result
, bool status
, query_type type
, void *data
)
234 struct blacklist_lookup
*bllookup
= (struct blacklist_lookup
*)data
;
235 struct blacklist_user
*bluser
;
236 struct auth_client
*auth
;
238 if (bllookup
== NULL
|| bllookup
->auth
== NULL
)
241 auth
= bllookup
->auth
;
242 bluser
= auth
->data
[PROVIDER_BLACKLIST
];
246 if (result
!= NULL
&& status
&& blacklist_check_reply(bllookup
, result
))
248 /* Match found, so proceed no further */
249 blacklists_cancel(auth
);
250 reject_client(auth
, PROVIDER_BLACKLIST
, bllookup
->bl
->reason
);
254 unref_blacklist(bllookup
->bl
);
255 rb_dlinkDelete(&bllookup
->node
, &bluser
->queries
);
258 if(!rb_dlink_list_length(&bluser
->queries
))
261 provider_done(auth
, PROVIDER_BLACKLIST
);
263 auth
->data
[PROVIDER_BLACKLIST
] = NULL
;
268 initiate_blacklist_dnsquery(struct blacklist
*bl
, struct auth_client
*auth
)
270 struct blacklist_lookup
*bllookup
= rb_malloc(sizeof(struct blacklist_lookup
));
271 struct blacklist_user
*bluser
= auth
->data
[PROVIDER_BLACKLIST
];
272 char buf
[IRCD_RES_HOSTLEN
+ 1];
276 bllookup
->auth
= auth
;
278 aftype
= GET_SS_FAMILY(&auth
->c_addr
);
279 if((aftype
== AF_INET
&& (bl
->iptype
& IPTYPE_IPV4
) == 0) ||
280 (aftype
== AF_INET6
&& (bl
->iptype
& IPTYPE_IPV6
) == 0))
281 /* Incorrect blacklist type for this IP... */
284 build_rdns(buf
, sizeof(buf
), &auth
->c_addr
, bl
->host
);
286 bllookup
->query
= lookup_ip(buf
, AF_INET
, blacklist_dns_callback
, bllookup
);
288 rb_dlinkAdd(bllookup
, &bllookup
->node
, &bluser
->queries
);
292 /* Timeout outstanding queries */
294 timeout_blacklist_queries_event(void *notused
)
296 struct auth_client
*auth
;
297 rb_dictionary_iter iter
;
299 RB_DICTIONARY_FOREACH(auth
, &iter
, auth_clients
)
301 struct blacklist_user
*bluser
= auth
->data
[PROVIDER_BLACKLIST
];
303 if(bluser
!= NULL
&& bluser
->timeout
< rb_current_time())
305 blacklists_cancel(auth
);
306 provider_done(auth
, PROVIDER_BLACKLIST
);
312 lookup_all_blacklists(struct auth_client
*auth
)
314 struct blacklist_user
*bluser
= auth
->data
[PROVIDER_BLACKLIST
];
317 RB_DLINK_FOREACH(ptr
, blacklist_list
.head
)
319 struct blacklist
*bl
= (struct blacklist
*)ptr
->data
;
322 initiate_blacklist_dnsquery(bl
, auth
);
325 bluser
->timeout
= rb_current_time() + blacklist_timeout
;
328 /* public interfaces */
330 blacklists_start(struct auth_client
*auth
)
332 if(auth
->data
[PROVIDER_BLACKLIST
] != NULL
)
335 if(!rb_dlink_list_length(&blacklist_list
))
336 /* Nothing to do... */
339 auth
->data
[PROVIDER_BLACKLIST
] = rb_malloc(sizeof(struct blacklist_user
));
341 if(is_provider_done(auth
, PROVIDER_RDNS
) && is_provider_done(auth
, PROVIDER_IDENT
))
342 /* This probably can't happen but let's handle this case anyway */
343 lookup_all_blacklists(auth
);
345 set_provider_on(auth
, PROVIDER_BLACKLIST
);
349 /* This is called every time a provider is completed */
351 blacklists_initiate(struct auth_client
*auth
, provider_t provider
)
353 struct blacklist_user
*bluser
= auth
->data
[PROVIDER_BLACKLIST
];
355 if(bluser
== NULL
|| is_provider_done(auth
, PROVIDER_BLACKLIST
) || rb_dlink_list_length(&bluser
->queries
))
358 else if(!is_provider_done(auth
, PROVIDER_RDNS
) && !is_provider_done(auth
, PROVIDER_IDENT
))
359 /* Don't start until we've completed these */
362 lookup_all_blacklists(auth
);
366 blacklists_cancel(struct auth_client
*auth
)
368 rb_dlink_node
*ptr
, *nptr
;
369 struct blacklist_user
*bluser
= auth
->data
[PROVIDER_BLACKLIST
];
374 RB_DLINK_FOREACH_SAFE(ptr
, nptr
, bluser
->queries
.head
)
376 struct blacklist_lookup
*bllookup
= ptr
->data
;
377 rb_dlinkDelete(&bllookup
->node
, &bluser
->queries
);
378 unref_blacklist(bllookup
->bl
);
379 cancel_query(bllookup
->query
);
384 auth
->data
[PROVIDER_BLACKLIST
] = NULL
;
388 blacklists_init(void)
390 timeout_ev
= rb_event_addish("timeout_blacklist_queries_event", timeout_blacklist_queries_event
, NULL
, 1);
391 return (timeout_ev
!= NULL
);
395 blacklists_destroy(void)
397 rb_dlink_node
*ptr
, *nptr
;
398 rb_dictionary_iter iter
;
399 struct blacklist
*bl
;
400 struct auth_client
*auth
;
402 RB_DICTIONARY_FOREACH(auth
, &iter
, auth_clients
)
404 blacklists_cancel(auth
);
407 RB_DLINK_FOREACH_SAFE(ptr
, nptr
, blacklist_list
.head
)
410 if (bl
->refcount
> 0)
415 rb_dlinkDestroy(ptr
, &blacklist_list
);
420 struct auth_provider blacklist_provider
=
422 .id
= PROVIDER_BLACKLIST
,
423 .init
= blacklists_init
,
424 .destroy
= blacklists_destroy
,
425 .start
= blacklists_start
,
426 .cancel
= blacklists_cancel
,
427 .completed
= blacklists_initiate
,