12be9e038Ssthen /* 22be9e038Ssthen * respip/respip.c - filtering response IP module 32be9e038Ssthen */ 42be9e038Ssthen 52be9e038Ssthen /** 62be9e038Ssthen * \file 72be9e038Ssthen * 82be9e038Ssthen * This file contains a module that inspects a result of recursive resolution 92be9e038Ssthen * to see if any IP address record should trigger a special action. 102be9e038Ssthen * If applicable these actions can modify the original response. 112be9e038Ssthen */ 122be9e038Ssthen #include "config.h" 132be9e038Ssthen 142be9e038Ssthen #include "services/localzone.h" 15eaf2578eSsthen #include "services/authzone.h" 162be9e038Ssthen #include "services/cache/dns.h" 172be9e038Ssthen #include "sldns/str2wire.h" 182be9e038Ssthen #include "util/config_file.h" 192be9e038Ssthen #include "util/fptr_wlist.h" 202be9e038Ssthen #include "util/module.h" 212be9e038Ssthen #include "util/net_help.h" 222be9e038Ssthen #include "util/regional.h" 232be9e038Ssthen #include "util/data/msgreply.h" 242be9e038Ssthen #include "util/storage/dnstree.h" 252be9e038Ssthen #include "respip/respip.h" 262be9e038Ssthen #include "services/view.h" 272be9e038Ssthen #include "sldns/rrdef.h" 28e21c60efSsthen #include "util/data/dname.h" 292be9e038Ssthen 302be9e038Ssthen 312be9e038Ssthen /** Subset of resp_addr.node, used for inform-variant logging */ 322be9e038Ssthen struct respip_addr_info { 332be9e038Ssthen struct sockaddr_storage addr; 342be9e038Ssthen socklen_t addrlen; 352be9e038Ssthen int net; 362be9e038Ssthen }; 372be9e038Ssthen 382be9e038Ssthen /** Query state regarding the response-ip module. */ 392be9e038Ssthen enum respip_state { 402be9e038Ssthen /** 412be9e038Ssthen * The general state. Unless CNAME chasing takes place, all processing 422be9e038Ssthen * is completed in this state without any other asynchronous event. 432be9e038Ssthen */ 442be9e038Ssthen RESPIP_INIT = 0, 452be9e038Ssthen 462be9e038Ssthen /** 472be9e038Ssthen * A subquery for CNAME chasing is completed. 482be9e038Ssthen */ 492be9e038Ssthen RESPIP_SUBQUERY_FINISHED 502be9e038Ssthen }; 512be9e038Ssthen 522be9e038Ssthen /** Per query state for the response-ip module. */ 532be9e038Ssthen struct respip_qstate { 542be9e038Ssthen enum respip_state state; 552be9e038Ssthen }; 562be9e038Ssthen 572be9e038Ssthen struct respip_set* 582be9e038Ssthen respip_set_create(void) 592be9e038Ssthen { 602be9e038Ssthen struct respip_set* set = calloc(1, sizeof(*set)); 612be9e038Ssthen if(!set) 622be9e038Ssthen return NULL; 632be9e038Ssthen set->region = regional_create(); 642be9e038Ssthen if(!set->region) { 652be9e038Ssthen free(set); 662be9e038Ssthen return NULL; 672be9e038Ssthen } 682be9e038Ssthen addr_tree_init(&set->ip_tree); 69eaf2578eSsthen lock_rw_init(&set->lock); 702be9e038Ssthen return set; 712be9e038Ssthen } 722be9e038Ssthen 73eaf2578eSsthen /** helper traverse to delete resp_addr nodes */ 74eaf2578eSsthen static void 75eaf2578eSsthen resp_addr_del(rbnode_type* n, void* ATTR_UNUSED(arg)) 76eaf2578eSsthen { 77eaf2578eSsthen struct resp_addr* r = (struct resp_addr*)n->key; 78eaf2578eSsthen lock_rw_destroy(&r->lock); 79eaf2578eSsthen #ifdef THREADS_DISABLED 80eaf2578eSsthen (void)r; 81eaf2578eSsthen #endif 82eaf2578eSsthen } 83eaf2578eSsthen 842be9e038Ssthen void 852be9e038Ssthen respip_set_delete(struct respip_set* set) 862be9e038Ssthen { 872be9e038Ssthen if(!set) 882be9e038Ssthen return; 89eaf2578eSsthen lock_rw_destroy(&set->lock); 90eaf2578eSsthen traverse_postorder(&set->ip_tree, resp_addr_del, NULL); 912be9e038Ssthen regional_destroy(set->region); 922be9e038Ssthen free(set); 932be9e038Ssthen } 942be9e038Ssthen 952be9e038Ssthen struct rbtree_type* 962be9e038Ssthen respip_set_get_tree(struct respip_set* set) 972be9e038Ssthen { 982be9e038Ssthen if(!set) 992be9e038Ssthen return NULL; 1002be9e038Ssthen return &set->ip_tree; 1012be9e038Ssthen } 1022be9e038Ssthen 103eaf2578eSsthen struct resp_addr* 104eaf2578eSsthen respip_sockaddr_find_or_create(struct respip_set* set, struct sockaddr_storage* addr, 105eaf2578eSsthen socklen_t addrlen, int net, int create, const char* ipstr) 106eaf2578eSsthen { 107eaf2578eSsthen struct resp_addr* node; 108eaf2578eSsthen node = (struct resp_addr*)addr_tree_find(&set->ip_tree, addr, addrlen, net); 109eaf2578eSsthen if(!node && create) { 110eaf2578eSsthen node = regional_alloc_zero(set->region, sizeof(*node)); 111eaf2578eSsthen if(!node) { 112eaf2578eSsthen log_err("out of memory"); 113eaf2578eSsthen return NULL; 114eaf2578eSsthen } 115eaf2578eSsthen lock_rw_init(&node->lock); 116eaf2578eSsthen node->action = respip_none; 117eaf2578eSsthen if(!addr_tree_insert(&set->ip_tree, &node->node, addr, 118eaf2578eSsthen addrlen, net)) { 119eaf2578eSsthen /* We know we didn't find it, so this should be 120eaf2578eSsthen * impossible. */ 121eaf2578eSsthen log_warn("unexpected: duplicate address: %s", ipstr); 122eaf2578eSsthen } 123eaf2578eSsthen } 124eaf2578eSsthen return node; 125eaf2578eSsthen } 126eaf2578eSsthen 127eaf2578eSsthen void 128eaf2578eSsthen respip_sockaddr_delete(struct respip_set* set, struct resp_addr* node) 129eaf2578eSsthen { 130eaf2578eSsthen struct resp_addr* prev; 131eaf2578eSsthen prev = (struct resp_addr*)rbtree_previous((struct rbnode_type*)node); 132eaf2578eSsthen lock_rw_destroy(&node->lock); 133191f22c6Ssthen (void)rbtree_delete(&set->ip_tree, node); 134eaf2578eSsthen /* no free'ing, all allocated in region */ 135eaf2578eSsthen if(!prev) 136eaf2578eSsthen addr_tree_init_parents((rbtree_type*)set); 137eaf2578eSsthen else 138eaf2578eSsthen addr_tree_init_parents_node(&prev->node); 139eaf2578eSsthen } 140eaf2578eSsthen 1412be9e038Ssthen /** returns the node in the address tree for the specified netblock string; 1422be9e038Ssthen * non-existent node will be created if 'create' is true */ 1432be9e038Ssthen static struct resp_addr* 1442be9e038Ssthen respip_find_or_create(struct respip_set* set, const char* ipstr, int create) 1452be9e038Ssthen { 1462be9e038Ssthen struct sockaddr_storage addr; 1472be9e038Ssthen int net; 1482be9e038Ssthen socklen_t addrlen; 1492be9e038Ssthen 1502be9e038Ssthen if(!netblockstrtoaddr(ipstr, 0, &addr, &addrlen, &net)) { 1512be9e038Ssthen log_err("cannot parse netblock: '%s'", ipstr); 1522be9e038Ssthen return NULL; 1532be9e038Ssthen } 154eaf2578eSsthen return respip_sockaddr_find_or_create(set, &addr, addrlen, net, create, 155eaf2578eSsthen ipstr); 1562be9e038Ssthen } 1572be9e038Ssthen 1582be9e038Ssthen static int 1592be9e038Ssthen respip_tag_cfg(struct respip_set* set, const char* ipstr, 1602be9e038Ssthen const uint8_t* taglist, size_t taglen) 1612be9e038Ssthen { 1622be9e038Ssthen struct resp_addr* node; 1632be9e038Ssthen 1642be9e038Ssthen if(!(node=respip_find_or_create(set, ipstr, 1))) 1652be9e038Ssthen return 0; 1662be9e038Ssthen if(node->taglist) { 1672be9e038Ssthen log_warn("duplicate response-address-tag for '%s', overridden.", 1682be9e038Ssthen ipstr); 1692be9e038Ssthen } 1702be9e038Ssthen node->taglist = regional_alloc_init(set->region, taglist, taglen); 1712be9e038Ssthen if(!node->taglist) { 1722be9e038Ssthen log_err("out of memory"); 1732be9e038Ssthen return 0; 1742be9e038Ssthen } 1752be9e038Ssthen node->taglen = taglen; 1762be9e038Ssthen return 1; 1772be9e038Ssthen } 1782be9e038Ssthen 1792be9e038Ssthen /** set action for the node specified by the netblock string */ 1802be9e038Ssthen static int 1812be9e038Ssthen respip_action_cfg(struct respip_set* set, const char* ipstr, 1822be9e038Ssthen const char* actnstr) 1832be9e038Ssthen { 1842be9e038Ssthen struct resp_addr* node; 1852be9e038Ssthen enum respip_action action; 1862be9e038Ssthen 1872be9e038Ssthen if(!(node=respip_find_or_create(set, ipstr, 1))) 1882be9e038Ssthen return 0; 1892be9e038Ssthen if(node->action != respip_none) { 190452a1548Ssthen verbose(VERB_QUERY, "duplicate response-ip action for '%s', overridden.", 1912be9e038Ssthen ipstr); 1922be9e038Ssthen } 1932be9e038Ssthen if(strcmp(actnstr, "deny") == 0) 1942be9e038Ssthen action = respip_deny; 1952be9e038Ssthen else if(strcmp(actnstr, "redirect") == 0) 1962be9e038Ssthen action = respip_redirect; 1972be9e038Ssthen else if(strcmp(actnstr, "inform") == 0) 1982be9e038Ssthen action = respip_inform; 1992be9e038Ssthen else if(strcmp(actnstr, "inform_deny") == 0) 2002be9e038Ssthen action = respip_inform_deny; 201c3b38330Ssthen else if(strcmp(actnstr, "inform_redirect") == 0) 202c3b38330Ssthen action = respip_inform_redirect; 2032be9e038Ssthen else if(strcmp(actnstr, "always_transparent") == 0) 2042be9e038Ssthen action = respip_always_transparent; 2052be9e038Ssthen else if(strcmp(actnstr, "always_refuse") == 0) 2062be9e038Ssthen action = respip_always_refuse; 2072be9e038Ssthen else if(strcmp(actnstr, "always_nxdomain") == 0) 2082be9e038Ssthen action = respip_always_nxdomain; 209eaf2578eSsthen else if(strcmp(actnstr, "always_nodata") == 0) 210eaf2578eSsthen action = respip_always_nodata; 211eaf2578eSsthen else if(strcmp(actnstr, "always_deny") == 0) 212eaf2578eSsthen action = respip_always_deny; 2132be9e038Ssthen else { 2142be9e038Ssthen log_err("unknown response-ip action %s", actnstr); 2152be9e038Ssthen return 0; 2162be9e038Ssthen } 2172be9e038Ssthen node->action = action; 2182be9e038Ssthen return 1; 2192be9e038Ssthen } 2202be9e038Ssthen 2212be9e038Ssthen /** allocate and initialize an rrset structure; this function is based 2222be9e038Ssthen * on new_local_rrset() from the localzone.c module */ 2232be9e038Ssthen static struct ub_packed_rrset_key* 2242be9e038Ssthen new_rrset(struct regional* region, uint16_t rrtype, uint16_t rrclass) 2252be9e038Ssthen { 2262be9e038Ssthen struct packed_rrset_data* pd; 2272be9e038Ssthen struct ub_packed_rrset_key* rrset = regional_alloc_zero( 2282be9e038Ssthen region, sizeof(*rrset)); 2292be9e038Ssthen if(!rrset) { 2302be9e038Ssthen log_err("out of memory"); 2312be9e038Ssthen return NULL; 2322be9e038Ssthen } 2332be9e038Ssthen rrset->entry.key = rrset; 2342be9e038Ssthen pd = regional_alloc_zero(region, sizeof(*pd)); 2352be9e038Ssthen if(!pd) { 2362be9e038Ssthen log_err("out of memory"); 2372be9e038Ssthen return NULL; 2382be9e038Ssthen } 2392be9e038Ssthen pd->trust = rrset_trust_prim_noglue; 2402be9e038Ssthen pd->security = sec_status_insecure; 2412be9e038Ssthen rrset->entry.data = pd; 2422be9e038Ssthen rrset->rk.dname = regional_alloc_zero(region, 1); 2432be9e038Ssthen if(!rrset->rk.dname) { 2442be9e038Ssthen log_err("out of memory"); 2452be9e038Ssthen return NULL; 2462be9e038Ssthen } 2472be9e038Ssthen rrset->rk.dname_len = 1; 2482be9e038Ssthen rrset->rk.type = htons(rrtype); 2492be9e038Ssthen rrset->rk.rrset_class = htons(rrclass); 2502be9e038Ssthen return rrset; 2512be9e038Ssthen } 2522be9e038Ssthen 2532be9e038Ssthen /** enter local data as resource records into a response-ip node */ 254eaf2578eSsthen 255eaf2578eSsthen int 2562be9e038Ssthen respip_enter_rr(struct regional* region, struct resp_addr* raddr, 257eaf2578eSsthen uint16_t rrtype, uint16_t rrclass, time_t ttl, uint8_t* rdata, 258eaf2578eSsthen size_t rdata_len, const char* rrstr, const char* netblockstr) 259eaf2578eSsthen { 260eaf2578eSsthen struct packed_rrset_data* pd; 261eaf2578eSsthen struct sockaddr* sa; 262eaf2578eSsthen sa = (struct sockaddr*)&raddr->node.addr; 263eaf2578eSsthen if (rrtype == LDNS_RR_TYPE_CNAME && raddr->data) { 264eaf2578eSsthen log_err("CNAME response-ip data (%s) can not co-exist with other " 265eaf2578eSsthen "response-ip data for netblock %s", rrstr, netblockstr); 266eaf2578eSsthen return 0; 267eaf2578eSsthen } else if (raddr->data && 268eaf2578eSsthen raddr->data->rk.type == htons(LDNS_RR_TYPE_CNAME)) { 269eaf2578eSsthen log_err("response-ip data (%s) can not be added; CNAME response-ip " 270eaf2578eSsthen "data already in place for netblock %s", rrstr, netblockstr); 271eaf2578eSsthen return 0; 272eaf2578eSsthen } else if((rrtype != LDNS_RR_TYPE_CNAME) && 273eaf2578eSsthen ((sa->sa_family == AF_INET && rrtype != LDNS_RR_TYPE_A) || 274eaf2578eSsthen (sa->sa_family == AF_INET6 && rrtype != LDNS_RR_TYPE_AAAA))) { 275eaf2578eSsthen log_err("response-ip data %s record type does not correspond " 276eaf2578eSsthen "to netblock %s address family", rrstr, netblockstr); 277eaf2578eSsthen return 0; 278eaf2578eSsthen } 279eaf2578eSsthen 280eaf2578eSsthen if(!raddr->data) { 281eaf2578eSsthen raddr->data = new_rrset(region, rrtype, rrclass); 282eaf2578eSsthen if(!raddr->data) 283eaf2578eSsthen return 0; 284eaf2578eSsthen } 285eaf2578eSsthen pd = raddr->data->entry.data; 286eaf2578eSsthen return rrset_insert_rr(region, pd, rdata, rdata_len, ttl, rrstr); 287eaf2578eSsthen } 288eaf2578eSsthen 289eaf2578eSsthen static int 290eaf2578eSsthen respip_enter_rrstr(struct regional* region, struct resp_addr* raddr, 2912be9e038Ssthen const char* rrstr, const char* netblock) 2922be9e038Ssthen { 2932be9e038Ssthen uint8_t* nm; 2942be9e038Ssthen uint16_t rrtype = 0, rrclass = 0; 2952be9e038Ssthen time_t ttl = 0; 2962be9e038Ssthen uint8_t rr[LDNS_RR_BUF_SIZE]; 2972be9e038Ssthen uint8_t* rdata = NULL; 2982be9e038Ssthen size_t rdata_len = 0; 2992be9e038Ssthen char buf[65536]; 3002be9e038Ssthen char bufshort[64]; 3012be9e038Ssthen int ret; 302c3b38330Ssthen if(raddr->action != respip_redirect 303c3b38330Ssthen && raddr->action != respip_inform_redirect) { 3042be9e038Ssthen log_err("cannot parse response-ip-data %s: response-ip " 3052be9e038Ssthen "action for %s is not redirect", rrstr, netblock); 3062be9e038Ssthen return 0; 3072be9e038Ssthen } 3082be9e038Ssthen ret = snprintf(buf, sizeof(buf), ". %s", rrstr); 3092be9e038Ssthen if(ret < 0 || ret >= (int)sizeof(buf)) { 3102be9e038Ssthen strlcpy(bufshort, rrstr, sizeof(bufshort)); 3112be9e038Ssthen log_err("bad response-ip-data: %s...", bufshort); 3122be9e038Ssthen return 0; 3132be9e038Ssthen } 3142be9e038Ssthen if(!rrstr_get_rr_content(buf, &nm, &rrtype, &rrclass, &ttl, rr, sizeof(rr), 3152be9e038Ssthen &rdata, &rdata_len)) { 3162be9e038Ssthen log_err("bad response-ip-data: %s", rrstr); 3172be9e038Ssthen return 0; 3182be9e038Ssthen } 3192be9e038Ssthen free(nm); 320eaf2578eSsthen return respip_enter_rr(region, raddr, rrtype, rrclass, ttl, rdata, 321eaf2578eSsthen rdata_len, rrstr, netblock); 3222be9e038Ssthen } 3232be9e038Ssthen 3242be9e038Ssthen static int 3252be9e038Ssthen respip_data_cfg(struct respip_set* set, const char* ipstr, const char* rrstr) 3262be9e038Ssthen { 3272be9e038Ssthen struct resp_addr* node; 3282be9e038Ssthen 3292be9e038Ssthen node=respip_find_or_create(set, ipstr, 0); 3302be9e038Ssthen if(!node || node->action == respip_none) { 3312be9e038Ssthen log_err("cannot parse response-ip-data %s: " 3322be9e038Ssthen "response-ip node for %s not found", rrstr, ipstr); 3332be9e038Ssthen return 0; 3342be9e038Ssthen } 335eaf2578eSsthen return respip_enter_rrstr(set->region, node, rrstr, ipstr); 3362be9e038Ssthen } 3372be9e038Ssthen 3382be9e038Ssthen static int 3392be9e038Ssthen respip_set_apply_cfg(struct respip_set* set, char* const* tagname, int num_tags, 3402be9e038Ssthen struct config_strbytelist* respip_tags, 3412be9e038Ssthen struct config_str2list* respip_actions, 3422be9e038Ssthen struct config_str2list* respip_data) 3432be9e038Ssthen { 3442be9e038Ssthen struct config_strbytelist* p; 3452be9e038Ssthen struct config_str2list* pa; 3462be9e038Ssthen struct config_str2list* pd; 3472be9e038Ssthen 3482be9e038Ssthen set->tagname = tagname; 3492be9e038Ssthen set->num_tags = num_tags; 3502be9e038Ssthen 3512be9e038Ssthen p = respip_tags; 3522be9e038Ssthen while(p) { 3532be9e038Ssthen struct config_strbytelist* np = p->next; 3542be9e038Ssthen 3552be9e038Ssthen log_assert(p->str && p->str2); 3562be9e038Ssthen if(!respip_tag_cfg(set, p->str, p->str2, p->str2len)) { 3572be9e038Ssthen config_del_strbytelist(p); 3582be9e038Ssthen return 0; 3592be9e038Ssthen } 3602be9e038Ssthen free(p->str); 3612be9e038Ssthen free(p->str2); 3622be9e038Ssthen free(p); 3632be9e038Ssthen p = np; 3642be9e038Ssthen } 3652be9e038Ssthen 3662be9e038Ssthen pa = respip_actions; 3672be9e038Ssthen while(pa) { 3682be9e038Ssthen struct config_str2list* np = pa->next; 3692be9e038Ssthen log_assert(pa->str && pa->str2); 3702be9e038Ssthen if(!respip_action_cfg(set, pa->str, pa->str2)) { 3712be9e038Ssthen config_deldblstrlist(pa); 3722be9e038Ssthen return 0; 3732be9e038Ssthen } 3742be9e038Ssthen free(pa->str); 3752be9e038Ssthen free(pa->str2); 3762be9e038Ssthen free(pa); 3772be9e038Ssthen pa = np; 3782be9e038Ssthen } 3792be9e038Ssthen 3802be9e038Ssthen pd = respip_data; 3812be9e038Ssthen while(pd) { 3822be9e038Ssthen struct config_str2list* np = pd->next; 3832be9e038Ssthen log_assert(pd->str && pd->str2); 3842be9e038Ssthen if(!respip_data_cfg(set, pd->str, pd->str2)) { 3852be9e038Ssthen config_deldblstrlist(pd); 3862be9e038Ssthen return 0; 3872be9e038Ssthen } 3882be9e038Ssthen free(pd->str); 3892be9e038Ssthen free(pd->str2); 3902be9e038Ssthen free(pd); 3912be9e038Ssthen pd = np; 3922be9e038Ssthen } 3938240c1b9Ssthen addr_tree_init_parents(&set->ip_tree); 3942be9e038Ssthen 3952be9e038Ssthen return 1; 3962be9e038Ssthen } 3972be9e038Ssthen 3982be9e038Ssthen int 3992be9e038Ssthen respip_global_apply_cfg(struct respip_set* set, struct config_file* cfg) 4002be9e038Ssthen { 4012be9e038Ssthen int ret = respip_set_apply_cfg(set, cfg->tagname, cfg->num_tags, 4022be9e038Ssthen cfg->respip_tags, cfg->respip_actions, cfg->respip_data); 4032be9e038Ssthen cfg->respip_data = NULL; 4042be9e038Ssthen cfg->respip_actions = NULL; 4052be9e038Ssthen cfg->respip_tags = NULL; 4062be9e038Ssthen return ret; 4072be9e038Ssthen } 4082be9e038Ssthen 4092be9e038Ssthen /** Iterate through raw view data and apply the view-specific respip 4102be9e038Ssthen * configuration; at this point we should have already seen all the views, 4112be9e038Ssthen * so if any of the views that respip data refer to does not exist, that's 4122be9e038Ssthen * an error. This additional iteration through view configuration data 4132be9e038Ssthen * is expected to not have significant performance impact (or rather, its 4142be9e038Ssthen * performance impact is not expected to be prohibitive in the configuration 4152be9e038Ssthen * processing phase). 4162be9e038Ssthen */ 4172be9e038Ssthen int 4182be9e038Ssthen respip_views_apply_cfg(struct views* vs, struct config_file* cfg, 4192be9e038Ssthen int* have_view_respip_cfg) 4202be9e038Ssthen { 4212be9e038Ssthen struct config_view* cv; 4222be9e038Ssthen struct view* v; 4232be9e038Ssthen int ret; 4242be9e038Ssthen 4252be9e038Ssthen for(cv = cfg->views; cv; cv = cv->next) { 4262be9e038Ssthen 4272be9e038Ssthen /** if no respip config for this view then there's 4282be9e038Ssthen * nothing to do; note that even though respip data must go 4292be9e038Ssthen * with respip action, we're checking for both here because 4302be9e038Ssthen * we want to catch the case where the respip action is missing 4312be9e038Ssthen * while the data is present */ 4322be9e038Ssthen if(!cv->respip_actions && !cv->respip_data) 4332be9e038Ssthen continue; 4342be9e038Ssthen 4352be9e038Ssthen if(!(v = views_find_view(vs, cv->name, 1))) { 4362be9e038Ssthen log_err("view '%s' unexpectedly missing", cv->name); 4372be9e038Ssthen return 0; 4382be9e038Ssthen } 4392be9e038Ssthen if(!v->respip_set) { 4402be9e038Ssthen v->respip_set = respip_set_create(); 4412be9e038Ssthen if(!v->respip_set) { 4422be9e038Ssthen log_err("out of memory"); 4432be9e038Ssthen lock_rw_unlock(&v->lock); 4442be9e038Ssthen return 0; 4452be9e038Ssthen } 4462be9e038Ssthen } 4472be9e038Ssthen ret = respip_set_apply_cfg(v->respip_set, NULL, 0, NULL, 4482be9e038Ssthen cv->respip_actions, cv->respip_data); 4492be9e038Ssthen lock_rw_unlock(&v->lock); 4502be9e038Ssthen if(!ret) { 4512be9e038Ssthen log_err("Error while applying respip configuration " 4522be9e038Ssthen "for view '%s'", cv->name); 4532be9e038Ssthen return 0; 4542be9e038Ssthen } 4552be9e038Ssthen *have_view_respip_cfg = (*have_view_respip_cfg || 4562be9e038Ssthen v->respip_set->ip_tree.count); 4572be9e038Ssthen cv->respip_actions = NULL; 4582be9e038Ssthen cv->respip_data = NULL; 4592be9e038Ssthen } 4602be9e038Ssthen return 1; 4612be9e038Ssthen } 4622be9e038Ssthen 4632be9e038Ssthen /** 4642be9e038Ssthen * make a deep copy of 'key' in 'region'. 4652be9e038Ssthen * This is largely derived from packed_rrset_copy_region() and 4662be9e038Ssthen * packed_rrset_ptr_fixup(), but differs in the following points: 4672be9e038Ssthen * 4682be9e038Ssthen * - It doesn't assume all data in 'key' are in a contiguous memory region. 4692be9e038Ssthen * Although that would be the case in most cases, 'key' can be passed from 4702be9e038Ssthen * a lower-level module and it might not build the rrset to meet the 4712be9e038Ssthen * assumption. In fact, an rrset specified as response-ip-data or generated 4722be9e038Ssthen * in local_data_find_tag_datas() breaks the assumption. So it would be 4732be9e038Ssthen * safer not to naively rely on the assumption. On the other hand, this 4742be9e038Ssthen * function ensures the copied rrset data are in a contiguous region so 4752be9e038Ssthen * that it won't cause a disruption even if an upper layer module naively 4762be9e038Ssthen * assumes the memory layout. 4772be9e038Ssthen * - It doesn't copy RRSIGs (if any) in 'key'. The rrset will be used in 4782be9e038Ssthen * a reply that was already faked, so it doesn't make much sense to provide 4792be9e038Ssthen * partial sigs even if they are valid themselves. 4802be9e038Ssthen * - It doesn't adjust TTLs as it basically has to be a verbatim copy of 'key' 4812be9e038Ssthen * just allocated in 'region' (the assumption is necessary TTL adjustment 4822be9e038Ssthen * has been already done in 'key'). 4832be9e038Ssthen * 4842be9e038Ssthen * This function returns the copied rrset key on success, and NULL on memory 4852be9e038Ssthen * allocation failure. 4862be9e038Ssthen */ 487e21c60efSsthen struct ub_packed_rrset_key* 488e21c60efSsthen respip_copy_rrset(const struct ub_packed_rrset_key* key, struct regional* region) 4892be9e038Ssthen { 4902be9e038Ssthen struct ub_packed_rrset_key* ck = regional_alloc(region, 4912be9e038Ssthen sizeof(struct ub_packed_rrset_key)); 4922be9e038Ssthen struct packed_rrset_data* d; 4932be9e038Ssthen struct packed_rrset_data* data = key->entry.data; 4942be9e038Ssthen size_t dsize, i; 4952be9e038Ssthen uint8_t* nextrdata; 4962be9e038Ssthen 4972be9e038Ssthen /* derived from packed_rrset_copy_region(), but don't use 4982be9e038Ssthen * packed_rrset_sizeof() and do exclude RRSIGs */ 4992be9e038Ssthen if(!ck) 5002be9e038Ssthen return NULL; 5012be9e038Ssthen ck->id = key->id; 5022be9e038Ssthen memset(&ck->entry, 0, sizeof(ck->entry)); 5032be9e038Ssthen ck->entry.hash = key->entry.hash; 5042be9e038Ssthen ck->entry.key = ck; 5052be9e038Ssthen ck->rk = key->rk; 506a3167c07Ssthen if(key->rk.dname) { 5072be9e038Ssthen ck->rk.dname = regional_alloc_init(region, key->rk.dname, 5082be9e038Ssthen key->rk.dname_len); 5092be9e038Ssthen if(!ck->rk.dname) 5102be9e038Ssthen return NULL; 511a3167c07Ssthen ck->rk.dname_len = key->rk.dname_len; 512a3167c07Ssthen } else { 513a3167c07Ssthen ck->rk.dname = NULL; 514a3167c07Ssthen ck->rk.dname_len = 0; 515a3167c07Ssthen } 5162be9e038Ssthen 517ebf5bb73Ssthen if((unsigned)data->count >= 0xffff00U) 518ebf5bb73Ssthen return NULL; /* guard against integer overflow in dsize */ 5192be9e038Ssthen dsize = sizeof(struct packed_rrset_data) + data->count * 5202be9e038Ssthen (sizeof(size_t)+sizeof(uint8_t*)+sizeof(time_t)); 521ebf5bb73Ssthen for(i=0; i<data->count; i++) { 522ebf5bb73Ssthen if((unsigned)dsize >= 0x0fffffffU || 523ebf5bb73Ssthen (unsigned)data->rr_len[i] >= 0x0fffffffU) 524ebf5bb73Ssthen return NULL; /* guard against integer overflow */ 5252be9e038Ssthen dsize += data->rr_len[i]; 526ebf5bb73Ssthen } 5279982a05dSsthen d = regional_alloc_zero(region, dsize); 5282be9e038Ssthen if(!d) 5292be9e038Ssthen return NULL; 5302be9e038Ssthen *d = *data; 5312be9e038Ssthen d->rrsig_count = 0; 5322be9e038Ssthen ck->entry.data = d; 5332be9e038Ssthen 5342be9e038Ssthen /* derived from packed_rrset_ptr_fixup() with copying the data */ 5352be9e038Ssthen d->rr_len = (size_t*)((uint8_t*)d + sizeof(struct packed_rrset_data)); 5362be9e038Ssthen d->rr_data = (uint8_t**)&(d->rr_len[d->count]); 5372be9e038Ssthen d->rr_ttl = (time_t*)&(d->rr_data[d->count]); 5382be9e038Ssthen nextrdata = (uint8_t*)&(d->rr_ttl[d->count]); 5392be9e038Ssthen for(i=0; i<d->count; i++) { 5402be9e038Ssthen d->rr_len[i] = data->rr_len[i]; 5412be9e038Ssthen d->rr_ttl[i] = data->rr_ttl[i]; 5422be9e038Ssthen d->rr_data[i] = nextrdata; 5432be9e038Ssthen memcpy(d->rr_data[i], data->rr_data[i], data->rr_len[i]); 5442be9e038Ssthen nextrdata += d->rr_len[i]; 5452be9e038Ssthen } 5462be9e038Ssthen 5472be9e038Ssthen return ck; 5482be9e038Ssthen } 5492be9e038Ssthen 5502be9e038Ssthen int 5512be9e038Ssthen respip_init(struct module_env* env, int id) 5522be9e038Ssthen { 5532be9e038Ssthen (void)env; 5542be9e038Ssthen (void)id; 5552be9e038Ssthen return 1; 5562be9e038Ssthen } 5572be9e038Ssthen 5582be9e038Ssthen void 5592be9e038Ssthen respip_deinit(struct module_env* env, int id) 5602be9e038Ssthen { 5612be9e038Ssthen (void)env; 5622be9e038Ssthen (void)id; 5632be9e038Ssthen } 5642be9e038Ssthen 5652be9e038Ssthen /** Convert a packed AAAA or A RRset to sockaddr. */ 5662be9e038Ssthen static int 5672be9e038Ssthen rdata2sockaddr(const struct packed_rrset_data* rd, uint16_t rtype, size_t i, 5682be9e038Ssthen struct sockaddr_storage* ss, socklen_t* addrlenp) 5692be9e038Ssthen { 5702be9e038Ssthen /* unbound can accept and cache odd-length AAAA/A records, so we have 5712be9e038Ssthen * to validate the length. */ 5722be9e038Ssthen if(rtype == LDNS_RR_TYPE_A && rd->rr_len[i] == 6) { 5732be9e038Ssthen struct sockaddr_in* sa4 = (struct sockaddr_in*)ss; 5742be9e038Ssthen 5752be9e038Ssthen memset(sa4, 0, sizeof(*sa4)); 5762be9e038Ssthen sa4->sin_family = AF_INET; 5772be9e038Ssthen memcpy(&sa4->sin_addr, rd->rr_data[i] + 2, 5782be9e038Ssthen sizeof(sa4->sin_addr)); 5792be9e038Ssthen *addrlenp = sizeof(*sa4); 5802be9e038Ssthen return 1; 5812be9e038Ssthen } else if(rtype == LDNS_RR_TYPE_AAAA && rd->rr_len[i] == 18) { 5822be9e038Ssthen struct sockaddr_in6* sa6 = (struct sockaddr_in6*)ss; 5832be9e038Ssthen 5842be9e038Ssthen memset(sa6, 0, sizeof(*sa6)); 5852be9e038Ssthen sa6->sin6_family = AF_INET6; 5862be9e038Ssthen memcpy(&sa6->sin6_addr, rd->rr_data[i] + 2, 5872be9e038Ssthen sizeof(sa6->sin6_addr)); 5882be9e038Ssthen *addrlenp = sizeof(*sa6); 5892be9e038Ssthen return 1; 5902be9e038Ssthen } 5912be9e038Ssthen return 0; 5922be9e038Ssthen } 5932be9e038Ssthen 5942be9e038Ssthen /** 5952be9e038Ssthen * Search the given 'iptree' for response address information that matches 5962be9e038Ssthen * any of the IP addresses in an AAAA or A in the answer section of the 5972be9e038Ssthen * response (stored in 'rep'). If found, a pointer to the matched resp_addr 5982be9e038Ssthen * structure will be returned, and '*rrset_id' is set to the index in 5992be9e038Ssthen * rep->rrsets for the RRset that contains the matching IP address record 6002be9e038Ssthen * (the index is normally 0, but can be larger than that if this is a CNAME 6012be9e038Ssthen * chain or type-ANY response). 602eaf2578eSsthen * Returns resp_addr holding read lock. 6032be9e038Ssthen */ 604eaf2578eSsthen static struct resp_addr* 605eaf2578eSsthen respip_addr_lookup(const struct reply_info *rep, struct respip_set* rs, 606e21c60efSsthen size_t* rrset_id, size_t* rr_id) 6072be9e038Ssthen { 6082be9e038Ssthen size_t i; 6092be9e038Ssthen struct resp_addr* ra; 6102be9e038Ssthen struct sockaddr_storage ss; 6112be9e038Ssthen socklen_t addrlen; 6122be9e038Ssthen 613eaf2578eSsthen lock_rw_rdlock(&rs->lock); 6142be9e038Ssthen for(i=0; i<rep->an_numrrsets; i++) { 6152be9e038Ssthen size_t j; 6162be9e038Ssthen const struct packed_rrset_data* rd; 6172be9e038Ssthen uint16_t rtype = ntohs(rep->rrsets[i]->rk.type); 6182be9e038Ssthen 6192be9e038Ssthen if(rtype != LDNS_RR_TYPE_A && rtype != LDNS_RR_TYPE_AAAA) 6202be9e038Ssthen continue; 6212be9e038Ssthen rd = rep->rrsets[i]->entry.data; 6222be9e038Ssthen for(j = 0; j < rd->count; j++) { 6232be9e038Ssthen if(!rdata2sockaddr(rd, rtype, j, &ss, &addrlen)) 6242be9e038Ssthen continue; 625eaf2578eSsthen ra = (struct resp_addr*)addr_tree_lookup(&rs->ip_tree, 626eaf2578eSsthen &ss, addrlen); 6272be9e038Ssthen if(ra) { 6282be9e038Ssthen *rrset_id = i; 629e21c60efSsthen *rr_id = j; 630eaf2578eSsthen lock_rw_rdlock(&ra->lock); 631eaf2578eSsthen lock_rw_unlock(&rs->lock); 6322be9e038Ssthen return ra; 6332be9e038Ssthen } 6342be9e038Ssthen } 6352be9e038Ssthen } 636eaf2578eSsthen lock_rw_unlock(&rs->lock); 6372be9e038Ssthen return NULL; 6382be9e038Ssthen } 6392be9e038Ssthen 6402be9e038Ssthen /** 6412be9e038Ssthen * See if response-ip or tag data should override the original answer rrset 6422be9e038Ssthen * (which is rep->rrsets[rrset_id]) and if so override it. 6432be9e038Ssthen * This is (mostly) equivalent to localzone.c:local_data_answer() but for 6442be9e038Ssthen * response-ip actions. 6452be9e038Ssthen * Note that this function distinguishes error conditions from "success but 6462be9e038Ssthen * not overridden". This is because we want to avoid accidentally applying 6472be9e038Ssthen * the "no data" action in case of error. 6482be9e038Ssthen * @param action: action to apply 649eaf2578eSsthen * @param data: RRset to use for override 6502be9e038Ssthen * @param qtype: original query type 6512be9e038Ssthen * @param rep: original reply message 6522be9e038Ssthen * @param rrset_id: the rrset ID in 'rep' to which the action should apply 6532be9e038Ssthen * @param new_repp: see respip_rewrite_reply 6542be9e038Ssthen * @param tag: if >= 0 the tag ID used to determine the action and data 6552be9e038Ssthen * @param tag_datas: data corresponding to 'tag'. 6562be9e038Ssthen * @param tag_datas_size: size of 'tag_datas' 6572be9e038Ssthen * @param tagname: array of tag names, used for logging 6582be9e038Ssthen * @param num_tags: size of 'tagname', used for logging 6592be9e038Ssthen * @param redirect_rrsetp: ptr to redirect record 6602be9e038Ssthen * @param region: region for building new reply 6612be9e038Ssthen * @return 1 if overridden, 0 if not overridden, -1 on error. 6622be9e038Ssthen */ 6632be9e038Ssthen static int 664eaf2578eSsthen respip_data_answer(enum respip_action action, 665eaf2578eSsthen struct ub_packed_rrset_key* data, 6662be9e038Ssthen uint16_t qtype, const struct reply_info* rep, 6672be9e038Ssthen size_t rrset_id, struct reply_info** new_repp, int tag, 6682be9e038Ssthen struct config_strlist** tag_datas, size_t tag_datas_size, 6692be9e038Ssthen char* const* tagname, int num_tags, 6702be9e038Ssthen struct ub_packed_rrset_key** redirect_rrsetp, struct regional* region) 6712be9e038Ssthen { 672eaf2578eSsthen struct ub_packed_rrset_key* rp = data; 6732be9e038Ssthen struct reply_info* new_rep; 6742be9e038Ssthen *redirect_rrsetp = NULL; 6752be9e038Ssthen 6762be9e038Ssthen if(action == respip_redirect && tag != -1 && 6772be9e038Ssthen (size_t)tag<tag_datas_size && tag_datas[tag]) { 6782be9e038Ssthen struct query_info dataqinfo; 6792be9e038Ssthen struct ub_packed_rrset_key r; 6802be9e038Ssthen 6812be9e038Ssthen /* Extract parameters of the original answer rrset that can be 6822be9e038Ssthen * rewritten below, in the form of query_info. Note that these 6832be9e038Ssthen * can be different from the info of the original query if the 6842be9e038Ssthen * rrset is a CNAME target.*/ 6852be9e038Ssthen memset(&dataqinfo, 0, sizeof(dataqinfo)); 6862be9e038Ssthen dataqinfo.qname = rep->rrsets[rrset_id]->rk.dname; 6872be9e038Ssthen dataqinfo.qname_len = rep->rrsets[rrset_id]->rk.dname_len; 6882be9e038Ssthen dataqinfo.qtype = ntohs(rep->rrsets[rrset_id]->rk.type); 6892be9e038Ssthen dataqinfo.qclass = ntohs(rep->rrsets[rrset_id]->rk.rrset_class); 6902be9e038Ssthen 6912be9e038Ssthen memset(&r, 0, sizeof(r)); 6922be9e038Ssthen if(local_data_find_tag_datas(&dataqinfo, tag_datas[tag], &r, 6932be9e038Ssthen region)) { 6942be9e038Ssthen verbose(VERB_ALGO, 6952be9e038Ssthen "response-ip redirect with tag data [%d] %s", 6962be9e038Ssthen tag, (tag<num_tags?tagname[tag]:"null")); 6972be9e038Ssthen /* use copy_rrset() to 'normalize' memory layout */ 698e21c60efSsthen rp = respip_copy_rrset(&r, region); 6992be9e038Ssthen if(!rp) 7002be9e038Ssthen return -1; 7012be9e038Ssthen } 7022be9e038Ssthen } 7032be9e038Ssthen if(!rp) 7042be9e038Ssthen return 0; 7052be9e038Ssthen 7062be9e038Ssthen /* If we are using response-ip-data, we need to make a copy of rrset 7072be9e038Ssthen * to replace the rrset's dname. Note that, unlike local data, we 7082be9e038Ssthen * rename the dname for other actions than redirect. This is because 7092be9e038Ssthen * response-ip-data isn't associated to any specific name. */ 710eaf2578eSsthen if(rp == data) { 711e21c60efSsthen rp = respip_copy_rrset(rp, region); 7122be9e038Ssthen if(!rp) 7132be9e038Ssthen return -1; 7142be9e038Ssthen rp->rk.dname = rep->rrsets[rrset_id]->rk.dname; 7152be9e038Ssthen rp->rk.dname_len = rep->rrsets[rrset_id]->rk.dname_len; 7162be9e038Ssthen } 7172be9e038Ssthen 7182be9e038Ssthen /* Build a new reply with redirect rrset. We keep any preceding CNAMEs 7192be9e038Ssthen * and replace the address rrset that triggers the action. If it's 7202be9e038Ssthen * type ANY query, however, no other answer records should be kept 7212be9e038Ssthen * (note that it can't be a CNAME chain in this case due to 7222be9e038Ssthen * sanitizing). */ 7232be9e038Ssthen if(qtype == LDNS_RR_TYPE_ANY) 7242be9e038Ssthen rrset_id = 0; 7252be9e038Ssthen new_rep = make_new_reply_info(rep, region, rrset_id + 1, rrset_id); 7262be9e038Ssthen if(!new_rep) 7272be9e038Ssthen return -1; 7282be9e038Ssthen rp->rk.flags |= PACKED_RRSET_FIXEDTTL; /* avoid adjusting TTL */ 7292be9e038Ssthen new_rep->rrsets[rrset_id] = rp; 7302be9e038Ssthen 7312be9e038Ssthen *redirect_rrsetp = rp; 7322be9e038Ssthen *new_repp = new_rep; 7332be9e038Ssthen return 1; 7342be9e038Ssthen } 7352be9e038Ssthen 7362be9e038Ssthen /** 7372be9e038Ssthen * apply response ip action in case where no action data is provided. 7382be9e038Ssthen * this is similar to localzone.c:lz_zone_answer() but simplified due to 7392be9e038Ssthen * the characteristics of response ip: 7402be9e038Ssthen * - 'deny' variants will be handled at the caller side 7412be9e038Ssthen * - no specific processing for 'transparent' variants: unlike local zones, 7422be9e038Ssthen * there is no such a case of 'no data but name existing'. so all variants 7432be9e038Ssthen * just mean 'transparent if no data'. 7442be9e038Ssthen * @param qtype: query type 7452be9e038Ssthen * @param action: found action 7462be9e038Ssthen * @param rep: 7472be9e038Ssthen * @param new_repp 7482be9e038Ssthen * @param rrset_id 7492be9e038Ssthen * @param region: region for building new reply 7502be9e038Ssthen * @return 1 on success, 0 on error. 7512be9e038Ssthen */ 7522be9e038Ssthen static int 7532be9e038Ssthen respip_nodata_answer(uint16_t qtype, enum respip_action action, 7542be9e038Ssthen const struct reply_info *rep, size_t rrset_id, 7552be9e038Ssthen struct reply_info** new_repp, struct regional* region) 7562be9e038Ssthen { 7572be9e038Ssthen struct reply_info* new_rep; 7582be9e038Ssthen 7592be9e038Ssthen if(action == respip_refuse || action == respip_always_refuse) { 7602be9e038Ssthen new_rep = make_new_reply_info(rep, region, 0, 0); 7612be9e038Ssthen if(!new_rep) 7622be9e038Ssthen return 0; 7632be9e038Ssthen FLAGS_SET_RCODE(new_rep->flags, LDNS_RCODE_REFUSED); 7642be9e038Ssthen *new_repp = new_rep; 7652be9e038Ssthen return 1; 7662be9e038Ssthen } else if(action == respip_static || action == respip_redirect || 767c3b38330Ssthen action == respip_always_nxdomain || 768eaf2578eSsthen action == respip_always_nodata || 769c3b38330Ssthen action == respip_inform_redirect) { 7702be9e038Ssthen /* Since we don't know about other types of the owner name, 7712be9e038Ssthen * we generally return NOERROR/NODATA unless an NXDOMAIN action 7722be9e038Ssthen * is explicitly specified. */ 7732be9e038Ssthen int rcode = (action == respip_always_nxdomain)? 7742be9e038Ssthen LDNS_RCODE_NXDOMAIN:LDNS_RCODE_NOERROR; 7752be9e038Ssthen /* We should empty the answer section except for any preceding 7762be9e038Ssthen * CNAMEs (in that case rrset_id > 0). Type-ANY case is 7772be9e038Ssthen * special as noted in respip_data_answer(). */ 7782be9e038Ssthen if(qtype == LDNS_RR_TYPE_ANY) 7792be9e038Ssthen rrset_id = 0; 7802be9e038Ssthen new_rep = make_new_reply_info(rep, region, rrset_id, rrset_id); 7812be9e038Ssthen if(!new_rep) 7822be9e038Ssthen return 0; 7832be9e038Ssthen FLAGS_SET_RCODE(new_rep->flags, rcode); 7842be9e038Ssthen *new_repp = new_rep; 7852be9e038Ssthen return 1; 7862be9e038Ssthen } 7872be9e038Ssthen 7882be9e038Ssthen return 1; 7892be9e038Ssthen } 7902be9e038Ssthen 7912be9e038Ssthen /** Populate action info structure with the results of response-ip action 7922be9e038Ssthen * processing, iff as the result of response-ip processing we are actually 7932be9e038Ssthen * taking some action. Only action is set if action_only is true. 7942be9e038Ssthen * Returns true on success, false on failure. 7952be9e038Ssthen */ 7962be9e038Ssthen static int 7972be9e038Ssthen populate_action_info(struct respip_action_info* actinfo, 7982be9e038Ssthen enum respip_action action, const struct resp_addr* raddr, 7992be9e038Ssthen const struct ub_packed_rrset_key* ATTR_UNUSED(rrset), 8002be9e038Ssthen int ATTR_UNUSED(tag), const struct respip_set* ATTR_UNUSED(ipset), 801eaf2578eSsthen int ATTR_UNUSED(action_only), struct regional* region, int rpz_used, 802eaf2578eSsthen int rpz_log, char* log_name, int rpz_cname_override) 8032be9e038Ssthen { 8042be9e038Ssthen if(action == respip_none || !raddr) 8052be9e038Ssthen return 1; 8062be9e038Ssthen actinfo->action = action; 807eaf2578eSsthen actinfo->rpz_used = rpz_used; 808eaf2578eSsthen actinfo->rpz_log = rpz_log; 809eaf2578eSsthen actinfo->log_name = log_name; 810eaf2578eSsthen actinfo->rpz_cname_override = rpz_cname_override; 8112be9e038Ssthen 8122be9e038Ssthen /* for inform variants, make a copy of the matched address block for 8132be9e038Ssthen * later logging. We make a copy to proactively avoid disruption if 8142be9e038Ssthen * and when we allow a dynamic update to the respip tree. */ 815eaf2578eSsthen if(action == respip_inform || action == respip_inform_deny || 816eaf2578eSsthen rpz_used) { 8172be9e038Ssthen struct respip_addr_info* a = 8182be9e038Ssthen regional_alloc_zero(region, sizeof(*a)); 8192be9e038Ssthen if(!a) { 8202be9e038Ssthen log_err("out of memory"); 8212be9e038Ssthen return 0; 8222be9e038Ssthen } 8232be9e038Ssthen a->addr = raddr->node.addr; 8242be9e038Ssthen a->addrlen = raddr->node.addrlen; 8252be9e038Ssthen a->net = raddr->node.net; 8262be9e038Ssthen actinfo->addrinfo = a; 8272be9e038Ssthen } 8282be9e038Ssthen 8292be9e038Ssthen return 1; 8302be9e038Ssthen } 8312be9e038Ssthen 832eaf2578eSsthen static int 833eaf2578eSsthen respip_use_rpz(struct resp_addr* raddr, struct rpz* r, 834eaf2578eSsthen enum respip_action* action, 835eaf2578eSsthen struct ub_packed_rrset_key** data, int* rpz_log, char** log_name, 8360bdb4f62Ssthen int* rpz_cname_override, struct regional* region, int* is_rpz, 8370bdb4f62Ssthen int* rpz_passthru) 838eaf2578eSsthen { 8390bdb4f62Ssthen if(rpz_passthru && *rpz_passthru) 8400bdb4f62Ssthen return 0; 841eaf2578eSsthen if(r->action_override == RPZ_DISABLED_ACTION) { 842eaf2578eSsthen *is_rpz = 0; 843eaf2578eSsthen return 1; 844eaf2578eSsthen } 845eaf2578eSsthen else if(r->action_override == RPZ_NO_OVERRIDE_ACTION) 846eaf2578eSsthen *action = raddr->action; 847eaf2578eSsthen else 848eaf2578eSsthen *action = rpz_action_to_respip_action(r->action_override); 849eaf2578eSsthen if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION && 850eaf2578eSsthen r->cname_override) { 851eaf2578eSsthen *data = r->cname_override; 852eaf2578eSsthen *rpz_cname_override = 1; 853eaf2578eSsthen } 8540bdb4f62Ssthen if(*action == respip_always_transparent /* RPZ_PASSTHRU_ACTION */ 8550bdb4f62Ssthen && rpz_passthru) 8560bdb4f62Ssthen *rpz_passthru = 1; 857eaf2578eSsthen *rpz_log = r->log; 858eaf2578eSsthen if(r->log_name) 859eaf2578eSsthen if(!(*log_name = regional_strdup(region, r->log_name))) 860eaf2578eSsthen return 0; 861eaf2578eSsthen *is_rpz = 1; 862eaf2578eSsthen return 1; 863eaf2578eSsthen } 864eaf2578eSsthen 8652be9e038Ssthen int 8662be9e038Ssthen respip_rewrite_reply(const struct query_info* qinfo, 8672be9e038Ssthen const struct respip_client_info* cinfo, const struct reply_info* rep, 8682be9e038Ssthen struct reply_info** new_repp, struct respip_action_info* actinfo, 8692be9e038Ssthen struct ub_packed_rrset_key** alias_rrset, int search_only, 8700bdb4f62Ssthen struct regional* region, struct auth_zones* az, int* rpz_passthru) 8712be9e038Ssthen { 8722be9e038Ssthen const uint8_t* ctaglist; 8732be9e038Ssthen size_t ctaglen; 8742be9e038Ssthen const uint8_t* tag_actions; 8752be9e038Ssthen size_t tag_actions_size; 8762be9e038Ssthen struct config_strlist** tag_datas; 8772be9e038Ssthen size_t tag_datas_size; 8782be9e038Ssthen struct view* view = NULL; 8792be9e038Ssthen struct respip_set* ipset = NULL; 880e21c60efSsthen size_t rrset_id = 0, rr_id = 0; 8812be9e038Ssthen enum respip_action action = respip_none; 8822be9e038Ssthen int tag = -1; 883eaf2578eSsthen struct resp_addr* raddr = NULL; 8842be9e038Ssthen int ret = 1; 8852be9e038Ssthen struct ub_packed_rrset_key* redirect_rrset = NULL; 886eaf2578eSsthen struct rpz* r; 887eba819a2Ssthen struct auth_zone* a = NULL; 888eaf2578eSsthen struct ub_packed_rrset_key* data = NULL; 889eaf2578eSsthen int rpz_used = 0; 890eaf2578eSsthen int rpz_log = 0; 891eaf2578eSsthen int rpz_cname_override = 0; 892eaf2578eSsthen char* log_name = NULL; 8932be9e038Ssthen 8942be9e038Ssthen if(!cinfo) 8952be9e038Ssthen goto done; 8962be9e038Ssthen ctaglist = cinfo->taglist; 8972be9e038Ssthen ctaglen = cinfo->taglen; 8982be9e038Ssthen tag_actions = cinfo->tag_actions; 8992be9e038Ssthen tag_actions_size = cinfo->tag_actions_size; 9002be9e038Ssthen tag_datas = cinfo->tag_datas; 9012be9e038Ssthen tag_datas_size = cinfo->tag_datas_size; 9022be9e038Ssthen view = cinfo->view; 9032be9e038Ssthen ipset = cinfo->respip_set; 9042be9e038Ssthen 905eaf2578eSsthen log_assert(ipset); 906eaf2578eSsthen 9072be9e038Ssthen /** Try to use response-ip config from the view first; use 9082be9e038Ssthen * global response-ip config if we don't have the view or we don't 9092be9e038Ssthen * have the matching per-view config (and the view allows the use 9102be9e038Ssthen * of global data in this case). 9112be9e038Ssthen * Note that we lock the view even if we only use view members that 9122be9e038Ssthen * currently don't change after creation. This is for safety for 9132be9e038Ssthen * future possible changes as the view documentation seems to expect 9142be9e038Ssthen * any of its member can change in the view's lifetime. 9152be9e038Ssthen * Note also that we assume 'view' is valid in this function, which 9162be9e038Ssthen * should be safe (see unbound bug #1191) */ 9172be9e038Ssthen if(view) { 9182be9e038Ssthen lock_rw_rdlock(&view->lock); 9192be9e038Ssthen if(view->respip_set) { 9202be9e038Ssthen if((raddr = respip_addr_lookup(rep, 921e21c60efSsthen view->respip_set, &rrset_id, &rr_id))) { 9222be9e038Ssthen /** for per-view respip directives the action 9232be9e038Ssthen * can only be direct (i.e. not tag-based) */ 9242be9e038Ssthen action = raddr->action; 9252be9e038Ssthen } 9262be9e038Ssthen } 9272be9e038Ssthen if(!raddr && !view->isfirst) 9282be9e038Ssthen goto done; 929a3167c07Ssthen if(!raddr && view->isfirst) { 930a3167c07Ssthen lock_rw_unlock(&view->lock); 931a3167c07Ssthen view = NULL; 932a3167c07Ssthen } 9332be9e038Ssthen } 934eaf2578eSsthen if(!raddr && (raddr = respip_addr_lookup(rep, ipset, 935e21c60efSsthen &rrset_id, &rr_id))) { 9362be9e038Ssthen action = (enum respip_action)local_data_find_tag_action( 9372be9e038Ssthen raddr->taglist, raddr->taglen, ctaglist, ctaglen, 9382be9e038Ssthen tag_actions, tag_actions_size, 9392be9e038Ssthen (enum localzone_type)raddr->action, &tag, 9402be9e038Ssthen ipset->tagname, ipset->num_tags); 9412be9e038Ssthen } 942eaf2578eSsthen lock_rw_rdlock(&az->rpz_lock); 9430bdb4f62Ssthen for(a = az->rpz_first; a && !raddr && !(rpz_passthru && *rpz_passthru); a = a->rpz_az_next) { 944a3167c07Ssthen lock_rw_rdlock(&a->lock); 945a3167c07Ssthen r = a->rpz; 946eaf2578eSsthen if(!r->taglist || taglist_intersect(r->taglist, 947eaf2578eSsthen r->taglistlen, ctaglist, ctaglen)) { 948eaf2578eSsthen if((raddr = respip_addr_lookup(rep, 949e21c60efSsthen r->respip_set, &rrset_id, &rr_id))) { 950eaf2578eSsthen if(!respip_use_rpz(raddr, r, &action, &data, 951eaf2578eSsthen &rpz_log, &log_name, &rpz_cname_override, 9520bdb4f62Ssthen region, &rpz_used, rpz_passthru)) { 953eaf2578eSsthen log_err("out of memory"); 954eaf2578eSsthen lock_rw_unlock(&raddr->lock); 955a3167c07Ssthen lock_rw_unlock(&a->lock); 956eaf2578eSsthen lock_rw_unlock(&az->rpz_lock); 957eaf2578eSsthen return 0; 958eaf2578eSsthen } 959a3167c07Ssthen if(rpz_used) { 960e21c60efSsthen if(verbosity >= VERB_ALGO) { 961e21c60efSsthen struct sockaddr_storage ss; 962e21c60efSsthen socklen_t ss_len = 0; 963e21c60efSsthen char nm[256], ip[256]; 964e21c60efSsthen char qn[255+1]; 965e21c60efSsthen if(!rdata2sockaddr(rep->rrsets[rrset_id]->entry.data, ntohs(rep->rrsets[rrset_id]->rk.type), rr_id, &ss, &ss_len)) 966e21c60efSsthen snprintf(ip, sizeof(ip), "invalidRRdata"); 967e21c60efSsthen else 968e21c60efSsthen addr_to_str(&ss, ss_len, ip, sizeof(ip)); 969e21c60efSsthen dname_str(qinfo->qname, qn); 970e21c60efSsthen addr_to_str(&raddr->node.addr, 971e21c60efSsthen raddr->node.addrlen, 972e21c60efSsthen nm, sizeof(nm)); 9730bdb4f62Ssthen verbose(VERB_ALGO, "respip: rpz: response-ip trigger %s/%d on %s %s with action %s", nm, raddr->node.net, qn, ip, rpz_action_to_string(respip_action_to_rpz_action(action))); 974e21c60efSsthen } 975a3167c07Ssthen /* break to make sure 'a' stays pointed 976a3167c07Ssthen * to used auth_zone, and keeps lock */ 977a3167c07Ssthen break; 978a3167c07Ssthen } 979eaf2578eSsthen lock_rw_unlock(&raddr->lock); 980eaf2578eSsthen raddr = NULL; 981eaf2578eSsthen actinfo->rpz_disabled++; 982eaf2578eSsthen } 983eaf2578eSsthen } 984a3167c07Ssthen lock_rw_unlock(&a->lock); 985eaf2578eSsthen } 986eaf2578eSsthen lock_rw_unlock(&az->rpz_lock); 9872be9e038Ssthen if(raddr && !search_only) { 9882be9e038Ssthen int result = 0; 9892be9e038Ssthen 9902be9e038Ssthen /* first, see if we have response-ip or tag action for the 9912be9e038Ssthen * action except for 'always' variants. */ 9922be9e038Ssthen if(action != respip_always_refuse 9932be9e038Ssthen && action != respip_always_transparent 9942be9e038Ssthen && action != respip_always_nxdomain 995eaf2578eSsthen && action != respip_always_nodata 996eaf2578eSsthen && action != respip_always_deny 997eaf2578eSsthen && (result = respip_data_answer(action, 998eaf2578eSsthen (data) ? data : raddr->data, qinfo->qtype, rep, 999eaf2578eSsthen rrset_id, new_repp, tag, tag_datas, tag_datas_size, 1000eaf2578eSsthen ipset->tagname, ipset->num_tags, &redirect_rrset, 1001eaf2578eSsthen region)) < 0) { 10022be9e038Ssthen ret = 0; 10032be9e038Ssthen goto done; 10042be9e038Ssthen } 10052be9e038Ssthen 10062be9e038Ssthen /* if no action data applied, take action specific to the 10072be9e038Ssthen * action without data. */ 10082be9e038Ssthen if(!result && !respip_nodata_answer(qinfo->qtype, action, rep, 10092be9e038Ssthen rrset_id, new_repp, region)) { 10102be9e038Ssthen ret = 0; 10112be9e038Ssthen goto done; 10122be9e038Ssthen } 10132be9e038Ssthen } 10142be9e038Ssthen done: 10152be9e038Ssthen if(view) { 10162be9e038Ssthen lock_rw_unlock(&view->lock); 10172be9e038Ssthen } 10182be9e038Ssthen if(ret) { 10192be9e038Ssthen /* If we're redirecting the original answer to a 10202be9e038Ssthen * CNAME, record the CNAME rrset so the caller can take 10212be9e038Ssthen * the appropriate action. Note that we don't check the 10222be9e038Ssthen * action type; it should normally be 'redirect', but it 10232be9e038Ssthen * can be of other type when a data-dependent tag action 10242be9e038Ssthen * uses redirect response-ip data. 10252be9e038Ssthen */ 10262be9e038Ssthen if(redirect_rrset && 10272be9e038Ssthen redirect_rrset->rk.type == ntohs(LDNS_RR_TYPE_CNAME) && 10282be9e038Ssthen qinfo->qtype != LDNS_RR_TYPE_ANY) 10292be9e038Ssthen *alias_rrset = redirect_rrset; 10302be9e038Ssthen /* on success, populate respip result structure */ 10312be9e038Ssthen ret = populate_action_info(actinfo, action, raddr, 1032eaf2578eSsthen redirect_rrset, tag, ipset, search_only, region, 1033eaf2578eSsthen rpz_used, rpz_log, log_name, rpz_cname_override); 1034eaf2578eSsthen } 1035eaf2578eSsthen if(raddr) { 1036eaf2578eSsthen lock_rw_unlock(&raddr->lock); 10372be9e038Ssthen } 1038a3167c07Ssthen if(rpz_used) { 1039a3167c07Ssthen lock_rw_unlock(&a->lock); 1040a3167c07Ssthen } 10412be9e038Ssthen return ret; 10422be9e038Ssthen } 10432be9e038Ssthen 10442be9e038Ssthen static int 10452be9e038Ssthen generate_cname_request(struct module_qstate* qstate, 10462be9e038Ssthen struct ub_packed_rrset_key* alias_rrset) 10472be9e038Ssthen { 10482be9e038Ssthen struct module_qstate* subq = NULL; 10492be9e038Ssthen struct query_info subqi; 10502be9e038Ssthen 10512be9e038Ssthen memset(&subqi, 0, sizeof(subqi)); 10522be9e038Ssthen get_cname_target(alias_rrset, &subqi.qname, &subqi.qname_len); 10532be9e038Ssthen if(!subqi.qname) 10542be9e038Ssthen return 0; /* unexpected: not a valid CNAME RDATA */ 10552be9e038Ssthen subqi.qtype = qstate->qinfo.qtype; 10562be9e038Ssthen subqi.qclass = qstate->qinfo.qclass; 10572be9e038Ssthen fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub)); 10582be9e038Ssthen return (*qstate->env->attach_sub)(qstate, &subqi, BIT_RD, 0, 0, &subq); 10592be9e038Ssthen } 10602be9e038Ssthen 10612be9e038Ssthen void 10622be9e038Ssthen respip_operate(struct module_qstate* qstate, enum module_ev event, int id, 10632be9e038Ssthen struct outbound_entry* outbound) 10642be9e038Ssthen { 10652be9e038Ssthen struct respip_qstate* rq = (struct respip_qstate*)qstate->minfo[id]; 10662be9e038Ssthen 10672be9e038Ssthen log_query_info(VERB_QUERY, "respip operate: query", &qstate->qinfo); 10682be9e038Ssthen (void)outbound; 10692be9e038Ssthen 10702be9e038Ssthen if(event == module_event_new || event == module_event_pass) { 10712be9e038Ssthen if(!rq) { 10722be9e038Ssthen rq = regional_alloc_zero(qstate->region, sizeof(*rq)); 10732be9e038Ssthen if(!rq) 10742be9e038Ssthen goto servfail; 10752be9e038Ssthen rq->state = RESPIP_INIT; 10762be9e038Ssthen qstate->minfo[id] = rq; 10772be9e038Ssthen } 10782be9e038Ssthen if(rq->state == RESPIP_SUBQUERY_FINISHED) { 10792be9e038Ssthen qstate->ext_state[id] = module_finished; 10802be9e038Ssthen return; 10812be9e038Ssthen } 10822be9e038Ssthen verbose(VERB_ALGO, "respip: pass to next module"); 10832be9e038Ssthen qstate->ext_state[id] = module_wait_module; 10842be9e038Ssthen } else if(event == module_event_moddone) { 10852be9e038Ssthen /* If the reply may be subject to response-ip rewriting 10862be9e038Ssthen * according to the query type, check the actions. If a 10872be9e038Ssthen * rewrite is necessary, we'll replace the reply in qstate 10882be9e038Ssthen * with the new one. */ 10892be9e038Ssthen enum module_ext_state next_state = module_finished; 10902be9e038Ssthen 10912be9e038Ssthen if((qstate->qinfo.qtype == LDNS_RR_TYPE_A || 10922be9e038Ssthen qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA || 10932be9e038Ssthen qstate->qinfo.qtype == LDNS_RR_TYPE_ANY) && 10942be9e038Ssthen qstate->return_msg && qstate->return_msg->rep) { 10952be9e038Ssthen struct reply_info* new_rep = qstate->return_msg->rep; 10962be9e038Ssthen struct ub_packed_rrset_key* alias_rrset = NULL; 1097eba819a2Ssthen struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL}; 1098eaf2578eSsthen actinfo.action = respip_none; 10992be9e038Ssthen 11002be9e038Ssthen if(!respip_rewrite_reply(&qstate->qinfo, 11012be9e038Ssthen qstate->client_info, qstate->return_msg->rep, 11022be9e038Ssthen &new_rep, &actinfo, &alias_rrset, 0, 11030bdb4f62Ssthen qstate->region, qstate->env->auth_zones, 11040bdb4f62Ssthen &qstate->rpz_passthru)) { 11052be9e038Ssthen goto servfail; 11062be9e038Ssthen } 11072be9e038Ssthen if(actinfo.action != respip_none) { 11082be9e038Ssthen /* save action info for logging on a 11092be9e038Ssthen * per-front-end-query basis */ 11102be9e038Ssthen if(!(qstate->respip_action_info = 11112be9e038Ssthen regional_alloc_init(qstate->region, 11122be9e038Ssthen &actinfo, sizeof(actinfo)))) 11132be9e038Ssthen { 11142be9e038Ssthen log_err("out of memory"); 11152be9e038Ssthen goto servfail; 11162be9e038Ssthen } 11172be9e038Ssthen } else { 11182be9e038Ssthen qstate->respip_action_info = NULL; 11192be9e038Ssthen } 1120eaf2578eSsthen if (actinfo.action == respip_always_deny || 1121eaf2578eSsthen (new_rep == qstate->return_msg->rep && 11222be9e038Ssthen (actinfo.action == respip_deny || 1123eaf2578eSsthen actinfo.action == respip_inform_deny))) { 11242be9e038Ssthen /* for deny-variant actions (unless response-ip 11252be9e038Ssthen * data is applied), mark the query state so 11262be9e038Ssthen * the response will be dropped for all 11272be9e038Ssthen * clients. */ 11282be9e038Ssthen qstate->is_drop = 1; 11292be9e038Ssthen } else if(alias_rrset) { 11302be9e038Ssthen if(!generate_cname_request(qstate, alias_rrset)) 11312be9e038Ssthen goto servfail; 11322be9e038Ssthen next_state = module_wait_subquery; 11332be9e038Ssthen } 11342be9e038Ssthen qstate->return_msg->rep = new_rep; 11352be9e038Ssthen } 11362be9e038Ssthen qstate->ext_state[id] = next_state; 11372be9e038Ssthen } else 11382be9e038Ssthen qstate->ext_state[id] = module_finished; 11392be9e038Ssthen 11402be9e038Ssthen return; 11412be9e038Ssthen 11422be9e038Ssthen servfail: 11432be9e038Ssthen qstate->return_rcode = LDNS_RCODE_SERVFAIL; 11442be9e038Ssthen qstate->return_msg = NULL; 11452be9e038Ssthen } 11462be9e038Ssthen 11472be9e038Ssthen int 11482be9e038Ssthen respip_merge_cname(struct reply_info* base_rep, 11492be9e038Ssthen const struct query_info* qinfo, const struct reply_info* tgt_rep, 11502be9e038Ssthen const struct respip_client_info* cinfo, int must_validate, 1151eaf2578eSsthen struct reply_info** new_repp, struct regional* region, 1152eaf2578eSsthen struct auth_zones* az) 11532be9e038Ssthen { 11542be9e038Ssthen struct reply_info* new_rep; 11552be9e038Ssthen struct reply_info* tmp_rep = NULL; /* just a placeholder */ 11562be9e038Ssthen struct ub_packed_rrset_key* alias_rrset = NULL; /* ditto */ 11572be9e038Ssthen uint16_t tgt_rcode; 11582be9e038Ssthen size_t i, j; 1159eba819a2Ssthen struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL}; 1160eaf2578eSsthen actinfo.action = respip_none; 11612be9e038Ssthen 11622be9e038Ssthen /* If the query for the CNAME target would result in an unusual rcode, 11632be9e038Ssthen * we generally translate it as a failure for the base query 11642be9e038Ssthen * (which would then be translated into SERVFAIL). The only exception 11652be9e038Ssthen * is NXDOMAIN and YXDOMAIN, which are passed to the end client(s). 11662be9e038Ssthen * The YXDOMAIN case would be rare but still possible (when 11672be9e038Ssthen * DNSSEC-validated DNAME has been cached but synthesizing CNAME 11682be9e038Ssthen * can't be generated due to length limitation) */ 11692be9e038Ssthen tgt_rcode = FLAGS_GET_RCODE(tgt_rep->flags); 11702be9e038Ssthen if((tgt_rcode != LDNS_RCODE_NOERROR && 11712be9e038Ssthen tgt_rcode != LDNS_RCODE_NXDOMAIN && 11722be9e038Ssthen tgt_rcode != LDNS_RCODE_YXDOMAIN) || 11732be9e038Ssthen (must_validate && tgt_rep->security <= sec_status_bogus)) { 11742be9e038Ssthen return 0; 11752be9e038Ssthen } 11762be9e038Ssthen 11772be9e038Ssthen /* see if the target reply would be subject to a response-ip action. */ 11782be9e038Ssthen if(!respip_rewrite_reply(qinfo, cinfo, tgt_rep, &tmp_rep, &actinfo, 11790bdb4f62Ssthen &alias_rrset, 1, region, az, NULL)) 11802be9e038Ssthen return 0; 11812be9e038Ssthen if(actinfo.action != respip_none) { 11822be9e038Ssthen log_info("CNAME target of redirect response-ip action would " 11832be9e038Ssthen "be subject to response-ip action, too; stripped"); 11842be9e038Ssthen *new_repp = base_rep; 11852be9e038Ssthen return 1; 11862be9e038Ssthen } 11872be9e038Ssthen 11882be9e038Ssthen /* Append target reply to the base. Since we cannot assume 11892be9e038Ssthen * tgt_rep->rrsets is valid throughout the lifetime of new_rep 11902be9e038Ssthen * or it can be safely shared by multiple threads, we need to make a 11912be9e038Ssthen * deep copy. */ 11922be9e038Ssthen new_rep = make_new_reply_info(base_rep, region, 11932be9e038Ssthen base_rep->an_numrrsets + tgt_rep->an_numrrsets, 11942be9e038Ssthen base_rep->an_numrrsets); 11952be9e038Ssthen if(!new_rep) 11962be9e038Ssthen return 0; 11972be9e038Ssthen for(i=0,j=base_rep->an_numrrsets; i<tgt_rep->an_numrrsets; i++,j++) { 1198e21c60efSsthen new_rep->rrsets[j] = respip_copy_rrset(tgt_rep->rrsets[i], region); 11992be9e038Ssthen if(!new_rep->rrsets[j]) 12002be9e038Ssthen return 0; 12012be9e038Ssthen } 12022be9e038Ssthen 12032be9e038Ssthen FLAGS_SET_RCODE(new_rep->flags, tgt_rcode); 12042be9e038Ssthen *new_repp = new_rep; 12052be9e038Ssthen return 1; 12062be9e038Ssthen } 12072be9e038Ssthen 12082be9e038Ssthen void 12092be9e038Ssthen respip_inform_super(struct module_qstate* qstate, int id, 12102be9e038Ssthen struct module_qstate* super) 12112be9e038Ssthen { 12122be9e038Ssthen struct respip_qstate* rq = (struct respip_qstate*)super->minfo[id]; 12132be9e038Ssthen struct reply_info* new_rep = NULL; 12142be9e038Ssthen 12152be9e038Ssthen rq->state = RESPIP_SUBQUERY_FINISHED; 12162be9e038Ssthen 12172be9e038Ssthen /* respip subquery should have always been created with a valid reply 12182be9e038Ssthen * in super. */ 12192be9e038Ssthen log_assert(super->return_msg && super->return_msg->rep); 12202be9e038Ssthen 12212be9e038Ssthen /* return_msg can be NULL when, e.g., the sub query resulted in 12222be9e038Ssthen * SERVFAIL, in which case we regard it as a failure of the original 12232be9e038Ssthen * query. Other checks are probably redundant, but we check them 12242be9e038Ssthen * for safety. */ 12252be9e038Ssthen if(!qstate->return_msg || !qstate->return_msg->rep || 12262be9e038Ssthen qstate->return_rcode != LDNS_RCODE_NOERROR) 12272be9e038Ssthen goto fail; 12282be9e038Ssthen 12292be9e038Ssthen if(!respip_merge_cname(super->return_msg->rep, &qstate->qinfo, 12302be9e038Ssthen qstate->return_msg->rep, super->client_info, 1231eaf2578eSsthen super->env->need_to_validate, &new_rep, super->region, 1232eaf2578eSsthen qstate->env->auth_zones)) 12332be9e038Ssthen goto fail; 12342be9e038Ssthen super->return_msg->rep = new_rep; 12352be9e038Ssthen return; 12362be9e038Ssthen 12372be9e038Ssthen fail: 12382be9e038Ssthen super->return_rcode = LDNS_RCODE_SERVFAIL; 12392be9e038Ssthen super->return_msg = NULL; 12402be9e038Ssthen return; 12412be9e038Ssthen } 12422be9e038Ssthen 12432be9e038Ssthen void 12442be9e038Ssthen respip_clear(struct module_qstate* qstate, int id) 12452be9e038Ssthen { 12462be9e038Ssthen qstate->minfo[id] = NULL; 12472be9e038Ssthen } 12482be9e038Ssthen 12492be9e038Ssthen size_t 12502be9e038Ssthen respip_get_mem(struct module_env* env, int id) 12512be9e038Ssthen { 12522be9e038Ssthen (void)env; 12532be9e038Ssthen (void)id; 12542be9e038Ssthen return 0; 12552be9e038Ssthen } 12562be9e038Ssthen 12572be9e038Ssthen /** 12582be9e038Ssthen * The response-ip function block 12592be9e038Ssthen */ 12602be9e038Ssthen static struct module_func_block respip_block = { 12612be9e038Ssthen "respip", 1262*98bc733bSsthen NULL, NULL, &respip_init, &respip_deinit, &respip_operate, 1263*98bc733bSsthen &respip_inform_super, &respip_clear, &respip_get_mem 12642be9e038Ssthen }; 12652be9e038Ssthen 12662be9e038Ssthen struct module_func_block* 12672be9e038Ssthen respip_get_funcblock(void) 12682be9e038Ssthen { 12692be9e038Ssthen return &respip_block; 12702be9e038Ssthen } 12712be9e038Ssthen 12722be9e038Ssthen enum respip_action 12732be9e038Ssthen resp_addr_get_action(const struct resp_addr* addr) 12742be9e038Ssthen { 12752be9e038Ssthen return addr ? addr->action : respip_none; 12762be9e038Ssthen } 12772be9e038Ssthen 12782be9e038Ssthen struct ub_packed_rrset_key* 12792be9e038Ssthen resp_addr_get_rrset(struct resp_addr* addr) 12802be9e038Ssthen { 12812be9e038Ssthen return addr ? addr->data : NULL; 12822be9e038Ssthen } 12832be9e038Ssthen 12842be9e038Ssthen int 12852be9e038Ssthen respip_set_is_empty(const struct respip_set* set) 12862be9e038Ssthen { 12872be9e038Ssthen return set ? set->ip_tree.count == 0 : 1; 12882be9e038Ssthen } 12892be9e038Ssthen 12902be9e038Ssthen void 1291eaf2578eSsthen respip_inform_print(struct respip_action_info* respip_actinfo, uint8_t* qname, 12922be9e038Ssthen uint16_t qtype, uint16_t qclass, struct local_rrset* local_alias, 129345872187Ssthen struct sockaddr_storage* addr, socklen_t addrlen) 12942be9e038Ssthen { 12952be9e038Ssthen char srcip[128], respip[128], txt[512]; 12962be9e038Ssthen unsigned port; 1297eaf2578eSsthen struct respip_addr_info* respip_addr = respip_actinfo->addrinfo; 1298eaf2578eSsthen size_t txtlen = 0; 1299eaf2578eSsthen const char* actionstr = NULL; 13002be9e038Ssthen 13012be9e038Ssthen if(local_alias) 13022be9e038Ssthen qname = local_alias->rrset->rk.dname; 130345872187Ssthen port = (unsigned)((addr->ss_family == AF_INET) ? 130445872187Ssthen ntohs(((struct sockaddr_in*)addr)->sin_port) : 130545872187Ssthen ntohs(((struct sockaddr_in6*)addr)->sin6_port)); 130645872187Ssthen addr_to_str(addr, addrlen, srcip, sizeof(srcip)); 13072be9e038Ssthen addr_to_str(&respip_addr->addr, respip_addr->addrlen, 13082be9e038Ssthen respip, sizeof(respip)); 1309eaf2578eSsthen if(respip_actinfo->rpz_log) { 1310eaf2578eSsthen txtlen += snprintf(txt+txtlen, sizeof(txt)-txtlen, "%s", 13110bdb4f62Ssthen "rpz: applied "); 1312eaf2578eSsthen if(respip_actinfo->rpz_cname_override) 1313eaf2578eSsthen actionstr = rpz_action_to_string( 1314eaf2578eSsthen RPZ_CNAME_OVERRIDE_ACTION); 1315eaf2578eSsthen else 1316eaf2578eSsthen actionstr = rpz_action_to_string( 1317eaf2578eSsthen respip_action_to_rpz_action( 1318eaf2578eSsthen respip_actinfo->action)); 1319eaf2578eSsthen } 1320eaf2578eSsthen if(respip_actinfo->log_name) { 1321eaf2578eSsthen txtlen += snprintf(txt+txtlen, sizeof(txt)-txtlen, 1322eaf2578eSsthen "[%s] ", respip_actinfo->log_name); 1323eaf2578eSsthen } 1324eaf2578eSsthen snprintf(txt+txtlen, sizeof(txt)-txtlen, 1325eaf2578eSsthen "%s/%d %s %s@%u", respip, respip_addr->net, 1326eaf2578eSsthen (actionstr) ? actionstr : "inform", srcip, port); 1327ebf5bb73Ssthen log_nametypeclass(NO_VERBOSE, txt, qname, qtype, qclass); 13282be9e038Ssthen } 1329