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#include <libmnl/libmnl.h>
21#include <linux/netfilter/nfnetlink.h>
22#include <linux/netfilter/ipset/ip_set.h>
23
24#define BUFF_LEN 256
25
26/**
27 * Return an error
28 * @param qstate: our query state
29 * @param id: module id
30 * @param rcode: error code (DNS errcode).
31 * @return: 0 for use by caller, to make notation easy, like:
32 * 	return error_response(..).
33 */
34static int error_response(struct module_qstate* qstate, int id, int rcode) {
35	verbose(VERB_QUERY, "return error response %s",
36		sldns_lookup_by_id(sldns_rcodes, rcode)?
37		sldns_lookup_by_id(sldns_rcodes, rcode)->name:"??");
38	qstate->return_rcode = rcode;
39	qstate->return_msg = NULL;
40	qstate->ext_state[id] = module_finished;
41	return 0;
42}
43
44static struct mnl_socket * open_mnl_socket() {
45	struct mnl_socket *mnl;
46
47	mnl = mnl_socket_open(NETLINK_NETFILTER);
48	if (!mnl) {
49		log_err("ipset: could not open netfilter.");
50		return NULL;
51	}
52
53	if (mnl_socket_bind(mnl, 0, MNL_SOCKET_AUTOPID) < 0) {
54		mnl_socket_close(mnl);
55		log_err("ipset: could not bind netfilter.");
56		return NULL;
57	}
58	return mnl;
59}
60
61static int add_to_ipset(struct mnl_socket *mnl, const char *setname, const void *ipaddr, int af) {
62	struct nlmsghdr *nlh;
63	struct nfgenmsg *nfg;
64	struct nlattr *nested[2];
65	static char buffer[BUFF_LEN];
66
67	if (strlen(setname) >= IPSET_MAXNAMELEN) {
68		errno = ENAMETOOLONG;
69		return -1;
70	}
71	if (af != AF_INET && af != AF_INET6) {
72		errno = EAFNOSUPPORT;
73		return -1;
74	}
75
76	nlh = mnl_nlmsg_put_header(buffer);
77	nlh->nlmsg_type = IPSET_CMD_ADD | (NFNL_SUBSYS_IPSET << 8);
78	nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL;
79
80	nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
81	nfg->nfgen_family = af;
82	nfg->version = NFNETLINK_V0;
83	nfg->res_id = htons(0);
84
85	mnl_attr_put_u8(nlh, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL);
86	mnl_attr_put(nlh, IPSET_ATTR_SETNAME, strlen(setname) + 1, setname);
87	nested[0] = mnl_attr_nest_start(nlh, IPSET_ATTR_DATA);
88	nested[1] = mnl_attr_nest_start(nlh, IPSET_ATTR_IP);
89	mnl_attr_put(nlh, (af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6)
90			| NLA_F_NET_BYTEORDER, (af == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr)), ipaddr);
91	mnl_attr_nest_end(nlh, nested[1]);
92	mnl_attr_nest_end(nlh, nested[0]);
93
94	if (mnl_socket_sendto(mnl, nlh, nlh->nlmsg_len) < 0) {
95		return -1;
96	}
97	return 0;
98}
99
100static void
101ipset_add_rrset_data(struct ipset_env *ie, struct mnl_socket *mnl,
102	struct packed_rrset_data *d, const char* setname, int af,
103	const char* dname)
104{
105	int ret;
106	size_t j, rr_len, rd_len;
107	uint8_t *rr_data;
108
109	/* to d->count, not d->rrsig_count, because we do not want to add the RRSIGs, only the addresses */
110	for (j = 0; j < d->count; j++) {
111		rr_len = d->rr_len[j];
112		rr_data = d->rr_data[j];
113
114		rd_len = sldns_read_uint16(rr_data);
115		if(af == AF_INET && rd_len != INET_SIZE)
116			continue;
117		if(af == AF_INET6 && rd_len != INET6_SIZE)
118			continue;
119		if (rr_len - 2 >= rd_len) {
120			if(verbosity >= VERB_QUERY) {
121				char ip[128];
122				if(inet_ntop(af, rr_data+2, ip, (socklen_t)sizeof(ip)) == 0)
123					snprintf(ip, sizeof(ip), "(inet_ntop_error)");
124				verbose(VERB_QUERY, "ipset: add %s to %s for %s", ip, setname, dname);
125			}
126			ret = add_to_ipset(mnl, setname, rr_data + 2, af);
127			if (ret < 0) {
128				log_err("ipset: could not add %s into %s", dname, setname);
129
130				mnl_socket_close(mnl);
131				ie->mnl = NULL;
132				break;
133			}
134		}
135	}
136}
137
138static int
139ipset_check_zones_for_rrset(struct module_env *env, struct ipset_env *ie,
140	struct mnl_socket *mnl, struct ub_packed_rrset_key *rrset,
141	const char *qname, const int qlen, const char *setname, int af)
142{
143	static char dname[BUFF_LEN];
144	const char *ds, *qs;
145	int dlen, plen;
146
147	struct config_strlist *p;
148	struct packed_rrset_data *d;
149
150	dlen = sldns_wire2str_dname_buf(rrset->rk.dname, rrset->rk.dname_len, dname, BUFF_LEN);
151	if (dlen == 0) {
152		log_err("bad domain name");
153		return -1;
154	}
155
156	for (p = env->cfg->local_zones_ipset; p; p = p->next) {
157		ds = NULL;
158		qs = NULL;
159		plen = strlen(p->str);
160
161		if (dlen == plen || (dlen > plen && dname[dlen - plen - 1] == '.' )) {
162			ds = dname + (dlen - plen);
163		}
164		if (qlen == plen || (qlen > plen && qname[qlen - plen - 1] == '.' )) {
165			qs = qname + (qlen - plen);
166		}
167		if ((ds && strncasecmp(p->str, ds, plen) == 0)
168			|| (qs && strncasecmp(p->str, qs, plen) == 0)) {
169			d = (struct packed_rrset_data*)rrset->entry.data;
170			ipset_add_rrset_data(ie, mnl, d, setname,
171				af, dname);
172			break;
173		}
174	}
175	return 0;
176}
177
178static int ipset_update(struct module_env *env, struct dns_msg *return_msg,
179	struct query_info qinfo, struct ipset_env *ie)
180{
181	struct mnl_socket *mnl;
182	size_t i;
183	const char *setname;
184	struct ub_packed_rrset_key *rrset;
185	int af;
186	static char qname[BUFF_LEN];
187	int qlen;
188
189	mnl = (struct mnl_socket *)ie->mnl;
190	if (!mnl) {
191		/* retry to create mnl socket */
192		mnl = open_mnl_socket();
193		if (!mnl) {
194			return -1;
195		}
196		ie->mnl = mnl;
197	}
198
199	qlen = sldns_wire2str_dname_buf(qinfo.qname, qinfo.qname_len,
200		qname, BUFF_LEN);
201	if(qlen == 0) {
202		log_err("bad domain name");
203		return -1;
204	}
205
206	for(i = 0; i < return_msg->rep->rrset_count; i++) {
207		setname = NULL;
208		rrset = return_msg->rep->rrsets[i];
209		if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A &&
210			ie->v4_enabled == 1) {
211			af = AF_INET;
212			setname = ie->name_v4;
213		} else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA &&
214			ie->v6_enabled == 1) {
215			af = AF_INET6;
216			setname = ie->name_v6;
217		}
218
219		if (setname) {
220			if(ipset_check_zones_for_rrset(env, ie, mnl, rrset,
221				qname, qlen, setname, af) == -1)
222				return -1;
223		}
224	}
225
226	return 0;
227}
228
229int ipset_init(struct module_env* env, int id) {
230	struct ipset_env *ipset_env;
231
232	ipset_env = (struct ipset_env *)calloc(1, sizeof(struct ipset_env));
233	if (!ipset_env) {
234		log_err("malloc failure");
235		return 0;
236	}
237
238	env->modinfo[id] = (void *)ipset_env;
239
240	ipset_env->mnl = NULL;
241
242	ipset_env->name_v4 = env->cfg->ipset_name_v4;
243	ipset_env->name_v6 = env->cfg->ipset_name_v6;
244
245	ipset_env->v4_enabled = !ipset_env->name_v4 || (strlen(ipset_env->name_v4) == 0) ? 0 : 1;
246	ipset_env->v6_enabled = !ipset_env->name_v6 || (strlen(ipset_env->name_v6) == 0) ? 0 : 1;
247
248	if ((ipset_env->v4_enabled < 1) && (ipset_env->v6_enabled < 1)) {
249		log_err("ipset: set name no configuration?");
250		return 0;
251	}
252
253	return 1;
254}
255
256void ipset_deinit(struct module_env *env, int id) {
257	struct mnl_socket *mnl;
258	struct ipset_env *ipset_env;
259
260	if (!env || !env->modinfo[id]) {
261		return;
262	}
263
264	ipset_env = (struct ipset_env *)env->modinfo[id];
265
266	mnl = (struct mnl_socket *)ipset_env->mnl;
267	if (mnl) {
268		mnl_socket_close(mnl);
269		ipset_env->mnl = NULL;
270	}
271
272	free(ipset_env);
273	env->modinfo[id] = NULL;
274}
275
276static int ipset_new(struct module_qstate* qstate, int id) {
277	struct ipset_qstate *iq = (struct ipset_qstate *)regional_alloc(
278		qstate->region, sizeof(struct ipset_qstate));
279	qstate->minfo[id] = iq;
280	if (!iq) {
281		return 0;
282	}
283
284	memset(iq, 0, sizeof(*iq));
285	/* initialise it */
286	/* TODO */
287
288	return 1;
289}
290
291void ipset_operate(struct module_qstate *qstate, enum module_ev event, int id,
292	struct outbound_entry *outbound) {
293	struct ipset_env *ie = (struct ipset_env *)qstate->env->modinfo[id];
294	struct ipset_qstate *iq = (struct ipset_qstate *)qstate->minfo[id];
295	verbose(VERB_QUERY, "ipset[module %d] operate: extstate:%s event:%s",
296		id, strextstate(qstate->ext_state[id]), strmodulevent(event));
297	if (iq) {
298		log_query_info(VERB_QUERY, "ipset operate: query", &qstate->qinfo);
299	}
300
301	/* perform ipset state machine */
302	if ((event == module_event_new || event == module_event_pass) && !iq) {
303		if (!ipset_new(qstate, id)) {
304			(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
305			return;
306		}
307		iq = (struct ipset_qstate*)qstate->minfo[id];
308	}
309
310	if (iq && (event == module_event_pass || event == module_event_new)) {
311		qstate->ext_state[id] = module_wait_module;
312		return;
313	}
314
315	if (iq && (event == module_event_moddone)) {
316		if (qstate->return_msg && qstate->return_msg->rep) {
317			ipset_update(qstate->env, qstate->return_msg, qstate->qinfo, ie);
318		}
319		qstate->ext_state[id] = module_finished;
320		return;
321	}
322
323	if (iq && outbound) {
324		/* ipset does not need to process responses at this time
325		 * ignore it.
326		ipset_process_response(qstate, iq, ie, id, outbound, event);
327		*/
328		return;
329	}
330
331	if (event == module_event_error) {
332		verbose(VERB_ALGO, "got called with event error, giving up");
333		(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
334		return;
335	}
336
337	if (!iq && (event == module_event_moddone)) {
338		/* during priming, module done but we never started */
339		qstate->ext_state[id] = module_finished;
340		return;
341	}
342
343	log_err("bad event for ipset");
344	(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
345}
346
347void ipset_inform_super(struct module_qstate *ATTR_UNUSED(qstate),
348	int ATTR_UNUSED(id), struct module_qstate *ATTR_UNUSED(super)) {
349	/* ipset does not use subordinate requests at this time */
350	verbose(VERB_ALGO, "ipset inform_super was called");
351}
352
353void ipset_clear(struct module_qstate *qstate, int id) {
354	struct cachedb_qstate *iq;
355	if (!qstate) {
356		return;
357	}
358	iq = (struct cachedb_qstate *)qstate->minfo[id];
359	if (iq) {
360		/* free contents of iq */
361		/* TODO */
362	}
363	qstate->minfo[id] = NULL;
364}
365
366size_t ipset_get_mem(struct module_env *env, int id) {
367	struct ipset_env *ie = (struct ipset_env *)env->modinfo[id];
368	if (!ie) {
369		return 0;
370	}
371	return sizeof(*ie);
372}
373
374/**
375 * The ipset function block
376 */
377static struct module_func_block ipset_block = {
378	"ipset",
379	&ipset_init, &ipset_deinit, &ipset_operate,
380	&ipset_inform_super, &ipset_clear, &ipset_get_mem
381};
382
383struct module_func_block * ipset_get_funcblock(void) {
384	return &ipset_block;
385}
386
387