xref: /freebsd/contrib/unbound/services/rpz.c (revision d485c77f203fb0f4cdc08dea5ff81631b51d8809)
1 /*
2  * services/rpz.c - rpz service
3  *
4  * Copyright (c) 2019, NLnet Labs. All rights reserved.
5  *
6  * This software is open source.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * Neither the name of the NLNET LABS nor the names of its contributors may
20  * be used to endorse or promote products derived from this software without
21  * specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 /**
37  * \file
38  *
39  * This file contains functions to enable RPZ service.
40  */
41 
42 #include "config.h"
43 #include "services/rpz.h"
44 #include "util/config_file.h"
45 #include "sldns/wire2str.h"
46 #include "sldns/str2wire.h"
47 #include "util/data/dname.h"
48 #include "util/net_help.h"
49 #include "util/log.h"
50 #include "util/data/dname.h"
51 #include "util/locks.h"
52 #include "util/regional.h"
53 
54 /** string for RPZ action enum */
55 const char*
56 rpz_action_to_string(enum rpz_action a)
57 {
58 	switch(a) {
59 	case RPZ_NXDOMAIN_ACTION:	return "nxdomain";
60 	case RPZ_NODATA_ACTION:		return "nodata";
61 	case RPZ_PASSTHRU_ACTION:	return "passthru";
62 	case RPZ_DROP_ACTION:		return "drop";
63 	case RPZ_TCP_ONLY_ACTION:	return "tcp_only";
64 	case RPZ_INVALID_ACTION:	return "invalid";
65 	case RPZ_LOCAL_DATA_ACTION:	return "local_data";
66 	case RPZ_DISABLED_ACTION:	return "disabled";
67 	case RPZ_CNAME_OVERRIDE_ACTION:	return "cname_override";
68 	case RPZ_NO_OVERRIDE_ACTION:	return "no_override";
69 	}
70 	return "unknown";
71 }
72 
73 /** RPZ action enum for config string */
74 static enum rpz_action
75 rpz_config_to_action(char* a)
76 {
77 	if(strcmp(a, "nxdomain") == 0)
78 		return RPZ_NXDOMAIN_ACTION;
79 	else if(strcmp(a, "nodata") == 0)
80 		return RPZ_NODATA_ACTION;
81 	else if(strcmp(a, "passthru") == 0)
82 		return RPZ_PASSTHRU_ACTION;
83 	else if(strcmp(a, "drop") == 0)
84 		return RPZ_DROP_ACTION;
85 	else if(strcmp(a, "tcp_only") == 0)
86 		return RPZ_TCP_ONLY_ACTION;
87 	else if(strcmp(a, "cname") == 0)
88 		return RPZ_CNAME_OVERRIDE_ACTION;
89 	else if(strcmp(a, "disabled") == 0)
90 		return RPZ_DISABLED_ACTION;
91 	return RPZ_INVALID_ACTION;
92 }
93 
94 /** string for RPZ trigger enum */
95 static const char*
96 rpz_trigger_to_string(enum rpz_trigger r)
97 {
98 	switch(r) {
99 	case RPZ_QNAME_TRIGGER:		return "qname";
100 	case RPZ_CLIENT_IP_TRIGGER:	return "client_ip";
101 	case RPZ_RESPONSE_IP_TRIGGER:	return "response_ip";
102 	case RPZ_NSDNAME_TRIGGER:	return "nsdname";
103 	case RPZ_NSIP_TRIGGER:		return "nsip";
104 	case RPZ_INVALID_TRIGGER:	return "invalid";
105 	}
106 	return "unknown";
107 }
108 
109 /**
110  * Get the label that is just before the root label.
111  * @param dname: dname to work on
112  * @param maxdnamelen: maximum length of the dname
113  * @return: pointer to TLD label, NULL if not found or invalid dname
114  */
115 static uint8_t*
116 get_tld_label(uint8_t* dname, size_t maxdnamelen)
117 {
118 	uint8_t* prevlab = dname;
119 	size_t dnamelen = 0;
120 
121 	/* one byte needed for label length */
122 	if(dnamelen+1 > maxdnamelen)
123 		return NULL;
124 
125 	/* only root label */
126 	if(*dname == 0)
127 		return NULL;
128 
129 	while(*dname) {
130 		dnamelen += ((size_t)*dname)+1;
131 		if(dnamelen+1 > maxdnamelen)
132 			return NULL;
133 		dname = dname+((size_t)*dname)+1;
134 		if(*dname != 0)
135 			prevlab = dname;
136 	}
137 	return prevlab;
138 }
139 
140 /**
141  * Classify RPZ action for RR type/rdata
142  * @param rr_type: the RR type
143  * @param rdatawl: RDATA with 2 bytes length
144  * @param rdatalen: the length of rdatawl (including its 2 bytes length)
145  * @return: the RPZ action
146  */
147 static enum rpz_action
148 rpz_rr_to_action(uint16_t rr_type, uint8_t* rdatawl, size_t rdatalen)
149 {
150 	char* endptr;
151 	uint8_t* rdata;
152 	int rdatalabs;
153 	uint8_t* tldlab = NULL;
154 
155 	switch(rr_type) {
156 		case LDNS_RR_TYPE_SOA:
157 		case LDNS_RR_TYPE_NS:
158 		case LDNS_RR_TYPE_DNAME:
159 		/* all DNSSEC-related RRs must be ignored */
160 		case LDNS_RR_TYPE_DNSKEY:
161 		case LDNS_RR_TYPE_DS:
162 		case LDNS_RR_TYPE_RRSIG:
163 		case LDNS_RR_TYPE_NSEC:
164 		case LDNS_RR_TYPE_NSEC3:
165 			return RPZ_INVALID_ACTION;
166 		case LDNS_RR_TYPE_CNAME:
167 			break;
168 		default:
169 			return RPZ_LOCAL_DATA_ACTION;
170 	}
171 
172 	/* use CNAME target to determine RPZ action */
173 	log_assert(rr_type == LDNS_RR_TYPE_CNAME);
174 	if(rdatalen < 3)
175 		return RPZ_INVALID_ACTION;
176 
177 	rdata = rdatawl + 2; /* 2 bytes of rdata length */
178 	if(dname_valid(rdata, rdatalen-2) != rdatalen-2)
179 		return RPZ_INVALID_ACTION;
180 
181 	rdatalabs = dname_count_labels(rdata);
182 	if(rdatalabs == 1)
183 		return RPZ_NXDOMAIN_ACTION;
184 	else if(rdatalabs == 2) {
185 		if(dname_subdomain_c(rdata, (uint8_t*)&"\001*\000"))
186 			return RPZ_NODATA_ACTION;
187 		else if(dname_subdomain_c(rdata,
188 			(uint8_t*)&"\014rpz-passthru\000"))
189 			return RPZ_PASSTHRU_ACTION;
190 		else if(dname_subdomain_c(rdata, (uint8_t*)&"\010rpz-drop\000"))
191 			return RPZ_DROP_ACTION;
192 		else if(dname_subdomain_c(rdata,
193 			(uint8_t*)&"\014rpz-tcp-only\000"))
194 			return RPZ_TCP_ONLY_ACTION;
195 	}
196 
197 	/* all other TLDs starting with "rpz-" are invalid */
198 	tldlab = get_tld_label(rdata, rdatalen-2);
199 	if(tldlab && dname_lab_startswith(tldlab, "rpz-", &endptr))
200 		return RPZ_INVALID_ACTION;
201 
202 	/* no special label found */
203 	return RPZ_LOCAL_DATA_ACTION;
204 }
205 
206 static enum localzone_type
207 rpz_action_to_localzone_type(enum rpz_action a)
208 {
209 	switch(a) {
210 	case RPZ_NXDOMAIN_ACTION:	return local_zone_always_nxdomain;
211 	case RPZ_NODATA_ACTION:		return local_zone_always_nodata;
212 	case RPZ_DROP_ACTION:		return local_zone_always_deny;
213 	case RPZ_PASSTHRU_ACTION:	return local_zone_always_transparent;
214 	case RPZ_LOCAL_DATA_ACTION:	/* fallthrough */
215 	case RPZ_CNAME_OVERRIDE_ACTION: return local_zone_redirect;
216 	case RPZ_INVALID_ACTION: 	/* fallthrough */
217 	case RPZ_TCP_ONLY_ACTION:	/* fallthrough */
218 	default:			return local_zone_invalid;
219 	}
220 }
221 
222 enum respip_action
223 rpz_action_to_respip_action(enum rpz_action a)
224 {
225 	switch(a) {
226 	case RPZ_NXDOMAIN_ACTION:	return respip_always_nxdomain;
227 	case RPZ_NODATA_ACTION:		return respip_always_nodata;
228 	case RPZ_DROP_ACTION:		return respip_always_deny;
229 	case RPZ_PASSTHRU_ACTION:	return respip_always_transparent;
230 	case RPZ_LOCAL_DATA_ACTION:	/* fallthrough */
231 	case RPZ_CNAME_OVERRIDE_ACTION: return respip_redirect;
232 	case RPZ_INVALID_ACTION:	/* fallthrough */
233 	case RPZ_TCP_ONLY_ACTION:	/* fallthrough */
234 	default:			return respip_invalid;
235 	}
236 }
237 
238 static enum rpz_action
239 localzone_type_to_rpz_action(enum localzone_type lzt)
240 {
241 	switch(lzt) {
242 	case local_zone_always_nxdomain:	return RPZ_NXDOMAIN_ACTION;
243 	case local_zone_always_nodata:		return RPZ_NODATA_ACTION;
244 	case local_zone_always_deny:		return RPZ_DROP_ACTION;
245 	case local_zone_always_transparent:	return RPZ_PASSTHRU_ACTION;
246 	case local_zone_redirect:		return RPZ_LOCAL_DATA_ACTION;
247 	case local_zone_invalid:
248 	default:
249 		return RPZ_INVALID_ACTION;
250 	}
251 }
252 
253 enum rpz_action
254 respip_action_to_rpz_action(enum respip_action a)
255 {
256 	switch(a) {
257 	case respip_always_nxdomain:	return RPZ_NXDOMAIN_ACTION;
258 	case respip_always_nodata:	return RPZ_NODATA_ACTION;
259 	case respip_always_deny:	return RPZ_DROP_ACTION;
260 	case respip_always_transparent:	return RPZ_PASSTHRU_ACTION;
261 	case respip_redirect:		return RPZ_LOCAL_DATA_ACTION;
262 	case respip_invalid:
263 	default:
264 		return RPZ_INVALID_ACTION;
265 	}
266 }
267 
268 /**
269  * Get RPZ trigger for dname
270  * @param dname: dname containing RPZ trigger
271  * @param dname_len: length of the dname
272  * @return: RPZ trigger enum
273  */
274 static enum rpz_trigger
275 rpz_dname_to_trigger(uint8_t* dname, size_t dname_len)
276 {
277 	uint8_t* tldlab;
278 	char* endptr;
279 
280 	if(dname_valid(dname, dname_len) != dname_len)
281 		return RPZ_INVALID_TRIGGER;
282 
283 	tldlab = get_tld_label(dname, dname_len);
284 	if(!tldlab || !dname_lab_startswith(tldlab, "rpz-", &endptr))
285 		return RPZ_QNAME_TRIGGER;
286 
287 	if(dname_subdomain_c(tldlab,
288 		(uint8_t*)&"\015rpz-client-ip\000"))
289 		return RPZ_CLIENT_IP_TRIGGER;
290 	else if(dname_subdomain_c(tldlab, (uint8_t*)&"\006rpz-ip\000"))
291 		return RPZ_RESPONSE_IP_TRIGGER;
292 	else if(dname_subdomain_c(tldlab, (uint8_t*)&"\013rpz-nsdname\000"))
293 		return RPZ_NSDNAME_TRIGGER;
294 	else if(dname_subdomain_c(tldlab, (uint8_t*)&"\010rpz-nsip\000"))
295 		return RPZ_NSIP_TRIGGER;
296 
297 	return RPZ_QNAME_TRIGGER;
298 }
299 
300 void rpz_delete(struct rpz* r)
301 {
302 	if(!r)
303 		return;
304 	local_zones_delete(r->local_zones);
305 	respip_set_delete(r->respip_set);
306 	regional_destroy(r->region);
307 	free(r->taglist);
308 	free(r->log_name);
309 	free(r);
310 }
311 
312 int
313 rpz_clear(struct rpz* r)
314 {
315 	/* must hold write lock on auth_zone */
316 	local_zones_delete(r->local_zones);
317 	respip_set_delete(r->respip_set);
318 	if(!(r->local_zones = local_zones_create())){
319 		return 0;
320 	}
321 	if(!(r->respip_set = respip_set_create())) {
322 		return 0;
323 	}
324 	return 1;
325 }
326 
327 void
328 rpz_finish_config(struct rpz* r)
329 {
330 	lock_rw_wrlock(&r->respip_set->lock);
331 	addr_tree_init_parents(&r->respip_set->ip_tree);
332 	lock_rw_unlock(&r->respip_set->lock);
333 }
334 
335 /** new rrset containing CNAME override, does not yet contain a dname */
336 static struct ub_packed_rrset_key*
337 new_cname_override(struct regional* region, uint8_t* ct, size_t ctlen)
338 {
339 	struct ub_packed_rrset_key* rrset;
340 	struct packed_rrset_data* pd;
341 	uint16_t rdlength = htons(ctlen);
342 	rrset = (struct ub_packed_rrset_key*)regional_alloc_zero(region,
343 		sizeof(*rrset));
344 	if(!rrset) {
345 		log_err("out of memory");
346 		return NULL;
347 	}
348 	rrset->entry.key = rrset;
349 	pd = (struct packed_rrset_data*)regional_alloc_zero(region, sizeof(*pd));
350 	if(!pd) {
351 		log_err("out of memory");
352 		return NULL;
353 	}
354 	pd->trust = rrset_trust_prim_noglue;
355 	pd->security = sec_status_insecure;
356 
357 	pd->count = 1;
358 	pd->rr_len = regional_alloc_zero(region, sizeof(*pd->rr_len));
359 	pd->rr_ttl = regional_alloc_zero(region, sizeof(*pd->rr_ttl));
360 	pd->rr_data = regional_alloc_zero(region, sizeof(*pd->rr_data));
361 	if(!pd->rr_len || !pd->rr_ttl || !pd->rr_data) {
362 		log_err("out of memory");
363 		return NULL;
364 	}
365 	pd->rr_len[0] = ctlen+2;
366 	pd->rr_ttl[0] = 3600;
367 	pd->rr_data[0] = regional_alloc_zero(region, 2 /* rdlength */ + ctlen);
368 	if(!pd->rr_data[0]) {
369 		log_err("out of memory");
370 		return NULL;
371 	}
372 	memmove(pd->rr_data[0], &rdlength, 2);
373 	memmove(pd->rr_data[0]+2, ct, ctlen);
374 
375 	rrset->entry.data = pd;
376 	rrset->rk.type = htons(LDNS_RR_TYPE_CNAME);
377 	rrset->rk.rrset_class = htons(LDNS_RR_CLASS_IN);
378 	return rrset;
379 }
380 
381 struct rpz*
382 rpz_create(struct config_auth* p)
383 {
384 	struct rpz* r = calloc(1, sizeof(*r));
385 	if(!r)
386 		goto err;
387 
388 	r->region = regional_create_custom(sizeof(struct regional));
389 	if(!r->region) {
390 		goto err;
391 	}
392 
393 	if(!(r->local_zones = local_zones_create())){
394 		goto err;
395 	}
396 	if(!(r->respip_set = respip_set_create())) {
397 		goto err;
398 	}
399 	r->taglistlen = p->rpz_taglistlen;
400 	r->taglist = memdup(p->rpz_taglist, r->taglistlen);
401 	if(p->rpz_action_override) {
402 		r->action_override = rpz_config_to_action(p->rpz_action_override);
403 	}
404 	else
405 		r->action_override = RPZ_NO_OVERRIDE_ACTION;
406 
407 	if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) {
408 		uint8_t nm[LDNS_MAX_DOMAINLEN+1];
409 		size_t nmlen = sizeof(nm);
410 
411 		if(!p->rpz_cname) {
412 			log_err("RPZ override with cname action found, but no "
413 				"rpz-cname-override configured");
414 			goto err;
415 		}
416 
417 		if(sldns_str2wire_dname_buf(p->rpz_cname, nm, &nmlen) != 0) {
418 			log_err("cannot parse RPZ cname override: %s",
419 				p->rpz_cname);
420 			goto err;
421 		}
422 		r->cname_override = new_cname_override(r->region, nm, nmlen);
423 		if(!r->cname_override) {
424 			goto err;
425 		}
426 	}
427 	r->log = p->rpz_log;
428 	if(p->rpz_log_name) {
429 		if(!(r->log_name = strdup(p->rpz_log_name))) {
430 			log_err("malloc failure on RPZ log_name strdup");
431 			goto err;
432 		}
433 	}
434 	return r;
435 err:
436 	if(r) {
437 		if(r->local_zones)
438 			local_zones_delete(r->local_zones);
439 		if(r->respip_set)
440 			respip_set_delete(r->respip_set);
441 		if(r->taglist)
442 			free(r->taglist);
443 		if(r->region)
444 			regional_destroy(r->region);
445 		free(r);
446 	}
447 	return NULL;
448 }
449 
450 /**
451  * Remove RPZ zone name from dname
452  * Copy dname to newdname, without the originlen number of trailing bytes
453  */
454 static size_t
455 strip_dname_origin(uint8_t* dname, size_t dnamelen, size_t originlen,
456 	uint8_t* newdname, size_t maxnewdnamelen)
457 {
458 	size_t newdnamelen;
459 	if(dnamelen < originlen)
460 		return 0;
461 	newdnamelen = dnamelen - originlen;
462 	if(newdnamelen+1 > maxnewdnamelen)
463 		return 0;
464 	memmove(newdname, dname, newdnamelen);
465 	newdname[newdnamelen] = 0;
466 	return newdnamelen + 1;	/* + 1 for root label */
467 }
468 
469 /** Insert RR into RPZ's local-zone */
470 static void
471 rpz_insert_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
472 	enum rpz_action a, uint16_t rrtype, uint16_t rrclass, uint32_t ttl,
473 	uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len)
474 {
475 	struct local_zone* z;
476 	enum localzone_type tp = local_zone_always_transparent;
477 	int dnamelabs = dname_count_labels(dname);
478 	char* rrstr;
479 	int newzone = 0;
480 
481 	if(a == RPZ_TCP_ONLY_ACTION || a == RPZ_INVALID_ACTION) {
482 		verbose(VERB_ALGO, "RPZ: skipping unsupported action: %s",
483 			rpz_action_to_string(a));
484 		free(dname);
485 		return;
486 	}
487 
488 	lock_rw_wrlock(&r->local_zones->lock);
489 	/* exact match */
490 	z = local_zones_find(r->local_zones, dname, dnamelen, dnamelabs,
491 		LDNS_RR_CLASS_IN);
492 	if(z && a != RPZ_LOCAL_DATA_ACTION) {
493 		rrstr = sldns_wire2str_rr(rr, rr_len);
494 		if(!rrstr) {
495 			log_err("malloc error while inserting RPZ qname "
496 				"trigger");
497 			free(dname);
498 			lock_rw_unlock(&r->local_zones->lock);
499 			return;
500 		}
501 		verbose(VERB_ALGO, "RPZ: skipping duplicate record: '%s'",
502 			rrstr);
503 		free(rrstr);
504 		free(dname);
505 		lock_rw_unlock(&r->local_zones->lock);
506 		return;
507 	}
508 	if(!z) {
509 		tp = rpz_action_to_localzone_type(a);
510 		if(!(z = local_zones_add_zone(r->local_zones, dname, dnamelen,
511 			dnamelabs, rrclass, tp))) {
512 			log_warn("RPZ create failed");
513 			lock_rw_unlock(&r->local_zones->lock);
514 			/* dname will be free'd in failed local_zone_create() */
515 			return;
516 		}
517 		newzone = 1;
518 	}
519 	if(a == RPZ_LOCAL_DATA_ACTION) {
520 		rrstr = sldns_wire2str_rr(rr, rr_len);
521 		if(!rrstr) {
522 			log_err("malloc error while inserting RPZ qname "
523 				"trigger");
524 			free(dname);
525 			lock_rw_unlock(&r->local_zones->lock);
526 			return;
527 		}
528 		lock_rw_wrlock(&z->lock);
529 		local_zone_enter_rr(z, dname, dnamelen, dnamelabs,
530 			rrtype, rrclass, ttl, rdata, rdata_len, rrstr);
531 		lock_rw_unlock(&z->lock);
532 		free(rrstr);
533 	}
534 	if(!newzone)
535 		free(dname);
536 	lock_rw_unlock(&r->local_zones->lock);
537 	return;
538 }
539 
540 /** Insert RR into RPZ's respip_set */
541 static int
542 rpz_insert_response_ip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
543 	enum rpz_action a, uint16_t rrtype, uint16_t rrclass, uint32_t ttl,
544 	uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len)
545 {
546 	struct resp_addr* node;
547 	struct sockaddr_storage addr;
548 	socklen_t addrlen;
549 	int net, af;
550 	char* rrstr;
551 	enum respip_action respa = rpz_action_to_respip_action(a);
552 
553 	if(a == RPZ_TCP_ONLY_ACTION || a == RPZ_INVALID_ACTION ||
554 		respa == respip_invalid) {
555 		verbose(VERB_ALGO, "RPZ: skipping unsupported action: %s",
556 			rpz_action_to_string(a));
557 		return 0;
558 	}
559 
560 	if(!netblockdnametoaddr(dname, dnamelen, &addr, &addrlen, &net, &af))
561 		return 0;
562 
563 	lock_rw_wrlock(&r->respip_set->lock);
564 	rrstr = sldns_wire2str_rr(rr, rr_len);
565 	if(!rrstr) {
566 		log_err("malloc error while inserting RPZ respip trigger");
567 		lock_rw_unlock(&r->respip_set->lock);
568 		return 0;
569 	}
570 	if(!(node=respip_sockaddr_find_or_create(r->respip_set, &addr, addrlen,
571 		net, 1, rrstr))) {
572 		lock_rw_unlock(&r->respip_set->lock);
573 		free(rrstr);
574 		return 0;
575 	}
576 
577 	lock_rw_wrlock(&node->lock);
578 	lock_rw_unlock(&r->respip_set->lock);
579 	node->action = respa;
580 
581 	if(a == RPZ_LOCAL_DATA_ACTION) {
582 		respip_enter_rr(r->respip_set->region, node, rrtype,
583 			rrclass, ttl, rdata, rdata_len, rrstr, "");
584 	}
585 	lock_rw_unlock(&node->lock);
586 	free(rrstr);
587 	return 1;
588 }
589 
590 int
591 rpz_insert_rr(struct rpz* r, uint8_t* azname, size_t aznamelen, uint8_t* dname,
592 	size_t dnamelen, uint16_t rr_type, uint16_t rr_class, uint32_t rr_ttl,
593 	uint8_t* rdatawl, size_t rdatalen, uint8_t* rr, size_t rr_len)
594 {
595 	size_t policydnamelen;
596 	/* name is free'd in local_zone delete */
597 	enum rpz_trigger t;
598 	enum rpz_action a;
599 	uint8_t* policydname;
600 
601 	if(!dname_subdomain_c(dname, azname)) {
602 		char* dname_str = sldns_wire2str_dname(dname, dnamelen);
603 		char* azname_str = sldns_wire2str_dname(azname, aznamelen);
604 		if(dname_str && azname_str) {
605 			log_err("RPZ: name of record (%s) to insert into RPZ is not a "
606 				"subdomain of the configured name of the RPZ zone (%s)",
607 				dname_str, azname_str);
608 		} else {
609 			log_err("RPZ: name of record to insert into RPZ is not a "
610 				"subdomain of the configured name of the RPZ zone");
611 		}
612 		free(dname_str);
613 		free(azname_str);
614 		return 0;
615 	}
616 
617 	log_assert(dnamelen >= aznamelen);
618 	if(!(policydname = calloc(1, (dnamelen-aznamelen)+1))) {
619 		log_err("malloc error while inserting RPZ RR");
620 		return 0;
621 	}
622 
623 	a = rpz_rr_to_action(rr_type, rdatawl, rdatalen);
624 	if(!(policydnamelen = strip_dname_origin(dname, dnamelen, aznamelen,
625 		policydname, (dnamelen-aznamelen)+1))) {
626 		free(policydname);
627 		return 0;
628 	}
629 	t = rpz_dname_to_trigger(policydname, policydnamelen);
630 	if(t == RPZ_INVALID_TRIGGER) {
631 		free(policydname);
632 		verbose(VERB_ALGO, "RPZ: skipping invalid trigger");
633 		return 1;
634 	}
635 	if(t == RPZ_QNAME_TRIGGER) {
636 		rpz_insert_qname_trigger(r, policydname, policydnamelen,
637 			a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr,
638 			rr_len);
639 	}
640 	else if(t == RPZ_RESPONSE_IP_TRIGGER) {
641 		rpz_insert_response_ip_trigger(r, policydname, policydnamelen,
642 			a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr,
643 			rr_len);
644 		free(policydname);
645 	}
646 	else {
647 		free(policydname);
648 		verbose(VERB_ALGO, "RPZ: skipping unsupported trigger: %s",
649 			rpz_trigger_to_string(t));
650 	}
651 	return 1;
652 }
653 
654 /**
655  * Find RPZ local-zone by qname.
656  * @param r: rpz containing local-zone tree
657  * @param qname: qname
658  * @param qname_len: length of qname
659  * @param qclass: qclass
660  * @param only_exact: if 1 only excact (non wildcard) matches are returned
661  * @param wr: get write lock for local-zone if 1, read lock if 0
662  * @param zones_keep_lock: if set do not release the r->local_zones lock, this
663  * 	  makes the caller of this function responsible for releasing the lock.
664  * @return: NULL or local-zone holding rd or wr lock
665  */
666 static struct local_zone*
667 rpz_find_zone(struct rpz* r, uint8_t* qname, size_t qname_len, uint16_t qclass,
668 	int only_exact, int wr, int zones_keep_lock)
669 {
670 	uint8_t* ce;
671 	size_t ce_len;
672 	int ce_labs;
673 	uint8_t wc[LDNS_MAX_DOMAINLEN+1];
674 	int exact;
675 	struct local_zone* z = NULL;
676 	if(wr) {
677 		lock_rw_wrlock(&r->local_zones->lock);
678 	} else {
679 		lock_rw_rdlock(&r->local_zones->lock);
680 	}
681 	z = local_zones_find_le(r->local_zones, qname, qname_len,
682 		dname_count_labels(qname),
683 		LDNS_RR_CLASS_IN, &exact);
684 	if(!z || (only_exact && !exact)) {
685 		lock_rw_unlock(&r->local_zones->lock);
686 		return NULL;
687 	}
688 	if(wr) {
689 		lock_rw_wrlock(&z->lock);
690 	} else {
691 		lock_rw_rdlock(&z->lock);
692 	}
693 	if(!zones_keep_lock) {
694 		lock_rw_unlock(&r->local_zones->lock);
695 	}
696 
697 	if(exact)
698 		return z;
699 
700 	/* No exact match found, lookup wildcard. closest encloser must
701 	 * be the shared parent between the qname and the best local
702 	 * zone match, append '*' to that and do another lookup. */
703 
704 	ce = dname_get_shared_topdomain(z->name, qname);
705 	if(!ce /* should not happen */ || !*ce /* root */) {
706 		lock_rw_unlock(&z->lock);
707 		if(zones_keep_lock) {
708 			lock_rw_unlock(&r->local_zones->lock);
709 		}
710 		return NULL;
711 	}
712 	ce_labs = dname_count_size_labels(ce, &ce_len);
713 	if(ce_len+2 > sizeof(wc)) {
714 		lock_rw_unlock(&z->lock);
715 		if(zones_keep_lock) {
716 			lock_rw_unlock(&r->local_zones->lock);
717 		}
718 		return NULL;
719 	}
720 	wc[0] = 1; /* length of wildcard label */
721 	wc[1] = (uint8_t)'*'; /* wildcard label */
722 	memmove(wc+2, ce, ce_len);
723 	lock_rw_unlock(&z->lock);
724 
725 	if(!zones_keep_lock) {
726 		if(wr) {
727 			lock_rw_wrlock(&r->local_zones->lock);
728 		} else {
729 			lock_rw_rdlock(&r->local_zones->lock);
730 		}
731 	}
732 	z = local_zones_find_le(r->local_zones, wc,
733 		ce_len+2, ce_labs+1, qclass, &exact);
734 	if(!z || !exact) {
735 		lock_rw_unlock(&r->local_zones->lock);
736 		return NULL;
737 	}
738 	if(wr) {
739 		lock_rw_wrlock(&z->lock);
740 	} else {
741 		lock_rw_rdlock(&z->lock);
742 	}
743 	if(!zones_keep_lock) {
744 		lock_rw_unlock(&r->local_zones->lock);
745 	}
746 	return z;
747 }
748 
749 /**
750  * Remove RR from RPZ's local-data
751  * @param z: local-zone for RPZ, holding write lock
752  * @param policydname: dname of RR to remove
753  * @param policydnamelen: lenth of policydname
754  * @param rr_type: RR type of RR to remove
755  * @param rdata: rdata of RR to remove
756  * @param rdatalen: length of rdata
757  * @return: 1 if zone must be removed after RR deletion
758  */
759 static int
760 rpz_data_delete_rr(struct local_zone* z, uint8_t* policydname,
761 	size_t policydnamelen, uint16_t rr_type, uint8_t* rdata,
762 	size_t rdatalen)
763 {
764 	struct local_data* ld;
765 	struct packed_rrset_data* d;
766 	size_t index;
767 	ld = local_zone_find_data(z, policydname, policydnamelen,
768 		dname_count_labels(policydname));
769 	if(ld) {
770 		struct local_rrset* prev=NULL, *p=ld->rrsets;
771 		while(p && ntohs(p->rrset->rk.type) != rr_type) {
772 			prev = p;
773 			p = p->next;
774 		}
775 		if(!p)
776 			return 0;
777 		d = (struct packed_rrset_data*)p->rrset->entry.data;
778 		if(packed_rrset_find_rr(d, rdata, rdatalen, &index)) {
779 			if(d->count == 1) {
780 				/* no memory recycling for zone deletions ... */
781 				if(prev) prev->next = p->next;
782 				else ld->rrsets = p->next;
783 			}
784 			if(d->count > 1) {
785 				if(!local_rrset_remove_rr(d, index))
786 					return 0;
787 			}
788 		}
789 	}
790 	if(ld && ld->rrsets)
791 		return 0;
792 	return 1;
793 }
794 
795 /**
796  * Remove RR from RPZ's respip set
797  * @param raddr: respip node
798  * @param rr_type: RR type of RR to remove
799  * @param rdata: rdata of RR to remove
800  * @param rdatalen: length of rdata
801  * @return: 1 if zone must be removed after RR deletion
802  */
803 static int
804 rpz_rrset_delete_rr(struct resp_addr* raddr, uint16_t rr_type, uint8_t* rdata,
805 	size_t rdatalen)
806 {
807 	size_t index;
808 	struct packed_rrset_data* d;
809 	if(!raddr->data)
810 		return 1;
811 	d = raddr->data->entry.data;
812 	if(ntohs(raddr->data->rk.type) != rr_type) {
813 		return 0;
814 	}
815 	if(packed_rrset_find_rr(d, rdata, rdatalen, &index)) {
816 		if(d->count == 1) {
817 			/* regional alloc'd */
818 			raddr->data->entry.data = NULL;
819 			raddr->data = NULL;
820 			return 1;
821 		}
822 		if(d->count > 1) {
823 			if(!local_rrset_remove_rr(d, index))
824 				return 0;
825 		}
826 	}
827 	return 0;
828 
829 }
830 
831 /** Remove RR from RPZ's local-zone */
832 static void
833 rpz_remove_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
834 	enum rpz_action a, uint16_t rr_type, uint16_t rr_class,
835 	uint8_t* rdatawl, size_t rdatalen)
836 {
837 	struct local_zone* z;
838 	int delete_zone = 1;
839 	z = rpz_find_zone(r, dname, dnamelen, rr_class,
840 		1 /* only exact */, 1 /* wr lock */, 1 /* keep lock*/);
841 	if(!z) {
842 		verbose(VERB_ALGO, "RPZ: cannot remove RR from IXFR, "
843 			"RPZ domain not found");
844 		return;
845 	}
846 	if(a == RPZ_LOCAL_DATA_ACTION)
847 		delete_zone = rpz_data_delete_rr(z, dname,
848 			dnamelen, rr_type, rdatawl, rdatalen);
849 	else if(a != localzone_type_to_rpz_action(z->type)) {
850 		lock_rw_unlock(&z->lock);
851 		lock_rw_unlock(&r->local_zones->lock);
852 		return;
853 	}
854 	lock_rw_unlock(&z->lock);
855 	if(delete_zone) {
856 		local_zones_del_zone(r->local_zones, z);
857 	}
858 	lock_rw_unlock(&r->local_zones->lock);
859 	return;
860 }
861 
862 static void
863 rpz_remove_response_ip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
864 	enum rpz_action a, uint16_t rr_type, uint8_t* rdatawl, size_t rdatalen)
865 {
866 	struct resp_addr* node;
867 	struct sockaddr_storage addr;
868 	socklen_t addrlen;
869 	int net, af;
870 	int delete_respip = 1;
871 
872 	if(!netblockdnametoaddr(dname, dnamelen, &addr, &addrlen, &net, &af))
873 		return;
874 
875 	lock_rw_wrlock(&r->respip_set->lock);
876 	if(!(node = (struct resp_addr*)addr_tree_find(
877 		&r->respip_set->ip_tree, &addr, addrlen, net))) {
878 		verbose(VERB_ALGO, "RPZ: cannot remove RR from IXFR, "
879 			"RPZ domain not found");
880 		lock_rw_unlock(&r->respip_set->lock);
881 		return;
882 	}
883 
884 	lock_rw_wrlock(&node->lock);
885 	if(a == RPZ_LOCAL_DATA_ACTION) {
886 		/* remove RR, signal whether RR can be removed */
887 		delete_respip = rpz_rrset_delete_rr(node, rr_type, rdatawl,
888 			rdatalen);
889 	}
890 	lock_rw_unlock(&node->lock);
891 	if(delete_respip)
892 		respip_sockaddr_delete(r->respip_set, node);
893 	lock_rw_unlock(&r->respip_set->lock);
894 }
895 
896 void
897 rpz_remove_rr(struct rpz* r, size_t aznamelen, uint8_t* dname, size_t dnamelen,
898 	uint16_t rr_type, uint16_t rr_class, uint8_t* rdatawl, size_t rdatalen)
899 {
900 	size_t policydnamelen;
901 	enum rpz_trigger t;
902 	enum rpz_action a;
903 	uint8_t* policydname;
904 
905 	if(!(policydname = calloc(1, LDNS_MAX_DOMAINLEN + 1)))
906 		return;
907 
908 	a = rpz_rr_to_action(rr_type, rdatawl, rdatalen);
909 	if(a == RPZ_INVALID_ACTION) {
910 		free(policydname);
911 		return;
912 	}
913 	if(!(policydnamelen = strip_dname_origin(dname, dnamelen, aznamelen,
914 		policydname, LDNS_MAX_DOMAINLEN + 1))) {
915 		free(policydname);
916 		return;
917 	}
918 	t = rpz_dname_to_trigger(policydname, policydnamelen);
919 	if(t == RPZ_QNAME_TRIGGER) {
920 		rpz_remove_qname_trigger(r, policydname, policydnamelen, a,
921 			rr_type, rr_class, rdatawl, rdatalen);
922 	} else if(t == RPZ_RESPONSE_IP_TRIGGER) {
923 		rpz_remove_response_ip_trigger(r, policydname, policydnamelen,
924 			a, rr_type, rdatawl, rdatalen);
925 	}
926 	free(policydname);
927 }
928 
929 /** print log information for an applied RPZ policy. Based on local-zone's
930  * lz_inform_print().
931  */
932 static void
933 log_rpz_apply(uint8_t* dname, enum rpz_action a, struct query_info* qinfo,
934 	struct comm_reply* repinfo, char* log_name)
935 {
936 	char ip[128], txt[512];
937 	char dnamestr[LDNS_MAX_DOMAINLEN+1];
938 	uint16_t port = ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port);
939 	dname_str(dname, dnamestr);
940 	addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip));
941 	if(log_name)
942 		snprintf(txt, sizeof(txt), "RPZ applied [%s] %s %s %s@%u",
943 			log_name, dnamestr, rpz_action_to_string(a), ip,
944 			(unsigned)port);
945 	else
946 		snprintf(txt, sizeof(txt), "RPZ applied %s %s %s@%u",
947 			dnamestr, rpz_action_to_string(a), ip, (unsigned)port);
948 	log_nametypeclass(0, txt, qinfo->qname, qinfo->qtype, qinfo->qclass);
949 }
950 
951 int
952 rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env,
953 	struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
954 	struct regional* temp, struct comm_reply* repinfo,
955 	uint8_t* taglist, size_t taglen, struct ub_server_stats* stats)
956 {
957 	struct rpz* r = NULL;
958 	struct auth_zone* a;
959 	int ret;
960 	enum localzone_type lzt;
961 	struct local_zone* z = NULL;
962 	struct local_data* ld = NULL;
963 	lock_rw_rdlock(&az->rpz_lock);
964 	for(a = az->rpz_first; a; a = a->rpz_az_next) {
965 		lock_rw_rdlock(&a->lock);
966 		r = a->rpz;
967 		if(!r->disabled && (!r->taglist || taglist_intersect(r->taglist,
968 			r->taglistlen, taglist, taglen))) {
969 			z = rpz_find_zone(r, qinfo->qname, qinfo->qname_len,
970 				qinfo->qclass, 0, 0, 0);
971 			if(z && r->action_override == RPZ_DISABLED_ACTION) {
972 				if(r->log)
973 					log_rpz_apply(z->name,
974 						r->action_override,
975 						qinfo, repinfo, r->log_name);
976 				/* TODO only register stats when stats_extended?
977 				 * */
978 				stats->rpz_action[r->action_override]++;
979 				lock_rw_unlock(&z->lock);
980 				z = NULL;
981 			}
982 			if(z)
983 				break;
984 		}
985 		lock_rw_unlock(&a->lock); /* not found in this auth_zone */
986 	}
987 	lock_rw_unlock(&az->rpz_lock);
988 	if(!z)
989 		return 0; /* not holding auth_zone.lock anymore */
990 
991 	log_assert(r);
992 	if(r->action_override == RPZ_NO_OVERRIDE_ACTION)
993 		lzt = z->type;
994 	else
995 		lzt = rpz_action_to_localzone_type(r->action_override);
996 
997 	if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) {
998 		qinfo->local_alias =
999 			regional_alloc_zero(temp, sizeof(struct local_rrset));
1000 		if(!qinfo->local_alias) {
1001 			lock_rw_unlock(&z->lock);
1002 			lock_rw_unlock(&a->lock);
1003 			return 0; /* out of memory */
1004 		}
1005 		qinfo->local_alias->rrset =
1006 			regional_alloc_init(temp, r->cname_override,
1007 				sizeof(*r->cname_override));
1008 		if(!qinfo->local_alias->rrset) {
1009 			lock_rw_unlock(&z->lock);
1010 			lock_rw_unlock(&a->lock);
1011 			return 0; /* out of memory */
1012 		}
1013 		qinfo->local_alias->rrset->rk.dname = qinfo->qname;
1014 		qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len;
1015 		if(r->log)
1016 			log_rpz_apply(z->name, RPZ_CNAME_OVERRIDE_ACTION,
1017 				qinfo, repinfo, r->log_name);
1018 		stats->rpz_action[RPZ_CNAME_OVERRIDE_ACTION]++;
1019 		lock_rw_unlock(&z->lock);
1020 		lock_rw_unlock(&a->lock);
1021 		return 0;
1022 	}
1023 
1024 	if(lzt == local_zone_redirect && local_data_answer(z, env, qinfo,
1025 		edns, repinfo, buf, temp, dname_count_labels(qinfo->qname),
1026 		&ld, lzt, -1, NULL, 0, NULL, 0)) {
1027 		if(r->log)
1028 			log_rpz_apply(z->name,
1029 				localzone_type_to_rpz_action(lzt), qinfo,
1030 				repinfo, r->log_name);
1031 		stats->rpz_action[localzone_type_to_rpz_action(lzt)]++;
1032 		lock_rw_unlock(&z->lock);
1033 		lock_rw_unlock(&a->lock);
1034 		return !qinfo->local_alias;
1035 	}
1036 
1037 	ret = local_zones_zone_answer(z, env, qinfo, edns, repinfo, buf, temp,
1038 		0 /* no local data used */, lzt);
1039 	if(r->log)
1040 		log_rpz_apply(z->name, localzone_type_to_rpz_action(lzt),
1041 			qinfo, repinfo, r->log_name);
1042 	stats->rpz_action[localzone_type_to_rpz_action(lzt)]++;
1043 	lock_rw_unlock(&z->lock);
1044 	lock_rw_unlock(&a->lock);
1045 
1046 	return ret;
1047 }
1048 
1049 void rpz_enable(struct rpz* r)
1050 {
1051     if(!r)
1052         return;
1053     r->disabled = 0;
1054 }
1055 
1056 void rpz_disable(struct rpz* r)
1057 {
1058     if(!r)
1059         return;
1060     r->disabled = 1;
1061 }
1062