165b390aaSDag-Erling Smørgrav /* 265b390aaSDag-Erling Smørgrav * respip/respip.c - filtering response IP module 365b390aaSDag-Erling Smørgrav */ 465b390aaSDag-Erling Smørgrav 565b390aaSDag-Erling Smørgrav /** 665b390aaSDag-Erling Smørgrav * \file 765b390aaSDag-Erling Smørgrav * 865b390aaSDag-Erling Smørgrav * This file contains a module that inspects a result of recursive resolution 965b390aaSDag-Erling Smørgrav * to see if any IP address record should trigger a special action. 1065b390aaSDag-Erling Smørgrav * If applicable these actions can modify the original response. 1165b390aaSDag-Erling Smørgrav */ 1265b390aaSDag-Erling Smørgrav #include "config.h" 1365b390aaSDag-Erling Smørgrav 1465b390aaSDag-Erling Smørgrav #include "services/localzone.h" 15091e9e46SCy Schubert #include "services/authzone.h" 1665b390aaSDag-Erling Smørgrav #include "services/cache/dns.h" 1765b390aaSDag-Erling Smørgrav #include "sldns/str2wire.h" 1865b390aaSDag-Erling Smørgrav #include "util/config_file.h" 1965b390aaSDag-Erling Smørgrav #include "util/fptr_wlist.h" 2065b390aaSDag-Erling Smørgrav #include "util/module.h" 2165b390aaSDag-Erling Smørgrav #include "util/net_help.h" 2265b390aaSDag-Erling Smørgrav #include "util/regional.h" 2365b390aaSDag-Erling Smørgrav #include "util/data/msgreply.h" 2465b390aaSDag-Erling Smørgrav #include "util/storage/dnstree.h" 2565b390aaSDag-Erling Smørgrav #include "respip/respip.h" 2665b390aaSDag-Erling Smørgrav #include "services/view.h" 2765b390aaSDag-Erling Smørgrav #include "sldns/rrdef.h" 2865b390aaSDag-Erling Smørgrav 2965b390aaSDag-Erling Smørgrav 3065b390aaSDag-Erling Smørgrav /** Subset of resp_addr.node, used for inform-variant logging */ 3165b390aaSDag-Erling Smørgrav struct respip_addr_info { 3265b390aaSDag-Erling Smørgrav struct sockaddr_storage addr; 3365b390aaSDag-Erling Smørgrav socklen_t addrlen; 3465b390aaSDag-Erling Smørgrav int net; 3565b390aaSDag-Erling Smørgrav }; 3665b390aaSDag-Erling Smørgrav 3765b390aaSDag-Erling Smørgrav /** Query state regarding the response-ip module. */ 3865b390aaSDag-Erling Smørgrav enum respip_state { 3965b390aaSDag-Erling Smørgrav /** 4065b390aaSDag-Erling Smørgrav * The general state. Unless CNAME chasing takes place, all processing 4165b390aaSDag-Erling Smørgrav * is completed in this state without any other asynchronous event. 4265b390aaSDag-Erling Smørgrav */ 4365b390aaSDag-Erling Smørgrav RESPIP_INIT = 0, 4465b390aaSDag-Erling Smørgrav 4565b390aaSDag-Erling Smørgrav /** 4665b390aaSDag-Erling Smørgrav * A subquery for CNAME chasing is completed. 4765b390aaSDag-Erling Smørgrav */ 4865b390aaSDag-Erling Smørgrav RESPIP_SUBQUERY_FINISHED 4965b390aaSDag-Erling Smørgrav }; 5065b390aaSDag-Erling Smørgrav 5165b390aaSDag-Erling Smørgrav /** Per query state for the response-ip module. */ 5265b390aaSDag-Erling Smørgrav struct respip_qstate { 5365b390aaSDag-Erling Smørgrav enum respip_state state; 5465b390aaSDag-Erling Smørgrav }; 5565b390aaSDag-Erling Smørgrav 5665b390aaSDag-Erling Smørgrav struct respip_set* 5765b390aaSDag-Erling Smørgrav respip_set_create(void) 5865b390aaSDag-Erling Smørgrav { 5965b390aaSDag-Erling Smørgrav struct respip_set* set = calloc(1, sizeof(*set)); 6065b390aaSDag-Erling Smørgrav if(!set) 6165b390aaSDag-Erling Smørgrav return NULL; 6265b390aaSDag-Erling Smørgrav set->region = regional_create(); 6365b390aaSDag-Erling Smørgrav if(!set->region) { 6465b390aaSDag-Erling Smørgrav free(set); 6565b390aaSDag-Erling Smørgrav return NULL; 6665b390aaSDag-Erling Smørgrav } 6765b390aaSDag-Erling Smørgrav addr_tree_init(&set->ip_tree); 68091e9e46SCy Schubert lock_rw_init(&set->lock); 6965b390aaSDag-Erling Smørgrav return set; 7065b390aaSDag-Erling Smørgrav } 7165b390aaSDag-Erling Smørgrav 72091e9e46SCy Schubert /** helper traverse to delete resp_addr nodes */ 73091e9e46SCy Schubert static void 74091e9e46SCy Schubert resp_addr_del(rbnode_type* n, void* ATTR_UNUSED(arg)) 75091e9e46SCy Schubert { 76091e9e46SCy Schubert struct resp_addr* r = (struct resp_addr*)n->key; 77091e9e46SCy Schubert lock_rw_destroy(&r->lock); 78091e9e46SCy Schubert #ifdef THREADS_DISABLED 79091e9e46SCy Schubert (void)r; 80091e9e46SCy Schubert #endif 81091e9e46SCy Schubert } 82091e9e46SCy Schubert 8365b390aaSDag-Erling Smørgrav void 8465b390aaSDag-Erling Smørgrav respip_set_delete(struct respip_set* set) 8565b390aaSDag-Erling Smørgrav { 8665b390aaSDag-Erling Smørgrav if(!set) 8765b390aaSDag-Erling Smørgrav return; 88091e9e46SCy Schubert lock_rw_destroy(&set->lock); 89091e9e46SCy Schubert traverse_postorder(&set->ip_tree, resp_addr_del, NULL); 9065b390aaSDag-Erling Smørgrav regional_destroy(set->region); 9165b390aaSDag-Erling Smørgrav free(set); 9265b390aaSDag-Erling Smørgrav } 9365b390aaSDag-Erling Smørgrav 9465b390aaSDag-Erling Smørgrav struct rbtree_type* 9565b390aaSDag-Erling Smørgrav respip_set_get_tree(struct respip_set* set) 9665b390aaSDag-Erling Smørgrav { 9765b390aaSDag-Erling Smørgrav if(!set) 9865b390aaSDag-Erling Smørgrav return NULL; 9965b390aaSDag-Erling Smørgrav return &set->ip_tree; 10065b390aaSDag-Erling Smørgrav } 10165b390aaSDag-Erling Smørgrav 102091e9e46SCy Schubert struct resp_addr* 103091e9e46SCy Schubert respip_sockaddr_find_or_create(struct respip_set* set, struct sockaddr_storage* addr, 104091e9e46SCy Schubert socklen_t addrlen, int net, int create, const char* ipstr) 105091e9e46SCy Schubert { 106091e9e46SCy Schubert struct resp_addr* node; 107091e9e46SCy Schubert node = (struct resp_addr*)addr_tree_find(&set->ip_tree, addr, addrlen, net); 108091e9e46SCy Schubert if(!node && create) { 109091e9e46SCy Schubert node = regional_alloc_zero(set->region, sizeof(*node)); 110091e9e46SCy Schubert if(!node) { 111091e9e46SCy Schubert log_err("out of memory"); 112091e9e46SCy Schubert return NULL; 113091e9e46SCy Schubert } 114091e9e46SCy Schubert lock_rw_init(&node->lock); 115091e9e46SCy Schubert node->action = respip_none; 116091e9e46SCy Schubert if(!addr_tree_insert(&set->ip_tree, &node->node, addr, 117091e9e46SCy Schubert addrlen, net)) { 118091e9e46SCy Schubert /* We know we didn't find it, so this should be 119091e9e46SCy Schubert * impossible. */ 120091e9e46SCy Schubert log_warn("unexpected: duplicate address: %s", ipstr); 121091e9e46SCy Schubert } 122091e9e46SCy Schubert } 123091e9e46SCy Schubert return node; 124091e9e46SCy Schubert } 125091e9e46SCy Schubert 126091e9e46SCy Schubert void 127091e9e46SCy Schubert respip_sockaddr_delete(struct respip_set* set, struct resp_addr* node) 128091e9e46SCy Schubert { 129091e9e46SCy Schubert struct resp_addr* prev; 130091e9e46SCy Schubert prev = (struct resp_addr*)rbtree_previous((struct rbnode_type*)node); 131091e9e46SCy Schubert lock_rw_destroy(&node->lock); 132*5469a995SCy Schubert (void)rbtree_delete(&set->ip_tree, node); 133091e9e46SCy Schubert /* no free'ing, all allocated in region */ 134091e9e46SCy Schubert if(!prev) 135091e9e46SCy Schubert addr_tree_init_parents((rbtree_type*)set); 136091e9e46SCy Schubert else 137091e9e46SCy Schubert addr_tree_init_parents_node(&prev->node); 138091e9e46SCy Schubert } 139091e9e46SCy Schubert 14065b390aaSDag-Erling Smørgrav /** returns the node in the address tree for the specified netblock string; 14165b390aaSDag-Erling Smørgrav * non-existent node will be created if 'create' is true */ 14265b390aaSDag-Erling Smørgrav static struct resp_addr* 14365b390aaSDag-Erling Smørgrav respip_find_or_create(struct respip_set* set, const char* ipstr, int create) 14465b390aaSDag-Erling Smørgrav { 14565b390aaSDag-Erling Smørgrav struct sockaddr_storage addr; 14665b390aaSDag-Erling Smørgrav int net; 14765b390aaSDag-Erling Smørgrav socklen_t addrlen; 14865b390aaSDag-Erling Smørgrav 14965b390aaSDag-Erling Smørgrav if(!netblockstrtoaddr(ipstr, 0, &addr, &addrlen, &net)) { 15065b390aaSDag-Erling Smørgrav log_err("cannot parse netblock: '%s'", ipstr); 15165b390aaSDag-Erling Smørgrav return NULL; 15265b390aaSDag-Erling Smørgrav } 153091e9e46SCy Schubert return respip_sockaddr_find_or_create(set, &addr, addrlen, net, create, 154091e9e46SCy Schubert ipstr); 15565b390aaSDag-Erling Smørgrav } 15665b390aaSDag-Erling Smørgrav 15765b390aaSDag-Erling Smørgrav static int 15865b390aaSDag-Erling Smørgrav respip_tag_cfg(struct respip_set* set, const char* ipstr, 15965b390aaSDag-Erling Smørgrav const uint8_t* taglist, size_t taglen) 16065b390aaSDag-Erling Smørgrav { 16165b390aaSDag-Erling Smørgrav struct resp_addr* node; 16265b390aaSDag-Erling Smørgrav 16365b390aaSDag-Erling Smørgrav if(!(node=respip_find_or_create(set, ipstr, 1))) 16465b390aaSDag-Erling Smørgrav return 0; 16565b390aaSDag-Erling Smørgrav if(node->taglist) { 16665b390aaSDag-Erling Smørgrav log_warn("duplicate response-address-tag for '%s', overridden.", 16765b390aaSDag-Erling Smørgrav ipstr); 16865b390aaSDag-Erling Smørgrav } 16965b390aaSDag-Erling Smørgrav node->taglist = regional_alloc_init(set->region, taglist, taglen); 17065b390aaSDag-Erling Smørgrav if(!node->taglist) { 17165b390aaSDag-Erling Smørgrav log_err("out of memory"); 17265b390aaSDag-Erling Smørgrav return 0; 17365b390aaSDag-Erling Smørgrav } 17465b390aaSDag-Erling Smørgrav node->taglen = taglen; 17565b390aaSDag-Erling Smørgrav return 1; 17665b390aaSDag-Erling Smørgrav } 17765b390aaSDag-Erling Smørgrav 17865b390aaSDag-Erling Smørgrav /** set action for the node specified by the netblock string */ 17965b390aaSDag-Erling Smørgrav static int 18065b390aaSDag-Erling Smørgrav respip_action_cfg(struct respip_set* set, const char* ipstr, 18165b390aaSDag-Erling Smørgrav const char* actnstr) 18265b390aaSDag-Erling Smørgrav { 18365b390aaSDag-Erling Smørgrav struct resp_addr* node; 18465b390aaSDag-Erling Smørgrav enum respip_action action; 18565b390aaSDag-Erling Smørgrav 18665b390aaSDag-Erling Smørgrav if(!(node=respip_find_or_create(set, ipstr, 1))) 18765b390aaSDag-Erling Smørgrav return 0; 18865b390aaSDag-Erling Smørgrav if(node->action != respip_none) { 189a755b6f6SDag-Erling Smørgrav verbose(VERB_QUERY, "duplicate response-ip action for '%s', overridden.", 19065b390aaSDag-Erling Smørgrav ipstr); 19165b390aaSDag-Erling Smørgrav } 19265b390aaSDag-Erling Smørgrav if(strcmp(actnstr, "deny") == 0) 19365b390aaSDag-Erling Smørgrav action = respip_deny; 19465b390aaSDag-Erling Smørgrav else if(strcmp(actnstr, "redirect") == 0) 19565b390aaSDag-Erling Smørgrav action = respip_redirect; 19665b390aaSDag-Erling Smørgrav else if(strcmp(actnstr, "inform") == 0) 19765b390aaSDag-Erling Smørgrav action = respip_inform; 19865b390aaSDag-Erling Smørgrav else if(strcmp(actnstr, "inform_deny") == 0) 19965b390aaSDag-Erling Smørgrav action = respip_inform_deny; 200e86b9096SDag-Erling Smørgrav else if(strcmp(actnstr, "inform_redirect") == 0) 201e86b9096SDag-Erling Smørgrav action = respip_inform_redirect; 20265b390aaSDag-Erling Smørgrav else if(strcmp(actnstr, "always_transparent") == 0) 20365b390aaSDag-Erling Smørgrav action = respip_always_transparent; 20465b390aaSDag-Erling Smørgrav else if(strcmp(actnstr, "always_refuse") == 0) 20565b390aaSDag-Erling Smørgrav action = respip_always_refuse; 20665b390aaSDag-Erling Smørgrav else if(strcmp(actnstr, "always_nxdomain") == 0) 20765b390aaSDag-Erling Smørgrav action = respip_always_nxdomain; 208091e9e46SCy Schubert else if(strcmp(actnstr, "always_nodata") == 0) 209091e9e46SCy Schubert action = respip_always_nodata; 210091e9e46SCy Schubert else if(strcmp(actnstr, "always_deny") == 0) 211091e9e46SCy Schubert action = respip_always_deny; 21265b390aaSDag-Erling Smørgrav else { 21365b390aaSDag-Erling Smørgrav log_err("unknown response-ip action %s", actnstr); 21465b390aaSDag-Erling Smørgrav return 0; 21565b390aaSDag-Erling Smørgrav } 21665b390aaSDag-Erling Smørgrav node->action = action; 21765b390aaSDag-Erling Smørgrav return 1; 21865b390aaSDag-Erling Smørgrav } 21965b390aaSDag-Erling Smørgrav 22065b390aaSDag-Erling Smørgrav /** allocate and initialize an rrset structure; this function is based 22165b390aaSDag-Erling Smørgrav * on new_local_rrset() from the localzone.c module */ 22265b390aaSDag-Erling Smørgrav static struct ub_packed_rrset_key* 22365b390aaSDag-Erling Smørgrav new_rrset(struct regional* region, uint16_t rrtype, uint16_t rrclass) 22465b390aaSDag-Erling Smørgrav { 22565b390aaSDag-Erling Smørgrav struct packed_rrset_data* pd; 22665b390aaSDag-Erling Smørgrav struct ub_packed_rrset_key* rrset = regional_alloc_zero( 22765b390aaSDag-Erling Smørgrav region, sizeof(*rrset)); 22865b390aaSDag-Erling Smørgrav if(!rrset) { 22965b390aaSDag-Erling Smørgrav log_err("out of memory"); 23065b390aaSDag-Erling Smørgrav return NULL; 23165b390aaSDag-Erling Smørgrav } 23265b390aaSDag-Erling Smørgrav rrset->entry.key = rrset; 23365b390aaSDag-Erling Smørgrav pd = regional_alloc_zero(region, sizeof(*pd)); 23465b390aaSDag-Erling Smørgrav if(!pd) { 23565b390aaSDag-Erling Smørgrav log_err("out of memory"); 23665b390aaSDag-Erling Smørgrav return NULL; 23765b390aaSDag-Erling Smørgrav } 23865b390aaSDag-Erling Smørgrav pd->trust = rrset_trust_prim_noglue; 23965b390aaSDag-Erling Smørgrav pd->security = sec_status_insecure; 24065b390aaSDag-Erling Smørgrav rrset->entry.data = pd; 24165b390aaSDag-Erling Smørgrav rrset->rk.dname = regional_alloc_zero(region, 1); 24265b390aaSDag-Erling Smørgrav if(!rrset->rk.dname) { 24365b390aaSDag-Erling Smørgrav log_err("out of memory"); 24465b390aaSDag-Erling Smørgrav return NULL; 24565b390aaSDag-Erling Smørgrav } 24665b390aaSDag-Erling Smørgrav rrset->rk.dname_len = 1; 24765b390aaSDag-Erling Smørgrav rrset->rk.type = htons(rrtype); 24865b390aaSDag-Erling Smørgrav rrset->rk.rrset_class = htons(rrclass); 24965b390aaSDag-Erling Smørgrav return rrset; 25065b390aaSDag-Erling Smørgrav } 25165b390aaSDag-Erling Smørgrav 25265b390aaSDag-Erling Smørgrav /** enter local data as resource records into a response-ip node */ 253091e9e46SCy Schubert 254091e9e46SCy Schubert int 25565b390aaSDag-Erling Smørgrav respip_enter_rr(struct regional* region, struct resp_addr* raddr, 256091e9e46SCy Schubert uint16_t rrtype, uint16_t rrclass, time_t ttl, uint8_t* rdata, 257091e9e46SCy Schubert size_t rdata_len, const char* rrstr, const char* netblockstr) 258091e9e46SCy Schubert { 259091e9e46SCy Schubert struct packed_rrset_data* pd; 260091e9e46SCy Schubert struct sockaddr* sa; 261091e9e46SCy Schubert sa = (struct sockaddr*)&raddr->node.addr; 262091e9e46SCy Schubert if (rrtype == LDNS_RR_TYPE_CNAME && raddr->data) { 263091e9e46SCy Schubert log_err("CNAME response-ip data (%s) can not co-exist with other " 264091e9e46SCy Schubert "response-ip data for netblock %s", rrstr, netblockstr); 265091e9e46SCy Schubert return 0; 266091e9e46SCy Schubert } else if (raddr->data && 267091e9e46SCy Schubert raddr->data->rk.type == htons(LDNS_RR_TYPE_CNAME)) { 268091e9e46SCy Schubert log_err("response-ip data (%s) can not be added; CNAME response-ip " 269091e9e46SCy Schubert "data already in place for netblock %s", rrstr, netblockstr); 270091e9e46SCy Schubert return 0; 271091e9e46SCy Schubert } else if((rrtype != LDNS_RR_TYPE_CNAME) && 272091e9e46SCy Schubert ((sa->sa_family == AF_INET && rrtype != LDNS_RR_TYPE_A) || 273091e9e46SCy Schubert (sa->sa_family == AF_INET6 && rrtype != LDNS_RR_TYPE_AAAA))) { 274091e9e46SCy Schubert log_err("response-ip data %s record type does not correspond " 275091e9e46SCy Schubert "to netblock %s address family", rrstr, netblockstr); 276091e9e46SCy Schubert return 0; 277091e9e46SCy Schubert } 278091e9e46SCy Schubert 279091e9e46SCy Schubert if(!raddr->data) { 280091e9e46SCy Schubert raddr->data = new_rrset(region, rrtype, rrclass); 281091e9e46SCy Schubert if(!raddr->data) 282091e9e46SCy Schubert return 0; 283091e9e46SCy Schubert } 284091e9e46SCy Schubert pd = raddr->data->entry.data; 285091e9e46SCy Schubert return rrset_insert_rr(region, pd, rdata, rdata_len, ttl, rrstr); 286091e9e46SCy Schubert } 287091e9e46SCy Schubert 288091e9e46SCy Schubert static int 289091e9e46SCy Schubert respip_enter_rrstr(struct regional* region, struct resp_addr* raddr, 29065b390aaSDag-Erling Smørgrav const char* rrstr, const char* netblock) 29165b390aaSDag-Erling Smørgrav { 29265b390aaSDag-Erling Smørgrav uint8_t* nm; 29365b390aaSDag-Erling Smørgrav uint16_t rrtype = 0, rrclass = 0; 29465b390aaSDag-Erling Smørgrav time_t ttl = 0; 29565b390aaSDag-Erling Smørgrav uint8_t rr[LDNS_RR_BUF_SIZE]; 29665b390aaSDag-Erling Smørgrav uint8_t* rdata = NULL; 29765b390aaSDag-Erling Smørgrav size_t rdata_len = 0; 29865b390aaSDag-Erling Smørgrav char buf[65536]; 29965b390aaSDag-Erling Smørgrav char bufshort[64]; 30065b390aaSDag-Erling Smørgrav int ret; 301e86b9096SDag-Erling Smørgrav if(raddr->action != respip_redirect 302e86b9096SDag-Erling Smørgrav && raddr->action != respip_inform_redirect) { 30365b390aaSDag-Erling Smørgrav log_err("cannot parse response-ip-data %s: response-ip " 30465b390aaSDag-Erling Smørgrav "action for %s is not redirect", rrstr, netblock); 30565b390aaSDag-Erling Smørgrav return 0; 30665b390aaSDag-Erling Smørgrav } 30765b390aaSDag-Erling Smørgrav ret = snprintf(buf, sizeof(buf), ". %s", rrstr); 30865b390aaSDag-Erling Smørgrav if(ret < 0 || ret >= (int)sizeof(buf)) { 30965b390aaSDag-Erling Smørgrav strlcpy(bufshort, rrstr, sizeof(bufshort)); 31065b390aaSDag-Erling Smørgrav log_err("bad response-ip-data: %s...", bufshort); 31165b390aaSDag-Erling Smørgrav return 0; 31265b390aaSDag-Erling Smørgrav } 31365b390aaSDag-Erling Smørgrav if(!rrstr_get_rr_content(buf, &nm, &rrtype, &rrclass, &ttl, rr, sizeof(rr), 31465b390aaSDag-Erling Smørgrav &rdata, &rdata_len)) { 31565b390aaSDag-Erling Smørgrav log_err("bad response-ip-data: %s", rrstr); 31665b390aaSDag-Erling Smørgrav return 0; 31765b390aaSDag-Erling Smørgrav } 318c7f4d7adSDag-Erling Smørgrav free(nm); 319091e9e46SCy Schubert return respip_enter_rr(region, raddr, rrtype, rrclass, ttl, rdata, 320091e9e46SCy Schubert rdata_len, rrstr, netblock); 32165b390aaSDag-Erling Smørgrav } 32265b390aaSDag-Erling Smørgrav 32365b390aaSDag-Erling Smørgrav static int 32465b390aaSDag-Erling Smørgrav respip_data_cfg(struct respip_set* set, const char* ipstr, const char* rrstr) 32565b390aaSDag-Erling Smørgrav { 32665b390aaSDag-Erling Smørgrav struct resp_addr* node; 32765b390aaSDag-Erling Smørgrav 32865b390aaSDag-Erling Smørgrav node=respip_find_or_create(set, ipstr, 0); 32965b390aaSDag-Erling Smørgrav if(!node || node->action == respip_none) { 33065b390aaSDag-Erling Smørgrav log_err("cannot parse response-ip-data %s: " 33165b390aaSDag-Erling Smørgrav "response-ip node for %s not found", rrstr, ipstr); 33265b390aaSDag-Erling Smørgrav return 0; 33365b390aaSDag-Erling Smørgrav } 334091e9e46SCy Schubert return respip_enter_rrstr(set->region, node, rrstr, ipstr); 33565b390aaSDag-Erling Smørgrav } 33665b390aaSDag-Erling Smørgrav 33765b390aaSDag-Erling Smørgrav static int 33865b390aaSDag-Erling Smørgrav respip_set_apply_cfg(struct respip_set* set, char* const* tagname, int num_tags, 33965b390aaSDag-Erling Smørgrav struct config_strbytelist* respip_tags, 34065b390aaSDag-Erling Smørgrav struct config_str2list* respip_actions, 34165b390aaSDag-Erling Smørgrav struct config_str2list* respip_data) 34265b390aaSDag-Erling Smørgrav { 34365b390aaSDag-Erling Smørgrav struct config_strbytelist* p; 34465b390aaSDag-Erling Smørgrav struct config_str2list* pa; 34565b390aaSDag-Erling Smørgrav struct config_str2list* pd; 34665b390aaSDag-Erling Smørgrav 34765b390aaSDag-Erling Smørgrav set->tagname = tagname; 34865b390aaSDag-Erling Smørgrav set->num_tags = num_tags; 34965b390aaSDag-Erling Smørgrav 35065b390aaSDag-Erling Smørgrav p = respip_tags; 35165b390aaSDag-Erling Smørgrav while(p) { 35265b390aaSDag-Erling Smørgrav struct config_strbytelist* np = p->next; 35365b390aaSDag-Erling Smørgrav 35465b390aaSDag-Erling Smørgrav log_assert(p->str && p->str2); 35565b390aaSDag-Erling Smørgrav if(!respip_tag_cfg(set, p->str, p->str2, p->str2len)) { 35665b390aaSDag-Erling Smørgrav config_del_strbytelist(p); 35765b390aaSDag-Erling Smørgrav return 0; 35865b390aaSDag-Erling Smørgrav } 35965b390aaSDag-Erling Smørgrav free(p->str); 36065b390aaSDag-Erling Smørgrav free(p->str2); 36165b390aaSDag-Erling Smørgrav free(p); 36265b390aaSDag-Erling Smørgrav p = np; 36365b390aaSDag-Erling Smørgrav } 36465b390aaSDag-Erling Smørgrav 36565b390aaSDag-Erling Smørgrav pa = respip_actions; 36665b390aaSDag-Erling Smørgrav while(pa) { 36765b390aaSDag-Erling Smørgrav struct config_str2list* np = pa->next; 36865b390aaSDag-Erling Smørgrav log_assert(pa->str && pa->str2); 36965b390aaSDag-Erling Smørgrav if(!respip_action_cfg(set, pa->str, pa->str2)) { 37065b390aaSDag-Erling Smørgrav config_deldblstrlist(pa); 37165b390aaSDag-Erling Smørgrav return 0; 37265b390aaSDag-Erling Smørgrav } 37365b390aaSDag-Erling Smørgrav free(pa->str); 37465b390aaSDag-Erling Smørgrav free(pa->str2); 37565b390aaSDag-Erling Smørgrav free(pa); 37665b390aaSDag-Erling Smørgrav pa = np; 37765b390aaSDag-Erling Smørgrav } 37865b390aaSDag-Erling Smørgrav 37965b390aaSDag-Erling Smørgrav pd = respip_data; 38065b390aaSDag-Erling Smørgrav while(pd) { 38165b390aaSDag-Erling Smørgrav struct config_str2list* np = pd->next; 38265b390aaSDag-Erling Smørgrav log_assert(pd->str && pd->str2); 38365b390aaSDag-Erling Smørgrav if(!respip_data_cfg(set, pd->str, pd->str2)) { 38465b390aaSDag-Erling Smørgrav config_deldblstrlist(pd); 38565b390aaSDag-Erling Smørgrav return 0; 38665b390aaSDag-Erling Smørgrav } 38765b390aaSDag-Erling Smørgrav free(pd->str); 38865b390aaSDag-Erling Smørgrav free(pd->str2); 38965b390aaSDag-Erling Smørgrav free(pd); 39065b390aaSDag-Erling Smørgrav pd = np; 39165b390aaSDag-Erling Smørgrav } 3920eefd307SCy Schubert addr_tree_init_parents(&set->ip_tree); 39365b390aaSDag-Erling Smørgrav 39465b390aaSDag-Erling Smørgrav return 1; 39565b390aaSDag-Erling Smørgrav } 39665b390aaSDag-Erling Smørgrav 39765b390aaSDag-Erling Smørgrav int 39865b390aaSDag-Erling Smørgrav respip_global_apply_cfg(struct respip_set* set, struct config_file* cfg) 39965b390aaSDag-Erling Smørgrav { 40065b390aaSDag-Erling Smørgrav int ret = respip_set_apply_cfg(set, cfg->tagname, cfg->num_tags, 40165b390aaSDag-Erling Smørgrav cfg->respip_tags, cfg->respip_actions, cfg->respip_data); 40265b390aaSDag-Erling Smørgrav cfg->respip_data = NULL; 40365b390aaSDag-Erling Smørgrav cfg->respip_actions = NULL; 40465b390aaSDag-Erling Smørgrav cfg->respip_tags = NULL; 40565b390aaSDag-Erling Smørgrav return ret; 40665b390aaSDag-Erling Smørgrav } 40765b390aaSDag-Erling Smørgrav 40865b390aaSDag-Erling Smørgrav /** Iterate through raw view data and apply the view-specific respip 40965b390aaSDag-Erling Smørgrav * configuration; at this point we should have already seen all the views, 41065b390aaSDag-Erling Smørgrav * so if any of the views that respip data refer to does not exist, that's 41165b390aaSDag-Erling Smørgrav * an error. This additional iteration through view configuration data 41265b390aaSDag-Erling Smørgrav * is expected to not have significant performance impact (or rather, its 41365b390aaSDag-Erling Smørgrav * performance impact is not expected to be prohibitive in the configuration 41465b390aaSDag-Erling Smørgrav * processing phase). 41565b390aaSDag-Erling Smørgrav */ 41665b390aaSDag-Erling Smørgrav int 41765b390aaSDag-Erling Smørgrav respip_views_apply_cfg(struct views* vs, struct config_file* cfg, 41865b390aaSDag-Erling Smørgrav int* have_view_respip_cfg) 41965b390aaSDag-Erling Smørgrav { 42065b390aaSDag-Erling Smørgrav struct config_view* cv; 42165b390aaSDag-Erling Smørgrav struct view* v; 42265b390aaSDag-Erling Smørgrav int ret; 42365b390aaSDag-Erling Smørgrav 42465b390aaSDag-Erling Smørgrav for(cv = cfg->views; cv; cv = cv->next) { 42565b390aaSDag-Erling Smørgrav 42665b390aaSDag-Erling Smørgrav /** if no respip config for this view then there's 42765b390aaSDag-Erling Smørgrav * nothing to do; note that even though respip data must go 42865b390aaSDag-Erling Smørgrav * with respip action, we're checking for both here because 42965b390aaSDag-Erling Smørgrav * we want to catch the case where the respip action is missing 43065b390aaSDag-Erling Smørgrav * while the data is present */ 43165b390aaSDag-Erling Smørgrav if(!cv->respip_actions && !cv->respip_data) 43265b390aaSDag-Erling Smørgrav continue; 43365b390aaSDag-Erling Smørgrav 43465b390aaSDag-Erling Smørgrav if(!(v = views_find_view(vs, cv->name, 1))) { 43565b390aaSDag-Erling Smørgrav log_err("view '%s' unexpectedly missing", cv->name); 43665b390aaSDag-Erling Smørgrav return 0; 43765b390aaSDag-Erling Smørgrav } 43865b390aaSDag-Erling Smørgrav if(!v->respip_set) { 43965b390aaSDag-Erling Smørgrav v->respip_set = respip_set_create(); 44065b390aaSDag-Erling Smørgrav if(!v->respip_set) { 44165b390aaSDag-Erling Smørgrav log_err("out of memory"); 44265b390aaSDag-Erling Smørgrav lock_rw_unlock(&v->lock); 44365b390aaSDag-Erling Smørgrav return 0; 44465b390aaSDag-Erling Smørgrav } 44565b390aaSDag-Erling Smørgrav } 44665b390aaSDag-Erling Smørgrav ret = respip_set_apply_cfg(v->respip_set, NULL, 0, NULL, 44765b390aaSDag-Erling Smørgrav cv->respip_actions, cv->respip_data); 44865b390aaSDag-Erling Smørgrav lock_rw_unlock(&v->lock); 44965b390aaSDag-Erling Smørgrav if(!ret) { 45065b390aaSDag-Erling Smørgrav log_err("Error while applying respip configuration " 45165b390aaSDag-Erling Smørgrav "for view '%s'", cv->name); 45265b390aaSDag-Erling Smørgrav return 0; 45365b390aaSDag-Erling Smørgrav } 45465b390aaSDag-Erling Smørgrav *have_view_respip_cfg = (*have_view_respip_cfg || 45565b390aaSDag-Erling Smørgrav v->respip_set->ip_tree.count); 45665b390aaSDag-Erling Smørgrav cv->respip_actions = NULL; 45765b390aaSDag-Erling Smørgrav cv->respip_data = NULL; 45865b390aaSDag-Erling Smørgrav } 45965b390aaSDag-Erling Smørgrav return 1; 46065b390aaSDag-Erling Smørgrav } 46165b390aaSDag-Erling Smørgrav 46265b390aaSDag-Erling Smørgrav /** 46365b390aaSDag-Erling Smørgrav * make a deep copy of 'key' in 'region'. 46465b390aaSDag-Erling Smørgrav * This is largely derived from packed_rrset_copy_region() and 46565b390aaSDag-Erling Smørgrav * packed_rrset_ptr_fixup(), but differs in the following points: 46665b390aaSDag-Erling Smørgrav * 46765b390aaSDag-Erling Smørgrav * - It doesn't assume all data in 'key' are in a contiguous memory region. 46865b390aaSDag-Erling Smørgrav * Although that would be the case in most cases, 'key' can be passed from 46965b390aaSDag-Erling Smørgrav * a lower-level module and it might not build the rrset to meet the 47065b390aaSDag-Erling Smørgrav * assumption. In fact, an rrset specified as response-ip-data or generated 47165b390aaSDag-Erling Smørgrav * in local_data_find_tag_datas() breaks the assumption. So it would be 47265b390aaSDag-Erling Smørgrav * safer not to naively rely on the assumption. On the other hand, this 47365b390aaSDag-Erling Smørgrav * function ensures the copied rrset data are in a contiguous region so 47465b390aaSDag-Erling Smørgrav * that it won't cause a disruption even if an upper layer module naively 47565b390aaSDag-Erling Smørgrav * assumes the memory layout. 47665b390aaSDag-Erling Smørgrav * - It doesn't copy RRSIGs (if any) in 'key'. The rrset will be used in 47765b390aaSDag-Erling Smørgrav * a reply that was already faked, so it doesn't make much sense to provide 47865b390aaSDag-Erling Smørgrav * partial sigs even if they are valid themselves. 47965b390aaSDag-Erling Smørgrav * - It doesn't adjust TTLs as it basically has to be a verbatim copy of 'key' 48065b390aaSDag-Erling Smørgrav * just allocated in 'region' (the assumption is necessary TTL adjustment 48165b390aaSDag-Erling Smørgrav * has been already done in 'key'). 48265b390aaSDag-Erling Smørgrav * 48365b390aaSDag-Erling Smørgrav * This function returns the copied rrset key on success, and NULL on memory 48465b390aaSDag-Erling Smørgrav * allocation failure. 48565b390aaSDag-Erling Smørgrav */ 48665b390aaSDag-Erling Smørgrav static struct ub_packed_rrset_key* 48765b390aaSDag-Erling Smørgrav copy_rrset(const struct ub_packed_rrset_key* key, struct regional* region) 48865b390aaSDag-Erling Smørgrav { 48965b390aaSDag-Erling Smørgrav struct ub_packed_rrset_key* ck = regional_alloc(region, 49065b390aaSDag-Erling Smørgrav sizeof(struct ub_packed_rrset_key)); 49165b390aaSDag-Erling Smørgrav struct packed_rrset_data* d; 49265b390aaSDag-Erling Smørgrav struct packed_rrset_data* data = key->entry.data; 49365b390aaSDag-Erling Smørgrav size_t dsize, i; 49465b390aaSDag-Erling Smørgrav uint8_t* nextrdata; 49565b390aaSDag-Erling Smørgrav 49665b390aaSDag-Erling Smørgrav /* derived from packed_rrset_copy_region(), but don't use 49765b390aaSDag-Erling Smørgrav * packed_rrset_sizeof() and do exclude RRSIGs */ 49865b390aaSDag-Erling Smørgrav if(!ck) 49965b390aaSDag-Erling Smørgrav return NULL; 50065b390aaSDag-Erling Smørgrav ck->id = key->id; 50165b390aaSDag-Erling Smørgrav memset(&ck->entry, 0, sizeof(ck->entry)); 50265b390aaSDag-Erling Smørgrav ck->entry.hash = key->entry.hash; 50365b390aaSDag-Erling Smørgrav ck->entry.key = ck; 50465b390aaSDag-Erling Smørgrav ck->rk = key->rk; 50525039b37SCy Schubert if(key->rk.dname) { 50665b390aaSDag-Erling Smørgrav ck->rk.dname = regional_alloc_init(region, key->rk.dname, 50765b390aaSDag-Erling Smørgrav key->rk.dname_len); 50865b390aaSDag-Erling Smørgrav if(!ck->rk.dname) 50965b390aaSDag-Erling Smørgrav return NULL; 51025039b37SCy Schubert ck->rk.dname_len = key->rk.dname_len; 51125039b37SCy Schubert } else { 51225039b37SCy Schubert ck->rk.dname = NULL; 51325039b37SCy Schubert ck->rk.dname_len = 0; 51425039b37SCy Schubert } 51565b390aaSDag-Erling Smørgrav 5160eefd307SCy Schubert if((unsigned)data->count >= 0xffff00U) 5170eefd307SCy Schubert return NULL; /* guard against integer overflow in dsize */ 51865b390aaSDag-Erling Smørgrav dsize = sizeof(struct packed_rrset_data) + data->count * 51965b390aaSDag-Erling Smørgrav (sizeof(size_t)+sizeof(uint8_t*)+sizeof(time_t)); 5200eefd307SCy Schubert for(i=0; i<data->count; i++) { 5210eefd307SCy Schubert if((unsigned)dsize >= 0x0fffffffU || 5220eefd307SCy Schubert (unsigned)data->rr_len[i] >= 0x0fffffffU) 5230eefd307SCy Schubert return NULL; /* guard against integer overflow */ 52465b390aaSDag-Erling Smørgrav dsize += data->rr_len[i]; 5250eefd307SCy Schubert } 526f44e67d1SCy Schubert d = regional_alloc_zero(region, dsize); 52765b390aaSDag-Erling Smørgrav if(!d) 52865b390aaSDag-Erling Smørgrav return NULL; 52965b390aaSDag-Erling Smørgrav *d = *data; 53065b390aaSDag-Erling Smørgrav d->rrsig_count = 0; 53165b390aaSDag-Erling Smørgrav ck->entry.data = d; 53265b390aaSDag-Erling Smørgrav 53365b390aaSDag-Erling Smørgrav /* derived from packed_rrset_ptr_fixup() with copying the data */ 53465b390aaSDag-Erling Smørgrav d->rr_len = (size_t*)((uint8_t*)d + sizeof(struct packed_rrset_data)); 53565b390aaSDag-Erling Smørgrav d->rr_data = (uint8_t**)&(d->rr_len[d->count]); 53665b390aaSDag-Erling Smørgrav d->rr_ttl = (time_t*)&(d->rr_data[d->count]); 53765b390aaSDag-Erling Smørgrav nextrdata = (uint8_t*)&(d->rr_ttl[d->count]); 53865b390aaSDag-Erling Smørgrav for(i=0; i<d->count; i++) { 53965b390aaSDag-Erling Smørgrav d->rr_len[i] = data->rr_len[i]; 54065b390aaSDag-Erling Smørgrav d->rr_ttl[i] = data->rr_ttl[i]; 54165b390aaSDag-Erling Smørgrav d->rr_data[i] = nextrdata; 54265b390aaSDag-Erling Smørgrav memcpy(d->rr_data[i], data->rr_data[i], data->rr_len[i]); 54365b390aaSDag-Erling Smørgrav nextrdata += d->rr_len[i]; 54465b390aaSDag-Erling Smørgrav } 54565b390aaSDag-Erling Smørgrav 54665b390aaSDag-Erling Smørgrav return ck; 54765b390aaSDag-Erling Smørgrav } 54865b390aaSDag-Erling Smørgrav 54965b390aaSDag-Erling Smørgrav int 55065b390aaSDag-Erling Smørgrav respip_init(struct module_env* env, int id) 55165b390aaSDag-Erling Smørgrav { 55265b390aaSDag-Erling Smørgrav (void)env; 55365b390aaSDag-Erling Smørgrav (void)id; 55465b390aaSDag-Erling Smørgrav return 1; 55565b390aaSDag-Erling Smørgrav } 55665b390aaSDag-Erling Smørgrav 55765b390aaSDag-Erling Smørgrav void 55865b390aaSDag-Erling Smørgrav respip_deinit(struct module_env* env, int id) 55965b390aaSDag-Erling Smørgrav { 56065b390aaSDag-Erling Smørgrav (void)env; 56165b390aaSDag-Erling Smørgrav (void)id; 56265b390aaSDag-Erling Smørgrav } 56365b390aaSDag-Erling Smørgrav 56465b390aaSDag-Erling Smørgrav /** Convert a packed AAAA or A RRset to sockaddr. */ 56565b390aaSDag-Erling Smørgrav static int 56665b390aaSDag-Erling Smørgrav rdata2sockaddr(const struct packed_rrset_data* rd, uint16_t rtype, size_t i, 56765b390aaSDag-Erling Smørgrav struct sockaddr_storage* ss, socklen_t* addrlenp) 56865b390aaSDag-Erling Smørgrav { 56965b390aaSDag-Erling Smørgrav /* unbound can accept and cache odd-length AAAA/A records, so we have 57065b390aaSDag-Erling Smørgrav * to validate the length. */ 57165b390aaSDag-Erling Smørgrav if(rtype == LDNS_RR_TYPE_A && rd->rr_len[i] == 6) { 57265b390aaSDag-Erling Smørgrav struct sockaddr_in* sa4 = (struct sockaddr_in*)ss; 57365b390aaSDag-Erling Smørgrav 57465b390aaSDag-Erling Smørgrav memset(sa4, 0, sizeof(*sa4)); 57565b390aaSDag-Erling Smørgrav sa4->sin_family = AF_INET; 57665b390aaSDag-Erling Smørgrav memcpy(&sa4->sin_addr, rd->rr_data[i] + 2, 57765b390aaSDag-Erling Smørgrav sizeof(sa4->sin_addr)); 57865b390aaSDag-Erling Smørgrav *addrlenp = sizeof(*sa4); 57965b390aaSDag-Erling Smørgrav return 1; 58065b390aaSDag-Erling Smørgrav } else if(rtype == LDNS_RR_TYPE_AAAA && rd->rr_len[i] == 18) { 58165b390aaSDag-Erling Smørgrav struct sockaddr_in6* sa6 = (struct sockaddr_in6*)ss; 58265b390aaSDag-Erling Smørgrav 58365b390aaSDag-Erling Smørgrav memset(sa6, 0, sizeof(*sa6)); 58465b390aaSDag-Erling Smørgrav sa6->sin6_family = AF_INET6; 58565b390aaSDag-Erling Smørgrav memcpy(&sa6->sin6_addr, rd->rr_data[i] + 2, 58665b390aaSDag-Erling Smørgrav sizeof(sa6->sin6_addr)); 58765b390aaSDag-Erling Smørgrav *addrlenp = sizeof(*sa6); 58865b390aaSDag-Erling Smørgrav return 1; 58965b390aaSDag-Erling Smørgrav } 59065b390aaSDag-Erling Smørgrav return 0; 59165b390aaSDag-Erling Smørgrav } 59265b390aaSDag-Erling Smørgrav 59365b390aaSDag-Erling Smørgrav /** 59465b390aaSDag-Erling Smørgrav * Search the given 'iptree' for response address information that matches 59565b390aaSDag-Erling Smørgrav * any of the IP addresses in an AAAA or A in the answer section of the 59665b390aaSDag-Erling Smørgrav * response (stored in 'rep'). If found, a pointer to the matched resp_addr 59765b390aaSDag-Erling Smørgrav * structure will be returned, and '*rrset_id' is set to the index in 59865b390aaSDag-Erling Smørgrav * rep->rrsets for the RRset that contains the matching IP address record 59965b390aaSDag-Erling Smørgrav * (the index is normally 0, but can be larger than that if this is a CNAME 60065b390aaSDag-Erling Smørgrav * chain or type-ANY response). 601091e9e46SCy Schubert * Returns resp_addr holding read lock. 60265b390aaSDag-Erling Smørgrav */ 603091e9e46SCy Schubert static struct resp_addr* 604091e9e46SCy Schubert respip_addr_lookup(const struct reply_info *rep, struct respip_set* rs, 60565b390aaSDag-Erling Smørgrav size_t* rrset_id) 60665b390aaSDag-Erling Smørgrav { 60765b390aaSDag-Erling Smørgrav size_t i; 60865b390aaSDag-Erling Smørgrav struct resp_addr* ra; 60965b390aaSDag-Erling Smørgrav struct sockaddr_storage ss; 61065b390aaSDag-Erling Smørgrav socklen_t addrlen; 61165b390aaSDag-Erling Smørgrav 612091e9e46SCy Schubert lock_rw_rdlock(&rs->lock); 61365b390aaSDag-Erling Smørgrav for(i=0; i<rep->an_numrrsets; i++) { 61465b390aaSDag-Erling Smørgrav size_t j; 61565b390aaSDag-Erling Smørgrav const struct packed_rrset_data* rd; 61665b390aaSDag-Erling Smørgrav uint16_t rtype = ntohs(rep->rrsets[i]->rk.type); 61765b390aaSDag-Erling Smørgrav 61865b390aaSDag-Erling Smørgrav if(rtype != LDNS_RR_TYPE_A && rtype != LDNS_RR_TYPE_AAAA) 61965b390aaSDag-Erling Smørgrav continue; 62065b390aaSDag-Erling Smørgrav rd = rep->rrsets[i]->entry.data; 62165b390aaSDag-Erling Smørgrav for(j = 0; j < rd->count; j++) { 62265b390aaSDag-Erling Smørgrav if(!rdata2sockaddr(rd, rtype, j, &ss, &addrlen)) 62365b390aaSDag-Erling Smørgrav continue; 624091e9e46SCy Schubert ra = (struct resp_addr*)addr_tree_lookup(&rs->ip_tree, 625091e9e46SCy Schubert &ss, addrlen); 62665b390aaSDag-Erling Smørgrav if(ra) { 62765b390aaSDag-Erling Smørgrav *rrset_id = i; 628091e9e46SCy Schubert lock_rw_rdlock(&ra->lock); 629091e9e46SCy Schubert lock_rw_unlock(&rs->lock); 63065b390aaSDag-Erling Smørgrav return ra; 63165b390aaSDag-Erling Smørgrav } 63265b390aaSDag-Erling Smørgrav } 63365b390aaSDag-Erling Smørgrav } 634091e9e46SCy Schubert lock_rw_unlock(&rs->lock); 63565b390aaSDag-Erling Smørgrav return NULL; 63665b390aaSDag-Erling Smørgrav } 63765b390aaSDag-Erling Smørgrav 63865b390aaSDag-Erling Smørgrav /* 63965b390aaSDag-Erling Smørgrav * Create a new reply_info based on 'rep'. The new info is based on 64065b390aaSDag-Erling Smørgrav * the passed 'rep', but ignores any rrsets except for the first 'an_numrrsets' 64165b390aaSDag-Erling Smørgrav * RRsets in the answer section. These answer rrsets are copied to the 64265b390aaSDag-Erling Smørgrav * new info, up to 'copy_rrsets' rrsets (which must not be larger than 64365b390aaSDag-Erling Smørgrav * 'an_numrrsets'). If an_numrrsets > copy_rrsets, the remaining rrsets array 64465b390aaSDag-Erling Smørgrav * entries will be kept empty so the caller can fill them later. When rrsets 64565b390aaSDag-Erling Smørgrav * are copied, they are shallow copied. The caller must ensure that the 64665b390aaSDag-Erling Smørgrav * copied rrsets are valid throughout its lifetime and must provide appropriate 64765b390aaSDag-Erling Smørgrav * mutex if it can be shared by multiple threads. 64865b390aaSDag-Erling Smørgrav */ 64965b390aaSDag-Erling Smørgrav static struct reply_info * 65065b390aaSDag-Erling Smørgrav make_new_reply_info(const struct reply_info* rep, struct regional* region, 65165b390aaSDag-Erling Smørgrav size_t an_numrrsets, size_t copy_rrsets) 65265b390aaSDag-Erling Smørgrav { 65365b390aaSDag-Erling Smørgrav struct reply_info* new_rep; 65465b390aaSDag-Erling Smørgrav size_t i; 65565b390aaSDag-Erling Smørgrav 65665b390aaSDag-Erling Smørgrav /* create a base struct. we specify 'insecure' security status as 65765b390aaSDag-Erling Smørgrav * the modified response won't be DNSSEC-valid. In our faked response 65865b390aaSDag-Erling Smørgrav * the authority and additional sections will be empty (except possible 65965b390aaSDag-Erling Smørgrav * EDNS0 OPT RR in the additional section appended on sending it out), 66065b390aaSDag-Erling Smørgrav * so the total number of RRsets is an_numrrsets. */ 66165b390aaSDag-Erling Smørgrav new_rep = construct_reply_info_base(region, rep->flags, 6624c75e3aaSDag-Erling Smørgrav rep->qdcount, rep->ttl, rep->prefetch_ttl, 6634c75e3aaSDag-Erling Smørgrav rep->serve_expired_ttl, an_numrrsets, 0, 0, an_numrrsets, 6644c75e3aaSDag-Erling Smørgrav sec_status_insecure); 66565b390aaSDag-Erling Smørgrav if(!new_rep) 66665b390aaSDag-Erling Smørgrav return NULL; 66765b390aaSDag-Erling Smørgrav if(!reply_info_alloc_rrset_keys(new_rep, NULL, region)) 66865b390aaSDag-Erling Smørgrav return NULL; 66965b390aaSDag-Erling Smørgrav for(i=0; i<copy_rrsets; i++) 67065b390aaSDag-Erling Smørgrav new_rep->rrsets[i] = rep->rrsets[i]; 67165b390aaSDag-Erling Smørgrav 67265b390aaSDag-Erling Smørgrav return new_rep; 67365b390aaSDag-Erling Smørgrav } 67465b390aaSDag-Erling Smørgrav 67565b390aaSDag-Erling Smørgrav /** 67665b390aaSDag-Erling Smørgrav * See if response-ip or tag data should override the original answer rrset 67765b390aaSDag-Erling Smørgrav * (which is rep->rrsets[rrset_id]) and if so override it. 67865b390aaSDag-Erling Smørgrav * This is (mostly) equivalent to localzone.c:local_data_answer() but for 67965b390aaSDag-Erling Smørgrav * response-ip actions. 68065b390aaSDag-Erling Smørgrav * Note that this function distinguishes error conditions from "success but 68165b390aaSDag-Erling Smørgrav * not overridden". This is because we want to avoid accidentally applying 68265b390aaSDag-Erling Smørgrav * the "no data" action in case of error. 68365b390aaSDag-Erling Smørgrav * @param action: action to apply 684091e9e46SCy Schubert * @param data: RRset to use for override 68565b390aaSDag-Erling Smørgrav * @param qtype: original query type 68665b390aaSDag-Erling Smørgrav * @param rep: original reply message 68765b390aaSDag-Erling Smørgrav * @param rrset_id: the rrset ID in 'rep' to which the action should apply 68865b390aaSDag-Erling Smørgrav * @param new_repp: see respip_rewrite_reply 68965b390aaSDag-Erling Smørgrav * @param tag: if >= 0 the tag ID used to determine the action and data 69065b390aaSDag-Erling Smørgrav * @param tag_datas: data corresponding to 'tag'. 69165b390aaSDag-Erling Smørgrav * @param tag_datas_size: size of 'tag_datas' 69265b390aaSDag-Erling Smørgrav * @param tagname: array of tag names, used for logging 69365b390aaSDag-Erling Smørgrav * @param num_tags: size of 'tagname', used for logging 69465b390aaSDag-Erling Smørgrav * @param redirect_rrsetp: ptr to redirect record 69565b390aaSDag-Erling Smørgrav * @param region: region for building new reply 69665b390aaSDag-Erling Smørgrav * @return 1 if overridden, 0 if not overridden, -1 on error. 69765b390aaSDag-Erling Smørgrav */ 69865b390aaSDag-Erling Smørgrav static int 699091e9e46SCy Schubert respip_data_answer(enum respip_action action, 700091e9e46SCy Schubert struct ub_packed_rrset_key* data, 70165b390aaSDag-Erling Smørgrav uint16_t qtype, const struct reply_info* rep, 70265b390aaSDag-Erling Smørgrav size_t rrset_id, struct reply_info** new_repp, int tag, 70365b390aaSDag-Erling Smørgrav struct config_strlist** tag_datas, size_t tag_datas_size, 70465b390aaSDag-Erling Smørgrav char* const* tagname, int num_tags, 70565b390aaSDag-Erling Smørgrav struct ub_packed_rrset_key** redirect_rrsetp, struct regional* region) 70665b390aaSDag-Erling Smørgrav { 707091e9e46SCy Schubert struct ub_packed_rrset_key* rp = data; 70865b390aaSDag-Erling Smørgrav struct reply_info* new_rep; 70965b390aaSDag-Erling Smørgrav *redirect_rrsetp = NULL; 71065b390aaSDag-Erling Smørgrav 71165b390aaSDag-Erling Smørgrav if(action == respip_redirect && tag != -1 && 71265b390aaSDag-Erling Smørgrav (size_t)tag<tag_datas_size && tag_datas[tag]) { 71365b390aaSDag-Erling Smørgrav struct query_info dataqinfo; 71465b390aaSDag-Erling Smørgrav struct ub_packed_rrset_key r; 71565b390aaSDag-Erling Smørgrav 71665b390aaSDag-Erling Smørgrav /* Extract parameters of the original answer rrset that can be 71765b390aaSDag-Erling Smørgrav * rewritten below, in the form of query_info. Note that these 71865b390aaSDag-Erling Smørgrav * can be different from the info of the original query if the 71965b390aaSDag-Erling Smørgrav * rrset is a CNAME target.*/ 72065b390aaSDag-Erling Smørgrav memset(&dataqinfo, 0, sizeof(dataqinfo)); 72165b390aaSDag-Erling Smørgrav dataqinfo.qname = rep->rrsets[rrset_id]->rk.dname; 72265b390aaSDag-Erling Smørgrav dataqinfo.qname_len = rep->rrsets[rrset_id]->rk.dname_len; 72365b390aaSDag-Erling Smørgrav dataqinfo.qtype = ntohs(rep->rrsets[rrset_id]->rk.type); 72465b390aaSDag-Erling Smørgrav dataqinfo.qclass = ntohs(rep->rrsets[rrset_id]->rk.rrset_class); 72565b390aaSDag-Erling Smørgrav 72665b390aaSDag-Erling Smørgrav memset(&r, 0, sizeof(r)); 72765b390aaSDag-Erling Smørgrav if(local_data_find_tag_datas(&dataqinfo, tag_datas[tag], &r, 72865b390aaSDag-Erling Smørgrav region)) { 72965b390aaSDag-Erling Smørgrav verbose(VERB_ALGO, 73065b390aaSDag-Erling Smørgrav "response-ip redirect with tag data [%d] %s", 73165b390aaSDag-Erling Smørgrav tag, (tag<num_tags?tagname[tag]:"null")); 73265b390aaSDag-Erling Smørgrav /* use copy_rrset() to 'normalize' memory layout */ 73365b390aaSDag-Erling Smørgrav rp = copy_rrset(&r, region); 73465b390aaSDag-Erling Smørgrav if(!rp) 73565b390aaSDag-Erling Smørgrav return -1; 73665b390aaSDag-Erling Smørgrav } 73765b390aaSDag-Erling Smørgrav } 73865b390aaSDag-Erling Smørgrav if(!rp) 73965b390aaSDag-Erling Smørgrav return 0; 74065b390aaSDag-Erling Smørgrav 74165b390aaSDag-Erling Smørgrav /* If we are using response-ip-data, we need to make a copy of rrset 74265b390aaSDag-Erling Smørgrav * to replace the rrset's dname. Note that, unlike local data, we 74365b390aaSDag-Erling Smørgrav * rename the dname for other actions than redirect. This is because 74465b390aaSDag-Erling Smørgrav * response-ip-data isn't associated to any specific name. */ 745091e9e46SCy Schubert if(rp == data) { 74665b390aaSDag-Erling Smørgrav rp = copy_rrset(rp, region); 74765b390aaSDag-Erling Smørgrav if(!rp) 74865b390aaSDag-Erling Smørgrav return -1; 74965b390aaSDag-Erling Smørgrav rp->rk.dname = rep->rrsets[rrset_id]->rk.dname; 75065b390aaSDag-Erling Smørgrav rp->rk.dname_len = rep->rrsets[rrset_id]->rk.dname_len; 75165b390aaSDag-Erling Smørgrav } 75265b390aaSDag-Erling Smørgrav 75365b390aaSDag-Erling Smørgrav /* Build a new reply with redirect rrset. We keep any preceding CNAMEs 75465b390aaSDag-Erling Smørgrav * and replace the address rrset that triggers the action. If it's 75565b390aaSDag-Erling Smørgrav * type ANY query, however, no other answer records should be kept 75665b390aaSDag-Erling Smørgrav * (note that it can't be a CNAME chain in this case due to 75765b390aaSDag-Erling Smørgrav * sanitizing). */ 75865b390aaSDag-Erling Smørgrav if(qtype == LDNS_RR_TYPE_ANY) 75965b390aaSDag-Erling Smørgrav rrset_id = 0; 76065b390aaSDag-Erling Smørgrav new_rep = make_new_reply_info(rep, region, rrset_id + 1, rrset_id); 76165b390aaSDag-Erling Smørgrav if(!new_rep) 76265b390aaSDag-Erling Smørgrav return -1; 76365b390aaSDag-Erling Smørgrav rp->rk.flags |= PACKED_RRSET_FIXEDTTL; /* avoid adjusting TTL */ 76465b390aaSDag-Erling Smørgrav new_rep->rrsets[rrset_id] = rp; 76565b390aaSDag-Erling Smørgrav 76665b390aaSDag-Erling Smørgrav *redirect_rrsetp = rp; 76765b390aaSDag-Erling Smørgrav *new_repp = new_rep; 76865b390aaSDag-Erling Smørgrav return 1; 76965b390aaSDag-Erling Smørgrav } 77065b390aaSDag-Erling Smørgrav 77165b390aaSDag-Erling Smørgrav /** 77265b390aaSDag-Erling Smørgrav * apply response ip action in case where no action data is provided. 77365b390aaSDag-Erling Smørgrav * this is similar to localzone.c:lz_zone_answer() but simplified due to 77465b390aaSDag-Erling Smørgrav * the characteristics of response ip: 77565b390aaSDag-Erling Smørgrav * - 'deny' variants will be handled at the caller side 77665b390aaSDag-Erling Smørgrav * - no specific processing for 'transparent' variants: unlike local zones, 77765b390aaSDag-Erling Smørgrav * there is no such a case of 'no data but name existing'. so all variants 77865b390aaSDag-Erling Smørgrav * just mean 'transparent if no data'. 77965b390aaSDag-Erling Smørgrav * @param qtype: query type 78065b390aaSDag-Erling Smørgrav * @param action: found action 78165b390aaSDag-Erling Smørgrav * @param rep: 78265b390aaSDag-Erling Smørgrav * @param new_repp 78365b390aaSDag-Erling Smørgrav * @param rrset_id 78465b390aaSDag-Erling Smørgrav * @param region: region for building new reply 78565b390aaSDag-Erling Smørgrav * @return 1 on success, 0 on error. 78665b390aaSDag-Erling Smørgrav */ 78765b390aaSDag-Erling Smørgrav static int 78865b390aaSDag-Erling Smørgrav respip_nodata_answer(uint16_t qtype, enum respip_action action, 78965b390aaSDag-Erling Smørgrav const struct reply_info *rep, size_t rrset_id, 79065b390aaSDag-Erling Smørgrav struct reply_info** new_repp, struct regional* region) 79165b390aaSDag-Erling Smørgrav { 79265b390aaSDag-Erling Smørgrav struct reply_info* new_rep; 79365b390aaSDag-Erling Smørgrav 79465b390aaSDag-Erling Smørgrav if(action == respip_refuse || action == respip_always_refuse) { 79565b390aaSDag-Erling Smørgrav new_rep = make_new_reply_info(rep, region, 0, 0); 79665b390aaSDag-Erling Smørgrav if(!new_rep) 79765b390aaSDag-Erling Smørgrav return 0; 79865b390aaSDag-Erling Smørgrav FLAGS_SET_RCODE(new_rep->flags, LDNS_RCODE_REFUSED); 79965b390aaSDag-Erling Smørgrav *new_repp = new_rep; 80065b390aaSDag-Erling Smørgrav return 1; 80165b390aaSDag-Erling Smørgrav } else if(action == respip_static || action == respip_redirect || 802e86b9096SDag-Erling Smørgrav action == respip_always_nxdomain || 803091e9e46SCy Schubert action == respip_always_nodata || 804e86b9096SDag-Erling Smørgrav action == respip_inform_redirect) { 80565b390aaSDag-Erling Smørgrav /* Since we don't know about other types of the owner name, 80665b390aaSDag-Erling Smørgrav * we generally return NOERROR/NODATA unless an NXDOMAIN action 80765b390aaSDag-Erling Smørgrav * is explicitly specified. */ 80865b390aaSDag-Erling Smørgrav int rcode = (action == respip_always_nxdomain)? 80965b390aaSDag-Erling Smørgrav LDNS_RCODE_NXDOMAIN:LDNS_RCODE_NOERROR; 81065b390aaSDag-Erling Smørgrav 81165b390aaSDag-Erling Smørgrav /* We should empty the answer section except for any preceding 81265b390aaSDag-Erling Smørgrav * CNAMEs (in that case rrset_id > 0). Type-ANY case is 81365b390aaSDag-Erling Smørgrav * special as noted in respip_data_answer(). */ 81465b390aaSDag-Erling Smørgrav if(qtype == LDNS_RR_TYPE_ANY) 81565b390aaSDag-Erling Smørgrav rrset_id = 0; 81665b390aaSDag-Erling Smørgrav new_rep = make_new_reply_info(rep, region, rrset_id, rrset_id); 81765b390aaSDag-Erling Smørgrav if(!new_rep) 81865b390aaSDag-Erling Smørgrav return 0; 81965b390aaSDag-Erling Smørgrav FLAGS_SET_RCODE(new_rep->flags, rcode); 82065b390aaSDag-Erling Smørgrav *new_repp = new_rep; 82165b390aaSDag-Erling Smørgrav return 1; 82265b390aaSDag-Erling Smørgrav } 82365b390aaSDag-Erling Smørgrav 82465b390aaSDag-Erling Smørgrav return 1; 82565b390aaSDag-Erling Smørgrav } 82665b390aaSDag-Erling Smørgrav 82765b390aaSDag-Erling Smørgrav /** Populate action info structure with the results of response-ip action 82865b390aaSDag-Erling Smørgrav * processing, iff as the result of response-ip processing we are actually 82965b390aaSDag-Erling Smørgrav * taking some action. Only action is set if action_only is true. 83065b390aaSDag-Erling Smørgrav * Returns true on success, false on failure. 83165b390aaSDag-Erling Smørgrav */ 83265b390aaSDag-Erling Smørgrav static int 83365b390aaSDag-Erling Smørgrav populate_action_info(struct respip_action_info* actinfo, 83465b390aaSDag-Erling Smørgrav enum respip_action action, const struct resp_addr* raddr, 83565b390aaSDag-Erling Smørgrav const struct ub_packed_rrset_key* ATTR_UNUSED(rrset), 83665b390aaSDag-Erling Smørgrav int ATTR_UNUSED(tag), const struct respip_set* ATTR_UNUSED(ipset), 837091e9e46SCy Schubert int ATTR_UNUSED(action_only), struct regional* region, int rpz_used, 838091e9e46SCy Schubert int rpz_log, char* log_name, int rpz_cname_override) 83965b390aaSDag-Erling Smørgrav { 84065b390aaSDag-Erling Smørgrav if(action == respip_none || !raddr) 84165b390aaSDag-Erling Smørgrav return 1; 84265b390aaSDag-Erling Smørgrav actinfo->action = action; 843091e9e46SCy Schubert actinfo->rpz_used = rpz_used; 844091e9e46SCy Schubert actinfo->rpz_log = rpz_log; 845091e9e46SCy Schubert actinfo->log_name = log_name; 846091e9e46SCy Schubert actinfo->rpz_cname_override = rpz_cname_override; 84765b390aaSDag-Erling Smørgrav 84865b390aaSDag-Erling Smørgrav /* for inform variants, make a copy of the matched address block for 84965b390aaSDag-Erling Smørgrav * later logging. We make a copy to proactively avoid disruption if 85065b390aaSDag-Erling Smørgrav * and when we allow a dynamic update to the respip tree. */ 851091e9e46SCy Schubert if(action == respip_inform || action == respip_inform_deny || 852091e9e46SCy Schubert rpz_used) { 85365b390aaSDag-Erling Smørgrav struct respip_addr_info* a = 85465b390aaSDag-Erling Smørgrav regional_alloc_zero(region, sizeof(*a)); 85565b390aaSDag-Erling Smørgrav if(!a) { 85665b390aaSDag-Erling Smørgrav log_err("out of memory"); 85765b390aaSDag-Erling Smørgrav return 0; 85865b390aaSDag-Erling Smørgrav } 85965b390aaSDag-Erling Smørgrav a->addr = raddr->node.addr; 86065b390aaSDag-Erling Smørgrav a->addrlen = raddr->node.addrlen; 86165b390aaSDag-Erling Smørgrav a->net = raddr->node.net; 86265b390aaSDag-Erling Smørgrav actinfo->addrinfo = a; 86365b390aaSDag-Erling Smørgrav } 86465b390aaSDag-Erling Smørgrav 86565b390aaSDag-Erling Smørgrav return 1; 86665b390aaSDag-Erling Smørgrav } 86765b390aaSDag-Erling Smørgrav 868091e9e46SCy Schubert static int 869091e9e46SCy Schubert respip_use_rpz(struct resp_addr* raddr, struct rpz* r, 870091e9e46SCy Schubert enum respip_action* action, 871091e9e46SCy Schubert struct ub_packed_rrset_key** data, int* rpz_log, char** log_name, 872091e9e46SCy Schubert int* rpz_cname_override, struct regional* region, int* is_rpz) 873091e9e46SCy Schubert { 874091e9e46SCy Schubert if(r->action_override == RPZ_DISABLED_ACTION) { 875091e9e46SCy Schubert *is_rpz = 0; 876091e9e46SCy Schubert return 1; 877091e9e46SCy Schubert } 878091e9e46SCy Schubert else if(r->action_override == RPZ_NO_OVERRIDE_ACTION) 879091e9e46SCy Schubert *action = raddr->action; 880091e9e46SCy Schubert else 881091e9e46SCy Schubert *action = rpz_action_to_respip_action(r->action_override); 882091e9e46SCy Schubert if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION && 883091e9e46SCy Schubert r->cname_override) { 884091e9e46SCy Schubert *data = r->cname_override; 885091e9e46SCy Schubert *rpz_cname_override = 1; 886091e9e46SCy Schubert } 887091e9e46SCy Schubert *rpz_log = r->log; 888091e9e46SCy Schubert if(r->log_name) 889091e9e46SCy Schubert if(!(*log_name = regional_strdup(region, r->log_name))) 890091e9e46SCy Schubert return 0; 891091e9e46SCy Schubert *is_rpz = 1; 892091e9e46SCy Schubert return 1; 893091e9e46SCy Schubert } 894091e9e46SCy Schubert 89565b390aaSDag-Erling Smørgrav int 89665b390aaSDag-Erling Smørgrav respip_rewrite_reply(const struct query_info* qinfo, 89765b390aaSDag-Erling Smørgrav const struct respip_client_info* cinfo, const struct reply_info* rep, 89865b390aaSDag-Erling Smørgrav struct reply_info** new_repp, struct respip_action_info* actinfo, 89965b390aaSDag-Erling Smørgrav struct ub_packed_rrset_key** alias_rrset, int search_only, 900091e9e46SCy Schubert struct regional* region, struct auth_zones* az) 90165b390aaSDag-Erling Smørgrav { 90265b390aaSDag-Erling Smørgrav const uint8_t* ctaglist; 90365b390aaSDag-Erling Smørgrav size_t ctaglen; 90465b390aaSDag-Erling Smørgrav const uint8_t* tag_actions; 90565b390aaSDag-Erling Smørgrav size_t tag_actions_size; 90665b390aaSDag-Erling Smørgrav struct config_strlist** tag_datas; 90765b390aaSDag-Erling Smørgrav size_t tag_datas_size; 90865b390aaSDag-Erling Smørgrav struct view* view = NULL; 90965b390aaSDag-Erling Smørgrav struct respip_set* ipset = NULL; 91065b390aaSDag-Erling Smørgrav size_t rrset_id = 0; 91165b390aaSDag-Erling Smørgrav enum respip_action action = respip_none; 91265b390aaSDag-Erling Smørgrav int tag = -1; 913091e9e46SCy Schubert struct resp_addr* raddr = NULL; 91465b390aaSDag-Erling Smørgrav int ret = 1; 91565b390aaSDag-Erling Smørgrav struct ub_packed_rrset_key* redirect_rrset = NULL; 916091e9e46SCy Schubert struct rpz* r; 917369c6923SCy Schubert struct auth_zone* a = NULL; 918091e9e46SCy Schubert struct ub_packed_rrset_key* data = NULL; 919091e9e46SCy Schubert int rpz_used = 0; 920091e9e46SCy Schubert int rpz_log = 0; 921091e9e46SCy Schubert int rpz_cname_override = 0; 922091e9e46SCy Schubert char* log_name = NULL; 92365b390aaSDag-Erling Smørgrav 92465b390aaSDag-Erling Smørgrav if(!cinfo) 92565b390aaSDag-Erling Smørgrav goto done; 92665b390aaSDag-Erling Smørgrav ctaglist = cinfo->taglist; 92765b390aaSDag-Erling Smørgrav ctaglen = cinfo->taglen; 92865b390aaSDag-Erling Smørgrav tag_actions = cinfo->tag_actions; 92965b390aaSDag-Erling Smørgrav tag_actions_size = cinfo->tag_actions_size; 93065b390aaSDag-Erling Smørgrav tag_datas = cinfo->tag_datas; 93165b390aaSDag-Erling Smørgrav tag_datas_size = cinfo->tag_datas_size; 93265b390aaSDag-Erling Smørgrav view = cinfo->view; 93365b390aaSDag-Erling Smørgrav ipset = cinfo->respip_set; 93465b390aaSDag-Erling Smørgrav 935091e9e46SCy Schubert log_assert(ipset); 936091e9e46SCy Schubert 93765b390aaSDag-Erling Smørgrav /** Try to use response-ip config from the view first; use 93865b390aaSDag-Erling Smørgrav * global response-ip config if we don't have the view or we don't 93965b390aaSDag-Erling Smørgrav * have the matching per-view config (and the view allows the use 94065b390aaSDag-Erling Smørgrav * of global data in this case). 94165b390aaSDag-Erling Smørgrav * Note that we lock the view even if we only use view members that 94265b390aaSDag-Erling Smørgrav * currently don't change after creation. This is for safety for 94365b390aaSDag-Erling Smørgrav * future possible changes as the view documentation seems to expect 94465b390aaSDag-Erling Smørgrav * any of its member can change in the view's lifetime. 94565b390aaSDag-Erling Smørgrav * Note also that we assume 'view' is valid in this function, which 94665b390aaSDag-Erling Smørgrav * should be safe (see unbound bug #1191) */ 94765b390aaSDag-Erling Smørgrav if(view) { 94865b390aaSDag-Erling Smørgrav lock_rw_rdlock(&view->lock); 94965b390aaSDag-Erling Smørgrav if(view->respip_set) { 95065b390aaSDag-Erling Smørgrav if((raddr = respip_addr_lookup(rep, 951091e9e46SCy Schubert view->respip_set, &rrset_id))) { 95265b390aaSDag-Erling Smørgrav /** for per-view respip directives the action 95365b390aaSDag-Erling Smørgrav * can only be direct (i.e. not tag-based) */ 95465b390aaSDag-Erling Smørgrav action = raddr->action; 95565b390aaSDag-Erling Smørgrav } 95665b390aaSDag-Erling Smørgrav } 95765b390aaSDag-Erling Smørgrav if(!raddr && !view->isfirst) 95865b390aaSDag-Erling Smørgrav goto done; 95925039b37SCy Schubert if(!raddr && view->isfirst) { 96025039b37SCy Schubert lock_rw_unlock(&view->lock); 96125039b37SCy Schubert view = NULL; 96225039b37SCy Schubert } 96365b390aaSDag-Erling Smørgrav } 964091e9e46SCy Schubert if(!raddr && (raddr = respip_addr_lookup(rep, ipset, 96565b390aaSDag-Erling Smørgrav &rrset_id))) { 96665b390aaSDag-Erling Smørgrav action = (enum respip_action)local_data_find_tag_action( 96765b390aaSDag-Erling Smørgrav raddr->taglist, raddr->taglen, ctaglist, ctaglen, 96865b390aaSDag-Erling Smørgrav tag_actions, tag_actions_size, 96965b390aaSDag-Erling Smørgrav (enum localzone_type)raddr->action, &tag, 97065b390aaSDag-Erling Smørgrav ipset->tagname, ipset->num_tags); 97165b390aaSDag-Erling Smørgrav } 972091e9e46SCy Schubert lock_rw_rdlock(&az->rpz_lock); 97325039b37SCy Schubert for(a = az->rpz_first; a && !raddr; a = a->rpz_az_next) { 97425039b37SCy Schubert lock_rw_rdlock(&a->lock); 97525039b37SCy Schubert r = a->rpz; 976091e9e46SCy Schubert if(!r->taglist || taglist_intersect(r->taglist, 977091e9e46SCy Schubert r->taglistlen, ctaglist, ctaglen)) { 978091e9e46SCy Schubert if((raddr = respip_addr_lookup(rep, 979091e9e46SCy Schubert r->respip_set, &rrset_id))) { 980091e9e46SCy Schubert if(!respip_use_rpz(raddr, r, &action, &data, 981091e9e46SCy Schubert &rpz_log, &log_name, &rpz_cname_override, 982091e9e46SCy Schubert region, &rpz_used)) { 983091e9e46SCy Schubert log_err("out of memory"); 984091e9e46SCy Schubert lock_rw_unlock(&raddr->lock); 98525039b37SCy Schubert lock_rw_unlock(&a->lock); 986091e9e46SCy Schubert lock_rw_unlock(&az->rpz_lock); 987091e9e46SCy Schubert return 0; 988091e9e46SCy Schubert } 98925039b37SCy Schubert if(rpz_used) { 99025039b37SCy Schubert /* break to make sure 'a' stays pointed 99125039b37SCy Schubert * to used auth_zone, and keeps lock */ 99225039b37SCy Schubert break; 99325039b37SCy Schubert } 994091e9e46SCy Schubert lock_rw_unlock(&raddr->lock); 995091e9e46SCy Schubert raddr = NULL; 996091e9e46SCy Schubert actinfo->rpz_disabled++; 997091e9e46SCy Schubert } 998091e9e46SCy Schubert } 99925039b37SCy Schubert lock_rw_unlock(&a->lock); 1000091e9e46SCy Schubert } 1001091e9e46SCy Schubert lock_rw_unlock(&az->rpz_lock); 100265b390aaSDag-Erling Smørgrav if(raddr && !search_only) { 100365b390aaSDag-Erling Smørgrav int result = 0; 100465b390aaSDag-Erling Smørgrav 100565b390aaSDag-Erling Smørgrav /* first, see if we have response-ip or tag action for the 100665b390aaSDag-Erling Smørgrav * action except for 'always' variants. */ 100765b390aaSDag-Erling Smørgrav if(action != respip_always_refuse 100865b390aaSDag-Erling Smørgrav && action != respip_always_transparent 100965b390aaSDag-Erling Smørgrav && action != respip_always_nxdomain 1010091e9e46SCy Schubert && action != respip_always_nodata 1011091e9e46SCy Schubert && action != respip_always_deny 1012091e9e46SCy Schubert && (result = respip_data_answer(action, 1013091e9e46SCy Schubert (data) ? data : raddr->data, qinfo->qtype, rep, 1014091e9e46SCy Schubert rrset_id, new_repp, tag, tag_datas, tag_datas_size, 1015091e9e46SCy Schubert ipset->tagname, ipset->num_tags, &redirect_rrset, 1016091e9e46SCy Schubert region)) < 0) { 101765b390aaSDag-Erling Smørgrav ret = 0; 101865b390aaSDag-Erling Smørgrav goto done; 101965b390aaSDag-Erling Smørgrav } 102065b390aaSDag-Erling Smørgrav 102165b390aaSDag-Erling Smørgrav /* if no action data applied, take action specific to the 102265b390aaSDag-Erling Smørgrav * action without data. */ 102365b390aaSDag-Erling Smørgrav if(!result && !respip_nodata_answer(qinfo->qtype, action, rep, 102465b390aaSDag-Erling Smørgrav rrset_id, new_repp, region)) { 102565b390aaSDag-Erling Smørgrav ret = 0; 102665b390aaSDag-Erling Smørgrav goto done; 102765b390aaSDag-Erling Smørgrav } 102865b390aaSDag-Erling Smørgrav } 102965b390aaSDag-Erling Smørgrav done: 103065b390aaSDag-Erling Smørgrav if(view) { 103165b390aaSDag-Erling Smørgrav lock_rw_unlock(&view->lock); 103265b390aaSDag-Erling Smørgrav } 103365b390aaSDag-Erling Smørgrav if(ret) { 103465b390aaSDag-Erling Smørgrav /* If we're redirecting the original answer to a 103565b390aaSDag-Erling Smørgrav * CNAME, record the CNAME rrset so the caller can take 103665b390aaSDag-Erling Smørgrav * the appropriate action. Note that we don't check the 103765b390aaSDag-Erling Smørgrav * action type; it should normally be 'redirect', but it 103865b390aaSDag-Erling Smørgrav * can be of other type when a data-dependent tag action 103965b390aaSDag-Erling Smørgrav * uses redirect response-ip data. 104065b390aaSDag-Erling Smørgrav */ 104165b390aaSDag-Erling Smørgrav if(redirect_rrset && 104265b390aaSDag-Erling Smørgrav redirect_rrset->rk.type == ntohs(LDNS_RR_TYPE_CNAME) && 104365b390aaSDag-Erling Smørgrav qinfo->qtype != LDNS_RR_TYPE_ANY) 104465b390aaSDag-Erling Smørgrav *alias_rrset = redirect_rrset; 104565b390aaSDag-Erling Smørgrav /* on success, populate respip result structure */ 104665b390aaSDag-Erling Smørgrav ret = populate_action_info(actinfo, action, raddr, 1047091e9e46SCy Schubert redirect_rrset, tag, ipset, search_only, region, 1048091e9e46SCy Schubert rpz_used, rpz_log, log_name, rpz_cname_override); 1049091e9e46SCy Schubert } 1050091e9e46SCy Schubert if(raddr) { 1051091e9e46SCy Schubert lock_rw_unlock(&raddr->lock); 105265b390aaSDag-Erling Smørgrav } 105325039b37SCy Schubert if(rpz_used) { 105425039b37SCy Schubert lock_rw_unlock(&a->lock); 105525039b37SCy Schubert } 105665b390aaSDag-Erling Smørgrav return ret; 105765b390aaSDag-Erling Smørgrav } 105865b390aaSDag-Erling Smørgrav 105965b390aaSDag-Erling Smørgrav static int 106065b390aaSDag-Erling Smørgrav generate_cname_request(struct module_qstate* qstate, 106165b390aaSDag-Erling Smørgrav struct ub_packed_rrset_key* alias_rrset) 106265b390aaSDag-Erling Smørgrav { 106365b390aaSDag-Erling Smørgrav struct module_qstate* subq = NULL; 106465b390aaSDag-Erling Smørgrav struct query_info subqi; 106565b390aaSDag-Erling Smørgrav 106665b390aaSDag-Erling Smørgrav memset(&subqi, 0, sizeof(subqi)); 106765b390aaSDag-Erling Smørgrav get_cname_target(alias_rrset, &subqi.qname, &subqi.qname_len); 106865b390aaSDag-Erling Smørgrav if(!subqi.qname) 106965b390aaSDag-Erling Smørgrav return 0; /* unexpected: not a valid CNAME RDATA */ 107065b390aaSDag-Erling Smørgrav subqi.qtype = qstate->qinfo.qtype; 107165b390aaSDag-Erling Smørgrav subqi.qclass = qstate->qinfo.qclass; 107265b390aaSDag-Erling Smørgrav fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub)); 107365b390aaSDag-Erling Smørgrav return (*qstate->env->attach_sub)(qstate, &subqi, BIT_RD, 0, 0, &subq); 107465b390aaSDag-Erling Smørgrav } 107565b390aaSDag-Erling Smørgrav 107665b390aaSDag-Erling Smørgrav void 107765b390aaSDag-Erling Smørgrav respip_operate(struct module_qstate* qstate, enum module_ev event, int id, 107865b390aaSDag-Erling Smørgrav struct outbound_entry* outbound) 107965b390aaSDag-Erling Smørgrav { 108065b390aaSDag-Erling Smørgrav struct respip_qstate* rq = (struct respip_qstate*)qstate->minfo[id]; 108165b390aaSDag-Erling Smørgrav 108265b390aaSDag-Erling Smørgrav log_query_info(VERB_QUERY, "respip operate: query", &qstate->qinfo); 108365b390aaSDag-Erling Smørgrav (void)outbound; 108465b390aaSDag-Erling Smørgrav 108565b390aaSDag-Erling Smørgrav if(event == module_event_new || event == module_event_pass) { 108665b390aaSDag-Erling Smørgrav if(!rq) { 108765b390aaSDag-Erling Smørgrav rq = regional_alloc_zero(qstate->region, sizeof(*rq)); 108865b390aaSDag-Erling Smørgrav if(!rq) 108965b390aaSDag-Erling Smørgrav goto servfail; 109065b390aaSDag-Erling Smørgrav rq->state = RESPIP_INIT; 109165b390aaSDag-Erling Smørgrav qstate->minfo[id] = rq; 109265b390aaSDag-Erling Smørgrav } 109365b390aaSDag-Erling Smørgrav if(rq->state == RESPIP_SUBQUERY_FINISHED) { 109465b390aaSDag-Erling Smørgrav qstate->ext_state[id] = module_finished; 109565b390aaSDag-Erling Smørgrav return; 109665b390aaSDag-Erling Smørgrav } 109765b390aaSDag-Erling Smørgrav verbose(VERB_ALGO, "respip: pass to next module"); 109865b390aaSDag-Erling Smørgrav qstate->ext_state[id] = module_wait_module; 109965b390aaSDag-Erling Smørgrav } else if(event == module_event_moddone) { 110065b390aaSDag-Erling Smørgrav /* If the reply may be subject to response-ip rewriting 110165b390aaSDag-Erling Smørgrav * according to the query type, check the actions. If a 110265b390aaSDag-Erling Smørgrav * rewrite is necessary, we'll replace the reply in qstate 110365b390aaSDag-Erling Smørgrav * with the new one. */ 110465b390aaSDag-Erling Smørgrav enum module_ext_state next_state = module_finished; 110565b390aaSDag-Erling Smørgrav 110665b390aaSDag-Erling Smørgrav if((qstate->qinfo.qtype == LDNS_RR_TYPE_A || 110765b390aaSDag-Erling Smørgrav qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA || 110865b390aaSDag-Erling Smørgrav qstate->qinfo.qtype == LDNS_RR_TYPE_ANY) && 110965b390aaSDag-Erling Smørgrav qstate->return_msg && qstate->return_msg->rep) { 111065b390aaSDag-Erling Smørgrav struct reply_info* new_rep = qstate->return_msg->rep; 111165b390aaSDag-Erling Smørgrav struct ub_packed_rrset_key* alias_rrset = NULL; 1112369c6923SCy Schubert struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL}; 1113091e9e46SCy Schubert actinfo.action = respip_none; 111465b390aaSDag-Erling Smørgrav 111565b390aaSDag-Erling Smørgrav if(!respip_rewrite_reply(&qstate->qinfo, 111665b390aaSDag-Erling Smørgrav qstate->client_info, qstate->return_msg->rep, 111765b390aaSDag-Erling Smørgrav &new_rep, &actinfo, &alias_rrset, 0, 1118091e9e46SCy Schubert qstate->region, qstate->env->auth_zones)) { 111965b390aaSDag-Erling Smørgrav goto servfail; 112065b390aaSDag-Erling Smørgrav } 112165b390aaSDag-Erling Smørgrav if(actinfo.action != respip_none) { 112265b390aaSDag-Erling Smørgrav /* save action info for logging on a 112365b390aaSDag-Erling Smørgrav * per-front-end-query basis */ 112465b390aaSDag-Erling Smørgrav if(!(qstate->respip_action_info = 112565b390aaSDag-Erling Smørgrav regional_alloc_init(qstate->region, 112665b390aaSDag-Erling Smørgrav &actinfo, sizeof(actinfo)))) 112765b390aaSDag-Erling Smørgrav { 112865b390aaSDag-Erling Smørgrav log_err("out of memory"); 112965b390aaSDag-Erling Smørgrav goto servfail; 113065b390aaSDag-Erling Smørgrav } 113165b390aaSDag-Erling Smørgrav } else { 113265b390aaSDag-Erling Smørgrav qstate->respip_action_info = NULL; 113365b390aaSDag-Erling Smørgrav } 1134091e9e46SCy Schubert if (actinfo.action == respip_always_deny || 1135091e9e46SCy Schubert (new_rep == qstate->return_msg->rep && 113665b390aaSDag-Erling Smørgrav (actinfo.action == respip_deny || 1137091e9e46SCy Schubert actinfo.action == respip_inform_deny))) { 113865b390aaSDag-Erling Smørgrav /* for deny-variant actions (unless response-ip 113965b390aaSDag-Erling Smørgrav * data is applied), mark the query state so 114065b390aaSDag-Erling Smørgrav * the response will be dropped for all 114165b390aaSDag-Erling Smørgrav * clients. */ 114265b390aaSDag-Erling Smørgrav qstate->is_drop = 1; 114365b390aaSDag-Erling Smørgrav } else if(alias_rrset) { 114465b390aaSDag-Erling Smørgrav if(!generate_cname_request(qstate, alias_rrset)) 114565b390aaSDag-Erling Smørgrav goto servfail; 114665b390aaSDag-Erling Smørgrav next_state = module_wait_subquery; 114765b390aaSDag-Erling Smørgrav } 114865b390aaSDag-Erling Smørgrav qstate->return_msg->rep = new_rep; 114965b390aaSDag-Erling Smørgrav } 115065b390aaSDag-Erling Smørgrav qstate->ext_state[id] = next_state; 115165b390aaSDag-Erling Smørgrav } else 115265b390aaSDag-Erling Smørgrav qstate->ext_state[id] = module_finished; 115365b390aaSDag-Erling Smørgrav 115465b390aaSDag-Erling Smørgrav return; 115565b390aaSDag-Erling Smørgrav 115665b390aaSDag-Erling Smørgrav servfail: 115765b390aaSDag-Erling Smørgrav qstate->return_rcode = LDNS_RCODE_SERVFAIL; 115865b390aaSDag-Erling Smørgrav qstate->return_msg = NULL; 115965b390aaSDag-Erling Smørgrav } 116065b390aaSDag-Erling Smørgrav 116165b390aaSDag-Erling Smørgrav int 116265b390aaSDag-Erling Smørgrav respip_merge_cname(struct reply_info* base_rep, 116365b390aaSDag-Erling Smørgrav const struct query_info* qinfo, const struct reply_info* tgt_rep, 116465b390aaSDag-Erling Smørgrav const struct respip_client_info* cinfo, int must_validate, 1165091e9e46SCy Schubert struct reply_info** new_repp, struct regional* region, 1166091e9e46SCy Schubert struct auth_zones* az) 116765b390aaSDag-Erling Smørgrav { 116865b390aaSDag-Erling Smørgrav struct reply_info* new_rep; 116965b390aaSDag-Erling Smørgrav struct reply_info* tmp_rep = NULL; /* just a placeholder */ 117065b390aaSDag-Erling Smørgrav struct ub_packed_rrset_key* alias_rrset = NULL; /* ditto */ 117165b390aaSDag-Erling Smørgrav uint16_t tgt_rcode; 117265b390aaSDag-Erling Smørgrav size_t i, j; 1173369c6923SCy Schubert struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL}; 1174091e9e46SCy Schubert actinfo.action = respip_none; 117565b390aaSDag-Erling Smørgrav 117665b390aaSDag-Erling Smørgrav /* If the query for the CNAME target would result in an unusual rcode, 117765b390aaSDag-Erling Smørgrav * we generally translate it as a failure for the base query 117865b390aaSDag-Erling Smørgrav * (which would then be translated into SERVFAIL). The only exception 117965b390aaSDag-Erling Smørgrav * is NXDOMAIN and YXDOMAIN, which are passed to the end client(s). 118065b390aaSDag-Erling Smørgrav * The YXDOMAIN case would be rare but still possible (when 118165b390aaSDag-Erling Smørgrav * DNSSEC-validated DNAME has been cached but synthesizing CNAME 118265b390aaSDag-Erling Smørgrav * can't be generated due to length limitation) */ 118365b390aaSDag-Erling Smørgrav tgt_rcode = FLAGS_GET_RCODE(tgt_rep->flags); 118465b390aaSDag-Erling Smørgrav if((tgt_rcode != LDNS_RCODE_NOERROR && 118565b390aaSDag-Erling Smørgrav tgt_rcode != LDNS_RCODE_NXDOMAIN && 118665b390aaSDag-Erling Smørgrav tgt_rcode != LDNS_RCODE_YXDOMAIN) || 118765b390aaSDag-Erling Smørgrav (must_validate && tgt_rep->security <= sec_status_bogus)) { 118865b390aaSDag-Erling Smørgrav return 0; 118965b390aaSDag-Erling Smørgrav } 119065b390aaSDag-Erling Smørgrav 119165b390aaSDag-Erling Smørgrav /* see if the target reply would be subject to a response-ip action. */ 119265b390aaSDag-Erling Smørgrav if(!respip_rewrite_reply(qinfo, cinfo, tgt_rep, &tmp_rep, &actinfo, 1193091e9e46SCy Schubert &alias_rrset, 1, region, az)) 119465b390aaSDag-Erling Smørgrav return 0; 119565b390aaSDag-Erling Smørgrav if(actinfo.action != respip_none) { 119665b390aaSDag-Erling Smørgrav log_info("CNAME target of redirect response-ip action would " 119765b390aaSDag-Erling Smørgrav "be subject to response-ip action, too; stripped"); 119865b390aaSDag-Erling Smørgrav *new_repp = base_rep; 119965b390aaSDag-Erling Smørgrav return 1; 120065b390aaSDag-Erling Smørgrav } 120165b390aaSDag-Erling Smørgrav 120265b390aaSDag-Erling Smørgrav /* Append target reply to the base. Since we cannot assume 120365b390aaSDag-Erling Smørgrav * tgt_rep->rrsets is valid throughout the lifetime of new_rep 120465b390aaSDag-Erling Smørgrav * or it can be safely shared by multiple threads, we need to make a 120565b390aaSDag-Erling Smørgrav * deep copy. */ 120665b390aaSDag-Erling Smørgrav new_rep = make_new_reply_info(base_rep, region, 120765b390aaSDag-Erling Smørgrav base_rep->an_numrrsets + tgt_rep->an_numrrsets, 120865b390aaSDag-Erling Smørgrav base_rep->an_numrrsets); 120965b390aaSDag-Erling Smørgrav if(!new_rep) 121065b390aaSDag-Erling Smørgrav return 0; 121165b390aaSDag-Erling Smørgrav for(i=0,j=base_rep->an_numrrsets; i<tgt_rep->an_numrrsets; i++,j++) { 121265b390aaSDag-Erling Smørgrav new_rep->rrsets[j] = copy_rrset(tgt_rep->rrsets[i], region); 121365b390aaSDag-Erling Smørgrav if(!new_rep->rrsets[j]) 121465b390aaSDag-Erling Smørgrav return 0; 121565b390aaSDag-Erling Smørgrav } 121665b390aaSDag-Erling Smørgrav 121765b390aaSDag-Erling Smørgrav FLAGS_SET_RCODE(new_rep->flags, tgt_rcode); 121865b390aaSDag-Erling Smørgrav *new_repp = new_rep; 121965b390aaSDag-Erling Smørgrav return 1; 122065b390aaSDag-Erling Smørgrav } 122165b390aaSDag-Erling Smørgrav 122265b390aaSDag-Erling Smørgrav void 122365b390aaSDag-Erling Smørgrav respip_inform_super(struct module_qstate* qstate, int id, 122465b390aaSDag-Erling Smørgrav struct module_qstate* super) 122565b390aaSDag-Erling Smørgrav { 122665b390aaSDag-Erling Smørgrav struct respip_qstate* rq = (struct respip_qstate*)super->minfo[id]; 122765b390aaSDag-Erling Smørgrav struct reply_info* new_rep = NULL; 122865b390aaSDag-Erling Smørgrav 122965b390aaSDag-Erling Smørgrav rq->state = RESPIP_SUBQUERY_FINISHED; 123065b390aaSDag-Erling Smørgrav 123165b390aaSDag-Erling Smørgrav /* respip subquery should have always been created with a valid reply 123265b390aaSDag-Erling Smørgrav * in super. */ 123365b390aaSDag-Erling Smørgrav log_assert(super->return_msg && super->return_msg->rep); 123465b390aaSDag-Erling Smørgrav 123565b390aaSDag-Erling Smørgrav /* return_msg can be NULL when, e.g., the sub query resulted in 123665b390aaSDag-Erling Smørgrav * SERVFAIL, in which case we regard it as a failure of the original 123765b390aaSDag-Erling Smørgrav * query. Other checks are probably redundant, but we check them 123865b390aaSDag-Erling Smørgrav * for safety. */ 123965b390aaSDag-Erling Smørgrav if(!qstate->return_msg || !qstate->return_msg->rep || 124065b390aaSDag-Erling Smørgrav qstate->return_rcode != LDNS_RCODE_NOERROR) 124165b390aaSDag-Erling Smørgrav goto fail; 124265b390aaSDag-Erling Smørgrav 124365b390aaSDag-Erling Smørgrav if(!respip_merge_cname(super->return_msg->rep, &qstate->qinfo, 124465b390aaSDag-Erling Smørgrav qstate->return_msg->rep, super->client_info, 1245091e9e46SCy Schubert super->env->need_to_validate, &new_rep, super->region, 1246091e9e46SCy Schubert qstate->env->auth_zones)) 124765b390aaSDag-Erling Smørgrav goto fail; 124865b390aaSDag-Erling Smørgrav super->return_msg->rep = new_rep; 124965b390aaSDag-Erling Smørgrav return; 125065b390aaSDag-Erling Smørgrav 125165b390aaSDag-Erling Smørgrav fail: 125265b390aaSDag-Erling Smørgrav super->return_rcode = LDNS_RCODE_SERVFAIL; 125365b390aaSDag-Erling Smørgrav super->return_msg = NULL; 125465b390aaSDag-Erling Smørgrav return; 125565b390aaSDag-Erling Smørgrav } 125665b390aaSDag-Erling Smørgrav 125765b390aaSDag-Erling Smørgrav void 125865b390aaSDag-Erling Smørgrav respip_clear(struct module_qstate* qstate, int id) 125965b390aaSDag-Erling Smørgrav { 126065b390aaSDag-Erling Smørgrav qstate->minfo[id] = NULL; 126165b390aaSDag-Erling Smørgrav } 126265b390aaSDag-Erling Smørgrav 126365b390aaSDag-Erling Smørgrav size_t 126465b390aaSDag-Erling Smørgrav respip_get_mem(struct module_env* env, int id) 126565b390aaSDag-Erling Smørgrav { 126665b390aaSDag-Erling Smørgrav (void)env; 126765b390aaSDag-Erling Smørgrav (void)id; 126865b390aaSDag-Erling Smørgrav return 0; 126965b390aaSDag-Erling Smørgrav } 127065b390aaSDag-Erling Smørgrav 127165b390aaSDag-Erling Smørgrav /** 127265b390aaSDag-Erling Smørgrav * The response-ip function block 127365b390aaSDag-Erling Smørgrav */ 127465b390aaSDag-Erling Smørgrav static struct module_func_block respip_block = { 127565b390aaSDag-Erling Smørgrav "respip", 127665b390aaSDag-Erling Smørgrav &respip_init, &respip_deinit, &respip_operate, &respip_inform_super, 127765b390aaSDag-Erling Smørgrav &respip_clear, &respip_get_mem 127865b390aaSDag-Erling Smørgrav }; 127965b390aaSDag-Erling Smørgrav 128065b390aaSDag-Erling Smørgrav struct module_func_block* 128165b390aaSDag-Erling Smørgrav respip_get_funcblock(void) 128265b390aaSDag-Erling Smørgrav { 128365b390aaSDag-Erling Smørgrav return &respip_block; 128465b390aaSDag-Erling Smørgrav } 128565b390aaSDag-Erling Smørgrav 128665b390aaSDag-Erling Smørgrav enum respip_action 128765b390aaSDag-Erling Smørgrav resp_addr_get_action(const struct resp_addr* addr) 128865b390aaSDag-Erling Smørgrav { 128965b390aaSDag-Erling Smørgrav return addr ? addr->action : respip_none; 129065b390aaSDag-Erling Smørgrav } 129165b390aaSDag-Erling Smørgrav 129265b390aaSDag-Erling Smørgrav struct ub_packed_rrset_key* 129365b390aaSDag-Erling Smørgrav resp_addr_get_rrset(struct resp_addr* addr) 129465b390aaSDag-Erling Smørgrav { 129565b390aaSDag-Erling Smørgrav return addr ? addr->data : NULL; 129665b390aaSDag-Erling Smørgrav } 129765b390aaSDag-Erling Smørgrav 129865b390aaSDag-Erling Smørgrav int 129965b390aaSDag-Erling Smørgrav respip_set_is_empty(const struct respip_set* set) 130065b390aaSDag-Erling Smørgrav { 130165b390aaSDag-Erling Smørgrav return set ? set->ip_tree.count == 0 : 1; 130265b390aaSDag-Erling Smørgrav } 130365b390aaSDag-Erling Smørgrav 130465b390aaSDag-Erling Smørgrav void 1305091e9e46SCy Schubert respip_inform_print(struct respip_action_info* respip_actinfo, uint8_t* qname, 130665b390aaSDag-Erling Smørgrav uint16_t qtype, uint16_t qclass, struct local_rrset* local_alias, 130765b390aaSDag-Erling Smørgrav struct comm_reply* repinfo) 130865b390aaSDag-Erling Smørgrav { 130965b390aaSDag-Erling Smørgrav char srcip[128], respip[128], txt[512]; 131065b390aaSDag-Erling Smørgrav unsigned port; 1311091e9e46SCy Schubert struct respip_addr_info* respip_addr = respip_actinfo->addrinfo; 1312091e9e46SCy Schubert size_t txtlen = 0; 1313091e9e46SCy Schubert const char* actionstr = NULL; 131465b390aaSDag-Erling Smørgrav 131565b390aaSDag-Erling Smørgrav if(local_alias) 131665b390aaSDag-Erling Smørgrav qname = local_alias->rrset->rk.dname; 131765b390aaSDag-Erling Smørgrav port = (unsigned)((repinfo->addr.ss_family == AF_INET) ? 131865b390aaSDag-Erling Smørgrav ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port) : 131965b390aaSDag-Erling Smørgrav ntohs(((struct sockaddr_in6*)&repinfo->addr)->sin6_port)); 132065b390aaSDag-Erling Smørgrav addr_to_str(&repinfo->addr, repinfo->addrlen, srcip, sizeof(srcip)); 132165b390aaSDag-Erling Smørgrav addr_to_str(&respip_addr->addr, respip_addr->addrlen, 132265b390aaSDag-Erling Smørgrav respip, sizeof(respip)); 1323091e9e46SCy Schubert if(respip_actinfo->rpz_log) { 1324091e9e46SCy Schubert txtlen += snprintf(txt+txtlen, sizeof(txt)-txtlen, "%s", 1325091e9e46SCy Schubert "RPZ applied "); 1326091e9e46SCy Schubert if(respip_actinfo->rpz_cname_override) 1327091e9e46SCy Schubert actionstr = rpz_action_to_string( 1328091e9e46SCy Schubert RPZ_CNAME_OVERRIDE_ACTION); 1329091e9e46SCy Schubert else 1330091e9e46SCy Schubert actionstr = rpz_action_to_string( 1331091e9e46SCy Schubert respip_action_to_rpz_action( 1332091e9e46SCy Schubert respip_actinfo->action)); 1333091e9e46SCy Schubert } 1334091e9e46SCy Schubert if(respip_actinfo->log_name) { 1335091e9e46SCy Schubert txtlen += snprintf(txt+txtlen, sizeof(txt)-txtlen, 1336091e9e46SCy Schubert "[%s] ", respip_actinfo->log_name); 1337091e9e46SCy Schubert } 1338091e9e46SCy Schubert snprintf(txt+txtlen, sizeof(txt)-txtlen, 1339091e9e46SCy Schubert "%s/%d %s %s@%u", respip, respip_addr->net, 1340091e9e46SCy Schubert (actionstr) ? actionstr : "inform", srcip, port); 13410eefd307SCy Schubert log_nametypeclass(NO_VERBOSE, txt, qname, qtype, qclass); 134265b390aaSDag-Erling Smørgrav } 1343