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 free(r); 444 } 445 return NULL; 446 } 447 448 /** 449 * Remove RPZ zone name from dname 450 * Copy dname to newdname, without the originlen number of trailing bytes 451 */ 452 static size_t 453 strip_dname_origin(uint8_t* dname, size_t dnamelen, size_t originlen, 454 uint8_t* newdname, size_t maxnewdnamelen) 455 { 456 size_t newdnamelen; 457 if(dnamelen < originlen) 458 return 0; 459 newdnamelen = dnamelen - originlen; 460 if(newdnamelen+1 > maxnewdnamelen) 461 return 0; 462 memmove(newdname, dname, newdnamelen); 463 newdname[newdnamelen] = 0; 464 return newdnamelen + 1; /* + 1 for root label */ 465 } 466 467 /** Insert RR into RPZ's local-zone */ 468 static void 469 rpz_insert_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen, 470 enum rpz_action a, uint16_t rrtype, uint16_t rrclass, uint32_t ttl, 471 uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len) 472 { 473 struct local_zone* z; 474 enum localzone_type tp = local_zone_always_transparent; 475 int dnamelabs = dname_count_labels(dname); 476 char* rrstr; 477 int newzone = 0; 478 479 if(a == RPZ_TCP_ONLY_ACTION || a == RPZ_INVALID_ACTION) { 480 verbose(VERB_ALGO, "RPZ: skipping unsupported action: %s", 481 rpz_action_to_string(a)); 482 free(dname); 483 return; 484 } 485 486 lock_rw_wrlock(&r->local_zones->lock); 487 /* exact match */ 488 z = local_zones_find(r->local_zones, dname, dnamelen, dnamelabs, 489 LDNS_RR_CLASS_IN); 490 if(z && a != RPZ_LOCAL_DATA_ACTION) { 491 rrstr = sldns_wire2str_rr(rr, rr_len); 492 if(!rrstr) { 493 log_err("malloc error while inserting RPZ qname " 494 "trigger"); 495 free(dname); 496 lock_rw_unlock(&r->local_zones->lock); 497 return; 498 } 499 verbose(VERB_ALGO, "RPZ: skipping duplicate record: '%s'", 500 rrstr); 501 free(rrstr); 502 free(dname); 503 lock_rw_unlock(&r->local_zones->lock); 504 return; 505 } 506 if(!z) { 507 tp = rpz_action_to_localzone_type(a); 508 if(!(z = local_zones_add_zone(r->local_zones, dname, dnamelen, 509 dnamelabs, rrclass, tp))) { 510 log_warn("RPZ create failed"); 511 lock_rw_unlock(&r->local_zones->lock); 512 /* dname will be free'd in failed local_zone_create() */ 513 return; 514 } 515 newzone = 1; 516 } 517 if(a == RPZ_LOCAL_DATA_ACTION) { 518 rrstr = sldns_wire2str_rr(rr, rr_len); 519 if(!rrstr) { 520 log_err("malloc error while inserting RPZ qname " 521 "trigger"); 522 free(dname); 523 lock_rw_unlock(&r->local_zones->lock); 524 return; 525 } 526 lock_rw_wrlock(&z->lock); 527 local_zone_enter_rr(z, dname, dnamelen, dnamelabs, 528 rrtype, rrclass, ttl, rdata, rdata_len, rrstr); 529 lock_rw_unlock(&z->lock); 530 free(rrstr); 531 } 532 if(!newzone) 533 free(dname); 534 lock_rw_unlock(&r->local_zones->lock); 535 return; 536 } 537 538 /** Insert RR into RPZ's respip_set */ 539 static int 540 rpz_insert_response_ip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen, 541 enum rpz_action a, uint16_t rrtype, uint16_t rrclass, uint32_t ttl, 542 uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len) 543 { 544 struct resp_addr* node; 545 struct sockaddr_storage addr; 546 socklen_t addrlen; 547 int net, af; 548 char* rrstr; 549 enum respip_action respa = rpz_action_to_respip_action(a); 550 551 if(a == RPZ_TCP_ONLY_ACTION || a == RPZ_INVALID_ACTION || 552 respa == respip_invalid) { 553 verbose(VERB_ALGO, "RPZ: skipping unsupported action: %s", 554 rpz_action_to_string(a)); 555 return 0; 556 } 557 558 if(!netblockdnametoaddr(dname, dnamelen, &addr, &addrlen, &net, &af)) 559 return 0; 560 561 lock_rw_wrlock(&r->respip_set->lock); 562 rrstr = sldns_wire2str_rr(rr, rr_len); 563 if(!rrstr) { 564 log_err("malloc error while inserting RPZ respip trigger"); 565 lock_rw_unlock(&r->respip_set->lock); 566 return 0; 567 } 568 if(!(node=respip_sockaddr_find_or_create(r->respip_set, &addr, addrlen, 569 net, 1, rrstr))) { 570 lock_rw_unlock(&r->respip_set->lock); 571 free(rrstr); 572 return 0; 573 } 574 575 lock_rw_wrlock(&node->lock); 576 lock_rw_unlock(&r->respip_set->lock); 577 node->action = respa; 578 579 if(a == RPZ_LOCAL_DATA_ACTION) { 580 respip_enter_rr(r->respip_set->region, node, rrtype, 581 rrclass, ttl, rdata, rdata_len, rrstr, ""); 582 } 583 lock_rw_unlock(&node->lock); 584 free(rrstr); 585 return 1; 586 } 587 588 int 589 rpz_insert_rr(struct rpz* r, size_t aznamelen, uint8_t* dname, 590 size_t dnamelen, uint16_t rr_type, uint16_t rr_class, uint32_t rr_ttl, 591 uint8_t* rdatawl, size_t rdatalen, uint8_t* rr, size_t rr_len) 592 { 593 size_t policydnamelen; 594 /* name is free'd in local_zone delete */ 595 enum rpz_trigger t; 596 enum rpz_action a; 597 uint8_t* policydname; 598 599 log_assert(dnamelen >= aznamelen); 600 if(!(policydname = calloc(1, (dnamelen-aznamelen)+1))) 601 return 0; 602 603 a = rpz_rr_to_action(rr_type, rdatawl, rdatalen); 604 if(!(policydnamelen = strip_dname_origin(dname, dnamelen, aznamelen, 605 policydname, (dnamelen-aznamelen)+1))) { 606 free(policydname); 607 return 0; 608 } 609 t = rpz_dname_to_trigger(policydname, policydnamelen); 610 if(t == RPZ_INVALID_TRIGGER) { 611 free(policydname); 612 verbose(VERB_ALGO, "RPZ: skipping invalid trigger"); 613 return 1; 614 } 615 if(t == RPZ_QNAME_TRIGGER) { 616 rpz_insert_qname_trigger(r, policydname, policydnamelen, 617 a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr, 618 rr_len); 619 } 620 else if(t == RPZ_RESPONSE_IP_TRIGGER) { 621 rpz_insert_response_ip_trigger(r, policydname, policydnamelen, 622 a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr, 623 rr_len); 624 free(policydname); 625 } 626 else { 627 free(policydname); 628 verbose(VERB_ALGO, "RPZ: skipping unsupported trigger: %s", 629 rpz_trigger_to_string(t)); 630 } 631 return 1; 632 } 633 634 /** 635 * Find RPZ local-zone by qname. 636 * @param r: rpz containing local-zone tree 637 * @param qname: qname 638 * @param qname_len: length of qname 639 * @param qclass: qclass 640 * @param only_exact: if 1 only excact (non wildcard) matches are returned 641 * @param wr: get write lock for local-zone if 1, read lock if 0 642 * @param zones_keep_lock: if set do not release the r->local_zones lock, this 643 * makes the caller of this function responsible for releasing the lock. 644 * @return: NULL or local-zone holding rd or wr lock 645 */ 646 static struct local_zone* 647 rpz_find_zone(struct rpz* r, uint8_t* qname, size_t qname_len, uint16_t qclass, 648 int only_exact, int wr, int zones_keep_lock) 649 { 650 uint8_t* ce; 651 size_t ce_len, ce_labs; 652 uint8_t wc[LDNS_MAX_DOMAINLEN+1]; 653 int exact; 654 struct local_zone* z = NULL; 655 if(wr) { 656 lock_rw_wrlock(&r->local_zones->lock); 657 } else { 658 lock_rw_rdlock(&r->local_zones->lock); 659 } 660 z = local_zones_find_le(r->local_zones, qname, qname_len, 661 dname_count_labels(qname), 662 LDNS_RR_CLASS_IN, &exact); 663 if(!z || (only_exact && !exact)) { 664 lock_rw_unlock(&r->local_zones->lock); 665 return NULL; 666 } 667 if(wr) { 668 lock_rw_wrlock(&z->lock); 669 } else { 670 lock_rw_rdlock(&z->lock); 671 } 672 if(!zones_keep_lock) { 673 lock_rw_unlock(&r->local_zones->lock); 674 } 675 676 if(exact) 677 return z; 678 679 /* No exact match found, lookup wildcard. closest encloser must 680 * be the shared parent between the qname and the best local 681 * zone match, append '*' to that and do another lookup. */ 682 683 ce = dname_get_shared_topdomain(z->name, qname); 684 if(!ce /* should not happen */ || !*ce /* root */) { 685 lock_rw_unlock(&z->lock); 686 if(zones_keep_lock) { 687 lock_rw_unlock(&r->local_zones->lock); 688 } 689 return NULL; 690 } 691 ce_labs = dname_count_size_labels(ce, &ce_len); 692 if(ce_len+2 > sizeof(wc)) { 693 lock_rw_unlock(&z->lock); 694 if(zones_keep_lock) { 695 lock_rw_unlock(&r->local_zones->lock); 696 } 697 return NULL; 698 } 699 wc[0] = 1; /* length of wildcard label */ 700 wc[1] = (uint8_t)'*'; /* wildcard label */ 701 memmove(wc+2, ce, ce_len); 702 lock_rw_unlock(&z->lock); 703 704 if(!zones_keep_lock) { 705 if(wr) { 706 lock_rw_wrlock(&r->local_zones->lock); 707 } else { 708 lock_rw_rdlock(&r->local_zones->lock); 709 } 710 } 711 z = local_zones_find_le(r->local_zones, wc, 712 ce_len+2, ce_labs+1, qclass, &exact); 713 if(!z || !exact) { 714 lock_rw_unlock(&r->local_zones->lock); 715 return NULL; 716 } 717 if(wr) { 718 lock_rw_wrlock(&z->lock); 719 } else { 720 lock_rw_rdlock(&z->lock); 721 } 722 if(!zones_keep_lock) { 723 lock_rw_unlock(&r->local_zones->lock); 724 } 725 return z; 726 } 727 728 /** 729 * Remove RR from RPZ's local-data 730 * @param z: local-zone for RPZ, holding write lock 731 * @param policydname: dname of RR to remove 732 * @param policydnamelen: lenth of policydname 733 * @param rr_type: RR type of RR to remove 734 * @param rdata: rdata of RR to remove 735 * @param rdatalen: length of rdata 736 * @return: 1 if zone must be removed after RR deletion 737 */ 738 static int 739 rpz_data_delete_rr(struct local_zone* z, uint8_t* policydname, 740 size_t policydnamelen, uint16_t rr_type, uint8_t* rdata, 741 size_t rdatalen) 742 { 743 struct local_data* ld; 744 struct packed_rrset_data* d; 745 size_t index; 746 ld = local_zone_find_data(z, policydname, policydnamelen, 747 dname_count_labels(policydname)); 748 if(ld) { 749 struct local_rrset* prev=NULL, *p=ld->rrsets; 750 while(p && ntohs(p->rrset->rk.type) != rr_type) { 751 prev = p; 752 p = p->next; 753 } 754 if(!p) 755 return 0; 756 d = (struct packed_rrset_data*)p->rrset->entry.data; 757 if(packed_rrset_find_rr(d, rdata, rdatalen, &index)) { 758 if(d->count == 1) { 759 /* no memory recycling for zone deletions ... */ 760 if(prev) prev->next = p->next; 761 else ld->rrsets = p->next; 762 } 763 if(d->count > 1) { 764 if(!local_rrset_remove_rr(d, index)) 765 return 0; 766 } 767 } 768 } 769 if(ld && ld->rrsets) 770 return 0; 771 return 1; 772 } 773 774 /** 775 * Remove RR from RPZ's respip set 776 * @param raddr: respip node 777 * @param rr_type: RR type of RR to remove 778 * @param rdata: rdata of RR to remove 779 * @param rdatalen: length of rdata 780 * @return: 1 if zone must be removed after RR deletion 781 */ 782 static int 783 rpz_rrset_delete_rr(struct resp_addr* raddr, uint16_t rr_type, uint8_t* rdata, 784 size_t rdatalen) 785 { 786 size_t index; 787 struct packed_rrset_data* d; 788 if(!raddr->data) 789 return 1; 790 d = raddr->data->entry.data; 791 if(ntohs(raddr->data->rk.type) != rr_type) { 792 return 0; 793 } 794 if(packed_rrset_find_rr(d, rdata, rdatalen, &index)) { 795 if(d->count == 1) { 796 /* regional alloc'd */ 797 raddr->data->entry.data = NULL; 798 raddr->data = NULL; 799 return 1; 800 } 801 if(d->count > 1) { 802 if(!local_rrset_remove_rr(d, index)) 803 return 0; 804 } 805 } 806 return 0; 807 808 } 809 810 /** Remove RR from RPZ's local-zone */ 811 static void 812 rpz_remove_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen, 813 enum rpz_action a, uint16_t rr_type, uint16_t rr_class, 814 uint8_t* rdatawl, size_t rdatalen) 815 { 816 struct local_zone* z; 817 int delete_zone = 1; 818 z = rpz_find_zone(r, dname, dnamelen, rr_class, 819 1 /* only exact */, 1 /* wr lock */, 1 /* keep lock*/); 820 if(!z) { 821 verbose(VERB_ALGO, "RPZ: cannot remove RR from IXFR, " 822 "RPZ domain not found"); 823 return; 824 } 825 if(a == RPZ_LOCAL_DATA_ACTION) 826 delete_zone = rpz_data_delete_rr(z, dname, 827 dnamelen, rr_type, rdatawl, rdatalen); 828 else if(a != localzone_type_to_rpz_action(z->type)) { 829 return; 830 } 831 lock_rw_unlock(&z->lock); 832 if(delete_zone) { 833 local_zones_del_zone(r->local_zones, z); 834 } 835 lock_rw_unlock(&r->local_zones->lock); 836 return; 837 } 838 839 static void 840 rpz_remove_response_ip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen, 841 enum rpz_action a, uint16_t rr_type, uint8_t* rdatawl, size_t rdatalen) 842 { 843 struct resp_addr* node; 844 struct sockaddr_storage addr; 845 socklen_t addrlen; 846 int net, af; 847 int delete_respip = 1; 848 849 if(!netblockdnametoaddr(dname, dnamelen, &addr, &addrlen, &net, &af)) 850 return; 851 852 lock_rw_wrlock(&r->respip_set->lock); 853 if(!(node = (struct resp_addr*)addr_tree_find( 854 &r->respip_set->ip_tree, &addr, addrlen, net))) { 855 verbose(VERB_ALGO, "RPZ: cannot remove RR from IXFR, " 856 "RPZ domain not found"); 857 lock_rw_unlock(&r->respip_set->lock); 858 return; 859 } 860 861 lock_rw_wrlock(&node->lock); 862 if(a == RPZ_LOCAL_DATA_ACTION) { 863 /* remove RR, signal whether RR can be removed */ 864 delete_respip = rpz_rrset_delete_rr(node, rr_type, rdatawl, 865 rdatalen); 866 } 867 lock_rw_unlock(&node->lock); 868 if(delete_respip) 869 respip_sockaddr_delete(r->respip_set, node); 870 lock_rw_unlock(&r->respip_set->lock); 871 } 872 873 void 874 rpz_remove_rr(struct rpz* r, size_t aznamelen, uint8_t* dname, size_t dnamelen, 875 uint16_t rr_type, uint16_t rr_class, uint8_t* rdatawl, size_t rdatalen) 876 { 877 size_t policydnamelen; 878 enum rpz_trigger t; 879 enum rpz_action a; 880 uint8_t* policydname; 881 882 if(!(policydname = calloc(1, LDNS_MAX_DOMAINLEN + 1))) 883 return; 884 885 a = rpz_rr_to_action(rr_type, rdatawl, rdatalen); 886 if(a == RPZ_INVALID_ACTION) { 887 free(policydname); 888 return; 889 } 890 if(!(policydnamelen = strip_dname_origin(dname, dnamelen, aznamelen, 891 policydname, LDNS_MAX_DOMAINLEN + 1))) { 892 free(policydname); 893 return; 894 } 895 t = rpz_dname_to_trigger(policydname, policydnamelen); 896 if(t == RPZ_QNAME_TRIGGER) { 897 rpz_remove_qname_trigger(r, policydname, policydnamelen, a, 898 rr_type, rr_class, rdatawl, rdatalen); 899 } else if(t == RPZ_RESPONSE_IP_TRIGGER) { 900 rpz_remove_response_ip_trigger(r, policydname, policydnamelen, 901 a, rr_type, rdatawl, rdatalen); 902 } 903 free(policydname); 904 } 905 906 /** print log information for an applied RPZ policy. Based on local-zone's 907 * lz_inform_print(). 908 */ 909 static void 910 log_rpz_apply(uint8_t* dname, enum rpz_action a, struct query_info* qinfo, 911 struct comm_reply* repinfo, char* log_name) 912 { 913 char ip[128], txt[512]; 914 char dnamestr[LDNS_MAX_DOMAINLEN+1]; 915 uint16_t port = ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port); 916 dname_str(dname, dnamestr); 917 addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip)); 918 if(log_name) 919 snprintf(txt, sizeof(txt), "RPZ applied [%s] %s %s %s@%u", 920 log_name, dnamestr, rpz_action_to_string(a), ip, 921 (unsigned)port); 922 else 923 snprintf(txt, sizeof(txt), "RPZ applied %s %s %s@%u", 924 dnamestr, rpz_action_to_string(a), ip, (unsigned)port); 925 log_nametypeclass(0, txt, qinfo->qname, qinfo->qtype, qinfo->qclass); 926 } 927 928 int 929 rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env, 930 struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf, 931 struct regional* temp, struct comm_reply* repinfo, 932 uint8_t* taglist, size_t taglen, struct ub_server_stats* stats) 933 { 934 struct rpz* r; 935 int ret; 936 enum localzone_type lzt; 937 struct local_zone* z = NULL; 938 struct local_data* ld = NULL; 939 lock_rw_rdlock(&az->rpz_lock); 940 for(r = az->rpz_first; r; r = r->next) { 941 if(!r->taglist || taglist_intersect(r->taglist, 942 r->taglistlen, taglist, taglen)) { 943 z = rpz_find_zone(r, qinfo->qname, qinfo->qname_len, 944 qinfo->qclass, 0, 0, 0); 945 if(z && r->action_override == RPZ_DISABLED_ACTION) { 946 if(r->log) 947 log_rpz_apply(z->name, 948 r->action_override, 949 qinfo, repinfo, r->log_name); 950 /* TODO only register stats when stats_extended? 951 * */ 952 stats->rpz_action[r->action_override]++; 953 lock_rw_unlock(&z->lock); 954 z = NULL; 955 } 956 if(z) 957 break; 958 } 959 } 960 lock_rw_unlock(&az->rpz_lock); 961 if(!z) 962 return 0; 963 964 965 if(r->action_override == RPZ_NO_OVERRIDE_ACTION) 966 lzt = z->type; 967 else 968 lzt = rpz_action_to_localzone_type(r->action_override); 969 970 if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) { 971 qinfo->local_alias = 972 regional_alloc_zero(temp, sizeof(struct local_rrset)); 973 if(!qinfo->local_alias) { 974 lock_rw_unlock(&z->lock); 975 return 0; /* out of memory */ 976 } 977 qinfo->local_alias->rrset = 978 regional_alloc_init(temp, r->cname_override, 979 sizeof(*r->cname_override)); 980 if(!qinfo->local_alias->rrset) { 981 lock_rw_unlock(&z->lock); 982 return 0; /* out of memory */ 983 } 984 qinfo->local_alias->rrset->rk.dname = qinfo->qname; 985 qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len; 986 if(r->log) 987 log_rpz_apply(z->name, RPZ_CNAME_OVERRIDE_ACTION, 988 qinfo, repinfo, r->log_name); 989 stats->rpz_action[RPZ_CNAME_OVERRIDE_ACTION]++; 990 lock_rw_unlock(&z->lock); 991 return 0; 992 } 993 994 if(lzt == local_zone_redirect && local_data_answer(z, env, qinfo, 995 edns, repinfo, buf, temp, dname_count_labels(qinfo->qname), 996 &ld, lzt, -1, NULL, 0, NULL, 0)) { 997 if(r->log) 998 log_rpz_apply(z->name, 999 localzone_type_to_rpz_action(lzt), qinfo, 1000 repinfo, r->log_name); 1001 stats->rpz_action[localzone_type_to_rpz_action(lzt)]++; 1002 lock_rw_unlock(&z->lock); 1003 return !qinfo->local_alias; 1004 } 1005 1006 ret = local_zones_zone_answer(z, env, qinfo, edns, repinfo, buf, temp, 1007 0 /* no local data used */, lzt); 1008 if(r->log) 1009 log_rpz_apply(z->name, localzone_type_to_rpz_action(lzt), 1010 qinfo, repinfo, r->log_name); 1011 stats->rpz_action[localzone_type_to_rpz_action(lzt)]++; 1012 lock_rw_unlock(&z->lock); 1013 1014 return ret; 1015 } 1016