]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/unbound/services/rpz.c
MFV r368464:
[FreeBSD/FreeBSD.git] / contrib / unbound / services / rpz.c
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, ce_labs;
672         uint8_t wc[LDNS_MAX_DOMAINLEN+1];
673         int exact;
674         struct local_zone* z = NULL;
675         if(wr) {
676                 lock_rw_wrlock(&r->local_zones->lock);
677         } else {
678                 lock_rw_rdlock(&r->local_zones->lock);
679         }
680         z = local_zones_find_le(r->local_zones, qname, qname_len,
681                 dname_count_labels(qname),
682                 LDNS_RR_CLASS_IN, &exact);
683         if(!z || (only_exact && !exact)) {
684                 lock_rw_unlock(&r->local_zones->lock);
685                 return NULL;
686         }
687         if(wr) {
688                 lock_rw_wrlock(&z->lock);
689         } else {
690                 lock_rw_rdlock(&z->lock);
691         }
692         if(!zones_keep_lock) {
693                 lock_rw_unlock(&r->local_zones->lock);
694         }
695
696         if(exact)
697                 return z;
698
699         /* No exact match found, lookup wildcard. closest encloser must
700          * be the shared parent between the qname and the best local
701          * zone match, append '*' to that and do another lookup. */
702
703         ce = dname_get_shared_topdomain(z->name, qname);
704         if(!ce /* should not happen */ || !*ce /* root */) {
705                 lock_rw_unlock(&z->lock);
706                 if(zones_keep_lock) {
707                         lock_rw_unlock(&r->local_zones->lock);
708                 }
709                 return NULL;
710         }
711         ce_labs = dname_count_size_labels(ce, &ce_len);
712         if(ce_len+2 > sizeof(wc)) {
713                 lock_rw_unlock(&z->lock);
714                 if(zones_keep_lock) {
715                         lock_rw_unlock(&r->local_zones->lock);
716                 }
717                 return NULL;
718         }
719         wc[0] = 1; /* length of wildcard label */
720         wc[1] = (uint8_t)'*'; /* wildcard label */
721         memmove(wc+2, ce, ce_len);
722         lock_rw_unlock(&z->lock);
723
724         if(!zones_keep_lock) {
725                 if(wr) {
726                         lock_rw_wrlock(&r->local_zones->lock);
727                 } else {
728                         lock_rw_rdlock(&r->local_zones->lock);
729                 }
730         }
731         z = local_zones_find_le(r->local_zones, wc,
732                 ce_len+2, ce_labs+1, qclass, &exact);
733         if(!z || !exact) {
734                 lock_rw_unlock(&r->local_zones->lock);
735                 return NULL;
736         }
737         if(wr) {
738                 lock_rw_wrlock(&z->lock);
739         } else {
740                 lock_rw_rdlock(&z->lock);
741         }
742         if(!zones_keep_lock) {
743                 lock_rw_unlock(&r->local_zones->lock);
744         }
745         return z;
746 }
747
748 /**
749  * Remove RR from RPZ's local-data
750  * @param z: local-zone for RPZ, holding write lock
751  * @param policydname: dname of RR to remove
752  * @param policydnamelen: lenth of policydname
753  * @param rr_type: RR type of RR to remove
754  * @param rdata: rdata of RR to remove
755  * @param rdatalen: length of rdata
756  * @return: 1 if zone must be removed after RR deletion
757  */
758 static int
759 rpz_data_delete_rr(struct local_zone* z, uint8_t* policydname,
760         size_t policydnamelen, uint16_t rr_type, uint8_t* rdata,
761         size_t rdatalen)
762 {
763         struct local_data* ld;
764         struct packed_rrset_data* d;
765         size_t index;
766         ld = local_zone_find_data(z, policydname, policydnamelen,
767                 dname_count_labels(policydname));
768         if(ld) {
769                 struct local_rrset* prev=NULL, *p=ld->rrsets;
770                 while(p && ntohs(p->rrset->rk.type) != rr_type) {
771                         prev = p;
772                         p = p->next;
773                 }
774                 if(!p)
775                         return 0;
776                 d = (struct packed_rrset_data*)p->rrset->entry.data;
777                 if(packed_rrset_find_rr(d, rdata, rdatalen, &index)) {
778                         if(d->count == 1) {
779                                 /* no memory recycling for zone deletions ... */
780                                 if(prev) prev->next = p->next;
781                                 else ld->rrsets = p->next;
782                         }
783                         if(d->count > 1) {
784                                 if(!local_rrset_remove_rr(d, index))
785                                         return 0;
786                         }
787                 }
788         }
789         if(ld && ld->rrsets)
790                 return 0;
791         return 1;
792 }
793
794 /**
795  * Remove RR from RPZ's respip set
796  * @param raddr: respip node
797  * @param rr_type: RR type of RR to remove
798  * @param rdata: rdata of RR to remove
799  * @param rdatalen: length of rdata
800  * @return: 1 if zone must be removed after RR deletion
801  */
802 static int
803 rpz_rrset_delete_rr(struct resp_addr* raddr, uint16_t rr_type, uint8_t* rdata,
804         size_t rdatalen)
805 {
806         size_t index;
807         struct packed_rrset_data* d;
808         if(!raddr->data)
809                 return 1;
810         d = raddr->data->entry.data;
811         if(ntohs(raddr->data->rk.type) != rr_type) {
812                 return 0;
813         }
814         if(packed_rrset_find_rr(d, rdata, rdatalen, &index)) {
815                 if(d->count == 1) {
816                         /* regional alloc'd */
817                         raddr->data->entry.data = NULL; 
818                         raddr->data = NULL;
819                         return 1;
820                 }
821                 if(d->count > 1) {
822                         if(!local_rrset_remove_rr(d, index))
823                                 return 0;
824                 }
825         }
826         return 0;
827
828 }
829
830 /** Remove RR from RPZ's local-zone */
831 static void
832 rpz_remove_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
833         enum rpz_action a, uint16_t rr_type, uint16_t rr_class,
834         uint8_t* rdatawl, size_t rdatalen)
835 {
836         struct local_zone* z;
837         int delete_zone = 1;
838         z = rpz_find_zone(r, dname, dnamelen, rr_class,
839                 1 /* only exact */, 1 /* wr lock */, 1 /* keep lock*/);
840         if(!z) {
841                 verbose(VERB_ALGO, "RPZ: cannot remove RR from IXFR, "
842                         "RPZ domain not found");
843                 return;
844         }
845         if(a == RPZ_LOCAL_DATA_ACTION)
846                 delete_zone = rpz_data_delete_rr(z, dname,
847                         dnamelen, rr_type, rdatawl, rdatalen);
848         else if(a != localzone_type_to_rpz_action(z->type)) {
849                 lock_rw_unlock(&z->lock);
850                 lock_rw_unlock(&r->local_zones->lock);
851                 return;
852         }
853         lock_rw_unlock(&z->lock); 
854         if(delete_zone) {
855                 local_zones_del_zone(r->local_zones, z);
856         }
857         lock_rw_unlock(&r->local_zones->lock); 
858         return;
859 }
860
861 static void
862 rpz_remove_response_ip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
863         enum rpz_action a, uint16_t rr_type, uint8_t* rdatawl, size_t rdatalen)
864 {
865         struct resp_addr* node;
866         struct sockaddr_storage addr;
867         socklen_t addrlen;
868         int net, af;
869         int delete_respip = 1;
870
871         if(!netblockdnametoaddr(dname, dnamelen, &addr, &addrlen, &net, &af))
872                 return;
873
874         lock_rw_wrlock(&r->respip_set->lock);
875         if(!(node = (struct resp_addr*)addr_tree_find(
876                 &r->respip_set->ip_tree, &addr, addrlen, net))) {
877                 verbose(VERB_ALGO, "RPZ: cannot remove RR from IXFR, "
878                         "RPZ domain not found");
879                 lock_rw_unlock(&r->respip_set->lock);
880                 return;
881         }
882
883         lock_rw_wrlock(&node->lock);
884         if(a == RPZ_LOCAL_DATA_ACTION) {
885                 /* remove RR, signal whether RR can be removed */
886                 delete_respip = rpz_rrset_delete_rr(node, rr_type, rdatawl, 
887                         rdatalen);
888         }
889         lock_rw_unlock(&node->lock);
890         if(delete_respip)
891                 respip_sockaddr_delete(r->respip_set, node);
892         lock_rw_unlock(&r->respip_set->lock);
893 }
894
895 void
896 rpz_remove_rr(struct rpz* r, size_t aznamelen, uint8_t* dname, size_t dnamelen,
897         uint16_t rr_type, uint16_t rr_class, uint8_t* rdatawl, size_t rdatalen)
898 {
899         size_t policydnamelen;
900         enum rpz_trigger t;
901         enum rpz_action a;
902         uint8_t* policydname;
903
904         if(!(policydname = calloc(1, LDNS_MAX_DOMAINLEN + 1)))
905                 return;
906
907         a = rpz_rr_to_action(rr_type, rdatawl, rdatalen);
908         if(a == RPZ_INVALID_ACTION) {
909                 free(policydname);
910                 return;
911         }
912         if(!(policydnamelen = strip_dname_origin(dname, dnamelen, aznamelen,
913                 policydname, LDNS_MAX_DOMAINLEN + 1))) {
914                 free(policydname);
915                 return;
916         }
917         t = rpz_dname_to_trigger(policydname, policydnamelen);
918         if(t == RPZ_QNAME_TRIGGER) {
919                 rpz_remove_qname_trigger(r, policydname, policydnamelen, a,
920                         rr_type, rr_class, rdatawl, rdatalen);
921         } else if(t == RPZ_RESPONSE_IP_TRIGGER) {
922                 rpz_remove_response_ip_trigger(r, policydname, policydnamelen,
923                         a, rr_type, rdatawl, rdatalen);
924         }
925         free(policydname);
926 }
927
928 /** print log information for an applied RPZ policy. Based on local-zone's
929  * lz_inform_print().
930  */
931 static void
932 log_rpz_apply(uint8_t* dname, enum rpz_action a, struct query_info* qinfo,
933         struct comm_reply* repinfo, char* log_name)
934 {
935         char ip[128], txt[512];
936         char dnamestr[LDNS_MAX_DOMAINLEN+1];
937         uint16_t port = ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port);
938         dname_str(dname, dnamestr);
939         addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip));
940         if(log_name)
941                 snprintf(txt, sizeof(txt), "RPZ applied [%s] %s %s %s@%u",
942                         log_name, dnamestr, rpz_action_to_string(a), ip,
943                         (unsigned)port);
944         else
945                 snprintf(txt, sizeof(txt), "RPZ applied %s %s %s@%u",
946                         dnamestr, rpz_action_to_string(a), ip, (unsigned)port);
947         log_nametypeclass(0, txt, qinfo->qname, qinfo->qtype, qinfo->qclass);
948 }
949
950 int
951 rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env,
952         struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
953         struct regional* temp, struct comm_reply* repinfo,
954         uint8_t* taglist, size_t taglen, struct ub_server_stats* stats)
955 {
956         struct rpz* r = NULL;
957         struct auth_zone* a;
958         int ret;
959         enum localzone_type lzt;
960         struct local_zone* z = NULL;
961         struct local_data* ld = NULL;
962         lock_rw_rdlock(&az->rpz_lock);
963         for(a = az->rpz_first; a; a = a->rpz_az_next) {
964                 lock_rw_rdlock(&a->lock);
965                 r = a->rpz;
966                 if(!r->taglist || taglist_intersect(r->taglist, 
967                         r->taglistlen, taglist, taglen)) {
968                         z = rpz_find_zone(r, qinfo->qname, qinfo->qname_len,
969                                 qinfo->qclass, 0, 0, 0);
970                         if(z && r->action_override == RPZ_DISABLED_ACTION) {
971                                 if(r->log)
972                                         log_rpz_apply(z->name,
973                                                 r->action_override,
974                                                 qinfo, repinfo, r->log_name);
975                                 /* TODO only register stats when stats_extended?
976                                  * */
977                                 stats->rpz_action[r->action_override]++;
978                                 lock_rw_unlock(&z->lock);
979                                 z = NULL;
980                         }
981                         if(z)
982                                 break;
983                 }
984                 lock_rw_unlock(&a->lock); /* not found in this auth_zone */
985         }
986         lock_rw_unlock(&az->rpz_lock);
987         if(!z)
988                 return 0; /* not holding auth_zone.lock anymore */
989
990         log_assert(r);
991         if(r->action_override == RPZ_NO_OVERRIDE_ACTION)
992                 lzt = z->type;
993         else
994                 lzt = rpz_action_to_localzone_type(r->action_override);
995
996         if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) {
997                 qinfo->local_alias =
998                         regional_alloc_zero(temp, sizeof(struct local_rrset));
999                 if(!qinfo->local_alias) {
1000                         lock_rw_unlock(&z->lock);
1001                         lock_rw_unlock(&a->lock);
1002                         return 0; /* out of memory */
1003                 }
1004                 qinfo->local_alias->rrset =
1005                         regional_alloc_init(temp, r->cname_override,
1006                                 sizeof(*r->cname_override));
1007                 if(!qinfo->local_alias->rrset) {
1008                         lock_rw_unlock(&z->lock);
1009                         lock_rw_unlock(&a->lock);
1010                         return 0; /* out of memory */
1011                 }
1012                 qinfo->local_alias->rrset->rk.dname = qinfo->qname;
1013                 qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len;
1014                 if(r->log)
1015                         log_rpz_apply(z->name, RPZ_CNAME_OVERRIDE_ACTION, 
1016                                 qinfo, repinfo, r->log_name);
1017                 stats->rpz_action[RPZ_CNAME_OVERRIDE_ACTION]++;
1018                 lock_rw_unlock(&z->lock);
1019                 lock_rw_unlock(&a->lock);
1020                 return 0;
1021         }
1022
1023         if(lzt == local_zone_redirect && local_data_answer(z, env, qinfo,
1024                 edns, repinfo, buf, temp, dname_count_labels(qinfo->qname),
1025                 &ld, lzt, -1, NULL, 0, NULL, 0)) {
1026                 if(r->log)
1027                         log_rpz_apply(z->name,
1028                                 localzone_type_to_rpz_action(lzt), qinfo,
1029                                 repinfo, r->log_name);
1030                 stats->rpz_action[localzone_type_to_rpz_action(lzt)]++;
1031                 lock_rw_unlock(&z->lock);
1032                 lock_rw_unlock(&a->lock);
1033                 return !qinfo->local_alias;
1034         }
1035
1036         ret = local_zones_zone_answer(z, env, qinfo, edns, repinfo, buf, temp,
1037                 0 /* no local data used */, lzt);
1038         if(r->log)
1039                 log_rpz_apply(z->name, localzone_type_to_rpz_action(lzt),
1040                         qinfo, repinfo, r->log_name);
1041         stats->rpz_action[localzone_type_to_rpz_action(lzt)]++;
1042         lock_rw_unlock(&z->lock);
1043         lock_rw_unlock(&a->lock);
1044
1045         return ret;
1046 }