1091e9e46SCy Schubert /* 2091e9e46SCy Schubert * services/rpz.c - rpz service 3091e9e46SCy Schubert * 4091e9e46SCy Schubert * Copyright (c) 2019, NLnet Labs. All rights reserved. 5091e9e46SCy Schubert * 6091e9e46SCy Schubert * This software is open source. 7091e9e46SCy Schubert * 8091e9e46SCy Schubert * Redistribution and use in source and binary forms, with or without 9091e9e46SCy Schubert * modification, are permitted provided that the following conditions 10091e9e46SCy Schubert * are met: 11091e9e46SCy Schubert * 12091e9e46SCy Schubert * Redistributions of source code must retain the above copyright notice, 13091e9e46SCy Schubert * this list of conditions and the following disclaimer. 14091e9e46SCy Schubert * 15091e9e46SCy Schubert * Redistributions in binary form must reproduce the above copyright notice, 16091e9e46SCy Schubert * this list of conditions and the following disclaimer in the documentation 17091e9e46SCy Schubert * and/or other materials provided with the distribution. 18091e9e46SCy Schubert * 19091e9e46SCy Schubert * Neither the name of the NLNET LABS nor the names of its contributors may 20091e9e46SCy Schubert * be used to endorse or promote products derived from this software without 21091e9e46SCy Schubert * specific prior written permission. 22091e9e46SCy Schubert * 23091e9e46SCy Schubert * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24091e9e46SCy Schubert * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25091e9e46SCy Schubert * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26091e9e46SCy Schubert * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27091e9e46SCy Schubert * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28091e9e46SCy Schubert * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29091e9e46SCy Schubert * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30091e9e46SCy Schubert * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31091e9e46SCy Schubert * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32091e9e46SCy Schubert * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33091e9e46SCy Schubert * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34091e9e46SCy Schubert */ 35091e9e46SCy Schubert 36091e9e46SCy Schubert /** 37091e9e46SCy Schubert * \file 38091e9e46SCy Schubert * 39091e9e46SCy Schubert * This file contains functions to enable RPZ service. 40091e9e46SCy Schubert */ 41091e9e46SCy Schubert 42091e9e46SCy Schubert #include "config.h" 43091e9e46SCy Schubert #include "services/rpz.h" 44091e9e46SCy Schubert #include "util/config_file.h" 45091e9e46SCy Schubert #include "sldns/wire2str.h" 46091e9e46SCy Schubert #include "sldns/str2wire.h" 47091e9e46SCy Schubert #include "util/data/dname.h" 48091e9e46SCy Schubert #include "util/net_help.h" 49091e9e46SCy Schubert #include "util/log.h" 50091e9e46SCy Schubert #include "util/data/dname.h" 51091e9e46SCy Schubert #include "util/locks.h" 52091e9e46SCy Schubert #include "util/regional.h" 5324e36522SCy Schubert #include "util/data/msgencode.h" 5424e36522SCy Schubert #include "services/cache/dns.h" 5524e36522SCy Schubert #include "iterator/iterator.h" 5624e36522SCy Schubert #include "iterator/iter_delegpt.h" 5724e36522SCy Schubert #include "daemon/worker.h" 5824e36522SCy Schubert 5924e36522SCy Schubert typedef struct resp_addr rpz_aclnode_type; 6024e36522SCy Schubert 6124e36522SCy Schubert struct matched_delegation_point { 6224e36522SCy Schubert uint8_t* dname; 6324e36522SCy Schubert size_t dname_len; 6424e36522SCy Schubert }; 65091e9e46SCy Schubert 66091e9e46SCy Schubert /** string for RPZ action enum */ 67091e9e46SCy Schubert const char* 68091e9e46SCy Schubert rpz_action_to_string(enum rpz_action a) 69091e9e46SCy Schubert { 70091e9e46SCy Schubert switch(a) { 7124e36522SCy Schubert case RPZ_NXDOMAIN_ACTION: return "rpz-nxdomain"; 7224e36522SCy Schubert case RPZ_NODATA_ACTION: return "rpz-nodata"; 7324e36522SCy Schubert case RPZ_PASSTHRU_ACTION: return "rpz-passthru"; 7424e36522SCy Schubert case RPZ_DROP_ACTION: return "rpz-drop"; 7524e36522SCy Schubert case RPZ_TCP_ONLY_ACTION: return "rpz-tcp-only"; 7624e36522SCy Schubert case RPZ_INVALID_ACTION: return "rpz-invalid"; 7724e36522SCy Schubert case RPZ_LOCAL_DATA_ACTION: return "rpz-local-data"; 7824e36522SCy Schubert case RPZ_DISABLED_ACTION: return "rpz-disabled"; 7924e36522SCy Schubert case RPZ_CNAME_OVERRIDE_ACTION: return "rpz-cname-override"; 8024e36522SCy Schubert case RPZ_NO_OVERRIDE_ACTION: return "rpz-no-override"; 8124e36522SCy Schubert default: return "rpz-unknown-action"; 82091e9e46SCy Schubert } 83091e9e46SCy Schubert } 84091e9e46SCy Schubert 85091e9e46SCy Schubert /** RPZ action enum for config string */ 86091e9e46SCy Schubert static enum rpz_action 87091e9e46SCy Schubert rpz_config_to_action(char* a) 88091e9e46SCy Schubert { 8924e36522SCy Schubert if(strcmp(a, "nxdomain") == 0) return RPZ_NXDOMAIN_ACTION; 9024e36522SCy Schubert else if(strcmp(a, "nodata") == 0) return RPZ_NODATA_ACTION; 9124e36522SCy Schubert else if(strcmp(a, "passthru") == 0) return RPZ_PASSTHRU_ACTION; 9224e36522SCy Schubert else if(strcmp(a, "drop") == 0) return RPZ_DROP_ACTION; 9324e36522SCy Schubert else if(strcmp(a, "tcp_only") == 0) return RPZ_TCP_ONLY_ACTION; 9424e36522SCy Schubert else if(strcmp(a, "cname") == 0) return RPZ_CNAME_OVERRIDE_ACTION; 9524e36522SCy Schubert else if(strcmp(a, "disabled") == 0) return RPZ_DISABLED_ACTION; 9624e36522SCy Schubert else return RPZ_INVALID_ACTION; 97091e9e46SCy Schubert } 98091e9e46SCy Schubert 99091e9e46SCy Schubert /** string for RPZ trigger enum */ 100091e9e46SCy Schubert static const char* 101091e9e46SCy Schubert rpz_trigger_to_string(enum rpz_trigger r) 102091e9e46SCy Schubert { 103091e9e46SCy Schubert switch(r) { 10424e36522SCy Schubert case RPZ_QNAME_TRIGGER: return "rpz-qname"; 10524e36522SCy Schubert case RPZ_CLIENT_IP_TRIGGER: return "rpz-client-ip"; 10624e36522SCy Schubert case RPZ_RESPONSE_IP_TRIGGER: return "rpz-response-ip"; 10724e36522SCy Schubert case RPZ_NSDNAME_TRIGGER: return "rpz-nsdname"; 10824e36522SCy Schubert case RPZ_NSIP_TRIGGER: return "rpz-nsip"; 10924e36522SCy Schubert case RPZ_INVALID_TRIGGER: return "rpz-invalid"; 11024e36522SCy Schubert default: return "rpz-unknown-trigger"; 111091e9e46SCy Schubert } 112091e9e46SCy Schubert } 113091e9e46SCy Schubert 114091e9e46SCy Schubert /** 115091e9e46SCy Schubert * Get the label that is just before the root label. 116091e9e46SCy Schubert * @param dname: dname to work on 117091e9e46SCy Schubert * @param maxdnamelen: maximum length of the dname 118091e9e46SCy Schubert * @return: pointer to TLD label, NULL if not found or invalid dname 119091e9e46SCy Schubert */ 120091e9e46SCy Schubert static uint8_t* 121091e9e46SCy Schubert get_tld_label(uint8_t* dname, size_t maxdnamelen) 122091e9e46SCy Schubert { 123091e9e46SCy Schubert uint8_t* prevlab = dname; 124091e9e46SCy Schubert size_t dnamelen = 0; 125091e9e46SCy Schubert 126091e9e46SCy Schubert /* one byte needed for label length */ 127091e9e46SCy Schubert if(dnamelen+1 > maxdnamelen) 128091e9e46SCy Schubert return NULL; 129091e9e46SCy Schubert 130091e9e46SCy Schubert /* only root label */ 131091e9e46SCy Schubert if(*dname == 0) 132091e9e46SCy Schubert return NULL; 133091e9e46SCy Schubert 134091e9e46SCy Schubert while(*dname) { 135091e9e46SCy Schubert dnamelen += ((size_t)*dname)+1; 136091e9e46SCy Schubert if(dnamelen+1 > maxdnamelen) 137091e9e46SCy Schubert return NULL; 138091e9e46SCy Schubert dname = dname+((size_t)*dname)+1; 139091e9e46SCy Schubert if(*dname != 0) 140091e9e46SCy Schubert prevlab = dname; 141091e9e46SCy Schubert } 142091e9e46SCy Schubert return prevlab; 143091e9e46SCy Schubert } 144091e9e46SCy Schubert 145091e9e46SCy Schubert /** 14624e36522SCy Schubert * The RR types that are to be ignored. 14724e36522SCy Schubert * DNSSEC RRs at the apex, and SOA and NS are ignored. 14824e36522SCy Schubert */ 14924e36522SCy Schubert static int 15024e36522SCy Schubert rpz_type_ignored(uint16_t rr_type) 15124e36522SCy Schubert { 15224e36522SCy Schubert switch(rr_type) { 15324e36522SCy Schubert case LDNS_RR_TYPE_SOA: 15424e36522SCy Schubert case LDNS_RR_TYPE_NS: 15524e36522SCy Schubert case LDNS_RR_TYPE_DNAME: 15624e36522SCy Schubert /* all DNSSEC-related RRs must be ignored */ 15724e36522SCy Schubert case LDNS_RR_TYPE_DNSKEY: 15824e36522SCy Schubert case LDNS_RR_TYPE_DS: 15924e36522SCy Schubert case LDNS_RR_TYPE_RRSIG: 16024e36522SCy Schubert case LDNS_RR_TYPE_NSEC: 16124e36522SCy Schubert case LDNS_RR_TYPE_NSEC3: 16224e36522SCy Schubert case LDNS_RR_TYPE_NSEC3PARAM: 16324e36522SCy Schubert return 1; 16424e36522SCy Schubert default: 16524e36522SCy Schubert break; 16624e36522SCy Schubert } 16724e36522SCy Schubert return 0; 16824e36522SCy Schubert } 16924e36522SCy Schubert 17024e36522SCy Schubert /** 171091e9e46SCy Schubert * Classify RPZ action for RR type/rdata 172091e9e46SCy Schubert * @param rr_type: the RR type 173091e9e46SCy Schubert * @param rdatawl: RDATA with 2 bytes length 174091e9e46SCy Schubert * @param rdatalen: the length of rdatawl (including its 2 bytes length) 175091e9e46SCy Schubert * @return: the RPZ action 176091e9e46SCy Schubert */ 177091e9e46SCy Schubert static enum rpz_action 178091e9e46SCy Schubert rpz_rr_to_action(uint16_t rr_type, uint8_t* rdatawl, size_t rdatalen) 179091e9e46SCy Schubert { 180091e9e46SCy Schubert char* endptr; 181091e9e46SCy Schubert uint8_t* rdata; 182091e9e46SCy Schubert int rdatalabs; 183091e9e46SCy Schubert uint8_t* tldlab = NULL; 184091e9e46SCy Schubert 185091e9e46SCy Schubert switch(rr_type) { 186091e9e46SCy Schubert case LDNS_RR_TYPE_SOA: 187091e9e46SCy Schubert case LDNS_RR_TYPE_NS: 188091e9e46SCy Schubert case LDNS_RR_TYPE_DNAME: 189091e9e46SCy Schubert /* all DNSSEC-related RRs must be ignored */ 190091e9e46SCy Schubert case LDNS_RR_TYPE_DNSKEY: 191091e9e46SCy Schubert case LDNS_RR_TYPE_DS: 192091e9e46SCy Schubert case LDNS_RR_TYPE_RRSIG: 193091e9e46SCy Schubert case LDNS_RR_TYPE_NSEC: 194091e9e46SCy Schubert case LDNS_RR_TYPE_NSEC3: 1955469a995SCy Schubert case LDNS_RR_TYPE_NSEC3PARAM: 196091e9e46SCy Schubert return RPZ_INVALID_ACTION; 197091e9e46SCy Schubert case LDNS_RR_TYPE_CNAME: 198091e9e46SCy Schubert break; 199091e9e46SCy Schubert default: 200091e9e46SCy Schubert return RPZ_LOCAL_DATA_ACTION; 201091e9e46SCy Schubert } 202091e9e46SCy Schubert 203091e9e46SCy Schubert /* use CNAME target to determine RPZ action */ 204091e9e46SCy Schubert log_assert(rr_type == LDNS_RR_TYPE_CNAME); 205091e9e46SCy Schubert if(rdatalen < 3) 206091e9e46SCy Schubert return RPZ_INVALID_ACTION; 207091e9e46SCy Schubert 208091e9e46SCy Schubert rdata = rdatawl + 2; /* 2 bytes of rdata length */ 209091e9e46SCy Schubert if(dname_valid(rdata, rdatalen-2) != rdatalen-2) 210091e9e46SCy Schubert return RPZ_INVALID_ACTION; 211091e9e46SCy Schubert 212091e9e46SCy Schubert rdatalabs = dname_count_labels(rdata); 213091e9e46SCy Schubert if(rdatalabs == 1) 214091e9e46SCy Schubert return RPZ_NXDOMAIN_ACTION; 215091e9e46SCy Schubert else if(rdatalabs == 2) { 216091e9e46SCy Schubert if(dname_subdomain_c(rdata, (uint8_t*)&"\001*\000")) 217091e9e46SCy Schubert return RPZ_NODATA_ACTION; 218091e9e46SCy Schubert else if(dname_subdomain_c(rdata, 219091e9e46SCy Schubert (uint8_t*)&"\014rpz-passthru\000")) 220091e9e46SCy Schubert return RPZ_PASSTHRU_ACTION; 221091e9e46SCy Schubert else if(dname_subdomain_c(rdata, (uint8_t*)&"\010rpz-drop\000")) 222091e9e46SCy Schubert return RPZ_DROP_ACTION; 223091e9e46SCy Schubert else if(dname_subdomain_c(rdata, 224091e9e46SCy Schubert (uint8_t*)&"\014rpz-tcp-only\000")) 225091e9e46SCy Schubert return RPZ_TCP_ONLY_ACTION; 226091e9e46SCy Schubert } 227091e9e46SCy Schubert 228091e9e46SCy Schubert /* all other TLDs starting with "rpz-" are invalid */ 229091e9e46SCy Schubert tldlab = get_tld_label(rdata, rdatalen-2); 230091e9e46SCy Schubert if(tldlab && dname_lab_startswith(tldlab, "rpz-", &endptr)) 231091e9e46SCy Schubert return RPZ_INVALID_ACTION; 232091e9e46SCy Schubert 233091e9e46SCy Schubert /* no special label found */ 234091e9e46SCy Schubert return RPZ_LOCAL_DATA_ACTION; 235091e9e46SCy Schubert } 236091e9e46SCy Schubert 237091e9e46SCy Schubert static enum localzone_type 238091e9e46SCy Schubert rpz_action_to_localzone_type(enum rpz_action a) 239091e9e46SCy Schubert { 240091e9e46SCy Schubert switch(a) { 241091e9e46SCy Schubert case RPZ_NXDOMAIN_ACTION: return local_zone_always_nxdomain; 242091e9e46SCy Schubert case RPZ_NODATA_ACTION: return local_zone_always_nodata; 243091e9e46SCy Schubert case RPZ_DROP_ACTION: return local_zone_always_deny; 244091e9e46SCy Schubert case RPZ_PASSTHRU_ACTION: return local_zone_always_transparent; 24556850988SCy Schubert case RPZ_LOCAL_DATA_ACTION: 24656850988SCy Schubert ATTR_FALLTHROUGH 24756850988SCy Schubert /* fallthrough */ 248091e9e46SCy Schubert case RPZ_CNAME_OVERRIDE_ACTION: return local_zone_redirect; 24924e36522SCy Schubert case RPZ_TCP_ONLY_ACTION: return local_zone_truncate; 25056850988SCy Schubert case RPZ_INVALID_ACTION: 25156850988SCy Schubert ATTR_FALLTHROUGH 25256850988SCy Schubert /* fallthrough */ 253091e9e46SCy Schubert default: return local_zone_invalid; 254091e9e46SCy Schubert } 255091e9e46SCy Schubert } 256091e9e46SCy Schubert 257091e9e46SCy Schubert enum respip_action 258091e9e46SCy Schubert rpz_action_to_respip_action(enum rpz_action a) 259091e9e46SCy Schubert { 260091e9e46SCy Schubert switch(a) { 261091e9e46SCy Schubert case RPZ_NXDOMAIN_ACTION: return respip_always_nxdomain; 262091e9e46SCy Schubert case RPZ_NODATA_ACTION: return respip_always_nodata; 263091e9e46SCy Schubert case RPZ_DROP_ACTION: return respip_always_deny; 264091e9e46SCy Schubert case RPZ_PASSTHRU_ACTION: return respip_always_transparent; 26556850988SCy Schubert case RPZ_LOCAL_DATA_ACTION: 26656850988SCy Schubert ATTR_FALLTHROUGH 26756850988SCy Schubert /* fallthrough */ 268091e9e46SCy Schubert case RPZ_CNAME_OVERRIDE_ACTION: return respip_redirect; 26924e36522SCy Schubert case RPZ_TCP_ONLY_ACTION: return respip_truncate; 27056850988SCy Schubert case RPZ_INVALID_ACTION: 27156850988SCy Schubert ATTR_FALLTHROUGH 27256850988SCy Schubert /* fallthrough */ 273091e9e46SCy Schubert default: return respip_invalid; 274091e9e46SCy Schubert } 275091e9e46SCy Schubert } 276091e9e46SCy Schubert 277091e9e46SCy Schubert static enum rpz_action 278091e9e46SCy Schubert localzone_type_to_rpz_action(enum localzone_type lzt) 279091e9e46SCy Schubert { 280091e9e46SCy Schubert switch(lzt) { 281091e9e46SCy Schubert case local_zone_always_nxdomain: return RPZ_NXDOMAIN_ACTION; 282091e9e46SCy Schubert case local_zone_always_nodata: return RPZ_NODATA_ACTION; 283091e9e46SCy Schubert case local_zone_always_deny: return RPZ_DROP_ACTION; 284091e9e46SCy Schubert case local_zone_always_transparent: return RPZ_PASSTHRU_ACTION; 285091e9e46SCy Schubert case local_zone_redirect: return RPZ_LOCAL_DATA_ACTION; 28624e36522SCy Schubert case local_zone_truncate: return RPZ_TCP_ONLY_ACTION; 28756850988SCy Schubert case local_zone_invalid: 28856850988SCy Schubert ATTR_FALLTHROUGH 28956850988SCy Schubert /* fallthrough */ 29024e36522SCy Schubert default: return RPZ_INVALID_ACTION; 291091e9e46SCy Schubert } 292091e9e46SCy Schubert } 293091e9e46SCy Schubert 294091e9e46SCy Schubert enum rpz_action 295091e9e46SCy Schubert respip_action_to_rpz_action(enum respip_action a) 296091e9e46SCy Schubert { 297091e9e46SCy Schubert switch(a) { 298091e9e46SCy Schubert case respip_always_nxdomain: return RPZ_NXDOMAIN_ACTION; 299091e9e46SCy Schubert case respip_always_nodata: return RPZ_NODATA_ACTION; 300091e9e46SCy Schubert case respip_always_deny: return RPZ_DROP_ACTION; 301091e9e46SCy Schubert case respip_always_transparent: return RPZ_PASSTHRU_ACTION; 302091e9e46SCy Schubert case respip_redirect: return RPZ_LOCAL_DATA_ACTION; 30324e36522SCy Schubert case respip_truncate: return RPZ_TCP_ONLY_ACTION; 30456850988SCy Schubert case respip_invalid: 30556850988SCy Schubert ATTR_FALLTHROUGH 30656850988SCy Schubert /* fallthrough */ 30724e36522SCy Schubert default: return RPZ_INVALID_ACTION; 308091e9e46SCy Schubert } 309091e9e46SCy Schubert } 310091e9e46SCy Schubert 311091e9e46SCy Schubert /** 312091e9e46SCy Schubert * Get RPZ trigger for dname 313091e9e46SCy Schubert * @param dname: dname containing RPZ trigger 314091e9e46SCy Schubert * @param dname_len: length of the dname 315091e9e46SCy Schubert * @return: RPZ trigger enum 316091e9e46SCy Schubert */ 317091e9e46SCy Schubert static enum rpz_trigger 318091e9e46SCy Schubert rpz_dname_to_trigger(uint8_t* dname, size_t dname_len) 319091e9e46SCy Schubert { 320091e9e46SCy Schubert uint8_t* tldlab; 321091e9e46SCy Schubert char* endptr; 322091e9e46SCy Schubert 323091e9e46SCy Schubert if(dname_valid(dname, dname_len) != dname_len) 324091e9e46SCy Schubert return RPZ_INVALID_TRIGGER; 325091e9e46SCy Schubert 326091e9e46SCy Schubert tldlab = get_tld_label(dname, dname_len); 327091e9e46SCy Schubert if(!tldlab || !dname_lab_startswith(tldlab, "rpz-", &endptr)) 328091e9e46SCy Schubert return RPZ_QNAME_TRIGGER; 329091e9e46SCy Schubert 330091e9e46SCy Schubert if(dname_subdomain_c(tldlab, 331091e9e46SCy Schubert (uint8_t*)&"\015rpz-client-ip\000")) 332091e9e46SCy Schubert return RPZ_CLIENT_IP_TRIGGER; 333091e9e46SCy Schubert else if(dname_subdomain_c(tldlab, (uint8_t*)&"\006rpz-ip\000")) 334091e9e46SCy Schubert return RPZ_RESPONSE_IP_TRIGGER; 335091e9e46SCy Schubert else if(dname_subdomain_c(tldlab, (uint8_t*)&"\013rpz-nsdname\000")) 336091e9e46SCy Schubert return RPZ_NSDNAME_TRIGGER; 337091e9e46SCy Schubert else if(dname_subdomain_c(tldlab, (uint8_t*)&"\010rpz-nsip\000")) 338091e9e46SCy Schubert return RPZ_NSIP_TRIGGER; 339091e9e46SCy Schubert 340091e9e46SCy Schubert return RPZ_QNAME_TRIGGER; 341091e9e46SCy Schubert } 342091e9e46SCy Schubert 34324e36522SCy Schubert static inline struct clientip_synthesized_rrset* 34424e36522SCy Schubert rpz_clientip_synthesized_set_create(void) 34524e36522SCy Schubert { 34624e36522SCy Schubert struct clientip_synthesized_rrset* set = calloc(1, sizeof(*set)); 34724e36522SCy Schubert if(set == NULL) { 34824e36522SCy Schubert return NULL; 34924e36522SCy Schubert } 35024e36522SCy Schubert set->region = regional_create(); 35124e36522SCy Schubert if(set->region == NULL) { 35224e36522SCy Schubert free(set); 35324e36522SCy Schubert return NULL; 35424e36522SCy Schubert } 35524e36522SCy Schubert addr_tree_init(&set->entries); 35624e36522SCy Schubert lock_rw_init(&set->lock); 35724e36522SCy Schubert return set; 35824e36522SCy Schubert } 35924e36522SCy Schubert 36024e36522SCy Schubert static void 36124e36522SCy Schubert rpz_clientip_synthesized_rr_delete(rbnode_type* n, void* ATTR_UNUSED(arg)) 36224e36522SCy Schubert { 36324e36522SCy Schubert struct clientip_synthesized_rr* r = (struct clientip_synthesized_rr*)n->key; 36424e36522SCy Schubert lock_rw_destroy(&r->lock); 36524e36522SCy Schubert #ifdef THREADS_DISABLED 36624e36522SCy Schubert (void)r; 36724e36522SCy Schubert #endif 36824e36522SCy Schubert } 36924e36522SCy Schubert 37024e36522SCy Schubert static inline void 37124e36522SCy Schubert rpz_clientip_synthesized_set_delete(struct clientip_synthesized_rrset* set) 37224e36522SCy Schubert { 37324e36522SCy Schubert if(set == NULL) { 37424e36522SCy Schubert return; 37524e36522SCy Schubert } 37624e36522SCy Schubert lock_rw_destroy(&set->lock); 37724e36522SCy Schubert traverse_postorder(&set->entries, rpz_clientip_synthesized_rr_delete, NULL); 37824e36522SCy Schubert regional_destroy(set->region); 37924e36522SCy Schubert free(set); 38024e36522SCy Schubert } 38124e36522SCy Schubert 38224e36522SCy Schubert void 38324e36522SCy Schubert rpz_delete(struct rpz* r) 384091e9e46SCy Schubert { 385091e9e46SCy Schubert if(!r) 386091e9e46SCy Schubert return; 387091e9e46SCy Schubert local_zones_delete(r->local_zones); 38824e36522SCy Schubert local_zones_delete(r->nsdname_zones); 389091e9e46SCy Schubert respip_set_delete(r->respip_set); 39024e36522SCy Schubert rpz_clientip_synthesized_set_delete(r->client_set); 39124e36522SCy Schubert rpz_clientip_synthesized_set_delete(r->ns_set); 392091e9e46SCy Schubert regional_destroy(r->region); 393091e9e46SCy Schubert free(r->taglist); 394091e9e46SCy Schubert free(r->log_name); 395091e9e46SCy Schubert free(r); 396091e9e46SCy Schubert } 397091e9e46SCy Schubert 398091e9e46SCy Schubert int 399091e9e46SCy Schubert rpz_clear(struct rpz* r) 400091e9e46SCy Schubert { 401091e9e46SCy Schubert /* must hold write lock on auth_zone */ 402091e9e46SCy Schubert local_zones_delete(r->local_zones); 40324e36522SCy Schubert r->local_zones = NULL; 40424e36522SCy Schubert local_zones_delete(r->nsdname_zones); 40524e36522SCy Schubert r->nsdname_zones = NULL; 406091e9e46SCy Schubert respip_set_delete(r->respip_set); 40724e36522SCy Schubert r->respip_set = NULL; 40824e36522SCy Schubert rpz_clientip_synthesized_set_delete(r->client_set); 40924e36522SCy Schubert r->client_set = NULL; 41024e36522SCy Schubert rpz_clientip_synthesized_set_delete(r->ns_set); 41124e36522SCy Schubert r->ns_set = NULL; 412091e9e46SCy Schubert if(!(r->local_zones = local_zones_create())){ 413091e9e46SCy Schubert return 0; 414091e9e46SCy Schubert } 41524e36522SCy Schubert r->nsdname_zones = local_zones_create(); 41624e36522SCy Schubert if(r->nsdname_zones == NULL) { 41724e36522SCy Schubert return 0; 41824e36522SCy Schubert } 419091e9e46SCy Schubert if(!(r->respip_set = respip_set_create())) { 420091e9e46SCy Schubert return 0; 421091e9e46SCy Schubert } 42224e36522SCy Schubert if(!(r->client_set = rpz_clientip_synthesized_set_create())) { 42324e36522SCy Schubert return 0; 42424e36522SCy Schubert } 42524e36522SCy Schubert if(!(r->ns_set = rpz_clientip_synthesized_set_create())) { 42624e36522SCy Schubert return 0; 42724e36522SCy Schubert } 428091e9e46SCy Schubert return 1; 429091e9e46SCy Schubert } 430091e9e46SCy Schubert 431091e9e46SCy Schubert void 432091e9e46SCy Schubert rpz_finish_config(struct rpz* r) 433091e9e46SCy Schubert { 434091e9e46SCy Schubert lock_rw_wrlock(&r->respip_set->lock); 435091e9e46SCy Schubert addr_tree_init_parents(&r->respip_set->ip_tree); 436091e9e46SCy Schubert lock_rw_unlock(&r->respip_set->lock); 43724e36522SCy Schubert 43824e36522SCy Schubert lock_rw_wrlock(&r->client_set->lock); 43924e36522SCy Schubert addr_tree_init_parents(&r->client_set->entries); 44024e36522SCy Schubert lock_rw_unlock(&r->client_set->lock); 44124e36522SCy Schubert 44224e36522SCy Schubert lock_rw_wrlock(&r->ns_set->lock); 44324e36522SCy Schubert addr_tree_init_parents(&r->ns_set->entries); 44424e36522SCy Schubert lock_rw_unlock(&r->ns_set->lock); 445091e9e46SCy Schubert } 446091e9e46SCy Schubert 447091e9e46SCy Schubert /** new rrset containing CNAME override, does not yet contain a dname */ 448091e9e46SCy Schubert static struct ub_packed_rrset_key* 449091e9e46SCy Schubert new_cname_override(struct regional* region, uint8_t* ct, size_t ctlen) 450091e9e46SCy Schubert { 451091e9e46SCy Schubert struct ub_packed_rrset_key* rrset; 452091e9e46SCy Schubert struct packed_rrset_data* pd; 453091e9e46SCy Schubert uint16_t rdlength = htons(ctlen); 454091e9e46SCy Schubert rrset = (struct ub_packed_rrset_key*)regional_alloc_zero(region, 455091e9e46SCy Schubert sizeof(*rrset)); 456091e9e46SCy Schubert if(!rrset) { 457091e9e46SCy Schubert log_err("out of memory"); 458091e9e46SCy Schubert return NULL; 459091e9e46SCy Schubert } 460091e9e46SCy Schubert rrset->entry.key = rrset; 461091e9e46SCy Schubert pd = (struct packed_rrset_data*)regional_alloc_zero(region, sizeof(*pd)); 462091e9e46SCy Schubert if(!pd) { 463091e9e46SCy Schubert log_err("out of memory"); 464091e9e46SCy Schubert return NULL; 465091e9e46SCy Schubert } 466091e9e46SCy Schubert pd->trust = rrset_trust_prim_noglue; 467091e9e46SCy Schubert pd->security = sec_status_insecure; 468091e9e46SCy Schubert 469091e9e46SCy Schubert pd->count = 1; 470091e9e46SCy Schubert pd->rr_len = regional_alloc_zero(region, sizeof(*pd->rr_len)); 471091e9e46SCy Schubert pd->rr_ttl = regional_alloc_zero(region, sizeof(*pd->rr_ttl)); 472091e9e46SCy Schubert pd->rr_data = regional_alloc_zero(region, sizeof(*pd->rr_data)); 473091e9e46SCy Schubert if(!pd->rr_len || !pd->rr_ttl || !pd->rr_data) { 474091e9e46SCy Schubert log_err("out of memory"); 475091e9e46SCy Schubert return NULL; 476091e9e46SCy Schubert } 477091e9e46SCy Schubert pd->rr_len[0] = ctlen+2; 478091e9e46SCy Schubert pd->rr_ttl[0] = 3600; 479091e9e46SCy Schubert pd->rr_data[0] = regional_alloc_zero(region, 2 /* rdlength */ + ctlen); 480091e9e46SCy Schubert if(!pd->rr_data[0]) { 481091e9e46SCy Schubert log_err("out of memory"); 482091e9e46SCy Schubert return NULL; 483091e9e46SCy Schubert } 484091e9e46SCy Schubert memmove(pd->rr_data[0], &rdlength, 2); 485091e9e46SCy Schubert memmove(pd->rr_data[0]+2, ct, ctlen); 486091e9e46SCy Schubert 487091e9e46SCy Schubert rrset->entry.data = pd; 488091e9e46SCy Schubert rrset->rk.type = htons(LDNS_RR_TYPE_CNAME); 489091e9e46SCy Schubert rrset->rk.rrset_class = htons(LDNS_RR_CLASS_IN); 490091e9e46SCy Schubert return rrset; 491091e9e46SCy Schubert } 492091e9e46SCy Schubert 493335c7cdaSCy Schubert /** delete the cname override */ 494335c7cdaSCy Schubert static void 495335c7cdaSCy Schubert delete_cname_override(struct rpz* r) 496335c7cdaSCy Schubert { 497335c7cdaSCy Schubert if(r->cname_override) { 498335c7cdaSCy Schubert /* The cname override is what is allocated in the region. */ 499335c7cdaSCy Schubert regional_free_all(r->region); 500335c7cdaSCy Schubert r->cname_override = NULL; 501335c7cdaSCy Schubert } 502335c7cdaSCy Schubert } 503335c7cdaSCy Schubert 504335c7cdaSCy Schubert /** Apply rpz config elements to the rpz structure, false on failure. */ 505335c7cdaSCy Schubert static int 506335c7cdaSCy Schubert rpz_apply_cfg_elements(struct rpz* r, struct config_auth* p) 507335c7cdaSCy Schubert { 508335c7cdaSCy Schubert if(p->rpz_taglist && p->rpz_taglistlen) { 509335c7cdaSCy Schubert r->taglistlen = p->rpz_taglistlen; 510335c7cdaSCy Schubert r->taglist = memdup(p->rpz_taglist, r->taglistlen); 511335c7cdaSCy Schubert if(!r->taglist) { 512335c7cdaSCy Schubert log_err("malloc failure on RPZ taglist alloc"); 513335c7cdaSCy Schubert return 0; 514335c7cdaSCy Schubert } 515335c7cdaSCy Schubert } 516335c7cdaSCy Schubert 517335c7cdaSCy Schubert if(p->rpz_action_override) { 518335c7cdaSCy Schubert r->action_override = rpz_config_to_action(p->rpz_action_override); 519335c7cdaSCy Schubert } 520335c7cdaSCy Schubert else 521335c7cdaSCy Schubert r->action_override = RPZ_NO_OVERRIDE_ACTION; 522335c7cdaSCy Schubert 523335c7cdaSCy Schubert if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) { 524335c7cdaSCy Schubert uint8_t nm[LDNS_MAX_DOMAINLEN+1]; 525335c7cdaSCy Schubert size_t nmlen = sizeof(nm); 526335c7cdaSCy Schubert 527335c7cdaSCy Schubert if(!p->rpz_cname) { 528335c7cdaSCy Schubert log_err("rpz: override with cname action found, but no " 529335c7cdaSCy Schubert "rpz-cname-override configured"); 530335c7cdaSCy Schubert return 0; 531335c7cdaSCy Schubert } 532335c7cdaSCy Schubert 533335c7cdaSCy Schubert if(sldns_str2wire_dname_buf(p->rpz_cname, nm, &nmlen) != 0) { 534335c7cdaSCy Schubert log_err("rpz: cannot parse cname override: %s", 535335c7cdaSCy Schubert p->rpz_cname); 536335c7cdaSCy Schubert return 0; 537335c7cdaSCy Schubert } 538335c7cdaSCy Schubert r->cname_override = new_cname_override(r->region, nm, nmlen); 539335c7cdaSCy Schubert if(!r->cname_override) { 540335c7cdaSCy Schubert return 0; 541335c7cdaSCy Schubert } 542335c7cdaSCy Schubert } 543335c7cdaSCy Schubert r->log = p->rpz_log; 544335c7cdaSCy Schubert r->signal_nxdomain_ra = p->rpz_signal_nxdomain_ra; 545335c7cdaSCy Schubert if(p->rpz_log_name) { 546335c7cdaSCy Schubert if(!(r->log_name = strdup(p->rpz_log_name))) { 547335c7cdaSCy Schubert log_err("malloc failure on RPZ log_name strdup"); 548335c7cdaSCy Schubert return 0; 549335c7cdaSCy Schubert } 550335c7cdaSCy Schubert } 551335c7cdaSCy Schubert return 1; 552335c7cdaSCy Schubert } 553335c7cdaSCy Schubert 554091e9e46SCy Schubert struct rpz* 555091e9e46SCy Schubert rpz_create(struct config_auth* p) 556091e9e46SCy Schubert { 557091e9e46SCy Schubert struct rpz* r = calloc(1, sizeof(*r)); 558091e9e46SCy Schubert if(!r) 559091e9e46SCy Schubert goto err; 560091e9e46SCy Schubert 561091e9e46SCy Schubert r->region = regional_create_custom(sizeof(struct regional)); 562091e9e46SCy Schubert if(!r->region) { 563091e9e46SCy Schubert goto err; 564091e9e46SCy Schubert } 565091e9e46SCy Schubert 566091e9e46SCy Schubert if(!(r->local_zones = local_zones_create())){ 567091e9e46SCy Schubert goto err; 568091e9e46SCy Schubert } 56924e36522SCy Schubert 57024e36522SCy Schubert r->nsdname_zones = local_zones_create(); 57124e36522SCy Schubert if(r->local_zones == NULL){ 57224e36522SCy Schubert goto err; 57324e36522SCy Schubert } 57424e36522SCy Schubert 575091e9e46SCy Schubert if(!(r->respip_set = respip_set_create())) { 576091e9e46SCy Schubert goto err; 577091e9e46SCy Schubert } 57824e36522SCy Schubert 57924e36522SCy Schubert r->client_set = rpz_clientip_synthesized_set_create(); 58024e36522SCy Schubert if(r->client_set == NULL) { 58124e36522SCy Schubert goto err; 58224e36522SCy Schubert } 58324e36522SCy Schubert 58424e36522SCy Schubert r->ns_set = rpz_clientip_synthesized_set_create(); 58524e36522SCy Schubert if(r->ns_set == NULL) { 58624e36522SCy Schubert goto err; 58724e36522SCy Schubert } 58824e36522SCy Schubert 589335c7cdaSCy Schubert if(!rpz_apply_cfg_elements(r, p)) 590091e9e46SCy Schubert goto err; 591091e9e46SCy Schubert return r; 592091e9e46SCy Schubert err: 593091e9e46SCy Schubert if(r) { 594091e9e46SCy Schubert if(r->local_zones) 595091e9e46SCy Schubert local_zones_delete(r->local_zones); 59624e36522SCy Schubert if(r->nsdname_zones) 59724e36522SCy Schubert local_zones_delete(r->nsdname_zones); 598091e9e46SCy Schubert if(r->respip_set) 599091e9e46SCy Schubert respip_set_delete(r->respip_set); 60024e36522SCy Schubert if(r->client_set != NULL) 60124e36522SCy Schubert rpz_clientip_synthesized_set_delete(r->client_set); 60224e36522SCy Schubert if(r->ns_set != NULL) 60324e36522SCy Schubert rpz_clientip_synthesized_set_delete(r->ns_set); 604091e9e46SCy Schubert if(r->taglist) 605091e9e46SCy Schubert free(r->taglist); 606369c6923SCy Schubert if(r->region) 607369c6923SCy Schubert regional_destroy(r->region); 608091e9e46SCy Schubert free(r); 609091e9e46SCy Schubert } 610091e9e46SCy Schubert return NULL; 611091e9e46SCy Schubert } 612091e9e46SCy Schubert 613335c7cdaSCy Schubert int 614335c7cdaSCy Schubert rpz_config(struct rpz* r, struct config_auth* p) 615335c7cdaSCy Schubert { 616335c7cdaSCy Schubert /* If the zonefile changes, it is read later, after which 617335c7cdaSCy Schubert * rpz_clear and rpz_finish_config is called. */ 618335c7cdaSCy Schubert 619335c7cdaSCy Schubert /* free taglist, if any */ 620335c7cdaSCy Schubert if(r->taglist) { 621335c7cdaSCy Schubert free(r->taglist); 622335c7cdaSCy Schubert r->taglist = NULL; 623335c7cdaSCy Schubert r->taglistlen = 0; 624335c7cdaSCy Schubert } 625335c7cdaSCy Schubert 626335c7cdaSCy Schubert /* free logname, if any */ 627335c7cdaSCy Schubert if(r->log_name) { 628335c7cdaSCy Schubert free(r->log_name); 629335c7cdaSCy Schubert r->log_name = NULL; 630335c7cdaSCy Schubert } 631335c7cdaSCy Schubert 632335c7cdaSCy Schubert delete_cname_override(r); 633335c7cdaSCy Schubert 634335c7cdaSCy Schubert if(!rpz_apply_cfg_elements(r, p)) 635335c7cdaSCy Schubert return 0; 636335c7cdaSCy Schubert return 1; 637335c7cdaSCy Schubert } 638335c7cdaSCy Schubert 639091e9e46SCy Schubert /** 640091e9e46SCy Schubert * Remove RPZ zone name from dname 641091e9e46SCy Schubert * Copy dname to newdname, without the originlen number of trailing bytes 642091e9e46SCy Schubert */ 643091e9e46SCy Schubert static size_t 644091e9e46SCy Schubert strip_dname_origin(uint8_t* dname, size_t dnamelen, size_t originlen, 645091e9e46SCy Schubert uint8_t* newdname, size_t maxnewdnamelen) 646091e9e46SCy Schubert { 647091e9e46SCy Schubert size_t newdnamelen; 648091e9e46SCy Schubert if(dnamelen < originlen) 649091e9e46SCy Schubert return 0; 650091e9e46SCy Schubert newdnamelen = dnamelen - originlen; 651091e9e46SCy Schubert if(newdnamelen+1 > maxnewdnamelen) 652091e9e46SCy Schubert return 0; 653091e9e46SCy Schubert memmove(newdname, dname, newdnamelen); 654091e9e46SCy Schubert newdname[newdnamelen] = 0; 655091e9e46SCy Schubert return newdnamelen + 1; /* + 1 for root label */ 656091e9e46SCy Schubert } 657091e9e46SCy Schubert 658091e9e46SCy Schubert static void 65924e36522SCy Schubert rpz_insert_local_zones_trigger(struct local_zones* lz, uint8_t* dname, 66024e36522SCy Schubert size_t dnamelen, enum rpz_action a, uint16_t rrtype, uint16_t rrclass, 66124e36522SCy Schubert uint32_t ttl, uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len) 662091e9e46SCy Schubert { 663091e9e46SCy Schubert struct local_zone* z; 664091e9e46SCy Schubert enum localzone_type tp = local_zone_always_transparent; 665091e9e46SCy Schubert int dnamelabs = dname_count_labels(dname); 666091e9e46SCy Schubert int newzone = 0; 667091e9e46SCy Schubert 66824e36522SCy Schubert if(a == RPZ_INVALID_ACTION) { 6695469a995SCy Schubert char str[255+1]; 6705469a995SCy Schubert if(rrtype == LDNS_RR_TYPE_SOA || rrtype == LDNS_RR_TYPE_NS || 6715469a995SCy Schubert rrtype == LDNS_RR_TYPE_DNAME || 6725469a995SCy Schubert rrtype == LDNS_RR_TYPE_DNSKEY || 6735469a995SCy Schubert rrtype == LDNS_RR_TYPE_RRSIG || 6745469a995SCy Schubert rrtype == LDNS_RR_TYPE_NSEC || 6755469a995SCy Schubert rrtype == LDNS_RR_TYPE_NSEC3PARAM || 6765469a995SCy Schubert rrtype == LDNS_RR_TYPE_NSEC3 || 6775469a995SCy Schubert rrtype == LDNS_RR_TYPE_DS) { 6785469a995SCy Schubert free(dname); 6795469a995SCy Schubert return; /* no need to log these types as unsupported */ 6805469a995SCy Schubert } 6815469a995SCy Schubert dname_str(dname, str); 682a39a5a69SCy Schubert verbose(VERB_ALGO, "rpz: qname trigger, %s skipping unsupported action: %s", 6835469a995SCy Schubert str, rpz_action_to_string(a)); 684091e9e46SCy Schubert free(dname); 685091e9e46SCy Schubert return; 686091e9e46SCy Schubert } 687091e9e46SCy Schubert 68824e36522SCy Schubert lock_rw_wrlock(&lz->lock); 689091e9e46SCy Schubert /* exact match */ 69024e36522SCy Schubert z = local_zones_find(lz, dname, dnamelen, dnamelabs, LDNS_RR_CLASS_IN); 69124e36522SCy Schubert if(z != NULL && a != RPZ_LOCAL_DATA_ACTION) { 69224e36522SCy Schubert char* rrstr = sldns_wire2str_rr(rr, rr_len); 69324e36522SCy Schubert if(rrstr == NULL) { 69424e36522SCy Schubert log_err("malloc error while inserting rpz nsdname trigger"); 695091e9e46SCy Schubert free(dname); 69624e36522SCy Schubert lock_rw_unlock(&lz->lock); 697091e9e46SCy Schubert return; 698091e9e46SCy Schubert } 69924e36522SCy Schubert if(rrstr[0]) 70024e36522SCy Schubert rrstr[strlen(rrstr)-1]=0; /* remove newline */ 70124e36522SCy Schubert verbose(VERB_ALGO, "rpz: skipping duplicate record: '%s'", rrstr); 702091e9e46SCy Schubert free(rrstr); 703091e9e46SCy Schubert free(dname); 70424e36522SCy Schubert lock_rw_unlock(&lz->lock); 705091e9e46SCy Schubert return; 706091e9e46SCy Schubert } 70724e36522SCy Schubert if(z == NULL) { 708091e9e46SCy Schubert tp = rpz_action_to_localzone_type(a); 70924e36522SCy Schubert z = local_zones_add_zone(lz, dname, dnamelen, 71024e36522SCy Schubert dnamelabs, rrclass, tp); 71124e36522SCy Schubert if(z == NULL) { 71224e36522SCy Schubert log_warn("rpz: create failed"); 71324e36522SCy Schubert lock_rw_unlock(&lz->lock); 714091e9e46SCy Schubert /* dname will be free'd in failed local_zone_create() */ 715091e9e46SCy Schubert return; 716091e9e46SCy Schubert } 717091e9e46SCy Schubert newzone = 1; 718091e9e46SCy Schubert } 719091e9e46SCy Schubert if(a == RPZ_LOCAL_DATA_ACTION) { 72024e36522SCy Schubert char* rrstr = sldns_wire2str_rr(rr, rr_len); 72124e36522SCy Schubert if(rrstr == NULL) { 72224e36522SCy Schubert log_err("malloc error while inserting rpz nsdname trigger"); 723091e9e46SCy Schubert free(dname); 72424e36522SCy Schubert lock_rw_unlock(&lz->lock); 725091e9e46SCy Schubert return; 726091e9e46SCy Schubert } 727091e9e46SCy Schubert lock_rw_wrlock(&z->lock); 72824e36522SCy Schubert local_zone_enter_rr(z, dname, dnamelen, dnamelabs, rrtype, 72924e36522SCy Schubert rrclass, ttl, rdata, rdata_len, rrstr); 730091e9e46SCy Schubert lock_rw_unlock(&z->lock); 731091e9e46SCy Schubert free(rrstr); 732091e9e46SCy Schubert } 73324e36522SCy Schubert if(!newzone) { 734091e9e46SCy Schubert free(dname); 73524e36522SCy Schubert } 73624e36522SCy Schubert lock_rw_unlock(&lz->lock); 73724e36522SCy Schubert } 73824e36522SCy Schubert 73924e36522SCy Schubert static void 74024e36522SCy Schubert rpz_log_dname(char const* msg, uint8_t* dname, size_t dname_len) 74124e36522SCy Schubert { 74224e36522SCy Schubert char buf[LDNS_MAX_DOMAINLEN+1]; 74324e36522SCy Schubert (void)dname_len; 74424e36522SCy Schubert dname_str(dname, buf); 74524e36522SCy Schubert verbose(VERB_ALGO, "rpz: %s: <%s>", msg, buf); 74624e36522SCy Schubert } 74724e36522SCy Schubert 74824e36522SCy Schubert static void 74924e36522SCy Schubert rpz_insert_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen, 75024e36522SCy Schubert enum rpz_action a, uint16_t rrtype, uint16_t rrclass, uint32_t ttl, 75124e36522SCy Schubert uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len) 75224e36522SCy Schubert { 75324e36522SCy Schubert if(a == RPZ_INVALID_ACTION) { 75424e36522SCy Schubert verbose(VERB_ALGO, "rpz: skipping invalid action"); 75524e36522SCy Schubert free(dname); 756091e9e46SCy Schubert return; 757091e9e46SCy Schubert } 758091e9e46SCy Schubert 75924e36522SCy Schubert rpz_insert_local_zones_trigger(r->local_zones, dname, dnamelen, a, rrtype, 76024e36522SCy Schubert rrclass, ttl, rdata, rdata_len, rr, rr_len); 76124e36522SCy Schubert } 76224e36522SCy Schubert 76324e36522SCy Schubert static int 76424e36522SCy Schubert rpz_strip_nsdname_suffix(uint8_t* dname, size_t maxdnamelen, 76524e36522SCy Schubert uint8_t** stripdname, size_t* stripdnamelen) 76624e36522SCy Schubert { 76724e36522SCy Schubert uint8_t* tldstart = get_tld_label(dname, maxdnamelen); 76824e36522SCy Schubert uint8_t swap; 76924e36522SCy Schubert if(tldstart == NULL) { 77024e36522SCy Schubert if(dname == NULL) { 77124e36522SCy Schubert *stripdname = NULL; 77224e36522SCy Schubert *stripdnamelen = 0; 77324e36522SCy Schubert return 0; 77424e36522SCy Schubert } 77524e36522SCy Schubert *stripdname = memdup(dname, maxdnamelen); 77624e36522SCy Schubert if(!*stripdname) { 77724e36522SCy Schubert *stripdnamelen = 0; 77824e36522SCy Schubert log_err("malloc failure for rpz strip suffix"); 77924e36522SCy Schubert return 0; 78024e36522SCy Schubert } 78124e36522SCy Schubert *stripdnamelen = maxdnamelen; 78224e36522SCy Schubert return 1; 78324e36522SCy Schubert } 78424e36522SCy Schubert /* shorten the domain name briefly, 78524e36522SCy Schubert * then we allocate a new name with the correct length */ 78624e36522SCy Schubert swap = *tldstart; 78724e36522SCy Schubert *tldstart = 0; 78824e36522SCy Schubert (void)dname_count_size_labels(dname, stripdnamelen); 78924e36522SCy Schubert *stripdname = memdup(dname, *stripdnamelen); 79024e36522SCy Schubert *tldstart = swap; 79124e36522SCy Schubert if(!*stripdname) { 79224e36522SCy Schubert *stripdnamelen = 0; 79324e36522SCy Schubert log_err("malloc failure for rpz strip suffix"); 79424e36522SCy Schubert return 0; 79524e36522SCy Schubert } 79624e36522SCy Schubert return 1; 79724e36522SCy Schubert } 79824e36522SCy Schubert 79924e36522SCy Schubert static void 80024e36522SCy Schubert rpz_insert_nsdname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen, 80124e36522SCy Schubert enum rpz_action a, uint16_t rrtype, uint16_t rrclass, uint32_t ttl, 80224e36522SCy Schubert uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len) 80324e36522SCy Schubert { 80424e36522SCy Schubert uint8_t* dname_stripped = NULL; 80524e36522SCy Schubert size_t dnamelen_stripped = 0; 80624e36522SCy Schubert 80724e36522SCy Schubert rpz_strip_nsdname_suffix(dname, dnamelen, &dname_stripped, 80824e36522SCy Schubert &dnamelen_stripped); 80924e36522SCy Schubert if(a == RPZ_INVALID_ACTION) { 81024e36522SCy Schubert verbose(VERB_ALGO, "rpz: skipping invalid action"); 81124e36522SCy Schubert free(dname_stripped); 81224e36522SCy Schubert return; 81324e36522SCy Schubert } 81424e36522SCy Schubert 81524e36522SCy Schubert /* dname_stripped is consumed or freed by the insert routine */ 81624e36522SCy Schubert rpz_insert_local_zones_trigger(r->nsdname_zones, dname_stripped, 81724e36522SCy Schubert dnamelen_stripped, a, rrtype, rrclass, ttl, rdata, rdata_len, 81824e36522SCy Schubert rr, rr_len); 81924e36522SCy Schubert } 82024e36522SCy Schubert 82124e36522SCy Schubert static int 82224e36522SCy Schubert rpz_insert_ipaddr_based_trigger(struct respip_set* set, struct sockaddr_storage* addr, 82324e36522SCy Schubert socklen_t addrlen, int net, enum rpz_action a, uint16_t rrtype, 82424e36522SCy Schubert uint16_t rrclass, uint32_t ttl, uint8_t* rdata, size_t rdata_len, 82524e36522SCy Schubert uint8_t* rr, size_t rr_len) 82624e36522SCy Schubert { 82724e36522SCy Schubert struct resp_addr* node; 82824e36522SCy Schubert char* rrstr; 82924e36522SCy Schubert enum respip_action respa = rpz_action_to_respip_action(a); 83024e36522SCy Schubert 83124e36522SCy Schubert lock_rw_wrlock(&set->lock); 83224e36522SCy Schubert rrstr = sldns_wire2str_rr(rr, rr_len); 83324e36522SCy Schubert if(rrstr == NULL) { 83424e36522SCy Schubert log_err("malloc error while inserting rpz ipaddr based trigger"); 83524e36522SCy Schubert lock_rw_unlock(&set->lock); 83624e36522SCy Schubert return 0; 83724e36522SCy Schubert } 83824e36522SCy Schubert 83924e36522SCy Schubert node = respip_sockaddr_find_or_create(set, addr, addrlen, net, 1, rrstr); 84024e36522SCy Schubert if(node == NULL) { 84124e36522SCy Schubert lock_rw_unlock(&set->lock); 84224e36522SCy Schubert free(rrstr); 84324e36522SCy Schubert return 0; 84424e36522SCy Schubert } 84524e36522SCy Schubert 84624e36522SCy Schubert lock_rw_wrlock(&node->lock); 84724e36522SCy Schubert lock_rw_unlock(&set->lock); 84824e36522SCy Schubert 84924e36522SCy Schubert node->action = respa; 85024e36522SCy Schubert 85124e36522SCy Schubert if(a == RPZ_LOCAL_DATA_ACTION) { 85224e36522SCy Schubert respip_enter_rr(set->region, node, rrtype, 85324e36522SCy Schubert rrclass, ttl, rdata, rdata_len, rrstr, ""); 85424e36522SCy Schubert } 85524e36522SCy Schubert 85624e36522SCy Schubert lock_rw_unlock(&node->lock); 85724e36522SCy Schubert free(rrstr); 85824e36522SCy Schubert return 1; 85924e36522SCy Schubert } 86024e36522SCy Schubert 86124e36522SCy Schubert static inline struct clientip_synthesized_rr* 86224e36522SCy Schubert rpz_clientip_ensure_entry(struct clientip_synthesized_rrset* set, 86324e36522SCy Schubert struct sockaddr_storage* addr, socklen_t addrlen, int net) 86424e36522SCy Schubert { 86524e36522SCy Schubert int insert_ok; 86624e36522SCy Schubert struct clientip_synthesized_rr* node = 86724e36522SCy Schubert (struct clientip_synthesized_rr*)addr_tree_find(&set->entries, 86824e36522SCy Schubert addr, addrlen, net); 86924e36522SCy Schubert 87024e36522SCy Schubert if(node != NULL) { return node; } 87124e36522SCy Schubert 87224e36522SCy Schubert /* node does not yet exist => allocate one */ 87324e36522SCy Schubert node = regional_alloc_zero(set->region, sizeof(*node)); 87424e36522SCy Schubert if(node == NULL) { 87524e36522SCy Schubert log_err("out of memory"); 87624e36522SCy Schubert return NULL; 87724e36522SCy Schubert } 87824e36522SCy Schubert 87924e36522SCy Schubert lock_rw_init(&node->lock); 88024e36522SCy Schubert node->action = RPZ_INVALID_ACTION; 88124e36522SCy Schubert insert_ok = addr_tree_insert(&set->entries, &node->node, 88224e36522SCy Schubert addr, addrlen, net); 88324e36522SCy Schubert if (!insert_ok) { 88424e36522SCy Schubert log_warn("rpz: unexpected: unable to insert clientip address node"); 88524e36522SCy Schubert /* we can not free the just allocated node. 88624e36522SCy Schubert * theoretically a memleak */ 88724e36522SCy Schubert return NULL; 88824e36522SCy Schubert } 88924e36522SCy Schubert 89024e36522SCy Schubert return node; 89124e36522SCy Schubert } 89224e36522SCy Schubert 89324e36522SCy Schubert static void 89424e36522SCy Schubert rpz_report_rrset_error(const char* msg, uint8_t* rr, size_t rr_len) { 89524e36522SCy Schubert char* rrstr = sldns_wire2str_rr(rr, rr_len); 89624e36522SCy Schubert if(rrstr == NULL) { 89724e36522SCy Schubert log_err("malloc error while inserting rpz clientip based record"); 89824e36522SCy Schubert return; 89924e36522SCy Schubert } 90024e36522SCy Schubert log_err("rpz: unexpected: unable to insert %s: %s", msg, rrstr); 90124e36522SCy Schubert free(rrstr); 90224e36522SCy Schubert } 90324e36522SCy Schubert 90424e36522SCy Schubert /* from localzone.c; difference is we don't have a dname */ 9059cf5bc93SCy Schubert static struct local_rrset* 90624e36522SCy Schubert rpz_clientip_new_rrset(struct regional* region, 90724e36522SCy Schubert struct clientip_synthesized_rr* raddr, uint16_t rrtype, uint16_t rrclass) 90824e36522SCy Schubert { 90924e36522SCy Schubert struct packed_rrset_data* pd; 91024e36522SCy Schubert struct local_rrset* rrset = (struct local_rrset*) 91124e36522SCy Schubert regional_alloc_zero(region, sizeof(*rrset)); 91224e36522SCy Schubert if(rrset == NULL) { 91324e36522SCy Schubert log_err("out of memory"); 91424e36522SCy Schubert return NULL; 91524e36522SCy Schubert } 91624e36522SCy Schubert rrset->next = raddr->data; 91724e36522SCy Schubert raddr->data = rrset; 91824e36522SCy Schubert rrset->rrset = (struct ub_packed_rrset_key*) 91924e36522SCy Schubert regional_alloc_zero(region, sizeof(*rrset->rrset)); 92024e36522SCy Schubert if(rrset->rrset == NULL) { 92124e36522SCy Schubert log_err("out of memory"); 92224e36522SCy Schubert return NULL; 92324e36522SCy Schubert } 92424e36522SCy Schubert rrset->rrset->entry.key = rrset->rrset; 92524e36522SCy Schubert pd = (struct packed_rrset_data*)regional_alloc_zero(region, sizeof(*pd)); 92624e36522SCy Schubert if(pd == NULL) { 92724e36522SCy Schubert log_err("out of memory"); 92824e36522SCy Schubert return NULL; 92924e36522SCy Schubert } 93024e36522SCy Schubert pd->trust = rrset_trust_prim_noglue; 93124e36522SCy Schubert pd->security = sec_status_insecure; 93224e36522SCy Schubert rrset->rrset->entry.data = pd; 93324e36522SCy Schubert rrset->rrset->rk.type = htons(rrtype); 93424e36522SCy Schubert rrset->rrset->rk.rrset_class = htons(rrclass); 93524e36522SCy Schubert rrset->rrset->rk.dname = regional_alloc_zero(region, 1); 93624e36522SCy Schubert if(rrset->rrset->rk.dname == NULL) { 93724e36522SCy Schubert log_err("out of memory"); 93824e36522SCy Schubert return NULL; 93924e36522SCy Schubert } 94024e36522SCy Schubert rrset->rrset->rk.dname_len = 1; 94124e36522SCy Schubert return rrset; 94224e36522SCy Schubert } 94324e36522SCy Schubert 94424e36522SCy Schubert static int 94524e36522SCy Schubert rpz_clientip_enter_rr(struct regional* region, struct clientip_synthesized_rr* raddr, 94624e36522SCy Schubert uint16_t rrtype, uint16_t rrclass, time_t ttl, uint8_t* rdata, 94724e36522SCy Schubert size_t rdata_len) 94824e36522SCy Schubert { 94924e36522SCy Schubert struct local_rrset* rrset; 95024e36522SCy Schubert if (rrtype == LDNS_RR_TYPE_CNAME && raddr->data != NULL) { 95124e36522SCy Schubert log_err("CNAME response-ip data can not co-exist with other " 95224e36522SCy Schubert "client-ip data"); 95324e36522SCy Schubert return 0; 95424e36522SCy Schubert } 95524e36522SCy Schubert 95624e36522SCy Schubert rrset = rpz_clientip_new_rrset(region, raddr, rrtype, rrclass); 95724e36522SCy Schubert if(raddr->data == NULL) { 95824e36522SCy Schubert return 0; 95924e36522SCy Schubert } 96024e36522SCy Schubert 96124e36522SCy Schubert return rrset_insert_rr(region, rrset->rrset->entry.data, rdata, rdata_len, ttl, ""); 96224e36522SCy Schubert } 96324e36522SCy Schubert 96424e36522SCy Schubert static int 96524e36522SCy Schubert rpz_clientip_insert_trigger_rr(struct clientip_synthesized_rrset* set, struct sockaddr_storage* addr, 96624e36522SCy Schubert socklen_t addrlen, int net, enum rpz_action a, uint16_t rrtype, 96724e36522SCy Schubert uint16_t rrclass, uint32_t ttl, uint8_t* rdata, size_t rdata_len, 96824e36522SCy Schubert uint8_t* rr, size_t rr_len) 96924e36522SCy Schubert { 97024e36522SCy Schubert struct clientip_synthesized_rr* node; 97124e36522SCy Schubert 97224e36522SCy Schubert lock_rw_wrlock(&set->lock); 97324e36522SCy Schubert 97424e36522SCy Schubert node = rpz_clientip_ensure_entry(set, addr, addrlen, net); 97524e36522SCy Schubert if(node == NULL) { 97624e36522SCy Schubert lock_rw_unlock(&set->lock); 97724e36522SCy Schubert rpz_report_rrset_error("client ip address", rr, rr_len); 97824e36522SCy Schubert return 0; 97924e36522SCy Schubert } 98024e36522SCy Schubert 98124e36522SCy Schubert lock_rw_wrlock(&node->lock); 98224e36522SCy Schubert lock_rw_unlock(&set->lock); 98324e36522SCy Schubert 98424e36522SCy Schubert node->action = a; 98524e36522SCy Schubert if(a == RPZ_LOCAL_DATA_ACTION) { 98624e36522SCy Schubert if(!rpz_clientip_enter_rr(set->region, node, rrtype, 98724e36522SCy Schubert rrclass, ttl, rdata, rdata_len)) { 98824e36522SCy Schubert verbose(VERB_ALGO, "rpz: unable to insert clientip rr"); 98924e36522SCy Schubert lock_rw_unlock(&node->lock); 99024e36522SCy Schubert return 0; 99124e36522SCy Schubert } 99224e36522SCy Schubert 99324e36522SCy Schubert } 99424e36522SCy Schubert 99524e36522SCy Schubert lock_rw_unlock(&node->lock); 99624e36522SCy Schubert 99724e36522SCy Schubert return 1; 99824e36522SCy Schubert } 99924e36522SCy Schubert 100024e36522SCy Schubert static int 100124e36522SCy Schubert rpz_insert_clientip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen, 100224e36522SCy Schubert enum rpz_action a, uint16_t rrtype, uint16_t rrclass, uint32_t ttl, 100324e36522SCy Schubert uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len) 100424e36522SCy Schubert { 100524e36522SCy Schubert struct sockaddr_storage addr; 100624e36522SCy Schubert socklen_t addrlen; 100724e36522SCy Schubert int net, af; 100824e36522SCy Schubert 100924e36522SCy Schubert if(a == RPZ_INVALID_ACTION) { 101024e36522SCy Schubert return 0; 101124e36522SCy Schubert } 101224e36522SCy Schubert 101324e36522SCy Schubert if(!netblockdnametoaddr(dname, dnamelen, &addr, &addrlen, &net, &af)) { 101424e36522SCy Schubert verbose(VERB_ALGO, "rpz: unable to parse client ip"); 101524e36522SCy Schubert return 0; 101624e36522SCy Schubert } 101724e36522SCy Schubert 101824e36522SCy Schubert return rpz_clientip_insert_trigger_rr(r->client_set, &addr, addrlen, net, 101924e36522SCy Schubert a, rrtype, rrclass, ttl, rdata, rdata_len, rr, rr_len); 102024e36522SCy Schubert } 102124e36522SCy Schubert 102224e36522SCy Schubert static int 102324e36522SCy Schubert rpz_insert_nsip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen, 102424e36522SCy Schubert enum rpz_action a, uint16_t rrtype, uint16_t rrclass, uint32_t ttl, 102524e36522SCy Schubert uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len) 102624e36522SCy Schubert { 102724e36522SCy Schubert struct sockaddr_storage addr; 102824e36522SCy Schubert socklen_t addrlen; 102924e36522SCy Schubert int net, af; 103024e36522SCy Schubert 103124e36522SCy Schubert if(a == RPZ_INVALID_ACTION) { 103224e36522SCy Schubert return 0; 103324e36522SCy Schubert } 103424e36522SCy Schubert 103524e36522SCy Schubert if(!netblockdnametoaddr(dname, dnamelen, &addr, &addrlen, &net, &af)) { 103624e36522SCy Schubert verbose(VERB_ALGO, "rpz: unable to parse ns ip"); 103724e36522SCy Schubert return 0; 103824e36522SCy Schubert } 103924e36522SCy Schubert 104024e36522SCy Schubert return rpz_clientip_insert_trigger_rr(r->ns_set, &addr, addrlen, net, 104124e36522SCy Schubert a, rrtype, rrclass, ttl, rdata, rdata_len, rr, rr_len); 104224e36522SCy Schubert } 104324e36522SCy Schubert 1044091e9e46SCy Schubert /** Insert RR into RPZ's respip_set */ 1045091e9e46SCy Schubert static int 1046091e9e46SCy Schubert rpz_insert_response_ip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen, 1047091e9e46SCy Schubert enum rpz_action a, uint16_t rrtype, uint16_t rrclass, uint32_t ttl, 1048091e9e46SCy Schubert uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len) 1049091e9e46SCy Schubert { 1050091e9e46SCy Schubert struct sockaddr_storage addr; 1051091e9e46SCy Schubert socklen_t addrlen; 1052091e9e46SCy Schubert int net, af; 1053091e9e46SCy Schubert 105424e36522SCy Schubert if(a == RPZ_INVALID_ACTION) { 105524e36522SCy Schubert return 0; 105624e36522SCy Schubert } 105724e36522SCy Schubert 105824e36522SCy Schubert if(!netblockdnametoaddr(dname, dnamelen, &addr, &addrlen, &net, &af)) { 105924e36522SCy Schubert verbose(VERB_ALGO, "rpz: unable to parse response ip"); 106024e36522SCy Schubert return 0; 106124e36522SCy Schubert } 106224e36522SCy Schubert 106324e36522SCy Schubert if(a == RPZ_INVALID_ACTION || 106424e36522SCy Schubert rpz_action_to_respip_action(a) == respip_invalid) { 10655469a995SCy Schubert char str[255+1]; 10665469a995SCy Schubert dname_str(dname, str); 1067a39a5a69SCy Schubert verbose(VERB_ALGO, "rpz: respip trigger, %s skipping unsupported action: %s", 10685469a995SCy Schubert str, rpz_action_to_string(a)); 1069091e9e46SCy Schubert return 0; 1070091e9e46SCy Schubert } 1071091e9e46SCy Schubert 107224e36522SCy Schubert return rpz_insert_ipaddr_based_trigger(r->respip_set, &addr, addrlen, net, 107324e36522SCy Schubert a, rrtype, rrclass, ttl, rdata, rdata_len, rr, rr_len); 1074091e9e46SCy Schubert } 1075091e9e46SCy Schubert 1076091e9e46SCy Schubert int 107725039b37SCy Schubert rpz_insert_rr(struct rpz* r, uint8_t* azname, size_t aznamelen, uint8_t* dname, 1078091e9e46SCy Schubert size_t dnamelen, uint16_t rr_type, uint16_t rr_class, uint32_t rr_ttl, 1079091e9e46SCy Schubert uint8_t* rdatawl, size_t rdatalen, uint8_t* rr, size_t rr_len) 1080091e9e46SCy Schubert { 1081091e9e46SCy Schubert size_t policydnamelen; 1082091e9e46SCy Schubert /* name is free'd in local_zone delete */ 1083091e9e46SCy Schubert enum rpz_trigger t; 1084091e9e46SCy Schubert enum rpz_action a; 1085091e9e46SCy Schubert uint8_t* policydname; 1086091e9e46SCy Schubert 108724e36522SCy Schubert if(rpz_type_ignored(rr_type)) { 108824e36522SCy Schubert /* this rpz action is not valid, eg. this is the SOA or NS RR */ 108924e36522SCy Schubert return 1; 109024e36522SCy Schubert } 109125039b37SCy Schubert if(!dname_subdomain_c(dname, azname)) { 1092c0caa2e2SCy Schubert char* dname_str = sldns_wire2str_dname(dname, dnamelen); 1093c0caa2e2SCy Schubert char* azname_str = sldns_wire2str_dname(azname, aznamelen); 1094c0caa2e2SCy Schubert if(dname_str && azname_str) { 109524e36522SCy Schubert log_err("rpz: name of record (%s) to insert into RPZ is not a " 1096c0caa2e2SCy Schubert "subdomain of the configured name of the RPZ zone (%s)", 1097c0caa2e2SCy Schubert dname_str, azname_str); 1098c0caa2e2SCy Schubert } else { 109924e36522SCy Schubert log_err("rpz: name of record to insert into RPZ is not a " 110025039b37SCy Schubert "subdomain of the configured name of the RPZ zone"); 1101c0caa2e2SCy Schubert } 1102c0caa2e2SCy Schubert free(dname_str); 1103c0caa2e2SCy Schubert free(azname_str); 1104091e9e46SCy Schubert return 0; 110525039b37SCy Schubert } 110625039b37SCy Schubert 110725039b37SCy Schubert log_assert(dnamelen >= aznamelen); 110825039b37SCy Schubert if(!(policydname = calloc(1, (dnamelen-aznamelen)+1))) { 110925039b37SCy Schubert log_err("malloc error while inserting RPZ RR"); 111025039b37SCy Schubert return 0; 111125039b37SCy Schubert } 1112091e9e46SCy Schubert 1113091e9e46SCy Schubert a = rpz_rr_to_action(rr_type, rdatawl, rdatalen); 1114091e9e46SCy Schubert if(!(policydnamelen = strip_dname_origin(dname, dnamelen, aznamelen, 1115091e9e46SCy Schubert policydname, (dnamelen-aznamelen)+1))) { 1116091e9e46SCy Schubert free(policydname); 1117091e9e46SCy Schubert return 0; 1118091e9e46SCy Schubert } 1119091e9e46SCy Schubert t = rpz_dname_to_trigger(policydname, policydnamelen); 1120091e9e46SCy Schubert if(t == RPZ_INVALID_TRIGGER) { 1121091e9e46SCy Schubert free(policydname); 112224e36522SCy Schubert verbose(VERB_ALGO, "rpz: skipping invalid trigger"); 1123091e9e46SCy Schubert return 1; 1124091e9e46SCy Schubert } 1125091e9e46SCy Schubert if(t == RPZ_QNAME_TRIGGER) { 112624e36522SCy Schubert /* policydname will be consumed, no free */ 1127091e9e46SCy Schubert rpz_insert_qname_trigger(r, policydname, policydnamelen, 1128091e9e46SCy Schubert a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr, 1129091e9e46SCy Schubert rr_len); 113024e36522SCy Schubert } else if(t == RPZ_RESPONSE_IP_TRIGGER) { 1131091e9e46SCy Schubert rpz_insert_response_ip_trigger(r, policydname, policydnamelen, 1132091e9e46SCy Schubert a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr, 1133091e9e46SCy Schubert rr_len); 1134091e9e46SCy Schubert free(policydname); 113524e36522SCy Schubert } else if(t == RPZ_CLIENT_IP_TRIGGER) { 113624e36522SCy Schubert rpz_insert_clientip_trigger(r, policydname, policydnamelen, 113724e36522SCy Schubert a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr, 113824e36522SCy Schubert rr_len); 1139091e9e46SCy Schubert free(policydname); 114024e36522SCy Schubert } else if(t == RPZ_NSIP_TRIGGER) { 114124e36522SCy Schubert rpz_insert_nsip_trigger(r, policydname, policydnamelen, 114224e36522SCy Schubert a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr, 114324e36522SCy Schubert rr_len); 114424e36522SCy Schubert free(policydname); 114524e36522SCy Schubert } else if(t == RPZ_NSDNAME_TRIGGER) { 114624e36522SCy Schubert rpz_insert_nsdname_trigger(r, policydname, policydnamelen, 114724e36522SCy Schubert a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr, 114824e36522SCy Schubert rr_len); 114924e36522SCy Schubert free(policydname); 115024e36522SCy Schubert } else { 115124e36522SCy Schubert free(policydname); 115224e36522SCy Schubert verbose(VERB_ALGO, "rpz: skipping unsupported trigger: %s", 1153091e9e46SCy Schubert rpz_trigger_to_string(t)); 1154091e9e46SCy Schubert } 1155091e9e46SCy Schubert return 1; 1156091e9e46SCy Schubert } 1157091e9e46SCy Schubert 1158091e9e46SCy Schubert /** 1159091e9e46SCy Schubert * Find RPZ local-zone by qname. 116024e36522SCy Schubert * @param zones: local-zone tree 1161091e9e46SCy Schubert * @param qname: qname 1162091e9e46SCy Schubert * @param qname_len: length of qname 1163091e9e46SCy Schubert * @param qclass: qclass 116424e36522SCy Schubert * @param only_exact: if 1 only exact (non wildcard) matches are returned 1165091e9e46SCy Schubert * @param wr: get write lock for local-zone if 1, read lock if 0 1166091e9e46SCy Schubert * @param zones_keep_lock: if set do not release the r->local_zones lock, this 1167091e9e46SCy Schubert * makes the caller of this function responsible for releasing the lock. 1168091e9e46SCy Schubert * @return: NULL or local-zone holding rd or wr lock 1169091e9e46SCy Schubert */ 1170091e9e46SCy Schubert static struct local_zone* 117124e36522SCy Schubert rpz_find_zone(struct local_zones* zones, uint8_t* qname, size_t qname_len, uint16_t qclass, 1172091e9e46SCy Schubert int only_exact, int wr, int zones_keep_lock) 1173091e9e46SCy Schubert { 1174091e9e46SCy Schubert uint8_t* ce; 1175f44e67d1SCy Schubert size_t ce_len; 1176f44e67d1SCy Schubert int ce_labs; 1177091e9e46SCy Schubert uint8_t wc[LDNS_MAX_DOMAINLEN+1]; 1178091e9e46SCy Schubert int exact; 1179091e9e46SCy Schubert struct local_zone* z = NULL; 118024e36522SCy Schubert 1181091e9e46SCy Schubert if(wr) { 118224e36522SCy Schubert lock_rw_wrlock(&zones->lock); 1183091e9e46SCy Schubert } else { 118424e36522SCy Schubert lock_rw_rdlock(&zones->lock); 1185091e9e46SCy Schubert } 118624e36522SCy Schubert z = local_zones_find_le(zones, qname, qname_len, 1187091e9e46SCy Schubert dname_count_labels(qname), 1188091e9e46SCy Schubert LDNS_RR_CLASS_IN, &exact); 1189091e9e46SCy Schubert if(!z || (only_exact && !exact)) { 119024e36522SCy Schubert if(!zones_keep_lock) { 119124e36522SCy Schubert lock_rw_unlock(&zones->lock); 119224e36522SCy Schubert } 1193091e9e46SCy Schubert return NULL; 1194091e9e46SCy Schubert } 1195091e9e46SCy Schubert if(wr) { 1196091e9e46SCy Schubert lock_rw_wrlock(&z->lock); 1197091e9e46SCy Schubert } else { 1198091e9e46SCy Schubert lock_rw_rdlock(&z->lock); 1199091e9e46SCy Schubert } 1200091e9e46SCy Schubert if(!zones_keep_lock) { 120124e36522SCy Schubert lock_rw_unlock(&zones->lock); 1202091e9e46SCy Schubert } 1203091e9e46SCy Schubert 1204091e9e46SCy Schubert if(exact) 1205091e9e46SCy Schubert return z; 1206091e9e46SCy Schubert 1207091e9e46SCy Schubert /* No exact match found, lookup wildcard. closest encloser must 1208091e9e46SCy Schubert * be the shared parent between the qname and the best local 1209091e9e46SCy Schubert * zone match, append '*' to that and do another lookup. */ 1210091e9e46SCy Schubert 1211091e9e46SCy Schubert ce = dname_get_shared_topdomain(z->name, qname); 12125469a995SCy Schubert if(!ce /* should not happen */) { 1213091e9e46SCy Schubert lock_rw_unlock(&z->lock); 1214091e9e46SCy Schubert if(zones_keep_lock) { 121524e36522SCy Schubert lock_rw_unlock(&zones->lock); 1216091e9e46SCy Schubert } 1217091e9e46SCy Schubert return NULL; 1218091e9e46SCy Schubert } 1219091e9e46SCy Schubert ce_labs = dname_count_size_labels(ce, &ce_len); 1220091e9e46SCy Schubert if(ce_len+2 > sizeof(wc)) { 1221091e9e46SCy Schubert lock_rw_unlock(&z->lock); 1222091e9e46SCy Schubert if(zones_keep_lock) { 122324e36522SCy Schubert lock_rw_unlock(&zones->lock); 1224091e9e46SCy Schubert } 1225091e9e46SCy Schubert return NULL; 1226091e9e46SCy Schubert } 1227091e9e46SCy Schubert wc[0] = 1; /* length of wildcard label */ 1228091e9e46SCy Schubert wc[1] = (uint8_t)'*'; /* wildcard label */ 1229091e9e46SCy Schubert memmove(wc+2, ce, ce_len); 1230091e9e46SCy Schubert lock_rw_unlock(&z->lock); 1231091e9e46SCy Schubert 1232091e9e46SCy Schubert if(!zones_keep_lock) { 1233091e9e46SCy Schubert if(wr) { 123424e36522SCy Schubert lock_rw_wrlock(&zones->lock); 1235091e9e46SCy Schubert } else { 123624e36522SCy Schubert lock_rw_rdlock(&zones->lock); 1237091e9e46SCy Schubert } 1238091e9e46SCy Schubert } 123924e36522SCy Schubert z = local_zones_find_le(zones, wc, 1240091e9e46SCy Schubert ce_len+2, ce_labs+1, qclass, &exact); 1241091e9e46SCy Schubert if(!z || !exact) { 124224e36522SCy Schubert lock_rw_unlock(&zones->lock); 1243091e9e46SCy Schubert return NULL; 1244091e9e46SCy Schubert } 1245091e9e46SCy Schubert if(wr) { 1246091e9e46SCy Schubert lock_rw_wrlock(&z->lock); 1247091e9e46SCy Schubert } else { 1248091e9e46SCy Schubert lock_rw_rdlock(&z->lock); 1249091e9e46SCy Schubert } 1250091e9e46SCy Schubert if(!zones_keep_lock) { 125124e36522SCy Schubert lock_rw_unlock(&zones->lock); 1252091e9e46SCy Schubert } 1253091e9e46SCy Schubert return z; 1254091e9e46SCy Schubert } 1255091e9e46SCy Schubert 12568f76bb7dSCy Schubert /** Find entry for RR type in the list of rrsets for the clientip. */ 12578f76bb7dSCy Schubert static struct local_rrset* 12588f76bb7dSCy Schubert rpz_find_synthesized_rrset(uint16_t qtype, 1259335c7cdaSCy Schubert struct clientip_synthesized_rr* data, int alias_ok) 12608f76bb7dSCy Schubert { 1261335c7cdaSCy Schubert struct local_rrset* cursor = data->data, *cname = NULL; 12628f76bb7dSCy Schubert while( cursor != NULL) { 12638f76bb7dSCy Schubert struct packed_rrset_key* packed_rrset = &cursor->rrset->rk; 12648f76bb7dSCy Schubert if(htons(qtype) == packed_rrset->type) { 12658f76bb7dSCy Schubert return cursor; 12668f76bb7dSCy Schubert } 1267335c7cdaSCy Schubert if(ntohs(packed_rrset->type) == LDNS_RR_TYPE_CNAME && alias_ok) 1268335c7cdaSCy Schubert cname = cursor; 12698f76bb7dSCy Schubert cursor = cursor->next; 12708f76bb7dSCy Schubert } 1271335c7cdaSCy Schubert if(alias_ok) 1272335c7cdaSCy Schubert return cname; 12738f76bb7dSCy Schubert return NULL; 12748f76bb7dSCy Schubert } 12758f76bb7dSCy Schubert 1276091e9e46SCy Schubert /** 1277091e9e46SCy Schubert * Remove RR from RPZ's local-data 1278091e9e46SCy Schubert * @param z: local-zone for RPZ, holding write lock 1279091e9e46SCy Schubert * @param policydname: dname of RR to remove 128024e36522SCy Schubert * @param policydnamelen: length of policydname 1281091e9e46SCy Schubert * @param rr_type: RR type of RR to remove 1282091e9e46SCy Schubert * @param rdata: rdata of RR to remove 1283091e9e46SCy Schubert * @param rdatalen: length of rdata 1284091e9e46SCy Schubert * @return: 1 if zone must be removed after RR deletion 1285091e9e46SCy Schubert */ 1286091e9e46SCy Schubert static int 1287091e9e46SCy Schubert rpz_data_delete_rr(struct local_zone* z, uint8_t* policydname, 1288091e9e46SCy Schubert size_t policydnamelen, uint16_t rr_type, uint8_t* rdata, 1289091e9e46SCy Schubert size_t rdatalen) 1290091e9e46SCy Schubert { 1291091e9e46SCy Schubert struct local_data* ld; 1292091e9e46SCy Schubert struct packed_rrset_data* d; 1293091e9e46SCy Schubert size_t index; 1294091e9e46SCy Schubert ld = local_zone_find_data(z, policydname, policydnamelen, 1295091e9e46SCy Schubert dname_count_labels(policydname)); 1296091e9e46SCy Schubert if(ld) { 1297091e9e46SCy Schubert struct local_rrset* prev=NULL, *p=ld->rrsets; 1298091e9e46SCy Schubert while(p && ntohs(p->rrset->rk.type) != rr_type) { 1299091e9e46SCy Schubert prev = p; 1300091e9e46SCy Schubert p = p->next; 1301091e9e46SCy Schubert } 1302091e9e46SCy Schubert if(!p) 1303091e9e46SCy Schubert return 0; 1304091e9e46SCy Schubert d = (struct packed_rrset_data*)p->rrset->entry.data; 1305091e9e46SCy Schubert if(packed_rrset_find_rr(d, rdata, rdatalen, &index)) { 1306091e9e46SCy Schubert if(d->count == 1) { 1307091e9e46SCy Schubert /* no memory recycling for zone deletions ... */ 1308091e9e46SCy Schubert if(prev) prev->next = p->next; 1309091e9e46SCy Schubert else ld->rrsets = p->next; 1310091e9e46SCy Schubert } 1311091e9e46SCy Schubert if(d->count > 1) { 1312091e9e46SCy Schubert if(!local_rrset_remove_rr(d, index)) 1313091e9e46SCy Schubert return 0; 1314091e9e46SCy Schubert } 1315091e9e46SCy Schubert } 1316091e9e46SCy Schubert } 1317091e9e46SCy Schubert if(ld && ld->rrsets) 1318091e9e46SCy Schubert return 0; 1319091e9e46SCy Schubert return 1; 1320091e9e46SCy Schubert } 1321091e9e46SCy Schubert 1322091e9e46SCy Schubert /** 1323091e9e46SCy Schubert * Remove RR from RPZ's respip set 1324091e9e46SCy Schubert * @param raddr: respip node 1325091e9e46SCy Schubert * @param rr_type: RR type of RR to remove 1326091e9e46SCy Schubert * @param rdata: rdata of RR to remove 1327091e9e46SCy Schubert * @param rdatalen: length of rdata 1328091e9e46SCy Schubert * @return: 1 if zone must be removed after RR deletion 1329091e9e46SCy Schubert */ 1330091e9e46SCy Schubert static int 1331091e9e46SCy Schubert rpz_rrset_delete_rr(struct resp_addr* raddr, uint16_t rr_type, uint8_t* rdata, 1332091e9e46SCy Schubert size_t rdatalen) 1333091e9e46SCy Schubert { 1334091e9e46SCy Schubert size_t index; 1335091e9e46SCy Schubert struct packed_rrset_data* d; 1336091e9e46SCy Schubert if(!raddr->data) 1337091e9e46SCy Schubert return 1; 1338091e9e46SCy Schubert d = raddr->data->entry.data; 1339091e9e46SCy Schubert if(ntohs(raddr->data->rk.type) != rr_type) { 1340091e9e46SCy Schubert return 0; 1341091e9e46SCy Schubert } 1342091e9e46SCy Schubert if(packed_rrset_find_rr(d, rdata, rdatalen, &index)) { 1343091e9e46SCy Schubert if(d->count == 1) { 1344091e9e46SCy Schubert /* regional alloc'd */ 1345091e9e46SCy Schubert raddr->data->entry.data = NULL; 1346091e9e46SCy Schubert raddr->data = NULL; 1347091e9e46SCy Schubert return 1; 1348091e9e46SCy Schubert } 1349091e9e46SCy Schubert if(d->count > 1) { 1350091e9e46SCy Schubert if(!local_rrset_remove_rr(d, index)) 1351091e9e46SCy Schubert return 0; 1352091e9e46SCy Schubert } 1353091e9e46SCy Schubert } 1354091e9e46SCy Schubert return 0; 1355091e9e46SCy Schubert 1356091e9e46SCy Schubert } 1357091e9e46SCy Schubert 13588f76bb7dSCy Schubert /** Remove RR from rpz localzones structure */ 1359091e9e46SCy Schubert static void 13608f76bb7dSCy Schubert rpz_remove_local_zones_trigger(struct local_zones* zones, uint8_t* dname, 13618f76bb7dSCy Schubert size_t dnamelen, enum rpz_action a, uint16_t rr_type, 13628f76bb7dSCy Schubert uint16_t rr_class, uint8_t* rdatawl, size_t rdatalen) 1363091e9e46SCy Schubert { 1364091e9e46SCy Schubert struct local_zone* z; 1365091e9e46SCy Schubert int delete_zone = 1; 13668f76bb7dSCy Schubert z = rpz_find_zone(zones, dname, dnamelen, rr_class, 1367091e9e46SCy Schubert 1 /* only exact */, 1 /* wr lock */, 1 /* keep lock*/); 1368091e9e46SCy Schubert if(!z) { 136924e36522SCy Schubert verbose(VERB_ALGO, "rpz: cannot remove RR from IXFR, " 1370091e9e46SCy Schubert "RPZ domain not found"); 1371091e9e46SCy Schubert return; 1372091e9e46SCy Schubert } 1373091e9e46SCy Schubert if(a == RPZ_LOCAL_DATA_ACTION) 1374091e9e46SCy Schubert delete_zone = rpz_data_delete_rr(z, dname, 1375091e9e46SCy Schubert dnamelen, rr_type, rdatawl, rdatalen); 1376091e9e46SCy Schubert else if(a != localzone_type_to_rpz_action(z->type)) { 137725039b37SCy Schubert lock_rw_unlock(&z->lock); 13788f76bb7dSCy Schubert lock_rw_unlock(&zones->lock); 1379091e9e46SCy Schubert return; 1380091e9e46SCy Schubert } 1381091e9e46SCy Schubert lock_rw_unlock(&z->lock); 1382091e9e46SCy Schubert if(delete_zone) { 13838f76bb7dSCy Schubert local_zones_del_zone(zones, z); 1384091e9e46SCy Schubert } 13858f76bb7dSCy Schubert lock_rw_unlock(&zones->lock); 13868f76bb7dSCy Schubert } 13878f76bb7dSCy Schubert 13888f76bb7dSCy Schubert /** Remove RR from RPZ's local-zone */ 13898f76bb7dSCy Schubert static void 13908f76bb7dSCy Schubert rpz_remove_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen, 13918f76bb7dSCy Schubert enum rpz_action a, uint16_t rr_type, uint16_t rr_class, 13928f76bb7dSCy Schubert uint8_t* rdatawl, size_t rdatalen) 13938f76bb7dSCy Schubert { 13948f76bb7dSCy Schubert rpz_remove_local_zones_trigger(r->local_zones, dname, dnamelen, 13958f76bb7dSCy Schubert a, rr_type, rr_class, rdatawl, rdatalen); 1396091e9e46SCy Schubert } 1397091e9e46SCy Schubert 1398091e9e46SCy Schubert static void 1399091e9e46SCy Schubert rpz_remove_response_ip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen, 1400091e9e46SCy Schubert enum rpz_action a, uint16_t rr_type, uint8_t* rdatawl, size_t rdatalen) 1401091e9e46SCy Schubert { 1402091e9e46SCy Schubert struct resp_addr* node; 1403091e9e46SCy Schubert struct sockaddr_storage addr; 1404091e9e46SCy Schubert socklen_t addrlen; 1405091e9e46SCy Schubert int net, af; 1406091e9e46SCy Schubert int delete_respip = 1; 1407091e9e46SCy Schubert 1408091e9e46SCy Schubert if(!netblockdnametoaddr(dname, dnamelen, &addr, &addrlen, &net, &af)) 1409091e9e46SCy Schubert return; 1410091e9e46SCy Schubert 1411091e9e46SCy Schubert lock_rw_wrlock(&r->respip_set->lock); 1412091e9e46SCy Schubert if(!(node = (struct resp_addr*)addr_tree_find( 1413091e9e46SCy Schubert &r->respip_set->ip_tree, &addr, addrlen, net))) { 141424e36522SCy Schubert verbose(VERB_ALGO, "rpz: cannot remove RR from IXFR, " 1415091e9e46SCy Schubert "RPZ domain not found"); 1416091e9e46SCy Schubert lock_rw_unlock(&r->respip_set->lock); 1417091e9e46SCy Schubert return; 1418091e9e46SCy Schubert } 1419091e9e46SCy Schubert 1420091e9e46SCy Schubert lock_rw_wrlock(&node->lock); 1421091e9e46SCy Schubert if(a == RPZ_LOCAL_DATA_ACTION) { 1422091e9e46SCy Schubert /* remove RR, signal whether RR can be removed */ 1423091e9e46SCy Schubert delete_respip = rpz_rrset_delete_rr(node, rr_type, rdatawl, 1424091e9e46SCy Schubert rdatalen); 1425091e9e46SCy Schubert } 1426091e9e46SCy Schubert lock_rw_unlock(&node->lock); 1427091e9e46SCy Schubert if(delete_respip) 1428091e9e46SCy Schubert respip_sockaddr_delete(r->respip_set, node); 1429091e9e46SCy Schubert lock_rw_unlock(&r->respip_set->lock); 1430091e9e46SCy Schubert } 1431091e9e46SCy Schubert 14328f76bb7dSCy Schubert /** find and remove type from list of local_rrset entries*/ 14338f76bb7dSCy Schubert static void 14348f76bb7dSCy Schubert del_local_rrset_from_list(struct local_rrset** list_head, uint16_t dtype) 14358f76bb7dSCy Schubert { 14368f76bb7dSCy Schubert struct local_rrset* prev=NULL, *p=*list_head; 14378f76bb7dSCy Schubert while(p && ntohs(p->rrset->rk.type) != dtype) { 14388f76bb7dSCy Schubert prev = p; 14398f76bb7dSCy Schubert p = p->next; 14408f76bb7dSCy Schubert } 14418f76bb7dSCy Schubert if(!p) 14428f76bb7dSCy Schubert return; /* rrset type not found */ 14438f76bb7dSCy Schubert /* unlink it */ 14448f76bb7dSCy Schubert if(prev) prev->next = p->next; 14458f76bb7dSCy Schubert else *list_head = p->next; 14468f76bb7dSCy Schubert /* no memory recycling for zone deletions ... */ 14478f76bb7dSCy Schubert } 14488f76bb7dSCy Schubert 14498f76bb7dSCy Schubert /** Delete client-ip trigger RR from its RRset and perhaps also the rrset 14508f76bb7dSCy Schubert * from the linked list. Returns if the local data is empty and the node can 14518f76bb7dSCy Schubert * be deleted too, or not. */ 14528f76bb7dSCy Schubert static int rpz_remove_clientip_rr(struct clientip_synthesized_rr* node, 14538f76bb7dSCy Schubert uint16_t rr_type, uint8_t* rdatawl, size_t rdatalen) 14548f76bb7dSCy Schubert { 14558f76bb7dSCy Schubert struct local_rrset* rrset; 14568f76bb7dSCy Schubert struct packed_rrset_data* d; 14578f76bb7dSCy Schubert size_t index; 1458335c7cdaSCy Schubert rrset = rpz_find_synthesized_rrset(rr_type, node, 0); 14598f76bb7dSCy Schubert if(rrset == NULL) 14608f76bb7dSCy Schubert return 0; /* type not found, ignore */ 14618f76bb7dSCy Schubert d = (struct packed_rrset_data*)rrset->rrset->entry.data; 14628f76bb7dSCy Schubert if(!packed_rrset_find_rr(d, rdatawl, rdatalen, &index)) 14638f76bb7dSCy Schubert return 0; /* RR not found, ignore */ 14648f76bb7dSCy Schubert if(d->count == 1) { 14658f76bb7dSCy Schubert /* regional alloc'd */ 14668f76bb7dSCy Schubert /* delete the type entry from the list */ 14678f76bb7dSCy Schubert del_local_rrset_from_list(&node->data, rr_type); 14688f76bb7dSCy Schubert /* if the list is empty, the node can be removed too */ 14698f76bb7dSCy Schubert if(node->data == NULL) 14708f76bb7dSCy Schubert return 1; 14718f76bb7dSCy Schubert } else if (d->count > 1) { 14728f76bb7dSCy Schubert if(!local_rrset_remove_rr(d, index)) 14738f76bb7dSCy Schubert return 0; 14748f76bb7dSCy Schubert } 14758f76bb7dSCy Schubert return 0; 14768f76bb7dSCy Schubert } 14778f76bb7dSCy Schubert 14788f76bb7dSCy Schubert /** remove trigger RR from clientip_syntheized set tree. */ 14798f76bb7dSCy Schubert static void 14808f76bb7dSCy Schubert rpz_clientip_remove_trigger_rr(struct clientip_synthesized_rrset* set, 14818f76bb7dSCy Schubert struct sockaddr_storage* addr, socklen_t addrlen, int net, 14828f76bb7dSCy Schubert enum rpz_action a, uint16_t rr_type, uint8_t* rdatawl, size_t rdatalen) 14838f76bb7dSCy Schubert { 14848f76bb7dSCy Schubert struct clientip_synthesized_rr* node; 14858f76bb7dSCy Schubert int delete_node = 1; 14868f76bb7dSCy Schubert 14878f76bb7dSCy Schubert lock_rw_wrlock(&set->lock); 14888f76bb7dSCy Schubert node = (struct clientip_synthesized_rr*)addr_tree_find(&set->entries, 14898f76bb7dSCy Schubert addr, addrlen, net); 14908f76bb7dSCy Schubert if(node == NULL) { 14918f76bb7dSCy Schubert /* netblock not found */ 14928f76bb7dSCy Schubert verbose(VERB_ALGO, "rpz: cannot remove RR from IXFR, " 14938f76bb7dSCy Schubert "RPZ address, netblock not found"); 14948f76bb7dSCy Schubert lock_rw_unlock(&set->lock); 14958f76bb7dSCy Schubert return; 14968f76bb7dSCy Schubert } 14978f76bb7dSCy Schubert lock_rw_wrlock(&node->lock); 14988f76bb7dSCy Schubert if(a == RPZ_LOCAL_DATA_ACTION) { 14998f76bb7dSCy Schubert /* remove RR, signal whether entry can be removed */ 15008f76bb7dSCy Schubert delete_node = rpz_remove_clientip_rr(node, rr_type, rdatawl, 15018f76bb7dSCy Schubert rdatalen); 15028f76bb7dSCy Schubert } else if(a != node->action) { 15038f76bb7dSCy Schubert /* ignore the RR with different action specification */ 15048f76bb7dSCy Schubert delete_node = 0; 15058f76bb7dSCy Schubert } 15068f76bb7dSCy Schubert if(delete_node) { 15078f76bb7dSCy Schubert rbtree_delete(&set->entries, node->node.node.key); 15088f76bb7dSCy Schubert } 15098f76bb7dSCy Schubert lock_rw_unlock(&set->lock); 15108f76bb7dSCy Schubert lock_rw_unlock(&node->lock); 15118f76bb7dSCy Schubert if(delete_node) { 15128f76bb7dSCy Schubert lock_rw_destroy(&node->lock); 15138f76bb7dSCy Schubert } 15148f76bb7dSCy Schubert } 15158f76bb7dSCy Schubert 15168f76bb7dSCy Schubert /** Remove clientip trigger RR from RPZ. */ 15178f76bb7dSCy Schubert static void 15188f76bb7dSCy Schubert rpz_remove_clientip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen, 15198f76bb7dSCy Schubert enum rpz_action a, uint16_t rr_type, uint8_t* rdatawl, size_t rdatalen) 15208f76bb7dSCy Schubert { 15218f76bb7dSCy Schubert struct sockaddr_storage addr; 15228f76bb7dSCy Schubert socklen_t addrlen; 15238f76bb7dSCy Schubert int net, af; 15248f76bb7dSCy Schubert if(a == RPZ_INVALID_ACTION) 15258f76bb7dSCy Schubert return; 15268f76bb7dSCy Schubert if(!netblockdnametoaddr(dname, dnamelen, &addr, &addrlen, &net, &af)) 15278f76bb7dSCy Schubert return; 15288f76bb7dSCy Schubert rpz_clientip_remove_trigger_rr(r->client_set, &addr, addrlen, net, 15298f76bb7dSCy Schubert a, rr_type, rdatawl, rdatalen); 15308f76bb7dSCy Schubert } 15318f76bb7dSCy Schubert 15328f76bb7dSCy Schubert /** Remove nsip trigger RR from RPZ. */ 15338f76bb7dSCy Schubert static void 15348f76bb7dSCy Schubert rpz_remove_nsip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen, 15358f76bb7dSCy Schubert enum rpz_action a, uint16_t rr_type, uint8_t* rdatawl, size_t rdatalen) 15368f76bb7dSCy Schubert { 15378f76bb7dSCy Schubert struct sockaddr_storage addr; 15388f76bb7dSCy Schubert socklen_t addrlen; 15398f76bb7dSCy Schubert int net, af; 15408f76bb7dSCy Schubert if(a == RPZ_INVALID_ACTION) 15418f76bb7dSCy Schubert return; 15428f76bb7dSCy Schubert if(!netblockdnametoaddr(dname, dnamelen, &addr, &addrlen, &net, &af)) 15438f76bb7dSCy Schubert return; 15448f76bb7dSCy Schubert rpz_clientip_remove_trigger_rr(r->ns_set, &addr, addrlen, net, 15458f76bb7dSCy Schubert a, rr_type, rdatawl, rdatalen); 15468f76bb7dSCy Schubert } 15478f76bb7dSCy Schubert 15488f76bb7dSCy Schubert /** Remove nsdname trigger RR from RPZ. */ 15498f76bb7dSCy Schubert static void 15508f76bb7dSCy Schubert rpz_remove_nsdname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen, 15518f76bb7dSCy Schubert enum rpz_action a, uint16_t rr_type, uint16_t rr_class, 15528f76bb7dSCy Schubert uint8_t* rdatawl, size_t rdatalen) 15538f76bb7dSCy Schubert { 15548f76bb7dSCy Schubert uint8_t* dname_stripped = NULL; 15558f76bb7dSCy Schubert size_t dnamelen_stripped = 0; 15568f76bb7dSCy Schubert if(a == RPZ_INVALID_ACTION) 15578f76bb7dSCy Schubert return; 15588f76bb7dSCy Schubert if(!rpz_strip_nsdname_suffix(dname, dnamelen, &dname_stripped, 15598f76bb7dSCy Schubert &dnamelen_stripped)) 15608f76bb7dSCy Schubert return; 15618f76bb7dSCy Schubert rpz_remove_local_zones_trigger(r->nsdname_zones, dname_stripped, 15628f76bb7dSCy Schubert dnamelen_stripped, a, rr_type, rr_class, rdatawl, rdatalen); 15638f76bb7dSCy Schubert free(dname_stripped); 15648f76bb7dSCy Schubert } 15658f76bb7dSCy Schubert 1566091e9e46SCy Schubert void 15678f76bb7dSCy Schubert rpz_remove_rr(struct rpz* r, uint8_t* azname, size_t aznamelen, uint8_t* dname, 15688f76bb7dSCy Schubert size_t dnamelen, uint16_t rr_type, uint16_t rr_class, uint8_t* rdatawl, 15698f76bb7dSCy Schubert size_t rdatalen) 1570091e9e46SCy Schubert { 1571091e9e46SCy Schubert size_t policydnamelen; 1572091e9e46SCy Schubert enum rpz_trigger t; 1573091e9e46SCy Schubert enum rpz_action a; 1574091e9e46SCy Schubert uint8_t* policydname; 1575091e9e46SCy Schubert 15768f76bb7dSCy Schubert if(rpz_type_ignored(rr_type)) { 15778f76bb7dSCy Schubert /* this rpz action is not valid, eg. this is the SOA or NS RR */ 15788f76bb7dSCy Schubert return; 15798f76bb7dSCy Schubert } 15808f76bb7dSCy Schubert if(!dname_subdomain_c(dname, azname)) { 15818f76bb7dSCy Schubert /* not subdomain of the RPZ zone. */ 15828f76bb7dSCy Schubert return; 15838f76bb7dSCy Schubert } 15848f76bb7dSCy Schubert 1585091e9e46SCy Schubert if(!(policydname = calloc(1, LDNS_MAX_DOMAINLEN + 1))) 1586091e9e46SCy Schubert return; 1587091e9e46SCy Schubert 1588091e9e46SCy Schubert a = rpz_rr_to_action(rr_type, rdatawl, rdatalen); 1589091e9e46SCy Schubert if(a == RPZ_INVALID_ACTION) { 1590091e9e46SCy Schubert free(policydname); 1591091e9e46SCy Schubert return; 1592091e9e46SCy Schubert } 1593091e9e46SCy Schubert if(!(policydnamelen = strip_dname_origin(dname, dnamelen, aznamelen, 1594091e9e46SCy Schubert policydname, LDNS_MAX_DOMAINLEN + 1))) { 1595091e9e46SCy Schubert free(policydname); 1596091e9e46SCy Schubert return; 1597091e9e46SCy Schubert } 1598091e9e46SCy Schubert t = rpz_dname_to_trigger(policydname, policydnamelen); 15998f76bb7dSCy Schubert if(t == RPZ_INVALID_TRIGGER) { 16008f76bb7dSCy Schubert /* skipping invalid trigger */ 16018f76bb7dSCy Schubert free(policydname); 16028f76bb7dSCy Schubert return; 16038f76bb7dSCy Schubert } 1604091e9e46SCy Schubert if(t == RPZ_QNAME_TRIGGER) { 1605091e9e46SCy Schubert rpz_remove_qname_trigger(r, policydname, policydnamelen, a, 1606091e9e46SCy Schubert rr_type, rr_class, rdatawl, rdatalen); 1607091e9e46SCy Schubert } else if(t == RPZ_RESPONSE_IP_TRIGGER) { 1608091e9e46SCy Schubert rpz_remove_response_ip_trigger(r, policydname, policydnamelen, 1609091e9e46SCy Schubert a, rr_type, rdatawl, rdatalen); 16108f76bb7dSCy Schubert } else if(t == RPZ_CLIENT_IP_TRIGGER) { 16118f76bb7dSCy Schubert rpz_remove_clientip_trigger(r, policydname, policydnamelen, a, 16128f76bb7dSCy Schubert rr_type, rdatawl, rdatalen); 16138f76bb7dSCy Schubert } else if(t == RPZ_NSIP_TRIGGER) { 16148f76bb7dSCy Schubert rpz_remove_nsip_trigger(r, policydname, policydnamelen, a, 16158f76bb7dSCy Schubert rr_type, rdatawl, rdatalen); 16168f76bb7dSCy Schubert } else if(t == RPZ_NSDNAME_TRIGGER) { 16178f76bb7dSCy Schubert rpz_remove_nsdname_trigger(r, policydname, policydnamelen, a, 16188f76bb7dSCy Schubert rr_type, rr_class, rdatawl, rdatalen); 1619091e9e46SCy Schubert } 16208f76bb7dSCy Schubert /* else it was an unsupported trigger, also skipped. */ 1621091e9e46SCy Schubert free(policydname); 1622091e9e46SCy Schubert } 1623091e9e46SCy Schubert 1624091e9e46SCy Schubert /** print log information for an applied RPZ policy. Based on local-zone's 1625091e9e46SCy Schubert * lz_inform_print(). 162624e36522SCy Schubert * The repinfo contains the reply address. If it is NULL, the module 162724e36522SCy Schubert * state is used to report the first IP address (if any). 162824e36522SCy Schubert * The dname is used, for the applied rpz, if NULL, addrnode is used. 1629091e9e46SCy Schubert */ 1630091e9e46SCy Schubert static void 163124e36522SCy Schubert log_rpz_apply(char* trigger, uint8_t* dname, struct addr_tree_node* addrnode, 163224e36522SCy Schubert enum rpz_action a, struct query_info* qinfo, 163324e36522SCy Schubert struct comm_reply* repinfo, struct module_qstate* ms, char* log_name) 1634091e9e46SCy Schubert { 163524e36522SCy Schubert char ip[128], txt[512], portstr[32]; 1636091e9e46SCy Schubert char dnamestr[LDNS_MAX_DOMAINLEN+1]; 163724e36522SCy Schubert uint16_t port = 0; 163824e36522SCy Schubert if(dname) { 1639091e9e46SCy Schubert dname_str(dname, dnamestr); 164024e36522SCy Schubert } else if(addrnode) { 16419cf5bc93SCy Schubert char addrbuf[128]; 16429cf5bc93SCy Schubert addr_to_str(&addrnode->addr, addrnode->addrlen, addrbuf, sizeof(addrbuf)); 16439cf5bc93SCy Schubert snprintf(dnamestr, sizeof(dnamestr), "%s/%d", addrbuf, addrnode->net); 164424e36522SCy Schubert } else { 164524e36522SCy Schubert dnamestr[0]=0; 164624e36522SCy Schubert } 164724e36522SCy Schubert if(repinfo) { 1648865f46b2SCy Schubert addr_to_str(&repinfo->client_addr, repinfo->client_addrlen, ip, sizeof(ip)); 1649865f46b2SCy Schubert port = ntohs(((struct sockaddr_in*)&repinfo->client_addr)->sin_port); 165024e36522SCy Schubert } else if(ms && ms->mesh_info && ms->mesh_info->reply_list) { 1651865f46b2SCy Schubert addr_to_str(&ms->mesh_info->reply_list->query_reply.client_addr, 1652865f46b2SCy Schubert ms->mesh_info->reply_list->query_reply.client_addrlen, 1653865f46b2SCy Schubert ip, sizeof(ip)); 1654865f46b2SCy Schubert port = ntohs(((struct sockaddr_in*)&ms->mesh_info->reply_list->query_reply.client_addr)->sin_port); 165524e36522SCy Schubert } else { 165624e36522SCy Schubert ip[0]=0; 165724e36522SCy Schubert port = 0; 165824e36522SCy Schubert } 165924e36522SCy Schubert snprintf(portstr, sizeof(portstr), "@%u", (unsigned)port); 166024e36522SCy Schubert snprintf(txt, sizeof(txt), "rpz: applied %s%s%s%s%s%s %s %s%s", 166124e36522SCy Schubert (log_name?"[":""), (log_name?log_name:""), (log_name?"] ":""), 166224e36522SCy Schubert (strcmp(trigger,"qname")==0?"":trigger), 166324e36522SCy Schubert (strcmp(trigger,"qname")==0?"":" "), 166424e36522SCy Schubert dnamestr, rpz_action_to_string(a), 166524e36522SCy Schubert (ip[0]?ip:""), (ip[0]?portstr:"")); 1666091e9e46SCy Schubert log_nametypeclass(0, txt, qinfo->qname, qinfo->qtype, qinfo->qclass); 1667091e9e46SCy Schubert } 1668091e9e46SCy Schubert 166924e36522SCy Schubert static struct clientip_synthesized_rr* 167024e36522SCy Schubert rpz_ipbased_trigger_lookup(struct clientip_synthesized_rrset* set, 167124e36522SCy Schubert struct sockaddr_storage* addr, socklen_t addrlen, char* triggername) 1672091e9e46SCy Schubert { 167324e36522SCy Schubert struct clientip_synthesized_rr* raddr = NULL; 167424e36522SCy Schubert enum rpz_action action = RPZ_INVALID_ACTION; 167524e36522SCy Schubert 167624e36522SCy Schubert lock_rw_rdlock(&set->lock); 167724e36522SCy Schubert 167824e36522SCy Schubert raddr = (struct clientip_synthesized_rr*)addr_tree_lookup(&set->entries, 167924e36522SCy Schubert addr, addrlen); 168024e36522SCy Schubert if(raddr != NULL) { 168124e36522SCy Schubert lock_rw_rdlock(&raddr->lock); 168224e36522SCy Schubert action = raddr->action; 168324e36522SCy Schubert if(verbosity >= VERB_ALGO) { 168424e36522SCy Schubert char ip[256], net[256]; 168524e36522SCy Schubert addr_to_str(addr, addrlen, ip, sizeof(ip)); 168624e36522SCy Schubert addr_to_str(&raddr->node.addr, raddr->node.addrlen, 168724e36522SCy Schubert net, sizeof(net)); 168824e36522SCy Schubert verbose(VERB_ALGO, "rpz: trigger %s %s/%d on %s action=%s", 168924e36522SCy Schubert triggername, net, raddr->node.net, ip, rpz_action_to_string(action)); 169024e36522SCy Schubert } 169124e36522SCy Schubert } 169224e36522SCy Schubert lock_rw_unlock(&set->lock); 169324e36522SCy Schubert 169424e36522SCy Schubert return raddr; 169524e36522SCy Schubert } 169624e36522SCy Schubert 169724e36522SCy Schubert static inline 169824e36522SCy Schubert struct clientip_synthesized_rr* 169924e36522SCy Schubert rpz_resolve_client_action_and_zone(struct auth_zones* az, struct query_info* qinfo, 170024e36522SCy Schubert struct comm_reply* repinfo, uint8_t* taglist, size_t taglen, 170124e36522SCy Schubert struct ub_server_stats* stats, 170224e36522SCy Schubert /* output parameters */ 170324e36522SCy Schubert struct local_zone** z_out, struct auth_zone** a_out, struct rpz** r_out) 170424e36522SCy Schubert { 170524e36522SCy Schubert struct clientip_synthesized_rr* node = NULL; 170624e36522SCy Schubert struct auth_zone* a = NULL; 170725039b37SCy Schubert struct rpz* r = NULL; 1708091e9e46SCy Schubert struct local_zone* z = NULL; 170924e36522SCy Schubert 1710091e9e46SCy Schubert lock_rw_rdlock(&az->rpz_lock); 171124e36522SCy Schubert 171225039b37SCy Schubert for(a = az->rpz_first; a; a = a->rpz_az_next) { 171325039b37SCy Schubert lock_rw_rdlock(&a->lock); 171425039b37SCy Schubert r = a->rpz; 171524e36522SCy Schubert if(r->disabled) { 171624e36522SCy Schubert lock_rw_unlock(&a->lock); 171724e36522SCy Schubert continue; 171824e36522SCy Schubert } 171924e36522SCy Schubert if(r->taglist && !taglist_intersect(r->taglist, 172024e36522SCy Schubert r->taglistlen, taglist, taglen)) { 172124e36522SCy Schubert lock_rw_unlock(&a->lock); 172224e36522SCy Schubert continue; 172324e36522SCy Schubert } 172424e36522SCy Schubert z = rpz_find_zone(r->local_zones, qinfo->qname, qinfo->qname_len, 1725091e9e46SCy Schubert qinfo->qclass, 0, 0, 0); 1726865f46b2SCy Schubert node = rpz_ipbased_trigger_lookup(r->client_set, 1727865f46b2SCy Schubert &repinfo->client_addr, repinfo->client_addrlen, 1728865f46b2SCy Schubert "clientip"); 172924e36522SCy Schubert if((z || node) && r->action_override == RPZ_DISABLED_ACTION) { 1730091e9e46SCy Schubert if(r->log) 173124e36522SCy Schubert log_rpz_apply((node?"clientip":"qname"), 173224e36522SCy Schubert (z?z->name:NULL), 173324e36522SCy Schubert (node?&node->node:NULL), 1734091e9e46SCy Schubert r->action_override, 173524e36522SCy Schubert qinfo, repinfo, NULL, r->log_name); 1736091e9e46SCy Schubert stats->rpz_action[r->action_override]++; 173724e36522SCy Schubert if(z != NULL) { 1738091e9e46SCy Schubert lock_rw_unlock(&z->lock); 1739091e9e46SCy Schubert z = NULL; 1740091e9e46SCy Schubert } 174124e36522SCy Schubert if(node != NULL) { 174224e36522SCy Schubert lock_rw_unlock(&node->lock); 174324e36522SCy Schubert node = NULL; 174424e36522SCy Schubert } 174524e36522SCy Schubert } 174624e36522SCy Schubert if(z || node) { 1747091e9e46SCy Schubert break; 1748091e9e46SCy Schubert } 174924e36522SCy Schubert /* not found in this auth_zone */ 175025039b37SCy Schubert lock_rw_unlock(&a->lock); 175124e36522SCy Schubert } 175224e36522SCy Schubert 175324e36522SCy Schubert lock_rw_unlock(&az->rpz_lock); 175424e36522SCy Schubert 175524e36522SCy Schubert *r_out = r; 175624e36522SCy Schubert *a_out = a; 175724e36522SCy Schubert *z_out = z; 175824e36522SCy Schubert 175924e36522SCy Schubert return node; 176024e36522SCy Schubert } 176124e36522SCy Schubert 176224e36522SCy Schubert static inline int 176324e36522SCy Schubert rpz_is_udp_query(struct comm_reply* repinfo) { 176424e36522SCy Schubert return repinfo != NULL 176524e36522SCy Schubert ? (repinfo->c != NULL 176624e36522SCy Schubert ? repinfo->c->type == comm_udp 176724e36522SCy Schubert : 0) 176824e36522SCy Schubert : 0; 176924e36522SCy Schubert } 177024e36522SCy Schubert 177124e36522SCy Schubert /** encode answer consisting of 1 rrset */ 177224e36522SCy Schubert static int 177324e36522SCy Schubert rpz_local_encode(struct module_env* env, struct query_info* qinfo, 177424e36522SCy Schubert struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf, 177524e36522SCy Schubert struct regional* temp, struct ub_packed_rrset_key* rrset, int ansec, 177624e36522SCy Schubert int rcode, struct ub_packed_rrset_key* soa_rrset) 177724e36522SCy Schubert { 177824e36522SCy Schubert struct reply_info rep; 177924e36522SCy Schubert uint16_t udpsize; 178024e36522SCy Schubert struct ub_packed_rrset_key* rrsetlist[3]; 178124e36522SCy Schubert 178224e36522SCy Schubert memset(&rep, 0, sizeof(rep)); 178324e36522SCy Schubert rep.flags = (uint16_t)((BIT_QR | BIT_AA | BIT_RA) | rcode); 178424e36522SCy Schubert rep.qdcount = 1; 178524e36522SCy Schubert rep.rrset_count = ansec; 178624e36522SCy Schubert rep.rrsets = rrsetlist; 178724e36522SCy Schubert if(ansec > 0) { 178824e36522SCy Schubert rep.an_numrrsets = 1; 178924e36522SCy Schubert rep.rrsets[0] = rrset; 179024e36522SCy Schubert rep.ttl = ((struct packed_rrset_data*)rrset->entry.data)->rr_ttl[0]; 179124e36522SCy Schubert } 179224e36522SCy Schubert if(soa_rrset != NULL) { 179324e36522SCy Schubert rep.ar_numrrsets = 1; 179424e36522SCy Schubert rep.rrsets[rep.rrset_count] = soa_rrset; 179524e36522SCy Schubert rep.rrset_count ++; 179624e36522SCy Schubert if(rep.ttl < ((struct packed_rrset_data*)soa_rrset->entry.data)->rr_ttl[0]) { 179724e36522SCy Schubert rep.ttl = ((struct packed_rrset_data*)soa_rrset->entry.data)->rr_ttl[0]; 179824e36522SCy Schubert } 179924e36522SCy Schubert } 180024e36522SCy Schubert 180124e36522SCy Schubert udpsize = edns->udp_size; 180224e36522SCy Schubert edns->edns_version = EDNS_ADVERTISED_VERSION; 180324e36522SCy Schubert edns->udp_size = EDNS_ADVERTISED_SIZE; 180424e36522SCy Schubert edns->ext_rcode = 0; 180524e36522SCy Schubert edns->bits &= EDNS_DO; 180624e36522SCy Schubert if(!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns, 180724e36522SCy Schubert repinfo, temp, env->now_tv) || 180824e36522SCy Schubert !reply_info_answer_encode(qinfo, &rep, 180924e36522SCy Schubert *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), 181024e36522SCy Schubert buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0)) { 181124e36522SCy Schubert error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo, 181224e36522SCy Schubert *(uint16_t*)sldns_buffer_begin(buf), 181324e36522SCy Schubert sldns_buffer_read_u16_at(buf, 2), edns); 181424e36522SCy Schubert } 181524e36522SCy Schubert 181624e36522SCy Schubert return 1; 181724e36522SCy Schubert } 181824e36522SCy Schubert 181924e36522SCy Schubert /** allocate SOA record ubrrsetkey in region */ 182024e36522SCy Schubert static struct ub_packed_rrset_key* 182124e36522SCy Schubert make_soa_ubrrset(struct auth_zone* auth_zone, struct auth_rrset* soa, 182224e36522SCy Schubert struct regional* temp) 182324e36522SCy Schubert { 182424e36522SCy Schubert struct ub_packed_rrset_key csoa; 182524e36522SCy Schubert if(!soa) 182624e36522SCy Schubert return NULL; 182724e36522SCy Schubert memset(&csoa, 0, sizeof(csoa)); 182824e36522SCy Schubert csoa.entry.key = &csoa; 182924e36522SCy Schubert csoa.rk.rrset_class = htons(LDNS_RR_CLASS_IN); 183024e36522SCy Schubert csoa.rk.type = htons(LDNS_RR_TYPE_SOA); 183124e36522SCy Schubert csoa.rk.flags |= PACKED_RRSET_FIXEDTTL 183224e36522SCy Schubert | PACKED_RRSET_RPZ; 183324e36522SCy Schubert csoa.rk.dname = auth_zone->name; 183424e36522SCy Schubert csoa.rk.dname_len = auth_zone->namelen; 183524e36522SCy Schubert csoa.entry.hash = rrset_key_hash(&csoa.rk); 183624e36522SCy Schubert csoa.entry.data = soa->data; 183724e36522SCy Schubert return respip_copy_rrset(&csoa, temp); 183824e36522SCy Schubert } 183924e36522SCy Schubert 184024e36522SCy Schubert static void 184124e36522SCy Schubert rpz_apply_clientip_localdata_action(struct clientip_synthesized_rr* raddr, 184224e36522SCy Schubert struct module_env* env, struct query_info* qinfo, 184324e36522SCy Schubert struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf, 184424e36522SCy Schubert struct regional* temp, struct auth_zone* auth_zone) 184524e36522SCy Schubert { 184624e36522SCy Schubert struct local_rrset* rrset; 184724e36522SCy Schubert enum rpz_action action = RPZ_INVALID_ACTION; 184824e36522SCy Schubert struct ub_packed_rrset_key* rp = NULL; 184924e36522SCy Schubert struct ub_packed_rrset_key* rsoa = NULL; 185024e36522SCy Schubert int rcode = LDNS_RCODE_NOERROR|BIT_AA; 185124e36522SCy Schubert int rrset_count = 1; 185224e36522SCy Schubert 185324e36522SCy Schubert /* prepare synthesized answer for client */ 185424e36522SCy Schubert action = raddr->action; 185524e36522SCy Schubert if(action == RPZ_LOCAL_DATA_ACTION && raddr->data == NULL ) { 185624e36522SCy Schubert verbose(VERB_ALGO, "rpz: bug: local-data action but no local data"); 185724e36522SCy Schubert return; 185824e36522SCy Schubert } 185924e36522SCy Schubert 186024e36522SCy Schubert /* check query type / rr type */ 1861335c7cdaSCy Schubert rrset = rpz_find_synthesized_rrset(qinfo->qtype, raddr, 1); 186224e36522SCy Schubert if(rrset == NULL) { 186324e36522SCy Schubert verbose(VERB_ALGO, "rpz: unable to find local-data for query"); 186424e36522SCy Schubert rrset_count = 0; 186524e36522SCy Schubert goto nodata; 186624e36522SCy Schubert } 186724e36522SCy Schubert 186824e36522SCy Schubert rp = respip_copy_rrset(rrset->rrset, temp); 186924e36522SCy Schubert if(!rp) { 187024e36522SCy Schubert verbose(VERB_ALGO, "rpz: local data action: out of memory"); 187124e36522SCy Schubert return; 187224e36522SCy Schubert } 187324e36522SCy Schubert 187424e36522SCy Schubert rp->rk.flags |= PACKED_RRSET_FIXEDTTL | PACKED_RRSET_RPZ; 187524e36522SCy Schubert rp->rk.dname = qinfo->qname; 187624e36522SCy Schubert rp->rk.dname_len = qinfo->qname_len; 187724e36522SCy Schubert rp->entry.hash = rrset_key_hash(&rp->rk); 187824e36522SCy Schubert nodata: 187924e36522SCy Schubert if(auth_zone) { 188024e36522SCy Schubert struct auth_rrset* soa = NULL; 188124e36522SCy Schubert soa = auth_zone_get_soa_rrset(auth_zone); 188224e36522SCy Schubert if(soa) { 188324e36522SCy Schubert rsoa = make_soa_ubrrset(auth_zone, soa, temp); 188424e36522SCy Schubert if(!rsoa) { 188524e36522SCy Schubert verbose(VERB_ALGO, "rpz: local data action soa: out of memory"); 188624e36522SCy Schubert return; 188724e36522SCy Schubert } 188824e36522SCy Schubert } 188924e36522SCy Schubert } 189024e36522SCy Schubert 189124e36522SCy Schubert rpz_local_encode(env, qinfo, edns, repinfo, buf, temp, rp, 189224e36522SCy Schubert rrset_count, rcode, rsoa); 189324e36522SCy Schubert } 189424e36522SCy Schubert 1895335c7cdaSCy Schubert /** Apply the cname override action, during worker request callback. 1896335c7cdaSCy Schubert * false on failure. */ 1897335c7cdaSCy Schubert static int 1898335c7cdaSCy Schubert rpz_apply_cname_override_action(struct rpz* r, 1899335c7cdaSCy Schubert struct query_info* qinfo, struct regional* temp) 1900335c7cdaSCy Schubert { 1901335c7cdaSCy Schubert if(!r) 1902335c7cdaSCy Schubert return 0; 1903335c7cdaSCy Schubert qinfo->local_alias = regional_alloc_zero(temp, 1904335c7cdaSCy Schubert sizeof(struct local_rrset)); 1905335c7cdaSCy Schubert if(qinfo->local_alias == NULL) 1906335c7cdaSCy Schubert return 0; /* out of memory */ 1907335c7cdaSCy Schubert qinfo->local_alias->rrset = respip_copy_rrset(r->cname_override, temp); 1908335c7cdaSCy Schubert if(qinfo->local_alias->rrset == NULL) { 1909335c7cdaSCy Schubert qinfo->local_alias = NULL; 1910335c7cdaSCy Schubert return 0; /* out of memory */ 1911335c7cdaSCy Schubert } 1912335c7cdaSCy Schubert qinfo->local_alias->rrset->rk.dname = qinfo->qname; 1913335c7cdaSCy Schubert qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len; 1914335c7cdaSCy Schubert return 1; 1915335c7cdaSCy Schubert } 1916335c7cdaSCy Schubert 191724e36522SCy Schubert /** add additional section SOA record to the reply. 191824e36522SCy Schubert * Since this gets fed into the normal iterator answer creation, it 191924e36522SCy Schubert * gets minimal-responses applied to it, that can remove the additional SOA 192024e36522SCy Schubert * again. */ 192124e36522SCy Schubert static int 192224e36522SCy Schubert rpz_add_soa(struct reply_info* rep, struct module_qstate* ms, 192324e36522SCy Schubert struct auth_zone* az) 192424e36522SCy Schubert { 192524e36522SCy Schubert struct auth_rrset* soa = NULL; 192624e36522SCy Schubert struct ub_packed_rrset_key* rsoa = NULL; 192724e36522SCy Schubert struct ub_packed_rrset_key** prevrrsets; 192824e36522SCy Schubert if(!az) return 1; 192924e36522SCy Schubert soa = auth_zone_get_soa_rrset(az); 193024e36522SCy Schubert if(!soa) return 1; 193124e36522SCy Schubert if(!rep) return 0; 193224e36522SCy Schubert rsoa = make_soa_ubrrset(az, soa, ms->region); 193324e36522SCy Schubert if(!rsoa) return 0; 193424e36522SCy Schubert prevrrsets = rep->rrsets; 193524e36522SCy Schubert rep->rrsets = regional_alloc_zero(ms->region, 193624e36522SCy Schubert sizeof(*rep->rrsets)*(rep->rrset_count+1)); 193724e36522SCy Schubert if(!rep->rrsets) 193824e36522SCy Schubert return 0; 193924e36522SCy Schubert if(prevrrsets && rep->rrset_count > 0) 194024e36522SCy Schubert memcpy(rep->rrsets, prevrrsets, rep->rrset_count*sizeof(*rep->rrsets)); 194124e36522SCy Schubert rep->rrset_count++; 194224e36522SCy Schubert rep->ar_numrrsets++; 194324e36522SCy Schubert rep->rrsets[rep->rrset_count-1] = rsoa; 194424e36522SCy Schubert return 1; 194524e36522SCy Schubert } 194624e36522SCy Schubert 194724e36522SCy Schubert static inline struct dns_msg* 194824e36522SCy Schubert rpz_dns_msg_new(struct regional* region) 194924e36522SCy Schubert { 195024e36522SCy Schubert struct dns_msg* msg = 195124e36522SCy Schubert (struct dns_msg*)regional_alloc(region, 195224e36522SCy Schubert sizeof(struct dns_msg)); 195324e36522SCy Schubert if(msg == NULL) { return NULL; } 195424e36522SCy Schubert memset(msg, 0, sizeof(struct dns_msg)); 195524e36522SCy Schubert 195624e36522SCy Schubert return msg; 195724e36522SCy Schubert } 195824e36522SCy Schubert 195924e36522SCy Schubert static inline struct dns_msg* 196024e36522SCy Schubert rpz_synthesize_nodata(struct rpz* ATTR_UNUSED(r), struct module_qstate* ms, 196124e36522SCy Schubert struct query_info* qinfo, struct auth_zone* az) 196224e36522SCy Schubert { 196324e36522SCy Schubert struct dns_msg* msg = rpz_dns_msg_new(ms->region); 196424e36522SCy Schubert if(msg == NULL) { return msg; } 196524e36522SCy Schubert msg->qinfo = *qinfo; 196624e36522SCy Schubert msg->rep = construct_reply_info_base(ms->region, 19679cf5bc93SCy Schubert LDNS_RCODE_NOERROR | BIT_QR | BIT_AA | BIT_RA, 196824e36522SCy Schubert 1, /* qd */ 196924e36522SCy Schubert 0, /* ttl */ 197024e36522SCy Schubert 0, /* prettl */ 197124e36522SCy Schubert 0, /* expttl */ 1972*46d2f618SCy Schubert 0, /* norecttl */ 197324e36522SCy Schubert 0, /* an */ 197424e36522SCy Schubert 0, /* ns */ 197524e36522SCy Schubert 0, /* ar */ 197624e36522SCy Schubert 0, /* total */ 19778f76bb7dSCy Schubert sec_status_insecure, 19788f76bb7dSCy Schubert LDNS_EDE_NONE); 197924e36522SCy Schubert if(msg->rep) 198024e36522SCy Schubert msg->rep->authoritative = 1; 198124e36522SCy Schubert if(!rpz_add_soa(msg->rep, ms, az)) 198224e36522SCy Schubert return NULL; 198324e36522SCy Schubert return msg; 198424e36522SCy Schubert } 198524e36522SCy Schubert 198624e36522SCy Schubert static inline struct dns_msg* 19879cf5bc93SCy Schubert rpz_synthesize_nxdomain(struct rpz* r, struct module_qstate* ms, 198824e36522SCy Schubert struct query_info* qinfo, struct auth_zone* az) 198924e36522SCy Schubert { 199024e36522SCy Schubert struct dns_msg* msg = rpz_dns_msg_new(ms->region); 19919cf5bc93SCy Schubert uint16_t flags; 199224e36522SCy Schubert if(msg == NULL) { return msg; } 199324e36522SCy Schubert msg->qinfo = *qinfo; 19949cf5bc93SCy Schubert flags = LDNS_RCODE_NXDOMAIN | BIT_QR | BIT_AA | BIT_RA; 19959cf5bc93SCy Schubert if(r->signal_nxdomain_ra) 19969cf5bc93SCy Schubert flags &= ~BIT_RA; 199724e36522SCy Schubert msg->rep = construct_reply_info_base(ms->region, 19989cf5bc93SCy Schubert flags, 199924e36522SCy Schubert 1, /* qd */ 200024e36522SCy Schubert 0, /* ttl */ 200124e36522SCy Schubert 0, /* prettl */ 200224e36522SCy Schubert 0, /* expttl */ 2003*46d2f618SCy Schubert 0, /* norecttl */ 200424e36522SCy Schubert 0, /* an */ 200524e36522SCy Schubert 0, /* ns */ 200624e36522SCy Schubert 0, /* ar */ 200724e36522SCy Schubert 0, /* total */ 20088f76bb7dSCy Schubert sec_status_insecure, 20098f76bb7dSCy Schubert LDNS_EDE_NONE); 201024e36522SCy Schubert if(msg->rep) 201124e36522SCy Schubert msg->rep->authoritative = 1; 201224e36522SCy Schubert if(!rpz_add_soa(msg->rep, ms, az)) 201324e36522SCy Schubert return NULL; 201424e36522SCy Schubert return msg; 201524e36522SCy Schubert } 201624e36522SCy Schubert 201724e36522SCy Schubert static inline struct dns_msg* 201824e36522SCy Schubert rpz_synthesize_localdata_from_rrset(struct rpz* ATTR_UNUSED(r), struct module_qstate* ms, 201924e36522SCy Schubert struct query_info* qi, struct local_rrset* rrset, struct auth_zone* az) 202024e36522SCy Schubert { 202124e36522SCy Schubert struct dns_msg* msg = NULL; 202224e36522SCy Schubert struct reply_info* new_reply_info; 202324e36522SCy Schubert struct ub_packed_rrset_key* rp; 202424e36522SCy Schubert 202524e36522SCy Schubert 202624e36522SCy Schubert msg = rpz_dns_msg_new(ms->region); 202724e36522SCy Schubert if(msg == NULL) { return NULL; } 202824e36522SCy Schubert 2029335c7cdaSCy Schubert msg->qinfo = *qi; 203024e36522SCy Schubert new_reply_info = construct_reply_info_base(ms->region, 20319cf5bc93SCy Schubert LDNS_RCODE_NOERROR | BIT_QR | BIT_AA | BIT_RA, 203224e36522SCy Schubert 1, /* qd */ 203324e36522SCy Schubert 0, /* ttl */ 203424e36522SCy Schubert 0, /* prettl */ 203524e36522SCy Schubert 0, /* expttl */ 2036*46d2f618SCy Schubert 0, /* norecttl */ 203724e36522SCy Schubert 1, /* an */ 203824e36522SCy Schubert 0, /* ns */ 203924e36522SCy Schubert 0, /* ar */ 204024e36522SCy Schubert 1, /* total */ 20418f76bb7dSCy Schubert sec_status_insecure, 20428f76bb7dSCy Schubert LDNS_EDE_NONE); 204324e36522SCy Schubert if(new_reply_info == NULL) { 204424e36522SCy Schubert log_err("out of memory"); 204524e36522SCy Schubert return NULL; 204624e36522SCy Schubert } 204724e36522SCy Schubert new_reply_info->authoritative = 1; 204824e36522SCy Schubert rp = respip_copy_rrset(rrset->rrset, ms->region); 204924e36522SCy Schubert if(rp == NULL) { 205024e36522SCy Schubert log_err("out of memory"); 205124e36522SCy Schubert return NULL; 205224e36522SCy Schubert } 205324e36522SCy Schubert rp->rk.dname = qi->qname; 205424e36522SCy Schubert rp->rk.dname_len = qi->qname_len; 205524e36522SCy Schubert /* this rrset is from the rpz data, or synthesized. 205624e36522SCy Schubert * It is not actually from the network, so we flag it with this 205724e36522SCy Schubert * flags as a fake RRset. If later the cache is used to look up 205824e36522SCy Schubert * rrsets, then the fake ones are not returned (if you look without 205924e36522SCy Schubert * the flag). For like CNAME lookups from the iterator or A, AAAA 206024e36522SCy Schubert * lookups for nameserver targets, it would use the without flag 206124e36522SCy Schubert * actual data. So that the actual network data and fake data 206224e36522SCy Schubert * are kept track of separately. */ 206324e36522SCy Schubert rp->rk.flags |= PACKED_RRSET_RPZ; 206424e36522SCy Schubert new_reply_info->rrsets[0] = rp; 206524e36522SCy Schubert msg->rep = new_reply_info; 206624e36522SCy Schubert if(!rpz_add_soa(msg->rep, ms, az)) 206724e36522SCy Schubert return NULL; 206824e36522SCy Schubert return msg; 206924e36522SCy Schubert } 207024e36522SCy Schubert 207124e36522SCy Schubert static inline struct dns_msg* 207224e36522SCy Schubert rpz_synthesize_nsip_localdata(struct rpz* r, struct module_qstate* ms, 2073335c7cdaSCy Schubert struct query_info* qi, struct clientip_synthesized_rr* data, 2074335c7cdaSCy Schubert struct auth_zone* az) 207524e36522SCy Schubert { 207624e36522SCy Schubert struct local_rrset* rrset; 207724e36522SCy Schubert 2078335c7cdaSCy Schubert rrset = rpz_find_synthesized_rrset(qi->qtype, data, 1); 207924e36522SCy Schubert if(rrset == NULL) { 208024e36522SCy Schubert verbose(VERB_ALGO, "rpz: nsip: no matching local data found"); 208124e36522SCy Schubert return NULL; 208224e36522SCy Schubert } 208324e36522SCy Schubert 2084335c7cdaSCy Schubert return rpz_synthesize_localdata_from_rrset(r, ms, qi, rrset, az); 208524e36522SCy Schubert } 208624e36522SCy Schubert 208724e36522SCy Schubert /* copy'n'paste from localzone.c */ 208824e36522SCy Schubert static struct local_rrset* 208924e36522SCy Schubert local_data_find_type(struct local_data* data, uint16_t type, int alias_ok) 209024e36522SCy Schubert { 2091335c7cdaSCy Schubert struct local_rrset* p, *cname = NULL; 209224e36522SCy Schubert type = htons(type); 209324e36522SCy Schubert for(p = data->rrsets; p; p = p->next) { 209424e36522SCy Schubert if(p->rrset->rk.type == type) 209524e36522SCy Schubert return p; 209624e36522SCy Schubert if(alias_ok && p->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME)) 2097335c7cdaSCy Schubert cname = p; 209824e36522SCy Schubert } 2099335c7cdaSCy Schubert if(alias_ok) 2100335c7cdaSCy Schubert return cname; 210124e36522SCy Schubert return NULL; 210224e36522SCy Schubert } 210324e36522SCy Schubert 210424e36522SCy Schubert /* based on localzone.c:local_data_answer() */ 210524e36522SCy Schubert static inline struct dns_msg* 210624e36522SCy Schubert rpz_synthesize_nsdname_localdata(struct rpz* r, struct module_qstate* ms, 2107335c7cdaSCy Schubert struct query_info* qi, struct local_zone* z, 2108335c7cdaSCy Schubert struct matched_delegation_point const* match, struct auth_zone* az) 210924e36522SCy Schubert { 211024e36522SCy Schubert struct local_data key; 211124e36522SCy Schubert struct local_data* ld; 211224e36522SCy Schubert struct local_rrset* rrset; 211324e36522SCy Schubert 211424e36522SCy Schubert if(match->dname == NULL) { return NULL; } 211524e36522SCy Schubert 211624e36522SCy Schubert key.node.key = &key; 211724e36522SCy Schubert key.name = match->dname; 211824e36522SCy Schubert key.namelen = match->dname_len; 211924e36522SCy Schubert key.namelabs = dname_count_labels(match->dname); 212024e36522SCy Schubert 212124e36522SCy Schubert rpz_log_dname("nsdname local data", key.name, key.namelen); 212224e36522SCy Schubert 212324e36522SCy Schubert ld = (struct local_data*)rbtree_search(&z->data, &key.node); 212424e36522SCy Schubert if(ld == NULL) { 212524e36522SCy Schubert verbose(VERB_ALGO, "rpz: nsdname: impossible: qname not found"); 212624e36522SCy Schubert return NULL; 212724e36522SCy Schubert } 212824e36522SCy Schubert 2129335c7cdaSCy Schubert rrset = local_data_find_type(ld, qi->qtype, 1); 213024e36522SCy Schubert if(rrset == NULL) { 213124e36522SCy Schubert verbose(VERB_ALGO, "rpz: nsdname: no matching local data found"); 213224e36522SCy Schubert return NULL; 213324e36522SCy Schubert } 213424e36522SCy Schubert 2135335c7cdaSCy Schubert return rpz_synthesize_localdata_from_rrset(r, ms, qi, rrset, az); 213624e36522SCy Schubert } 213724e36522SCy Schubert 213824e36522SCy Schubert /* like local_data_answer for qname triggers after a cname */ 213924e36522SCy Schubert static struct dns_msg* 214024e36522SCy Schubert rpz_synthesize_qname_localdata_msg(struct rpz* r, struct module_qstate* ms, 214124e36522SCy Schubert struct query_info* qinfo, struct local_zone* z, struct auth_zone* az) 214224e36522SCy Schubert { 214324e36522SCy Schubert struct local_data key; 214424e36522SCy Schubert struct local_data* ld; 214524e36522SCy Schubert struct local_rrset* rrset; 214624e36522SCy Schubert key.node.key = &key; 214724e36522SCy Schubert key.name = qinfo->qname; 214824e36522SCy Schubert key.namelen = qinfo->qname_len; 214924e36522SCy Schubert key.namelabs = dname_count_labels(qinfo->qname); 215024e36522SCy Schubert ld = (struct local_data*)rbtree_search(&z->data, &key.node); 215124e36522SCy Schubert if(ld == NULL) { 2152335c7cdaSCy Schubert verbose(VERB_ALGO, "rpz: qname: name not found"); 215324e36522SCy Schubert return NULL; 215424e36522SCy Schubert } 215524e36522SCy Schubert rrset = local_data_find_type(ld, qinfo->qtype, 1); 215624e36522SCy Schubert if(rrset == NULL) { 2157335c7cdaSCy Schubert verbose(VERB_ALGO, "rpz: qname: type not found"); 215824e36522SCy Schubert return NULL; 215924e36522SCy Schubert } 216024e36522SCy Schubert return rpz_synthesize_localdata_from_rrset(r, ms, qinfo, rrset, az); 216124e36522SCy Schubert } 216224e36522SCy Schubert 2163335c7cdaSCy Schubert /** Synthesize a CNAME message for RPZ action override */ 2164335c7cdaSCy Schubert static struct dns_msg* 2165335c7cdaSCy Schubert rpz_synthesize_cname_override_msg(struct rpz* r, struct module_qstate* ms, 2166335c7cdaSCy Schubert struct query_info* qinfo) 2167335c7cdaSCy Schubert { 2168335c7cdaSCy Schubert struct dns_msg* msg = NULL; 2169335c7cdaSCy Schubert struct reply_info* new_reply_info; 2170335c7cdaSCy Schubert struct ub_packed_rrset_key* rp; 2171335c7cdaSCy Schubert 2172335c7cdaSCy Schubert msg = rpz_dns_msg_new(ms->region); 2173335c7cdaSCy Schubert if(msg == NULL) { return NULL; } 2174335c7cdaSCy Schubert 2175335c7cdaSCy Schubert msg->qinfo = *qinfo; 2176335c7cdaSCy Schubert new_reply_info = construct_reply_info_base(ms->region, 2177335c7cdaSCy Schubert LDNS_RCODE_NOERROR | BIT_QR | BIT_AA | BIT_RA, 2178335c7cdaSCy Schubert 1, /* qd */ 2179335c7cdaSCy Schubert 0, /* ttl */ 2180335c7cdaSCy Schubert 0, /* prettl */ 2181335c7cdaSCy Schubert 0, /* expttl */ 2182*46d2f618SCy Schubert 0, /* norecttl */ 2183335c7cdaSCy Schubert 1, /* an */ 2184335c7cdaSCy Schubert 0, /* ns */ 2185335c7cdaSCy Schubert 0, /* ar */ 2186335c7cdaSCy Schubert 1, /* total */ 2187335c7cdaSCy Schubert sec_status_insecure, 2188335c7cdaSCy Schubert LDNS_EDE_NONE); 2189335c7cdaSCy Schubert if(new_reply_info == NULL) { 2190335c7cdaSCy Schubert log_err("out of memory"); 2191335c7cdaSCy Schubert return NULL; 2192335c7cdaSCy Schubert } 2193335c7cdaSCy Schubert new_reply_info->authoritative = 1; 2194335c7cdaSCy Schubert 2195335c7cdaSCy Schubert rp = respip_copy_rrset(r->cname_override, ms->region); 2196335c7cdaSCy Schubert if(rp == NULL) { 2197335c7cdaSCy Schubert log_err("out of memory"); 2198335c7cdaSCy Schubert return NULL; 2199335c7cdaSCy Schubert } 2200335c7cdaSCy Schubert rp->rk.dname = qinfo->qname; 2201335c7cdaSCy Schubert rp->rk.dname_len = qinfo->qname_len; 2202335c7cdaSCy Schubert /* this rrset is from the rpz data, or synthesized. 2203335c7cdaSCy Schubert * It is not actually from the network, so we flag it with this 2204335c7cdaSCy Schubert * flags as a fake RRset. If later the cache is used to look up 2205335c7cdaSCy Schubert * rrsets, then the fake ones are not returned (if you look without 2206335c7cdaSCy Schubert * the flag). For like CNAME lookups from the iterator or A, AAAA 2207335c7cdaSCy Schubert * lookups for nameserver targets, it would use the without flag 2208335c7cdaSCy Schubert * actual data. So that the actual network data and fake data 2209335c7cdaSCy Schubert * are kept track of separately. */ 2210335c7cdaSCy Schubert rp->rk.flags |= PACKED_RRSET_RPZ; 2211335c7cdaSCy Schubert new_reply_info->rrsets[0] = rp; 2212335c7cdaSCy Schubert 2213335c7cdaSCy Schubert msg->rep = new_reply_info; 2214335c7cdaSCy Schubert return msg; 2215335c7cdaSCy Schubert } 2216335c7cdaSCy Schubert 221724e36522SCy Schubert static int 221824e36522SCy Schubert rpz_synthesize_qname_localdata(struct module_env* env, struct rpz* r, 221924e36522SCy Schubert struct local_zone* z, enum localzone_type lzt, struct query_info* qinfo, 222024e36522SCy Schubert struct edns_data* edns, sldns_buffer* buf, struct regional* temp, 222124e36522SCy Schubert struct comm_reply* repinfo, struct ub_server_stats* stats) 222224e36522SCy Schubert { 222324e36522SCy Schubert struct local_data* ld = NULL; 222424e36522SCy Schubert int ret = 0; 222524e36522SCy Schubert if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) { 2226335c7cdaSCy Schubert if(!rpz_apply_cname_override_action(r, qinfo, temp)) 2227335c7cdaSCy Schubert return 0; 222824e36522SCy Schubert if(r->log) { 222924e36522SCy Schubert log_rpz_apply("qname", z->name, NULL, RPZ_CNAME_OVERRIDE_ACTION, 223024e36522SCy Schubert qinfo, repinfo, NULL, r->log_name); 223124e36522SCy Schubert } 2232091e9e46SCy Schubert stats->rpz_action[RPZ_CNAME_OVERRIDE_ACTION]++; 2233091e9e46SCy Schubert return 0; 2234091e9e46SCy Schubert } 2235091e9e46SCy Schubert 2236091e9e46SCy Schubert if(lzt == local_zone_redirect && local_data_answer(z, env, qinfo, 2237091e9e46SCy Schubert edns, repinfo, buf, temp, dname_count_labels(qinfo->qname), 2238091e9e46SCy Schubert &ld, lzt, -1, NULL, 0, NULL, 0)) { 223924e36522SCy Schubert if(r->log) { 224024e36522SCy Schubert log_rpz_apply("qname", z->name, NULL, 2241091e9e46SCy Schubert localzone_type_to_rpz_action(lzt), qinfo, 224224e36522SCy Schubert repinfo, NULL, r->log_name); 224324e36522SCy Schubert } 2244091e9e46SCy Schubert stats->rpz_action[localzone_type_to_rpz_action(lzt)]++; 2245091e9e46SCy Schubert return !qinfo->local_alias; 2246091e9e46SCy Schubert } 2247091e9e46SCy Schubert 2248091e9e46SCy Schubert ret = local_zones_zone_answer(z, env, qinfo, edns, repinfo, buf, temp, 2249091e9e46SCy Schubert 0 /* no local data used */, lzt); 22509cf5bc93SCy Schubert if(r->signal_nxdomain_ra && LDNS_RCODE_WIRE(sldns_buffer_begin(buf)) 22519cf5bc93SCy Schubert == LDNS_RCODE_NXDOMAIN) 22529cf5bc93SCy Schubert LDNS_RA_CLR(sldns_buffer_begin(buf)); 225324e36522SCy Schubert if(r->log) { 225424e36522SCy Schubert log_rpz_apply("qname", z->name, NULL, localzone_type_to_rpz_action(lzt), 225524e36522SCy Schubert qinfo, repinfo, NULL, r->log_name); 225624e36522SCy Schubert } 2257091e9e46SCy Schubert stats->rpz_action[localzone_type_to_rpz_action(lzt)]++; 225824e36522SCy Schubert return ret; 225924e36522SCy Schubert } 226024e36522SCy Schubert 22619cf5bc93SCy Schubert static struct clientip_synthesized_rr* 226224e36522SCy Schubert rpz_delegation_point_ipbased_trigger_lookup(struct rpz* rpz, struct iter_qstate* is) 226324e36522SCy Schubert { 226424e36522SCy Schubert struct delegpt_addr* cursor; 226524e36522SCy Schubert struct clientip_synthesized_rr* action = NULL; 226624e36522SCy Schubert if(is->dp == NULL) { return NULL; } 226724e36522SCy Schubert for(cursor = is->dp->target_list; 226824e36522SCy Schubert cursor != NULL; 226924e36522SCy Schubert cursor = cursor->next_target) { 227024e36522SCy Schubert if(cursor->bogus) { continue; } 227124e36522SCy Schubert action = rpz_ipbased_trigger_lookup(rpz->ns_set, &cursor->addr, 227224e36522SCy Schubert cursor->addrlen, "nsip"); 227324e36522SCy Schubert if(action != NULL) { return action; } 227424e36522SCy Schubert } 227524e36522SCy Schubert return NULL; 227624e36522SCy Schubert } 227724e36522SCy Schubert 22789cf5bc93SCy Schubert static struct dns_msg* 2279335c7cdaSCy Schubert rpz_apply_nsip_trigger(struct module_qstate* ms, struct query_info* qchase, 2280335c7cdaSCy Schubert struct rpz* r, struct clientip_synthesized_rr* raddr, 2281335c7cdaSCy Schubert struct auth_zone* az) 228224e36522SCy Schubert { 228324e36522SCy Schubert enum rpz_action action = raddr->action; 228424e36522SCy Schubert struct dns_msg* ret = NULL; 228524e36522SCy Schubert 228624e36522SCy Schubert if(r->action_override != RPZ_NO_OVERRIDE_ACTION) { 228724e36522SCy Schubert verbose(VERB_ALGO, "rpz: using override action=%s (replaces=%s)", 228824e36522SCy Schubert rpz_action_to_string(r->action_override), rpz_action_to_string(action)); 228924e36522SCy Schubert action = r->action_override; 229024e36522SCy Schubert } 229124e36522SCy Schubert 229224e36522SCy Schubert if(action == RPZ_LOCAL_DATA_ACTION && raddr->data == NULL) { 229324e36522SCy Schubert verbose(VERB_ALGO, "rpz: bug: nsip local data action but no local data"); 2294335c7cdaSCy Schubert ret = rpz_synthesize_nodata(r, ms, qchase, az); 2295*46d2f618SCy Schubert ms->rpz_applied = 1; 229624e36522SCy Schubert goto done; 229724e36522SCy Schubert } 229824e36522SCy Schubert 229924e36522SCy Schubert switch(action) { 230024e36522SCy Schubert case RPZ_NXDOMAIN_ACTION: 2301335c7cdaSCy Schubert ret = rpz_synthesize_nxdomain(r, ms, qchase, az); 2302*46d2f618SCy Schubert ms->rpz_applied = 1; 230324e36522SCy Schubert break; 230424e36522SCy Schubert case RPZ_NODATA_ACTION: 2305335c7cdaSCy Schubert ret = rpz_synthesize_nodata(r, ms, qchase, az); 2306*46d2f618SCy Schubert ms->rpz_applied = 1; 230724e36522SCy Schubert break; 230824e36522SCy Schubert case RPZ_TCP_ONLY_ACTION: 230924e36522SCy Schubert /* basically a passthru here but the tcp-only will be 231024e36522SCy Schubert * honored before the query gets sent. */ 2311103ba509SCy Schubert ms->tcp_required = 1; 231224e36522SCy Schubert ret = NULL; 231324e36522SCy Schubert break; 231424e36522SCy Schubert case RPZ_DROP_ACTION: 2315335c7cdaSCy Schubert ret = rpz_synthesize_nodata(r, ms, qchase, az); 2316*46d2f618SCy Schubert ms->rpz_applied = 1; 231724e36522SCy Schubert ms->is_drop = 1; 231824e36522SCy Schubert break; 231924e36522SCy Schubert case RPZ_LOCAL_DATA_ACTION: 2320335c7cdaSCy Schubert ret = rpz_synthesize_nsip_localdata(r, ms, qchase, raddr, az); 2321335c7cdaSCy Schubert if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, qchase, az); } 2322*46d2f618SCy Schubert ms->rpz_applied = 1; 232324e36522SCy Schubert break; 232424e36522SCy Schubert case RPZ_PASSTHRU_ACTION: 232524e36522SCy Schubert ret = NULL; 2326a39a5a69SCy Schubert ms->rpz_passthru = 1; 232724e36522SCy Schubert break; 2328335c7cdaSCy Schubert case RPZ_CNAME_OVERRIDE_ACTION: 2329335c7cdaSCy Schubert ret = rpz_synthesize_cname_override_msg(r, ms, qchase); 2330*46d2f618SCy Schubert ms->rpz_applied = 1; 2331335c7cdaSCy Schubert break; 233224e36522SCy Schubert default: 233324e36522SCy Schubert verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'", 233424e36522SCy Schubert rpz_action_to_string(action)); 233524e36522SCy Schubert ret = NULL; 233624e36522SCy Schubert } 233724e36522SCy Schubert 233824e36522SCy Schubert done: 233924e36522SCy Schubert if(r->log) 234024e36522SCy Schubert log_rpz_apply("nsip", NULL, &raddr->node, 234124e36522SCy Schubert action, &ms->qinfo, NULL, ms, r->log_name); 234224e36522SCy Schubert if(ms->env->worker) 234324e36522SCy Schubert ms->env->worker->stats.rpz_action[action]++; 234424e36522SCy Schubert lock_rw_unlock(&raddr->lock); 234524e36522SCy Schubert return ret; 234624e36522SCy Schubert } 234724e36522SCy Schubert 23489cf5bc93SCy Schubert static struct dns_msg* 2349335c7cdaSCy Schubert rpz_apply_nsdname_trigger(struct module_qstate* ms, struct query_info* qchase, 2350335c7cdaSCy Schubert struct rpz* r, struct local_zone* z, 2351335c7cdaSCy Schubert struct matched_delegation_point const* match, struct auth_zone* az) 235224e36522SCy Schubert { 235324e36522SCy Schubert struct dns_msg* ret = NULL; 235424e36522SCy Schubert enum rpz_action action = localzone_type_to_rpz_action(z->type); 235524e36522SCy Schubert 235624e36522SCy Schubert if(r->action_override != RPZ_NO_OVERRIDE_ACTION) { 235724e36522SCy Schubert verbose(VERB_ALGO, "rpz: using override action=%s (replaces=%s)", 235824e36522SCy Schubert rpz_action_to_string(r->action_override), rpz_action_to_string(action)); 235924e36522SCy Schubert action = r->action_override; 236024e36522SCy Schubert } 236124e36522SCy Schubert 236224e36522SCy Schubert switch(action) { 236324e36522SCy Schubert case RPZ_NXDOMAIN_ACTION: 2364335c7cdaSCy Schubert ret = rpz_synthesize_nxdomain(r, ms, qchase, az); 2365*46d2f618SCy Schubert ms->rpz_applied = 1; 236624e36522SCy Schubert break; 236724e36522SCy Schubert case RPZ_NODATA_ACTION: 2368335c7cdaSCy Schubert ret = rpz_synthesize_nodata(r, ms, qchase, az); 2369*46d2f618SCy Schubert ms->rpz_applied = 1; 237024e36522SCy Schubert break; 237124e36522SCy Schubert case RPZ_TCP_ONLY_ACTION: 237224e36522SCy Schubert /* basically a passthru here but the tcp-only will be 237324e36522SCy Schubert * honored before the query gets sent. */ 2374103ba509SCy Schubert ms->tcp_required = 1; 237524e36522SCy Schubert ret = NULL; 237624e36522SCy Schubert break; 237724e36522SCy Schubert case RPZ_DROP_ACTION: 2378335c7cdaSCy Schubert ret = rpz_synthesize_nodata(r, ms, qchase, az); 2379*46d2f618SCy Schubert ms->rpz_applied = 1; 238024e36522SCy Schubert ms->is_drop = 1; 238124e36522SCy Schubert break; 238224e36522SCy Schubert case RPZ_LOCAL_DATA_ACTION: 2383335c7cdaSCy Schubert ret = rpz_synthesize_nsdname_localdata(r, ms, qchase, z, match, az); 2384335c7cdaSCy Schubert if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, qchase, az); } 2385*46d2f618SCy Schubert ms->rpz_applied = 1; 238624e36522SCy Schubert break; 238724e36522SCy Schubert case RPZ_PASSTHRU_ACTION: 238824e36522SCy Schubert ret = NULL; 2389a39a5a69SCy Schubert ms->rpz_passthru = 1; 239024e36522SCy Schubert break; 2391335c7cdaSCy Schubert case RPZ_CNAME_OVERRIDE_ACTION: 2392335c7cdaSCy Schubert ret = rpz_synthesize_cname_override_msg(r, ms, qchase); 2393*46d2f618SCy Schubert ms->rpz_applied = 1; 2394335c7cdaSCy Schubert break; 239524e36522SCy Schubert default: 2396335c7cdaSCy Schubert verbose(VERB_ALGO, "rpz: nsdname: bug: unhandled or invalid action: '%s'", 239724e36522SCy Schubert rpz_action_to_string(action)); 239824e36522SCy Schubert ret = NULL; 239924e36522SCy Schubert } 240024e36522SCy Schubert 240124e36522SCy Schubert if(r->log) 240224e36522SCy Schubert log_rpz_apply("nsdname", match->dname, NULL, 240324e36522SCy Schubert action, &ms->qinfo, NULL, ms, r->log_name); 240424e36522SCy Schubert if(ms->env->worker) 240524e36522SCy Schubert ms->env->worker->stats.rpz_action[action]++; 240624e36522SCy Schubert lock_rw_unlock(&z->lock); 240724e36522SCy Schubert return ret; 240824e36522SCy Schubert } 240924e36522SCy Schubert 241024e36522SCy Schubert static struct local_zone* 241124e36522SCy Schubert rpz_delegation_point_zone_lookup(struct delegpt* dp, struct local_zones* zones, 241224e36522SCy Schubert uint16_t qclass, 241324e36522SCy Schubert /* output parameter */ 241424e36522SCy Schubert struct matched_delegation_point* match) 241524e36522SCy Schubert { 241624e36522SCy Schubert struct delegpt_ns* nameserver; 241724e36522SCy Schubert struct local_zone* z = NULL; 241824e36522SCy Schubert 241924e36522SCy Schubert /* the rpz specs match the nameserver names (NS records), not the 242024e36522SCy Schubert * name of the delegation point itself, to the nsdname triggers */ 242124e36522SCy Schubert for(nameserver = dp->nslist; 242224e36522SCy Schubert nameserver != NULL; 242324e36522SCy Schubert nameserver = nameserver->next) { 242424e36522SCy Schubert z = rpz_find_zone(zones, nameserver->name, nameserver->namelen, 242524e36522SCy Schubert qclass, 0, 0, 0); 242624e36522SCy Schubert if(z != NULL) { 242724e36522SCy Schubert match->dname = nameserver->name; 242824e36522SCy Schubert match->dname_len = nameserver->namelen; 242924e36522SCy Schubert if(verbosity >= VERB_ALGO) { 243024e36522SCy Schubert char nm[255+1], zn[255+1]; 243124e36522SCy Schubert dname_str(match->dname, nm); 243224e36522SCy Schubert dname_str(z->name, zn); 243324e36522SCy Schubert if(strcmp(nm, zn) != 0) 243424e36522SCy Schubert verbose(VERB_ALGO, "rpz: trigger nsdname %s on %s action=%s", 243524e36522SCy Schubert zn, nm, rpz_action_to_string(localzone_type_to_rpz_action(z->type))); 243624e36522SCy Schubert else 243724e36522SCy Schubert verbose(VERB_ALGO, "rpz: trigger nsdname %s action=%s", 243824e36522SCy Schubert nm, rpz_action_to_string(localzone_type_to_rpz_action(z->type))); 243924e36522SCy Schubert } 244024e36522SCy Schubert break; 244124e36522SCy Schubert } 244224e36522SCy Schubert } 244324e36522SCy Schubert 244424e36522SCy Schubert return z; 244524e36522SCy Schubert } 244624e36522SCy Schubert 244724e36522SCy Schubert struct dns_msg* 244824e36522SCy Schubert rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate* is) 244924e36522SCy Schubert { 245024e36522SCy Schubert struct auth_zones* az; 245124e36522SCy Schubert struct auth_zone* a; 245224e36522SCy Schubert struct clientip_synthesized_rr* raddr = NULL; 245324e36522SCy Schubert struct rpz* r = NULL; 245424e36522SCy Schubert struct local_zone* z = NULL; 245524e36522SCy Schubert struct matched_delegation_point match = {0}; 245624e36522SCy Schubert 2457a39a5a69SCy Schubert if(ms->rpz_passthru) { 2458a39a5a69SCy Schubert verbose(VERB_ALGO, "query is rpz_passthru, no further processing"); 2459a39a5a69SCy Schubert return NULL; 2460a39a5a69SCy Schubert } 2461a39a5a69SCy Schubert 246224e36522SCy Schubert if(ms->env == NULL || ms->env->auth_zones == NULL) { return 0; } 246324e36522SCy Schubert 246424e36522SCy Schubert az = ms->env->auth_zones; 246556850988SCy Schubert lock_rw_rdlock(&az->rpz_lock); 246624e36522SCy Schubert 246724e36522SCy Schubert verbose(VERB_ALGO, "rpz: iterator module callback: have_rpz=%d", az->rpz_first != NULL); 246824e36522SCy Schubert 246924e36522SCy Schubert /* precedence of RPZ works, loosely, like this: 247024e36522SCy Schubert * CNAMEs in order of the CNAME chain. rpzs in the order they are 247124e36522SCy Schubert * configured. In an RPZ: first client-IP addr, then QNAME, then 247224e36522SCy Schubert * response IP, then NSDNAME, then NSIP. Longest match first. Smallest 247324e36522SCy Schubert * one from a set. */ 247424e36522SCy Schubert /* we use the precedence rules for the topics and triggers that 247524e36522SCy Schubert * are pertinent at this stage of the resolve processing */ 247624e36522SCy Schubert for(a = az->rpz_first; a != NULL; a = a->rpz_az_next) { 247724e36522SCy Schubert lock_rw_rdlock(&a->lock); 247824e36522SCy Schubert r = a->rpz; 247924e36522SCy Schubert if(r->disabled) { 248024e36522SCy Schubert lock_rw_unlock(&a->lock); 248124e36522SCy Schubert continue; 248224e36522SCy Schubert } 248356850988SCy Schubert if(r->taglist && (!ms->client_info || 248456850988SCy Schubert !taglist_intersect(r->taglist, r->taglistlen, 248556850988SCy Schubert ms->client_info->taglist, 248656850988SCy Schubert ms->client_info->taglen))) { 248756850988SCy Schubert lock_rw_unlock(&a->lock); 248856850988SCy Schubert continue; 248956850988SCy Schubert } 249024e36522SCy Schubert 249124e36522SCy Schubert /* the nsdname has precedence over the nsip triggers */ 249224e36522SCy Schubert z = rpz_delegation_point_zone_lookup(is->dp, r->nsdname_zones, 2493335c7cdaSCy Schubert is->qchase.qclass, &match); 249424e36522SCy Schubert if(z != NULL) { 249524e36522SCy Schubert lock_rw_unlock(&a->lock); 249624e36522SCy Schubert break; 249724e36522SCy Schubert } 249824e36522SCy Schubert 249924e36522SCy Schubert raddr = rpz_delegation_point_ipbased_trigger_lookup(r, is); 250024e36522SCy Schubert if(raddr != NULL) { 250124e36522SCy Schubert lock_rw_unlock(&a->lock); 250224e36522SCy Schubert break; 250324e36522SCy Schubert } 250424e36522SCy Schubert lock_rw_unlock(&a->lock); 250524e36522SCy Schubert } 250624e36522SCy Schubert 250724e36522SCy Schubert lock_rw_unlock(&az->rpz_lock); 250824e36522SCy Schubert 2509865f46b2SCy Schubert if(raddr == NULL && z == NULL) 2510865f46b2SCy Schubert return NULL; 2511865f46b2SCy Schubert 2512865f46b2SCy Schubert if(raddr != NULL) { 251324e36522SCy Schubert if(z) { 251424e36522SCy Schubert lock_rw_unlock(&z->lock); 251524e36522SCy Schubert } 2516335c7cdaSCy Schubert return rpz_apply_nsip_trigger(ms, &is->qchase, r, raddr, a); 251724e36522SCy Schubert } 2518335c7cdaSCy Schubert return rpz_apply_nsdname_trigger(ms, &is->qchase, r, z, &match, a); 251924e36522SCy Schubert } 252024e36522SCy Schubert 252124e36522SCy Schubert struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms, 252224e36522SCy Schubert struct iter_qstate* is) 252324e36522SCy Schubert { 252424e36522SCy Schubert struct auth_zones* az; 252524e36522SCy Schubert struct auth_zone* a = NULL; 252624e36522SCy Schubert struct rpz* r = NULL; 252724e36522SCy Schubert struct local_zone* z = NULL; 252824e36522SCy Schubert enum localzone_type lzt; 252924e36522SCy Schubert struct dns_msg* ret = NULL; 253024e36522SCy Schubert 2531a39a5a69SCy Schubert if(ms->rpz_passthru) { 2532a39a5a69SCy Schubert verbose(VERB_ALGO, "query is rpz_passthru, no further processing"); 2533a39a5a69SCy Schubert return NULL; 2534a39a5a69SCy Schubert } 2535a39a5a69SCy Schubert 253624e36522SCy Schubert if(ms->env == NULL || ms->env->auth_zones == NULL) { return 0; } 253724e36522SCy Schubert az = ms->env->auth_zones; 253824e36522SCy Schubert 253924e36522SCy Schubert lock_rw_rdlock(&az->rpz_lock); 254024e36522SCy Schubert 254124e36522SCy Schubert for(a = az->rpz_first; a; a = a->rpz_az_next) { 254224e36522SCy Schubert lock_rw_rdlock(&a->lock); 254324e36522SCy Schubert r = a->rpz; 254424e36522SCy Schubert if(r->disabled) { 254524e36522SCy Schubert lock_rw_unlock(&a->lock); 254624e36522SCy Schubert continue; 254724e36522SCy Schubert } 254856850988SCy Schubert if(r->taglist && (!ms->client_info || 254956850988SCy Schubert !taglist_intersect(r->taglist, r->taglistlen, 255056850988SCy Schubert ms->client_info->taglist, 255156850988SCy Schubert ms->client_info->taglen))) { 255256850988SCy Schubert lock_rw_unlock(&a->lock); 255356850988SCy Schubert continue; 255456850988SCy Schubert } 255524e36522SCy Schubert z = rpz_find_zone(r->local_zones, is->qchase.qname, 255624e36522SCy Schubert is->qchase.qname_len, is->qchase.qclass, 0, 0, 0); 255724e36522SCy Schubert if(z && r->action_override == RPZ_DISABLED_ACTION) { 255824e36522SCy Schubert if(r->log) 255924e36522SCy Schubert log_rpz_apply("qname", z->name, NULL, 256024e36522SCy Schubert r->action_override, 256124e36522SCy Schubert &ms->qinfo, NULL, ms, r->log_name); 256224e36522SCy Schubert if(ms->env->worker) 256324e36522SCy Schubert ms->env->worker->stats.rpz_action[r->action_override]++; 256424e36522SCy Schubert lock_rw_unlock(&z->lock); 256524e36522SCy Schubert z = NULL; 256624e36522SCy Schubert } 256724e36522SCy Schubert if(z) { 256824e36522SCy Schubert break; 256924e36522SCy Schubert } 257024e36522SCy Schubert /* not found in this auth_zone */ 257124e36522SCy Schubert lock_rw_unlock(&a->lock); 257224e36522SCy Schubert } 257324e36522SCy Schubert lock_rw_unlock(&az->rpz_lock); 257424e36522SCy Schubert 257524e36522SCy Schubert if(z == NULL) 257624e36522SCy Schubert return NULL; 257724e36522SCy Schubert if(r->action_override == RPZ_NO_OVERRIDE_ACTION) { 257824e36522SCy Schubert lzt = z->type; 257924e36522SCy Schubert } else { 258024e36522SCy Schubert lzt = rpz_action_to_localzone_type(r->action_override); 258124e36522SCy Schubert } 258224e36522SCy Schubert 258324e36522SCy Schubert if(verbosity >= VERB_ALGO) { 258424e36522SCy Schubert char nm[255+1], zn[255+1]; 258524e36522SCy Schubert dname_str(is->qchase.qname, nm); 258624e36522SCy Schubert dname_str(z->name, zn); 258724e36522SCy Schubert if(strcmp(zn, nm) != 0) 2588335c7cdaSCy Schubert verbose(VERB_ALGO, "rpz: qname trigger %s on %s, with action=%s", 258924e36522SCy Schubert zn, nm, rpz_action_to_string(localzone_type_to_rpz_action(lzt))); 259024e36522SCy Schubert else 2591335c7cdaSCy Schubert verbose(VERB_ALGO, "rpz: qname trigger %s, with action=%s", 259224e36522SCy Schubert nm, rpz_action_to_string(localzone_type_to_rpz_action(lzt))); 259324e36522SCy Schubert } 259424e36522SCy Schubert switch(localzone_type_to_rpz_action(lzt)) { 259524e36522SCy Schubert case RPZ_NXDOMAIN_ACTION: 259624e36522SCy Schubert ret = rpz_synthesize_nxdomain(r, ms, &is->qchase, a); 2597*46d2f618SCy Schubert ms->rpz_applied = 1; 259824e36522SCy Schubert break; 259924e36522SCy Schubert case RPZ_NODATA_ACTION: 260024e36522SCy Schubert ret = rpz_synthesize_nodata(r, ms, &is->qchase, a); 2601*46d2f618SCy Schubert ms->rpz_applied = 1; 260224e36522SCy Schubert break; 260324e36522SCy Schubert case RPZ_TCP_ONLY_ACTION: 260424e36522SCy Schubert /* basically a passthru here but the tcp-only will be 260524e36522SCy Schubert * honored before the query gets sent. */ 2606103ba509SCy Schubert ms->tcp_required = 1; 260724e36522SCy Schubert ret = NULL; 260824e36522SCy Schubert break; 260924e36522SCy Schubert case RPZ_DROP_ACTION: 261024e36522SCy Schubert ret = rpz_synthesize_nodata(r, ms, &is->qchase, a); 2611*46d2f618SCy Schubert ms->rpz_applied = 1; 261224e36522SCy Schubert ms->is_drop = 1; 261324e36522SCy Schubert break; 261424e36522SCy Schubert case RPZ_LOCAL_DATA_ACTION: 261524e36522SCy Schubert ret = rpz_synthesize_qname_localdata_msg(r, ms, &is->qchase, z, a); 261624e36522SCy Schubert if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, &is->qchase, a); } 2617*46d2f618SCy Schubert ms->rpz_applied = 1; 261824e36522SCy Schubert break; 261924e36522SCy Schubert case RPZ_PASSTHRU_ACTION: 262024e36522SCy Schubert ret = NULL; 2621a39a5a69SCy Schubert ms->rpz_passthru = 1; 262224e36522SCy Schubert break; 262324e36522SCy Schubert default: 2624335c7cdaSCy Schubert verbose(VERB_ALGO, "rpz: qname trigger: bug: unhandled or invalid action: '%s'", 262524e36522SCy Schubert rpz_action_to_string(localzone_type_to_rpz_action(lzt))); 262624e36522SCy Schubert ret = NULL; 262724e36522SCy Schubert } 2628103ba509SCy Schubert if(r->log) 2629103ba509SCy Schubert log_rpz_apply("qname", (z?z->name:NULL), NULL, 2630103ba509SCy Schubert localzone_type_to_rpz_action(lzt), 2631103ba509SCy Schubert &is->qchase, NULL, ms, r->log_name); 263224e36522SCy Schubert lock_rw_unlock(&z->lock); 263324e36522SCy Schubert lock_rw_unlock(&a->lock); 263424e36522SCy Schubert return ret; 263524e36522SCy Schubert } 263624e36522SCy Schubert 263724e36522SCy Schubert static int 263824e36522SCy Schubert rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env, 263924e36522SCy Schubert struct query_info* qinfo, struct edns_data* edns, struct comm_reply* repinfo, 264024e36522SCy Schubert uint8_t* taglist, size_t taglen, struct ub_server_stats* stats, 264124e36522SCy Schubert sldns_buffer* buf, struct regional* temp, 264224e36522SCy Schubert /* output parameters */ 2643a39a5a69SCy Schubert struct local_zone** z_out, struct auth_zone** a_out, struct rpz** r_out, 2644a39a5a69SCy Schubert int* passthru) 264524e36522SCy Schubert { 264624e36522SCy Schubert int ret = 0; 264724e36522SCy Schubert enum rpz_action client_action; 264824e36522SCy Schubert struct clientip_synthesized_rr* node = rpz_resolve_client_action_and_zone( 264924e36522SCy Schubert az, qinfo, repinfo, taglist, taglen, stats, z_out, a_out, r_out); 265024e36522SCy Schubert 265124e36522SCy Schubert client_action = ((node == NULL) ? RPZ_INVALID_ACTION : node->action); 2652335c7cdaSCy Schubert if(node != NULL && *r_out && 2653335c7cdaSCy Schubert (*r_out)->action_override != RPZ_NO_OVERRIDE_ACTION) { 2654335c7cdaSCy Schubert client_action = (*r_out)->action_override; 2655335c7cdaSCy Schubert } 2656a39a5a69SCy Schubert if(client_action == RPZ_PASSTHRU_ACTION) { 2657335c7cdaSCy Schubert if(*r_out && (*r_out)->log) 2658335c7cdaSCy Schubert log_rpz_apply( 2659335c7cdaSCy Schubert (node?"clientip":"qname"), 2660335c7cdaSCy Schubert ((*z_out)?(*z_out)->name:NULL), 2661335c7cdaSCy Schubert (node?&node->node:NULL), 2662335c7cdaSCy Schubert client_action, qinfo, repinfo, NULL, 2663335c7cdaSCy Schubert (*r_out)->log_name); 2664a39a5a69SCy Schubert *passthru = 1; 2665335c7cdaSCy Schubert ret = 0; 2666335c7cdaSCy Schubert goto done; 2667a39a5a69SCy Schubert } 266824e36522SCy Schubert if(*z_out == NULL || (client_action != RPZ_INVALID_ACTION && 266924e36522SCy Schubert client_action != RPZ_PASSTHRU_ACTION)) { 267024e36522SCy Schubert if(client_action == RPZ_PASSTHRU_ACTION 267124e36522SCy Schubert || client_action == RPZ_INVALID_ACTION 267224e36522SCy Schubert || (client_action == RPZ_TCP_ONLY_ACTION 267324e36522SCy Schubert && !rpz_is_udp_query(repinfo))) { 267424e36522SCy Schubert ret = 0; 267524e36522SCy Schubert goto done; 267624e36522SCy Schubert } 267724e36522SCy Schubert stats->rpz_action[client_action]++; 267824e36522SCy Schubert if(client_action == RPZ_LOCAL_DATA_ACTION) { 267924e36522SCy Schubert rpz_apply_clientip_localdata_action(node, env, qinfo, 268024e36522SCy Schubert edns, repinfo, buf, temp, *a_out); 2681335c7cdaSCy Schubert ret = 1; 2682335c7cdaSCy Schubert } else if(client_action == RPZ_CNAME_OVERRIDE_ACTION) { 2683335c7cdaSCy Schubert if(!rpz_apply_cname_override_action(*r_out, qinfo, 2684335c7cdaSCy Schubert temp)) { 2685335c7cdaSCy Schubert ret = 0; 2686335c7cdaSCy Schubert goto done; 2687335c7cdaSCy Schubert } 2688335c7cdaSCy Schubert ret = 0; 268924e36522SCy Schubert } else { 269024e36522SCy Schubert local_zones_zone_answer(*z_out /*likely NULL, no zone*/, env, qinfo, edns, 269124e36522SCy Schubert repinfo, buf, temp, 0 /* no local data used */, 269224e36522SCy Schubert rpz_action_to_localzone_type(client_action)); 26939cf5bc93SCy Schubert if(*r_out && (*r_out)->signal_nxdomain_ra && 26949cf5bc93SCy Schubert LDNS_RCODE_WIRE(sldns_buffer_begin(buf)) 26959cf5bc93SCy Schubert == LDNS_RCODE_NXDOMAIN) 26969cf5bc93SCy Schubert LDNS_RA_CLR(sldns_buffer_begin(buf)); 269724e36522SCy Schubert ret = 1; 2698335c7cdaSCy Schubert } 2699335c7cdaSCy Schubert if(*r_out && (*r_out)->log) 2700335c7cdaSCy Schubert log_rpz_apply( 2701335c7cdaSCy Schubert (node?"clientip":"qname"), 2702335c7cdaSCy Schubert ((*z_out)?(*z_out)->name:NULL), 2703335c7cdaSCy Schubert (node?&node->node:NULL), 2704335c7cdaSCy Schubert client_action, qinfo, repinfo, NULL, 2705335c7cdaSCy Schubert (*r_out)->log_name); 270624e36522SCy Schubert goto done; 270724e36522SCy Schubert } 270824e36522SCy Schubert ret = -1; 270924e36522SCy Schubert done: 271024e36522SCy Schubert if(node != NULL) { 271124e36522SCy Schubert lock_rw_unlock(&node->lock); 271224e36522SCy Schubert } 271324e36522SCy Schubert return ret; 271424e36522SCy Schubert } 271524e36522SCy Schubert 271624e36522SCy Schubert int 271724e36522SCy Schubert rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env, 271824e36522SCy Schubert struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf, 271924e36522SCy Schubert struct regional* temp, struct comm_reply* repinfo, uint8_t* taglist, 2720a39a5a69SCy Schubert size_t taglen, struct ub_server_stats* stats, int* passthru) 272124e36522SCy Schubert { 272224e36522SCy Schubert struct rpz* r = NULL; 272324e36522SCy Schubert struct auth_zone* a = NULL; 272424e36522SCy Schubert struct local_zone* z = NULL; 272524e36522SCy Schubert int ret; 272624e36522SCy Schubert enum localzone_type lzt; 272724e36522SCy Schubert 272824e36522SCy Schubert int clientip_trigger = rpz_apply_maybe_clientip_trigger(az, env, qinfo, 2729a39a5a69SCy Schubert edns, repinfo, taglist, taglen, stats, buf, temp, &z, &a, &r, 2730a39a5a69SCy Schubert passthru); 273124e36522SCy Schubert if(clientip_trigger >= 0) { 273224e36522SCy Schubert if(a) { 273324e36522SCy Schubert lock_rw_unlock(&a->lock); 273424e36522SCy Schubert } 273524e36522SCy Schubert if(z) { 273624e36522SCy Schubert lock_rw_unlock(&z->lock); 273724e36522SCy Schubert } 273824e36522SCy Schubert return clientip_trigger; 273924e36522SCy Schubert } 274024e36522SCy Schubert 274124e36522SCy Schubert if(z == NULL) { 274224e36522SCy Schubert if(a) { 274324e36522SCy Schubert lock_rw_unlock(&a->lock); 274424e36522SCy Schubert } 274524e36522SCy Schubert return 0; 274624e36522SCy Schubert } 274724e36522SCy Schubert 274824e36522SCy Schubert log_assert(r); 274924e36522SCy Schubert 275024e36522SCy Schubert if(r->action_override == RPZ_NO_OVERRIDE_ACTION) { 275124e36522SCy Schubert lzt = z->type; 275224e36522SCy Schubert } else { 275324e36522SCy Schubert lzt = rpz_action_to_localzone_type(r->action_override); 275424e36522SCy Schubert } 2755a39a5a69SCy Schubert if(r->action_override == RPZ_PASSTHRU_ACTION || 2756a39a5a69SCy Schubert lzt == local_zone_always_transparent /* RPZ_PASSTHRU_ACTION */) { 2757a39a5a69SCy Schubert *passthru = 1; 2758a39a5a69SCy Schubert } 275924e36522SCy Schubert 276024e36522SCy Schubert if(verbosity >= VERB_ALGO) { 276124e36522SCy Schubert char nm[255+1], zn[255+1]; 276224e36522SCy Schubert dname_str(qinfo->qname, nm); 276324e36522SCy Schubert dname_str(z->name, zn); 276424e36522SCy Schubert if(strcmp(zn, nm) != 0) 276524e36522SCy Schubert verbose(VERB_ALGO, "rpz: qname trigger %s on %s with action=%s", 276624e36522SCy Schubert zn, nm, rpz_action_to_string(localzone_type_to_rpz_action(lzt))); 276724e36522SCy Schubert else 276824e36522SCy Schubert verbose(VERB_ALGO, "rpz: qname trigger %s with action=%s", 276924e36522SCy Schubert nm, rpz_action_to_string(localzone_type_to_rpz_action(lzt))); 277024e36522SCy Schubert } 277124e36522SCy Schubert 277224e36522SCy Schubert ret = rpz_synthesize_qname_localdata(env, r, z, lzt, qinfo, edns, buf, temp, 277324e36522SCy Schubert repinfo, stats); 277424e36522SCy Schubert 2775091e9e46SCy Schubert lock_rw_unlock(&z->lock); 277625039b37SCy Schubert lock_rw_unlock(&a->lock); 2777091e9e46SCy Schubert 2778091e9e46SCy Schubert return ret; 2779091e9e46SCy Schubert } 2780f44e67d1SCy Schubert 2781f44e67d1SCy Schubert void rpz_enable(struct rpz* r) 2782f44e67d1SCy Schubert { 2783f44e67d1SCy Schubert if(!r) 2784f44e67d1SCy Schubert return; 2785f44e67d1SCy Schubert r->disabled = 0; 2786f44e67d1SCy Schubert } 2787f44e67d1SCy Schubert 2788f44e67d1SCy Schubert void rpz_disable(struct rpz* r) 2789f44e67d1SCy Schubert { 2790f44e67d1SCy Schubert if(!r) 2791f44e67d1SCy Schubert return; 2792f44e67d1SCy Schubert r->disabled = 1; 2793f44e67d1SCy Schubert } 2794