]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/unbound/ipset/ipset.c
Fix multiple vulnerabilities in unbound.
[FreeBSD/FreeBSD.git] / contrib / unbound / ipset / ipset.c
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  */
34 static 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
44 static 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
61 static 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
100 static void
101 ipset_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
138 static int
139 ipset_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 *setname, int af)
142 {
143         static char dname[BUFF_LEN];
144         const char *s;
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         if (dname[dlen - 1] == '.') {
156                 dlen--;
157         }
158
159         for (p = env->cfg->local_zones_ipset; p; p = p->next) {
160                 plen = strlen(p->str);
161
162                 if (dlen >= plen) {
163                         s = dname + (dlen - plen);
164
165                         if (strncasecmp(p->str, s, plen) == 0) {
166                                 d = (struct packed_rrset_data*)rrset->entry.data;
167                                 ipset_add_rrset_data(ie, mnl, d, setname,
168                                         af, dname);
169                                 break;
170                         }
171                 }
172         }
173         return 0;
174 }
175
176 static int ipset_update(struct module_env *env, struct dns_msg *return_msg, struct ipset_env *ie) {
177         struct mnl_socket *mnl;
178
179         size_t i;
180
181         const char *setname;
182
183         struct ub_packed_rrset_key *rrset;
184
185         int af;
186
187
188         mnl = (struct mnl_socket *)ie->mnl;
189         if (!mnl) {
190                 // retry to create mnl socket
191                 mnl = open_mnl_socket();
192                 if (!mnl) {
193                         return -1;
194                 }
195
196                 ie->mnl = mnl;
197         }
198
199         for (i = 0; i < return_msg->rep->rrset_count; ++i) {
200                 setname = NULL;
201
202                 rrset = return_msg->rep->rrsets[i];
203
204                 if (rrset->rk.type == htons(LDNS_RR_TYPE_A)) {
205                         af = AF_INET;
206                         if ((ie->v4_enabled == 1)) {
207                                 setname = ie->name_v4;
208                         }
209                 } else {
210                         af = AF_INET6;
211                         if ((ie->v6_enabled == 1)) {
212                                 setname = ie->name_v6;
213                         }
214                 }
215
216                 if (setname) {
217                         if(ipset_check_zones_for_rrset(env, ie, mnl, rrset,
218                                 setname, af) == -1)
219                                 return -1;
220                 }
221         }
222
223         return 0;
224 }
225
226 int ipset_init(struct module_env* env, int id) {
227         struct ipset_env *ipset_env;
228
229         ipset_env = (struct ipset_env *)calloc(1, sizeof(struct ipset_env));
230         if (!ipset_env) {
231                 log_err("malloc failure");
232                 return 0;
233         }
234
235         env->modinfo[id] = (void *)ipset_env;
236
237         ipset_env->mnl = NULL;
238
239         ipset_env->name_v4 = env->cfg->ipset_name_v4;
240         ipset_env->name_v6 = env->cfg->ipset_name_v6;
241
242         ipset_env->v4_enabled = !ipset_env->name_v4 || (strlen(ipset_env->name_v4) == 0) ? 0 : 1;
243         ipset_env->v6_enabled = !ipset_env->name_v6 || (strlen(ipset_env->name_v6) == 0) ? 0 : 1;
244
245         if ((ipset_env->v4_enabled < 1) && (ipset_env->v6_enabled < 1)) {
246                 log_err("ipset: set name no configuration?");
247                 return 0;
248         }
249
250         return 1;
251 }
252
253 void ipset_deinit(struct module_env *env, int id) {
254         struct mnl_socket *mnl;
255         struct ipset_env *ipset_env;
256
257         if (!env || !env->modinfo[id]) {
258                 return;
259         }
260
261         ipset_env = (struct ipset_env *)env->modinfo[id];
262
263         mnl = (struct mnl_socket *)ipset_env->mnl;
264         if (mnl) {
265                 mnl_socket_close(mnl);
266                 ipset_env->mnl = NULL;
267         }
268
269         free(ipset_env);
270         env->modinfo[id] = NULL;
271 }
272
273 static int ipset_new(struct module_qstate* qstate, int id) {
274         struct ipset_qstate *iq = (struct ipset_qstate *)regional_alloc(
275                 qstate->region, sizeof(struct ipset_qstate));
276         qstate->minfo[id] = iq;
277         if (!iq) {
278                 return 0;
279         }
280
281         memset(iq, 0, sizeof(*iq));
282         /* initialise it */
283         /* TODO */
284
285         return 1;
286 }
287
288 void ipset_operate(struct module_qstate *qstate, enum module_ev event, int id,
289         struct outbound_entry *outbound) {
290         struct ipset_env *ie = (struct ipset_env *)qstate->env->modinfo[id];
291         struct ipset_qstate *iq = (struct ipset_qstate *)qstate->minfo[id];
292         verbose(VERB_QUERY, "ipset[module %d] operate: extstate:%s event:%s",
293                 id, strextstate(qstate->ext_state[id]), strmodulevent(event));
294         if (iq) {
295                 log_query_info(VERB_QUERY, "ipset operate: query", &qstate->qinfo);
296         }
297
298         /* perform ipset state machine */
299         if ((event == module_event_new || event == module_event_pass) && !iq) {
300                 if (!ipset_new(qstate, id)) {
301                         (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
302                         return;
303                 }
304                 iq = (struct ipset_qstate*)qstate->minfo[id];
305         }
306
307         if (iq && (event == module_event_pass || event == module_event_new)) {
308                 qstate->ext_state[id] = module_wait_module;
309                 return;
310         }
311
312         if (iq && (event == module_event_moddone)) {
313                 if (qstate->return_msg && qstate->return_msg->rep) {
314                         ipset_update(qstate->env, qstate->return_msg, ie);
315                 }
316                 qstate->ext_state[id] = module_finished;
317                 return;
318         }
319
320         if (iq && outbound) {
321                 /* ipset does not need to process responses at this time
322                  * ignore it.
323                 ipset_process_response(qstate, iq, ie, id, outbound, event);
324                 */
325                 return;
326         }
327
328         if (event == module_event_error) {
329                 verbose(VERB_ALGO, "got called with event error, giving up");
330                 (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
331                 return;
332         }
333
334         if (!iq && (event == module_event_moddone)) {
335                 /* during priming, module done but we never started */
336                 qstate->ext_state[id] = module_finished;
337                 return;
338         }
339
340         log_err("bad event for ipset");
341         (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
342 }
343
344 void ipset_inform_super(struct module_qstate *ATTR_UNUSED(qstate),
345         int ATTR_UNUSED(id), struct module_qstate *ATTR_UNUSED(super)) {
346         /* ipset does not use subordinate requests at this time */
347         verbose(VERB_ALGO, "ipset inform_super was called");
348 }
349
350 void ipset_clear(struct module_qstate *qstate, int id) {
351         struct cachedb_qstate *iq;
352         if (!qstate) {
353                 return;
354         }
355         iq = (struct cachedb_qstate *)qstate->minfo[id];
356         if (iq) {
357                 /* free contents of iq */
358                 /* TODO */
359         }
360         qstate->minfo[id] = NULL;
361 }
362
363 size_t ipset_get_mem(struct module_env *env, int id) {
364         struct ipset_env *ie = (struct ipset_env *)env->modinfo[id];
365         if (!ie) {
366                 return 0;
367         }
368         return sizeof(*ie);
369 }
370
371 /**
372  * The ipset function block 
373  */
374 static struct module_func_block ipset_block = {
375         "ipset",
376         &ipset_init, &ipset_deinit, &ipset_operate,
377         &ipset_inform_super, &ipset_clear, &ipset_get_mem
378 };
379
380 struct module_func_block * ipset_get_funcblock(void) {
381         return &ipset_block;
382 }
383