xref: /freebsd/contrib/unbound/ipset/ipset.c (revision 7a789145f88a6aceacc59029a0cafe7de7aeefea)
1 /**
2  * \file
3  * This file implements the ipset module.  It can handle packets by putting
4  * the A and AAAA addresses that are configured in unbound.conf as type
5  * ipset (local-zone statements) into a firewall rule IPSet.  For firewall
6  * blacklist and whitelist usage.
7  */
8 #include "config.h"
9 #include "ipset/ipset.h"
10 #include "util/regional.h"
11 #include "util/net_help.h"
12 #include "util/config_file.h"
13 
14 #include "services/cache/dns.h"
15 
16 #include "sldns/sbuffer.h"
17 #include "sldns/wire2str.h"
18 #include "sldns/parseutil.h"
19 
20 #ifdef HAVE_NET_PFVAR_H
21 #include <fcntl.h>
22 #include <sys/ioctl.h>
23 #include <netinet/in.h>
24 #include <net/if.h>
25 #include <net/pfvar.h>
26 typedef intptr_t filter_dev;
27 #else
28 #include <libmnl/libmnl.h>
29 #include <linux/netfilter/nfnetlink.h>
30 #include <linux/netfilter/ipset/ip_set.h>
31 typedef struct mnl_socket * filter_dev;
32 #endif
33 
34 #define BUFF_LEN 256
35 
36 /**
37  * Return an error
38  * @param qstate: our query state
39  * @param id: module id
40  * @param rcode: error code (DNS errcode).
41  * @return: 0 for use by caller, to make notation easy, like:
42  * 	return error_response(..).
43  */
error_response(struct module_qstate * qstate,int id,int rcode)44 static int error_response(struct module_qstate* qstate, int id, int rcode) {
45 	verbose(VERB_QUERY, "return error response %s",
46 		sldns_lookup_by_id(sldns_rcodes, rcode)?
47 		sldns_lookup_by_id(sldns_rcodes, rcode)->name:"??");
48 	qstate->return_rcode = rcode;
49 	qstate->return_msg = NULL;
50 	qstate->ext_state[id] = module_finished;
51 	return 0;
52 }
53 
54 #ifdef HAVE_NET_PFVAR_H
open_filter()55 static void * open_filter() {
56 	filter_dev dev;
57 
58 	dev = open("/dev/pf", O_RDWR);
59 	if (dev == -1) {
60 		log_err("open(\"/dev/pf\") failed: %s", strerror(errno));
61 		return NULL;
62 	}
63 	else
64 		return (void *)dev;
65 }
66 #else
open_filter()67 static void * open_filter() {
68 	filter_dev dev;
69 
70 	dev = mnl_socket_open(NETLINK_NETFILTER);
71 	if (!dev) {
72 		log_err("ipset: could not open netfilter.");
73 		return NULL;
74 	}
75 
76 	if (mnl_socket_bind(dev, 0, MNL_SOCKET_AUTOPID) < 0) {
77 		mnl_socket_close(dev);
78 		log_err("ipset: could not bind netfilter.");
79 		return NULL;
80 	}
81 	return (void *)dev;
82 }
83 #endif
84 
85 #ifdef HAVE_NET_PFVAR_H
add_to_ipset(filter_dev dev,const char * setname,const void * ipaddr,int af)86 static int add_to_ipset(filter_dev dev, const char *setname, const void *ipaddr, int af) {
87 	struct pfioc_table io;
88 	struct pfr_addr addr;
89 	const char *p;
90 	int i;
91 
92 	bzero(&io, sizeof(io));
93 	bzero(&addr, sizeof(addr));
94 
95 	p = strrchr(setname, '/');
96 	if (p) {
97 		i = p - setname;
98 		if (i >= PATH_MAX) {
99 			errno = ENAMETOOLONG;
100 			return -1;
101 		}
102 		memcpy(io.pfrio_table.pfrt_anchor, setname, i);
103 		if (i < PATH_MAX)
104 			io.pfrio_table.pfrt_anchor[i] = '\0';
105 		p++;
106 	}
107 	else
108 		p = setname;
109 
110 	if (strlen(p) >= PF_TABLE_NAME_SIZE) {
111 		errno = ENAMETOOLONG;
112 		return -1;
113 	}
114 	strlcpy(io.pfrio_table.pfrt_name, p, PF_TABLE_NAME_SIZE);
115 
116 	io.pfrio_buffer = &addr;
117 	io.pfrio_size = 1;
118 	io.pfrio_esize = sizeof(addr);
119 
120 	switch (af) {
121 		case AF_INET:
122 			addr.pfra_ip4addr = *(struct in_addr *)ipaddr;
123 			addr.pfra_net = 32;
124 			break;
125 		case AF_INET6:
126 			addr.pfra_ip6addr = *(struct in6_addr *)ipaddr;
127 			addr.pfra_net = 128;
128 			break;
129 		default:
130 		errno = EAFNOSUPPORT;
131 		return -1;
132 	}
133 	addr.pfra_af = af;
134 
135 	if (ioctl(dev, DIOCRADDADDRS, &io) == -1) {
136 		log_err("ioctl failed: %s", strerror(errno));
137 		return -1;
138 	}
139 	return 0;
140 }
141 #else
add_to_ipset(filter_dev dev,const char * setname,const void * ipaddr,int af)142 static int add_to_ipset(filter_dev dev, const char *setname, const void *ipaddr, int af) {
143 	struct nlmsghdr *nlh;
144 	struct nfgenmsg *nfg;
145 	struct nlattr *nested[2];
146 	char buffer[BUFF_LEN];
147 
148 	if (strlen(setname) >= IPSET_MAXNAMELEN) {
149 		errno = ENAMETOOLONG;
150 		return -1;
151 	}
152 	if (af != AF_INET && af != AF_INET6) {
153 		errno = EAFNOSUPPORT;
154 		return -1;
155 	}
156 
157 	nlh = mnl_nlmsg_put_header(buffer);
158 	nlh->nlmsg_type = IPSET_CMD_ADD | (NFNL_SUBSYS_IPSET << 8);
159 	nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL;
160 
161 	nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
162 	nfg->nfgen_family = af;
163 	nfg->version = NFNETLINK_V0;
164 	nfg->res_id = htons(0);
165 
166 	mnl_attr_put_u8(nlh, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL);
167 	mnl_attr_put(nlh, IPSET_ATTR_SETNAME, strlen(setname) + 1, setname);
168 	nested[0] = mnl_attr_nest_start(nlh, IPSET_ATTR_DATA);
169 	nested[1] = mnl_attr_nest_start(nlh, IPSET_ATTR_IP);
170 	mnl_attr_put(nlh, (af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6)
171 			| NLA_F_NET_BYTEORDER, (af == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr)), ipaddr);
172 	mnl_attr_nest_end(nlh, nested[1]);
173 	mnl_attr_nest_end(nlh, nested[0]);
174 
175 	if (mnl_socket_sendto(dev, nlh, nlh->nlmsg_len) < 0) {
176 		return -1;
177 	}
178 	return 0;
179 }
180 #endif
181 
182 static void
ipset_add_rrset_data(struct ipset_env * ie,struct packed_rrset_data * d,const char * setname,int af,const char * dname)183 ipset_add_rrset_data(struct ipset_env *ie,
184 	struct packed_rrset_data *d, const char* setname, int af,
185 	const char* dname)
186 {
187 	int ret;
188 	size_t j, rr_len, rd_len;
189 	uint8_t *rr_data;
190 
191 	/* to d->count, not d->rrsig_count, because we do not want to add the RRSIGs, only the addresses */
192 	for (j = 0; j < d->count; j++) {
193 		rr_len = d->rr_len[j];
194 		rr_data = d->rr_data[j];
195 
196 		rd_len = sldns_read_uint16(rr_data);
197 		if(af == AF_INET && rd_len != INET_SIZE)
198 			continue;
199 		if(af == AF_INET6 && rd_len != INET6_SIZE)
200 			continue;
201 		if (rr_len - 2 >= rd_len) {
202 			if(verbosity >= VERB_QUERY) {
203 				char ip[128];
204 				if(inet_ntop(af, rr_data+2, ip, (socklen_t)sizeof(ip)) == 0)
205 					snprintf(ip, sizeof(ip), "(inet_ntop_error)");
206 				verbose(VERB_QUERY, "ipset: add %s to %s for %s", ip, setname, dname);
207 			}
208 			ret = add_to_ipset((filter_dev)ie->dev, setname, rr_data + 2, af);
209 			if (ret < 0) {
210 				log_err("ipset: could not add %s into %s", dname, setname);
211 				break;
212 			}
213 		}
214 	}
215 }
216 
217 static int
ipset_check_zones_for_rrset(struct module_env * env,struct ipset_env * ie,struct ub_packed_rrset_key * rrset,const char * qname,int qlen,const char * setname,int af)218 ipset_check_zones_for_rrset(struct module_env *env, struct ipset_env *ie,
219 	struct ub_packed_rrset_key *rrset, const char *qname, int qlen,
220 	const char *setname, int af)
221 {
222 	char dname[LDNS_MAX_DOMAINLEN*4+16];
223 	const char *ds, *qs;
224 	int dlen, plen;
225 
226 	struct config_strlist *p;
227 	struct packed_rrset_data *d;
228 
229 	dlen = sldns_wire2str_dname_buf(rrset->rk.dname, rrset->rk.dname_len, dname, sizeof(dname));
230 	if (dlen == 0 || dlen >= (int)sizeof(dname)) {
231 		log_err("bad domain name");
232 		return -1;
233 	}
234 	if (dname[dlen - 1] == '.') {
235 		dlen--;
236 	}
237 	if (qname[qlen - 1] == '.') {
238 		qlen--;
239 	}
240 
241 	for (p = env->cfg->local_zones_ipset; p; p = p->next) {
242 		ds = NULL;
243 		qs = NULL;
244 		plen = strlen(p->str);
245 		if (p->str[plen - 1] == '.') {
246 			plen--;
247 		}
248 
249 		if (dlen == plen || (dlen > plen && dname[dlen - plen - 1] == '.' )) {
250 			ds = dname + (dlen - plen);
251 		}
252 		if (qlen == plen || (qlen > plen && qname[qlen - plen - 1] == '.' )) {
253 			qs = qname + (qlen - plen);
254 		}
255 		if ((ds && strncasecmp(p->str, ds, plen) == 0)
256 			|| (qs && strncasecmp(p->str, qs, plen) == 0)) {
257 			d = (struct packed_rrset_data*)rrset->entry.data;
258 			ipset_add_rrset_data(ie, d, setname, af, dname);
259 			break;
260 		}
261 	}
262 	return 0;
263 }
264 
ipset_update(struct module_env * env,struct dns_msg * return_msg,struct query_info qinfo,struct ipset_env * ie)265 static int ipset_update(struct module_env *env, struct dns_msg *return_msg,
266 	struct query_info qinfo, struct ipset_env *ie)
267 {
268 	size_t i;
269 	const char *setname;
270 	struct ub_packed_rrset_key *rrset;
271 	int af;
272 	char qname[LDNS_MAX_DOMAINLEN*4+16];
273 	int qlen;
274 
275 #ifdef HAVE_NET_PFVAR_H
276 #else
277 	if (!ie->dev) {
278 		/* retry to create mnl socket */
279 		ie->dev = open_filter();
280 		if (!ie->dev) {
281 			log_warn("ipset open_filter failed");
282 			return -1;
283 		}
284 	}
285 #endif
286 
287 	qlen = sldns_wire2str_dname_buf(qinfo.qname, qinfo.qname_len,
288 		qname, sizeof(qname));
289 	if(qlen == 0 || qlen >= (int)sizeof(qname)) {
290 		log_err("bad domain name");
291 		return -1;
292 	}
293 
294 	for(i = 0; i < return_msg->rep->rrset_count; i++) {
295 		setname = NULL;
296 		rrset = return_msg->rep->rrsets[i];
297 		if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A &&
298 			ie->v4_enabled == 1) {
299 			af = AF_INET;
300 			setname = ie->name_v4;
301 		} else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA &&
302 			ie->v6_enabled == 1) {
303 			af = AF_INET6;
304 			setname = ie->name_v6;
305 		}
306 
307 		if (setname) {
308 			if(ipset_check_zones_for_rrset(env, ie, rrset, qname,
309 				qlen, setname, af) == -1)
310 				return -1;
311 		}
312 	}
313 
314 	return 0;
315 }
316 
ipset_startup(struct module_env * env,int id)317 int ipset_startup(struct module_env* env, int id) {
318 	struct ipset_env *ipset_env;
319 
320 	ipset_env = (struct ipset_env *)calloc(1, sizeof(struct ipset_env));
321 	if (!ipset_env) {
322 		log_err("malloc failure");
323 		return 0;
324 	}
325 
326 	env->modinfo[id] = (void *)ipset_env;
327 
328 #ifdef HAVE_NET_PFVAR_H
329 	ipset_env->dev = open_filter();
330 	if (!ipset_env->dev) {
331 		log_err("ipset open_filter failed");
332 		return 0;
333 	}
334 #else
335 	ipset_env->dev = NULL;
336 #endif
337 	return 1;
338 }
339 
ipset_destartup(struct module_env * env,int id)340 void ipset_destartup(struct module_env* env, int id) {
341 	filter_dev dev;
342 	struct ipset_env *ipset_env;
343 
344 	if (!env || !env->modinfo[id]) {
345 		return;
346 	}
347 	ipset_env = (struct ipset_env*)env->modinfo[id];
348 
349 	dev = (filter_dev)ipset_env->dev;
350 	if (dev) {
351 #if HAVE_NET_PFVAR_H
352 		close(dev);
353 #else
354 		mnl_socket_close(dev);
355 #endif
356 		ipset_env->dev = NULL;
357 	}
358 
359 	free(ipset_env);
360 	env->modinfo[id] = NULL;
361 }
362 
ipset_init(struct module_env * env,int id)363 int ipset_init(struct module_env* env, int id) {
364 	struct ipset_env *ipset_env = env->modinfo[id];
365 
366 	ipset_env->name_v4 = env->cfg->ipset_name_v4;
367 	ipset_env->name_v6 = env->cfg->ipset_name_v6;
368 #ifndef HAVE_NET_PFVAR_H
369 	if (ipset_env->name_v4 && strlen(ipset_env->name_v4) >= IPSET_MAXNAMELEN) {
370 		log_err("ipset: name-v4 exceeds IPSET_MAXNAMELEN (%d)", IPSET_MAXNAMELEN);
371 		return 0;
372 	}
373 	if (ipset_env->name_v6 && strlen(ipset_env->name_v6) >= IPSET_MAXNAMELEN) {
374 		log_err("ipset: name-v6 exceeds IPSET_MAXNAMELEN (%d)", IPSET_MAXNAMELEN);
375 		return 0;
376 	}
377 #endif
378 
379 	ipset_env->v4_enabled = !ipset_env->name_v4 || (strlen(ipset_env->name_v4) == 0) ? 0 : 1;
380 	ipset_env->v6_enabled = !ipset_env->name_v6 || (strlen(ipset_env->name_v6) == 0) ? 0 : 1;
381 
382 	if ((ipset_env->v4_enabled < 1) && (ipset_env->v6_enabled < 1)) {
383 		log_err("ipset: set name no configuration?");
384 		return 0;
385 	}
386 
387 	return 1;
388 }
389 
ipset_deinit(struct module_env * ATTR_UNUSED (env),int ATTR_UNUSED (id))390 void ipset_deinit(struct module_env *ATTR_UNUSED(env), int ATTR_UNUSED(id)) {
391 	/* nothing */
392 }
393 
ipset_new(struct module_qstate * qstate,int id)394 static int ipset_new(struct module_qstate* qstate, int id) {
395 	struct ipset_qstate *iq = (struct ipset_qstate *)regional_alloc(
396 		qstate->region, sizeof(struct ipset_qstate));
397 	qstate->minfo[id] = iq;
398 	if (!iq) {
399 		return 0;
400 	}
401 
402 	memset(iq, 0, sizeof(*iq));
403 	/* initialise it */
404 	/* TODO */
405 
406 	return 1;
407 }
408 
ipset_operate(struct module_qstate * qstate,enum module_ev event,int id,struct outbound_entry * outbound)409 void ipset_operate(struct module_qstate *qstate, enum module_ev event, int id,
410 	struct outbound_entry *outbound) {
411 	struct ipset_env *ie = (struct ipset_env *)qstate->env->modinfo[id];
412 	struct ipset_qstate *iq = (struct ipset_qstate *)qstate->minfo[id];
413 	verbose(VERB_QUERY, "ipset[module %d] operate: extstate:%s event:%s",
414 		id, strextstate(qstate->ext_state[id]), strmodulevent(event));
415 	if (iq) {
416 		log_query_info(VERB_QUERY, "ipset operate: query", &qstate->qinfo);
417 	}
418 
419 	/* perform ipset state machine */
420 	if ((event == module_event_new || event == module_event_pass) && !iq) {
421 		if (!ipset_new(qstate, id)) {
422 			(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
423 			return;
424 		}
425 		iq = (struct ipset_qstate*)qstate->minfo[id];
426 	}
427 
428 	if (iq && (event == module_event_pass || event == module_event_new)) {
429 		qstate->ext_state[id] = module_wait_module;
430 		return;
431 	}
432 
433 	if (iq && (event == module_event_moddone)) {
434 		if (qstate->return_msg && qstate->return_msg->rep) {
435 			ipset_update(qstate->env, qstate->return_msg, qstate->qinfo, ie);
436 		}
437 		qstate->ext_state[id] = module_finished;
438 		return;
439 	}
440 
441 	if (iq && outbound) {
442 		/* ipset does not need to process responses at this time
443 		 * ignore it.
444 		ipset_process_response(qstate, iq, ie, id, outbound, event);
445 		*/
446 		return;
447 	}
448 
449 	if (event == module_event_error) {
450 		verbose(VERB_ALGO, "got called with event error, giving up");
451 		(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
452 		return;
453 	}
454 
455 	if (!iq && (event == module_event_moddone)) {
456 		/* during priming, module done but we never started */
457 		qstate->ext_state[id] = module_finished;
458 		return;
459 	}
460 
461 	log_err("bad event for ipset");
462 	(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
463 }
464 
ipset_inform_super(struct module_qstate * ATTR_UNUSED (qstate),int ATTR_UNUSED (id),struct module_qstate * ATTR_UNUSED (super))465 void ipset_inform_super(struct module_qstate *ATTR_UNUSED(qstate),
466 	int ATTR_UNUSED(id), struct module_qstate *ATTR_UNUSED(super)) {
467 	/* ipset does not use subordinate requests at this time */
468 	verbose(VERB_ALGO, "ipset inform_super was called");
469 }
470 
ipset_clear(struct module_qstate * qstate,int id)471 void ipset_clear(struct module_qstate *qstate, int id) {
472 	struct cachedb_qstate *iq;
473 	if (!qstate) {
474 		return;
475 	}
476 	iq = (struct cachedb_qstate *)qstate->minfo[id];
477 	if (iq) {
478 		/* free contents of iq */
479 		/* TODO */
480 	}
481 	qstate->minfo[id] = NULL;
482 }
483 
ipset_get_mem(struct module_env * env,int id)484 size_t ipset_get_mem(struct module_env *env, int id) {
485 	struct ipset_env *ie = (struct ipset_env *)env->modinfo[id];
486 	if (!ie) {
487 		return 0;
488 	}
489 	return sizeof(*ie);
490 }
491 
492 /**
493  * The ipset function block
494  */
495 static struct module_func_block ipset_block = {
496 	"ipset",
497 	&ipset_startup, &ipset_destartup, &ipset_init, &ipset_deinit,
498 	&ipset_operate, &ipset_inform_super, &ipset_clear, &ipset_get_mem
499 };
500 
ipset_get_funcblock(void)501 struct module_func_block * ipset_get_funcblock(void) {
502 	return &ipset_block;
503 }
504 
505