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 */
55const char*
56rpz_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 */
74static enum rpz_action
75rpz_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 */
95static const char*
96rpz_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 */
115static uint8_t*
116get_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 */
147static enum rpz_action
148rpz_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
206static enum localzone_type
207rpz_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
222enum respip_action
223rpz_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
238static enum rpz_action
239localzone_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
253enum rpz_action
254respip_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 */
274static enum rpz_trigger
275rpz_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
300void 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
312int
313rpz_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
327void
328rpz_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 */
336static struct ub_packed_rrset_key*
337new_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
381struct rpz*
382rpz_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;
435err:
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 */
454static size_t
455strip_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 */
470static void
471rpz_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 */
541static int
542rpz_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
590int
591rpz_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 */
666static struct local_zone*
667rpz_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 */
759static int
760rpz_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 */
803static int
804rpz_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 */
832static void
833rpz_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
862static void
863rpz_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
896void
897rpz_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 */
932static void
933log_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
951int
952rpz_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
1049void rpz_enable(struct rpz* r)
1050{
1051    if(!r)
1052        return;
1053    r->disabled = 0;
1054}
1055
1056void rpz_disable(struct rpz* r)
1057{
1058    if(!r)
1059        return;
1060    r->disabled = 1;
1061}
1062