12be9e038Ssthen /* 22be9e038Ssthen * edns-subnet/subnetmod.c - edns subnet module. Must be called before validator 32be9e038Ssthen * and iterator. 42be9e038Ssthen * 52be9e038Ssthen * Copyright (c) 2013, NLnet Labs. All rights reserved. 62be9e038Ssthen * 72be9e038Ssthen * This software is open source. 82be9e038Ssthen * 92be9e038Ssthen * Redistribution and use in source and binary forms, with or without 102be9e038Ssthen * modification, are permitted provided that the following conditions 112be9e038Ssthen * are met: 122be9e038Ssthen * 132be9e038Ssthen * Redistributions of source code must retain the above copyright notice, 142be9e038Ssthen * this list of conditions and the following disclaimer. 152be9e038Ssthen * 162be9e038Ssthen * Redistributions in binary form must reproduce the above copyright notice, 172be9e038Ssthen * this list of conditions and the following disclaimer in the documentation 182be9e038Ssthen * and/or other materials provided with the distribution. 192be9e038Ssthen * 202be9e038Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may 212be9e038Ssthen * be used to endorse or promote products derived from this software without 222be9e038Ssthen * specific prior written permission. 232be9e038Ssthen * 242be9e038Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 252be9e038Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 262be9e038Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 272be9e038Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 282be9e038Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 292be9e038Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 302be9e038Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 312be9e038Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 322be9e038Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 332be9e038Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 342be9e038Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 352be9e038Ssthen */ 362be9e038Ssthen /** 372be9e038Ssthen * \file 382be9e038Ssthen * subnet module for unbound. 392be9e038Ssthen */ 402be9e038Ssthen 412be9e038Ssthen #include "config.h" 422be9e038Ssthen 432be9e038Ssthen #ifdef CLIENT_SUBNET /* keeps splint happy */ 442be9e038Ssthen 452be9e038Ssthen #include "edns-subnet/subnetmod.h" 462be9e038Ssthen #include "edns-subnet/edns-subnet.h" 472be9e038Ssthen #include "edns-subnet/addrtree.h" 482be9e038Ssthen #include "edns-subnet/subnet-whitelist.h" 492be9e038Ssthen 502be9e038Ssthen #include "services/mesh.h" 512be9e038Ssthen #include "services/cache/dns.h" 522be9e038Ssthen #include "util/module.h" 532be9e038Ssthen #include "util/regional.h" 542be9e038Ssthen #include "util/storage/slabhash.h" 552be9e038Ssthen #include "util/config_file.h" 562be9e038Ssthen #include "util/data/msgreply.h" 572be9e038Ssthen #include "sldns/sbuffer.h" 5845872187Ssthen #include "sldns/wire2str.h" 593150e5f6Ssthen #include "iterator/iter_utils.h" 602bdc0ed1Ssthen #ifdef USE_CACHEDB 612bdc0ed1Ssthen #include "cachedb/cachedb.h" 622bdc0ed1Ssthen #endif 632be9e038Ssthen 642be9e038Ssthen /** externally called */ 652be9e038Ssthen void 662be9e038Ssthen subnet_data_delete(void *d, void *ATTR_UNUSED(arg)) 672be9e038Ssthen { 682be9e038Ssthen struct subnet_msg_cache_data *r; 692be9e038Ssthen r = (struct subnet_msg_cache_data*)d; 702be9e038Ssthen addrtree_delete(r->tree4); 712be9e038Ssthen addrtree_delete(r->tree6); 722be9e038Ssthen free(r); 732be9e038Ssthen } 742be9e038Ssthen 752be9e038Ssthen /** externally called */ 762be9e038Ssthen size_t 772be9e038Ssthen msg_cache_sizefunc(void *k, void *d) 782be9e038Ssthen { 792be9e038Ssthen struct msgreply_entry *q = (struct msgreply_entry*)k; 802be9e038Ssthen struct subnet_msg_cache_data *r = (struct subnet_msg_cache_data*)d; 812be9e038Ssthen size_t s = sizeof(struct msgreply_entry) 822be9e038Ssthen + sizeof(struct subnet_msg_cache_data) 832be9e038Ssthen + q->key.qname_len + lock_get_mem(&q->entry.lock); 842be9e038Ssthen s += addrtree_size(r->tree4); 852be9e038Ssthen s += addrtree_size(r->tree6); 862be9e038Ssthen return s; 872be9e038Ssthen } 882be9e038Ssthen 892be9e038Ssthen /** new query for ecs module */ 902be9e038Ssthen static int 912be9e038Ssthen subnet_new_qstate(struct module_qstate *qstate, int id) 922be9e038Ssthen { 932be9e038Ssthen struct subnet_qstate *sq = (struct subnet_qstate*)regional_alloc( 942be9e038Ssthen qstate->region, sizeof(struct subnet_qstate)); 952be9e038Ssthen if(!sq) 962be9e038Ssthen return 0; 972be9e038Ssthen qstate->minfo[id] = sq; 982be9e038Ssthen memset(sq, 0, sizeof(*sq)); 993150e5f6Ssthen sq->started_no_cache_store = qstate->no_cache_store; 100d1e2768aSsthen sq->started_no_cache_lookup = qstate->no_cache_lookup; 1012be9e038Ssthen return 1; 1022be9e038Ssthen } 1032be9e038Ssthen 1042be9e038Ssthen /** Add ecs struct to edns list, after parsing it to wire format. */ 1050bdb4f62Ssthen void 1060bdb4f62Ssthen subnet_ecs_opt_list_append(struct ecs_data* ecs, struct edns_option** list, 107d1e2768aSsthen struct module_qstate *qstate, struct regional *region) 1082be9e038Ssthen { 1092be9e038Ssthen size_t sn_octs, sn_octs_remainder; 1102be9e038Ssthen sldns_buffer* buf = qstate->env->scratch_buffer; 1112be9e038Ssthen 1122be9e038Ssthen if(ecs->subnet_validdata) { 1132be9e038Ssthen log_assert(ecs->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4 || 1142be9e038Ssthen ecs->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP6); 1152be9e038Ssthen log_assert(ecs->subnet_addr_fam != EDNSSUBNET_ADDRFAM_IP4 || 1162be9e038Ssthen ecs->subnet_source_mask <= INET_SIZE*8); 1172be9e038Ssthen log_assert(ecs->subnet_addr_fam != EDNSSUBNET_ADDRFAM_IP6 || 1182be9e038Ssthen ecs->subnet_source_mask <= INET6_SIZE*8); 1192be9e038Ssthen 1202be9e038Ssthen sn_octs = ecs->subnet_source_mask / 8; 1212be9e038Ssthen sn_octs_remainder = 1222be9e038Ssthen (size_t)((ecs->subnet_source_mask % 8)>0?1:0); 1232be9e038Ssthen 1242be9e038Ssthen log_assert(sn_octs + sn_octs_remainder <= INET6_SIZE); 1252be9e038Ssthen 1262be9e038Ssthen sldns_buffer_clear(buf); 1272be9e038Ssthen sldns_buffer_write_u16(buf, ecs->subnet_addr_fam); 1282be9e038Ssthen sldns_buffer_write_u8(buf, ecs->subnet_source_mask); 1292be9e038Ssthen sldns_buffer_write_u8(buf, ecs->subnet_scope_mask); 1302be9e038Ssthen sldns_buffer_write(buf, ecs->subnet_addr, sn_octs); 1312be9e038Ssthen if(sn_octs_remainder) 1322be9e038Ssthen sldns_buffer_write_u8(buf, ecs->subnet_addr[sn_octs] & 1332be9e038Ssthen ~(0xFF >> (ecs->subnet_source_mask % 8))); 1342be9e038Ssthen sldns_buffer_flip(buf); 1352be9e038Ssthen 1362be9e038Ssthen edns_opt_list_append(list, 1372be9e038Ssthen qstate->env->cfg->client_subnet_opcode, 1382be9e038Ssthen sn_octs + sn_octs_remainder + 4, 139d1e2768aSsthen sldns_buffer_begin(buf), region); 1402be9e038Ssthen } 1412be9e038Ssthen } 1422be9e038Ssthen 1432be9e038Ssthen int ecs_whitelist_check(struct query_info* qinfo, 1442be9e038Ssthen uint16_t ATTR_UNUSED(flags), struct module_qstate* qstate, 1452be9e038Ssthen struct sockaddr_storage* addr, socklen_t addrlen, 1462be9e038Ssthen uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), 147d1e2768aSsthen struct regional *region, int id, void* ATTR_UNUSED(cbargs)) 1482be9e038Ssthen { 1492be9e038Ssthen struct subnet_qstate *sq; 1502be9e038Ssthen struct subnet_env *sn_env; 1512be9e038Ssthen 1522be9e038Ssthen if(!(sq=(struct subnet_qstate*)qstate->minfo[id])) 1532be9e038Ssthen return 1; 1542be9e038Ssthen sn_env = (struct subnet_env*)qstate->env->modinfo[id]; 1552be9e038Ssthen 1562be9e038Ssthen /* Cache by default, might be disabled after parsing EDNS option 1572be9e038Ssthen * received from nameserver. */ 1582bdc0ed1Ssthen if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL, NULL, 0)) { 1592be9e038Ssthen qstate->no_cache_store = 0; 1603150e5f6Ssthen } 1612be9e038Ssthen 162d896b962Ssthen sq->subnet_sent_no_subnet = 0; 1632be9e038Ssthen if(sq->ecs_server_out.subnet_validdata && ((sq->subnet_downstream && 1642be9e038Ssthen qstate->env->cfg->client_subnet_always_forward) || 1652be9e038Ssthen ecs_is_whitelisted(sn_env->whitelist, 1662be9e038Ssthen addr, addrlen, qinfo->qname, qinfo->qname_len, 1672be9e038Ssthen qinfo->qclass))) { 1682be9e038Ssthen /* Address on whitelist or client query contains ECS option, we 1692be9e038Ssthen * want to sent out ECS. Only add option if it is not already 1702be9e038Ssthen * set. */ 1710bdb4f62Ssthen if(!edns_opt_list_find(qstate->edns_opts_back_out, 1720bdb4f62Ssthen qstate->env->cfg->client_subnet_opcode)) { 173d896b962Ssthen /* if the client is not wanting an EDNS subnet option, 174d896b962Ssthen * omit it and store that we omitted it but actually 175d896b962Ssthen * are doing EDNS subnet to the server. */ 176d896b962Ssthen if(sq->ecs_server_out.subnet_source_mask == 0) { 177d896b962Ssthen sq->subnet_sent_no_subnet = 1; 178d896b962Ssthen sq->subnet_sent = 0; 179d896b962Ssthen return 1; 180d896b962Ssthen } 1810bdb4f62Ssthen subnet_ecs_opt_list_append(&sq->ecs_server_out, 182d1e2768aSsthen &qstate->edns_opts_back_out, qstate, region); 1830bdb4f62Ssthen } 1842be9e038Ssthen sq->subnet_sent = 1; 1852be9e038Ssthen } 1860bdb4f62Ssthen else { 1872be9e038Ssthen /* Outgoing ECS option is set, but we don't want to sent it to 1882be9e038Ssthen * this address, remove option. */ 1890bdb4f62Ssthen if(edns_opt_list_find(qstate->edns_opts_back_out, 1900bdb4f62Ssthen qstate->env->cfg->client_subnet_opcode)) { 1912be9e038Ssthen edns_opt_list_remove(&qstate->edns_opts_back_out, 1922be9e038Ssthen qstate->env->cfg->client_subnet_opcode); 1930bdb4f62Ssthen } 1942be9e038Ssthen sq->subnet_sent = 0; 1952be9e038Ssthen } 1962be9e038Ssthen return 1; 1972be9e038Ssthen } 1982be9e038Ssthen 1992be9e038Ssthen 2003150e5f6Ssthen void 2013150e5f6Ssthen subnet_markdel(void* key) 2023150e5f6Ssthen { 2033150e5f6Ssthen struct msgreply_entry *e = (struct msgreply_entry*)key; 2043150e5f6Ssthen e->key.qtype = 0; 2053150e5f6Ssthen e->key.qclass = 0; 2063150e5f6Ssthen } 2073150e5f6Ssthen 2082be9e038Ssthen int 2092be9e038Ssthen subnetmod_init(struct module_env *env, int id) 2102be9e038Ssthen { 2112be9e038Ssthen struct subnet_env *sn_env = (struct subnet_env*)calloc(1, 2122be9e038Ssthen sizeof(struct subnet_env)); 2132be9e038Ssthen if(!sn_env) { 2142be9e038Ssthen log_err("malloc failure"); 2152be9e038Ssthen return 0; 2162be9e038Ssthen } 2172be9e038Ssthen alloc_init(&sn_env->alloc, NULL, 0); 2182be9e038Ssthen env->modinfo[id] = (void*)sn_env; 2198b7325afSsthen 2208b7325afSsthen /* Warn that serve-expired and prefetch do not work with the subnet 2218b7325afSsthen * module cache. */ 2228b7325afSsthen if(env->cfg->serve_expired) 2238b7325afSsthen log_warn( 2248b7325afSsthen "subnetcache: serve-expired is set but not working " 2258b7325afSsthen "for data originating from the subnet module cache."); 2268b7325afSsthen if(env->cfg->prefetch) 2278b7325afSsthen log_warn( 2288b7325afSsthen "subnetcache: prefetch is set but not working " 2298b7325afSsthen "for data originating from the subnet module cache."); 2302be9e038Ssthen /* Copy msg_cache settings */ 2312be9e038Ssthen sn_env->subnet_msg_cache = slabhash_create(env->cfg->msg_cache_slabs, 2322be9e038Ssthen HASH_DEFAULT_STARTARRAY, env->cfg->msg_cache_size, 2332be9e038Ssthen msg_cache_sizefunc, query_info_compare, query_entry_delete, 2342be9e038Ssthen subnet_data_delete, NULL); 2353150e5f6Ssthen slabhash_setmarkdel(sn_env->subnet_msg_cache, &subnet_markdel); 2362be9e038Ssthen if(!sn_env->subnet_msg_cache) { 237191f22c6Ssthen log_err("subnetcache: could not create cache"); 2382be9e038Ssthen free(sn_env); 2392be9e038Ssthen env->modinfo[id] = NULL; 2402be9e038Ssthen return 0; 2412be9e038Ssthen } 2422be9e038Ssthen /* whitelist for edns subnet capable servers */ 2432be9e038Ssthen sn_env->whitelist = ecs_whitelist_create(); 2442be9e038Ssthen if(!sn_env->whitelist || 2452be9e038Ssthen !ecs_whitelist_apply_cfg(sn_env->whitelist, env->cfg)) { 246191f22c6Ssthen log_err("subnetcache: could not create ECS whitelist"); 2472be9e038Ssthen slabhash_delete(sn_env->subnet_msg_cache); 2482be9e038Ssthen free(sn_env); 2492be9e038Ssthen env->modinfo[id] = NULL; 2502be9e038Ssthen return 0; 2512be9e038Ssthen } 2522be9e038Ssthen 253191f22c6Ssthen verbose(VERB_QUERY, "subnetcache: option registered (%d)", 2542be9e038Ssthen env->cfg->client_subnet_opcode); 2552be9e038Ssthen /* Create new mesh state for all queries. */ 2562be9e038Ssthen env->unique_mesh = 1; 2572be9e038Ssthen if(!edns_register_option(env->cfg->client_subnet_opcode, 2582be9e038Ssthen env->cfg->client_subnet_always_forward /* bypass cache */, 2590bdb4f62Ssthen 1 /* no aggregation */, env)) { 260191f22c6Ssthen log_err("subnetcache: could not register opcode"); 2612be9e038Ssthen ecs_whitelist_delete(sn_env->whitelist); 2622be9e038Ssthen slabhash_delete(sn_env->subnet_msg_cache); 2632be9e038Ssthen free(sn_env); 2642be9e038Ssthen env->modinfo[id] = NULL; 2652be9e038Ssthen return 0; 2662be9e038Ssthen } 2672be9e038Ssthen inplace_cb_register((void*)ecs_whitelist_check, inplace_cb_query, NULL, 2682be9e038Ssthen env, id); 2692be9e038Ssthen inplace_cb_register((void*)ecs_edns_back_parsed, 2702be9e038Ssthen inplace_cb_edns_back_parsed, NULL, env, id); 2712be9e038Ssthen inplace_cb_register((void*)ecs_query_response, 2722be9e038Ssthen inplace_cb_query_response, NULL, env, id); 2732be9e038Ssthen lock_rw_init(&sn_env->biglock); 2742be9e038Ssthen return 1; 2752be9e038Ssthen } 2762be9e038Ssthen 2772be9e038Ssthen void 2782be9e038Ssthen subnetmod_deinit(struct module_env *env, int id) 2792be9e038Ssthen { 2802be9e038Ssthen struct subnet_env *sn_env; 2812be9e038Ssthen if(!env || !env->modinfo[id]) 2822be9e038Ssthen return; 2832be9e038Ssthen sn_env = (struct subnet_env*)env->modinfo[id]; 2842be9e038Ssthen lock_rw_destroy(&sn_env->biglock); 2852be9e038Ssthen inplace_cb_delete(env, inplace_cb_edns_back_parsed, id); 2862be9e038Ssthen inplace_cb_delete(env, inplace_cb_query, id); 2872be9e038Ssthen inplace_cb_delete(env, inplace_cb_query_response, id); 2882be9e038Ssthen ecs_whitelist_delete(sn_env->whitelist); 2892be9e038Ssthen slabhash_delete(sn_env->subnet_msg_cache); 2902be9e038Ssthen alloc_clear(&sn_env->alloc); 2912be9e038Ssthen free(sn_env); 2922be9e038Ssthen env->modinfo[id] = NULL; 2932be9e038Ssthen } 2942be9e038Ssthen 2952be9e038Ssthen /** Tells client that upstream has no/improper support */ 2962be9e038Ssthen static void 2972be9e038Ssthen cp_edns_bad_response(struct ecs_data *target, struct ecs_data *source) 2982be9e038Ssthen { 2992be9e038Ssthen target->subnet_scope_mask = 0; 3002be9e038Ssthen target->subnet_source_mask = source->subnet_source_mask; 3012be9e038Ssthen target->subnet_addr_fam = source->subnet_addr_fam; 3022be9e038Ssthen memcpy(target->subnet_addr, source->subnet_addr, INET6_SIZE); 3032be9e038Ssthen target->subnet_validdata = 1; 3042be9e038Ssthen } 3052be9e038Ssthen 3062be9e038Ssthen static void 3072be9e038Ssthen delfunc(void *envptr, void *elemptr) { 3082be9e038Ssthen struct reply_info *elem = (struct reply_info *)elemptr; 3092be9e038Ssthen struct subnet_env *env = (struct subnet_env *)envptr; 3102be9e038Ssthen reply_info_parsedelete(elem, &env->alloc); 3112be9e038Ssthen } 3122be9e038Ssthen 3132be9e038Ssthen static size_t 3142be9e038Ssthen sizefunc(void *elemptr) { 3152be9e038Ssthen struct reply_info *elem = (struct reply_info *)elemptr; 3162bdc0ed1Ssthen size_t s = sizeof (struct reply_info) - sizeof (struct rrset_ref) 3172be9e038Ssthen + elem->rrset_count * sizeof (struct rrset_ref) 3182be9e038Ssthen + elem->rrset_count * sizeof (struct ub_packed_rrset_key *); 3192bdc0ed1Ssthen size_t i; 3202bdc0ed1Ssthen for (i = 0; i < elem->rrset_count; i++) { 3212bdc0ed1Ssthen struct ub_packed_rrset_key *key = elem->rrsets[i]; 3222bdc0ed1Ssthen struct packed_rrset_data *data = key->entry.data; 3232bdc0ed1Ssthen s += ub_rrset_sizefunc(key, data); 3242bdc0ed1Ssthen } 3252bdc0ed1Ssthen if(elem->reason_bogus_str) 3262bdc0ed1Ssthen s += strlen(elem->reason_bogus_str)+1; 3272bdc0ed1Ssthen return s; 3282be9e038Ssthen } 3292be9e038Ssthen 3302be9e038Ssthen /** 3312be9e038Ssthen * Select tree from cache entry based on edns data. 3322be9e038Ssthen * If for address family not present it will create a new one. 3332be9e038Ssthen * NULL on failure to create. */ 3342be9e038Ssthen static struct addrtree* 3352be9e038Ssthen get_tree(struct subnet_msg_cache_data *data, struct ecs_data *edns, 3362be9e038Ssthen struct subnet_env *env, struct config_file* cfg) 3372be9e038Ssthen { 3382be9e038Ssthen struct addrtree *tree; 3392be9e038Ssthen if (edns->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4) { 3402be9e038Ssthen if (!data->tree4) 3412be9e038Ssthen data->tree4 = addrtree_create( 3422be9e038Ssthen cfg->max_client_subnet_ipv4, &delfunc, 3433150e5f6Ssthen &sizefunc, env, cfg->max_ecs_tree_size_ipv4); 3442be9e038Ssthen tree = data->tree4; 3452be9e038Ssthen } else { 3462be9e038Ssthen if (!data->tree6) 3472be9e038Ssthen data->tree6 = addrtree_create( 3482be9e038Ssthen cfg->max_client_subnet_ipv6, &delfunc, 3493150e5f6Ssthen &sizefunc, env, cfg->max_ecs_tree_size_ipv6); 3502be9e038Ssthen tree = data->tree6; 3512be9e038Ssthen } 3522be9e038Ssthen return tree; 3532be9e038Ssthen } 3542be9e038Ssthen 3552be9e038Ssthen static void 3562be9e038Ssthen update_cache(struct module_qstate *qstate, int id) 3572be9e038Ssthen { 3582be9e038Ssthen struct msgreply_entry *mrep_entry; 3592be9e038Ssthen struct addrtree *tree; 3602be9e038Ssthen struct reply_info *rep; 3612be9e038Ssthen struct query_info qinf; 3622be9e038Ssthen struct subnet_env *sne = qstate->env->modinfo[id]; 3632be9e038Ssthen struct subnet_qstate *sq = (struct subnet_qstate*)qstate->minfo[id]; 3642be9e038Ssthen struct slabhash *subnet_msg_cache = sne->subnet_msg_cache; 3652be9e038Ssthen struct ecs_data *edns = &sq->ecs_client_in; 3662be9e038Ssthen size_t i; 3672bdc0ed1Ssthen int only_match_scope_zero, diff_size; 3682be9e038Ssthen 369d1e2768aSsthen /* We already calculated hash upon lookup (lookup_and_reply) if we were 370d1e2768aSsthen * allowed to look in the ECS cache */ 371d1e2768aSsthen hashvalue_type h = qstate->minfo[id] && 372d1e2768aSsthen ((struct subnet_qstate*)qstate->minfo[id])->qinfo_hash_calculated? 3732be9e038Ssthen ((struct subnet_qstate*)qstate->minfo[id])->qinfo_hash : 3742be9e038Ssthen query_info_hash(&qstate->qinfo, qstate->query_flags); 3752be9e038Ssthen /* Step 1, general qinfo lookup */ 3762be9e038Ssthen struct lruhash_entry* lru_entry = slabhash_lookup(subnet_msg_cache, h, 3772be9e038Ssthen &qstate->qinfo, 1); 378550cf4a9Ssthen int need_to_insert = (lru_entry == NULL); 3792be9e038Ssthen if (!lru_entry) { 380550cf4a9Ssthen void* data = calloc(1, 381550cf4a9Ssthen sizeof(struct subnet_msg_cache_data)); 382550cf4a9Ssthen if(!data) { 383550cf4a9Ssthen log_err("malloc failed"); 384550cf4a9Ssthen return; 385550cf4a9Ssthen } 3862be9e038Ssthen qinf = qstate->qinfo; 3872be9e038Ssthen qinf.qname = memdup(qstate->qinfo.qname, 3882be9e038Ssthen qstate->qinfo.qname_len); 3892be9e038Ssthen if(!qinf.qname) { 390550cf4a9Ssthen free(data); 3912be9e038Ssthen log_err("memdup failed"); 3922be9e038Ssthen return; 3932be9e038Ssthen } 394550cf4a9Ssthen mrep_entry = query_info_entrysetup(&qinf, data, h); 3952be9e038Ssthen free(qinf.qname); /* if qname 'consumed', it is set to NULL */ 3962be9e038Ssthen if (!mrep_entry) { 397550cf4a9Ssthen free(data); 3982be9e038Ssthen log_err("query_info_entrysetup failed"); 3992be9e038Ssthen return; 4002be9e038Ssthen } 4012be9e038Ssthen lru_entry = &mrep_entry->entry; 402938a3a5eSflorian lock_rw_wrlock(&lru_entry->lock); 4032be9e038Ssthen } 404550cf4a9Ssthen /* lru_entry->lock is locked regardless of how we got here, 405550cf4a9Ssthen * either from the slabhash_lookup, or above in the new allocated */ 4062be9e038Ssthen /* Step 2, find the correct tree */ 4072be9e038Ssthen if (!(tree = get_tree(lru_entry->data, edns, sne, qstate->env->cfg))) { 408550cf4a9Ssthen lock_rw_unlock(&lru_entry->lock); 409191f22c6Ssthen log_err("subnetcache: cache insertion failed"); 4102be9e038Ssthen return; 4112be9e038Ssthen } 412938a3a5eSflorian lock_quick_lock(&sne->alloc.lock); 4132be9e038Ssthen rep = reply_info_copy(qstate->return_msg->rep, &sne->alloc, NULL); 414938a3a5eSflorian lock_quick_unlock(&sne->alloc.lock); 4152be9e038Ssthen if (!rep) { 416550cf4a9Ssthen lock_rw_unlock(&lru_entry->lock); 417191f22c6Ssthen log_err("subnetcache: cache insertion failed"); 4182be9e038Ssthen return; 4192be9e038Ssthen } 4202be9e038Ssthen 4212be9e038Ssthen /* store RRsets */ 4222be9e038Ssthen for(i=0; i<rep->rrset_count; i++) { 4232be9e038Ssthen rep->ref[i].key = rep->rrsets[i]; 4242be9e038Ssthen rep->ref[i].id = rep->rrsets[i]->id; 4252be9e038Ssthen } 4262be9e038Ssthen reply_info_set_ttls(rep, *qstate->env->now); 4272bdc0ed1Ssthen reply_info_sortref(rep); 4282be9e038Ssthen rep->flags |= (BIT_RA | BIT_QR); /* fix flags to be sensible for */ 4292be9e038Ssthen rep->flags &= ~(BIT_AA | BIT_CD);/* a reply based on the cache */ 43045872187Ssthen if(edns->subnet_source_mask == 0 && edns->subnet_scope_mask == 0) 43145872187Ssthen only_match_scope_zero = 1; 43245872187Ssthen else only_match_scope_zero = 0; 4332bdc0ed1Ssthen diff_size = (int)tree->size_bytes; 4342be9e038Ssthen addrtree_insert(tree, (addrkey_t*)edns->subnet_addr, 435a3167c07Ssthen edns->subnet_source_mask, sq->max_scope, rep, 43645872187Ssthen rep->ttl, *qstate->env->now, only_match_scope_zero); 4372bdc0ed1Ssthen diff_size = (int)tree->size_bytes - diff_size; 438550cf4a9Ssthen 4392be9e038Ssthen lock_rw_unlock(&lru_entry->lock); 440550cf4a9Ssthen if (need_to_insert) { 4412be9e038Ssthen slabhash_insert(subnet_msg_cache, h, lru_entry, lru_entry->data, 4422be9e038Ssthen NULL); 4432bdc0ed1Ssthen } else { 4442bdc0ed1Ssthen slabhash_update_space_used(subnet_msg_cache, h, NULL, 4452bdc0ed1Ssthen diff_size); 4462be9e038Ssthen } 4472be9e038Ssthen } 4482be9e038Ssthen 4492be9e038Ssthen /** Lookup in cache and reply true iff reply is sent. */ 4502be9e038Ssthen static int 4518b7325afSsthen lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq, int prefetch) 4522be9e038Ssthen { 4532be9e038Ssthen struct lruhash_entry *e; 4542be9e038Ssthen struct module_env *env = qstate->env; 4552be9e038Ssthen struct subnet_env *sne = (struct subnet_env*)env->modinfo[id]; 4562be9e038Ssthen hashvalue_type h = query_info_hash(&qstate->qinfo, qstate->query_flags); 4572be9e038Ssthen struct subnet_msg_cache_data *data; 4582be9e038Ssthen struct ecs_data *ecs = &sq->ecs_client_in; 4592be9e038Ssthen struct addrtree *tree; 4602be9e038Ssthen struct addrnode *node; 4612be9e038Ssthen uint8_t scope; 4622be9e038Ssthen 4632be9e038Ssthen memset(&sq->ecs_client_out, 0, sizeof(sq->ecs_client_out)); 4642be9e038Ssthen 465d1e2768aSsthen if (sq) { 466d1e2768aSsthen sq->qinfo_hash = h; /* Might be useful on cache miss */ 467d1e2768aSsthen sq->qinfo_hash_calculated = 1; 468d1e2768aSsthen } 4692be9e038Ssthen e = slabhash_lookup(sne->subnet_msg_cache, h, &qstate->qinfo, 1); 4702be9e038Ssthen if (!e) return 0; /* qinfo not in cache */ 4712be9e038Ssthen data = e->data; 4722be9e038Ssthen tree = (ecs->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4)? 4732be9e038Ssthen data->tree4 : data->tree6; 4742be9e038Ssthen if (!tree) { /* qinfo in cache but not for this family */ 4752be9e038Ssthen lock_rw_unlock(&e->lock); 4762be9e038Ssthen return 0; 4772be9e038Ssthen } 4782be9e038Ssthen node = addrtree_find(tree, (addrkey_t*)ecs->subnet_addr, 4792be9e038Ssthen ecs->subnet_source_mask, *env->now); 4802be9e038Ssthen if (!node) { /* plain old cache miss */ 4812be9e038Ssthen lock_rw_unlock(&e->lock); 4822be9e038Ssthen return 0; 4832be9e038Ssthen } 4842be9e038Ssthen 4852be9e038Ssthen qstate->return_msg = tomsg(NULL, &qstate->qinfo, 486eaf2578eSsthen (struct reply_info *)node->elem, qstate->region, *env->now, 0, 4872be9e038Ssthen env->scratch); 4882be9e038Ssthen scope = (uint8_t)node->scope; 4892be9e038Ssthen lock_rw_unlock(&e->lock); 4902be9e038Ssthen 4912be9e038Ssthen if (!qstate->return_msg) { /* Failed allocation or expired TTL */ 4922be9e038Ssthen return 0; 4932be9e038Ssthen } 4942be9e038Ssthen 4952be9e038Ssthen if (sq->subnet_downstream) { /* relay to interested client */ 4962be9e038Ssthen sq->ecs_client_out.subnet_scope_mask = scope; 4972be9e038Ssthen sq->ecs_client_out.subnet_addr_fam = ecs->subnet_addr_fam; 4982be9e038Ssthen sq->ecs_client_out.subnet_source_mask = ecs->subnet_source_mask; 4992be9e038Ssthen memcpy(&sq->ecs_client_out.subnet_addr, &ecs->subnet_addr, 5002be9e038Ssthen INET6_SIZE); 5012be9e038Ssthen sq->ecs_client_out.subnet_validdata = 1; 5022be9e038Ssthen } 5038b7325afSsthen 5048b7325afSsthen if (prefetch && *qstate->env->now >= ((struct reply_info *)node->elem)->prefetch_ttl) { 5058b7325afSsthen qstate->need_refetch = 1; 5068b7325afSsthen } 5072be9e038Ssthen return 1; 5082be9e038Ssthen } 5092be9e038Ssthen 5102be9e038Ssthen /** 5112be9e038Ssthen * Test first bits of addresses for equality. Caller is responsible 5122be9e038Ssthen * for making sure that both a and b are at least net/8 octets long. 5132be9e038Ssthen * @param a: first address. 5142be9e038Ssthen * @param a: seconds address. 5152be9e038Ssthen * @param net: Number of bits to test. 5162be9e038Ssthen * @return: 1 if equal, 0 otherwise. 5172be9e038Ssthen */ 5182be9e038Ssthen static int 5192be9e038Ssthen common_prefix(uint8_t *a, uint8_t *b, uint8_t net) 5202be9e038Ssthen { 5212be9e038Ssthen size_t n = (size_t)net / 8; 5222be9e038Ssthen return !memcmp(a, b, n) && ((net % 8) == 0 || a[n] == b[n]); 5232be9e038Ssthen } 5242be9e038Ssthen 5252be9e038Ssthen static enum module_ext_state 5262be9e038Ssthen eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq) 5272be9e038Ssthen { 5282be9e038Ssthen struct subnet_env *sne = qstate->env->modinfo[id]; 5292be9e038Ssthen 5302be9e038Ssthen struct ecs_data *c_in = &sq->ecs_client_in; /* rcvd from client */ 5312be9e038Ssthen struct ecs_data *c_out = &sq->ecs_client_out;/* will send to client */ 5322be9e038Ssthen struct ecs_data *s_in = &sq->ecs_server_in; /* rcvd from auth */ 5332be9e038Ssthen struct ecs_data *s_out = &sq->ecs_server_out;/* sent to auth */ 5342be9e038Ssthen 5352be9e038Ssthen memset(c_out, 0, sizeof(*c_out)); 5362be9e038Ssthen 5372308e98cSsthen if (!qstate->return_msg) { 5382308e98cSsthen /* already an answer and its not a message, but retain 5392308e98cSsthen * the actual rcode, instead of module_error, so send 5402308e98cSsthen * module_finished */ 5412308e98cSsthen return module_finished; 5422308e98cSsthen } 5432be9e038Ssthen 5442be9e038Ssthen /* We have not asked for subnet data */ 545d896b962Ssthen if (!sq->subnet_sent && !sq->subnet_sent_no_subnet) { 5462be9e038Ssthen if (s_in->subnet_validdata) 547191f22c6Ssthen verbose(VERB_QUERY, "subnetcache: received spurious data"); 5482be9e038Ssthen if (sq->subnet_downstream) /* Copy back to client */ 5492be9e038Ssthen cp_edns_bad_response(c_out, c_in); 5502be9e038Ssthen return module_finished; 5512be9e038Ssthen } 5522be9e038Ssthen 5532be9e038Ssthen /* subnet sent but nothing came back */ 554d896b962Ssthen if (!s_in->subnet_validdata && !sq->subnet_sent_no_subnet) { 5552be9e038Ssthen /* The authority indicated no support for edns subnet. As a 5562be9e038Ssthen * consequence the answer ended up in the regular cache. It 557e21c60efSsthen * is still useful to put it in the edns subnet cache for 5582be9e038Ssthen * when a client explicitly asks for subnet specific answer. */ 559191f22c6Ssthen verbose(VERB_QUERY, "subnetcache: Authority indicates no support"); 5603150e5f6Ssthen if(!sq->started_no_cache_store) { 5612be9e038Ssthen lock_rw_wrlock(&sne->biglock); 5622be9e038Ssthen update_cache(qstate, id); 5632be9e038Ssthen lock_rw_unlock(&sne->biglock); 5643150e5f6Ssthen } 5652be9e038Ssthen if (sq->subnet_downstream) 5662be9e038Ssthen cp_edns_bad_response(c_out, c_in); 5672be9e038Ssthen return module_finished; 5682be9e038Ssthen } 5692be9e038Ssthen 570d896b962Ssthen /* Purposefully there was no sent subnet, and there is consequently 571d896b962Ssthen * no subnet in the answer. If there was, use the subnet in the answer 572d896b962Ssthen * anyway. But if there is not, treat it as a prefix 0 answer. */ 573d896b962Ssthen if(sq->subnet_sent_no_subnet && !s_in->subnet_validdata) { 574d896b962Ssthen /* Fill in 0.0.0.0/0 scope 0, or ::0/0 scope 0, for caching. */ 575d896b962Ssthen s_in->subnet_addr_fam = s_out->subnet_addr_fam; 576d896b962Ssthen s_in->subnet_source_mask = 0; 577d896b962Ssthen s_in->subnet_scope_mask = 0; 578d896b962Ssthen memset(s_in->subnet_addr, 0, INET6_SIZE); 579d896b962Ssthen s_in->subnet_validdata = 1; 580d896b962Ssthen } 581d896b962Ssthen 5822be9e038Ssthen /* Being here means we have asked for and got a subnet specific 5832be9e038Ssthen * answer. Also, the answer from the authority is not yet cached 5842be9e038Ssthen * anywhere. */ 5852be9e038Ssthen 5862be9e038Ssthen /* can we accept response? */ 5872be9e038Ssthen if(s_out->subnet_addr_fam != s_in->subnet_addr_fam || 5882be9e038Ssthen s_out->subnet_source_mask != s_in->subnet_source_mask || 5892be9e038Ssthen !common_prefix(s_out->subnet_addr, s_in->subnet_addr, 5902be9e038Ssthen s_out->subnet_source_mask)) 5912be9e038Ssthen { 5922be9e038Ssthen /* we can not accept, restart query without option */ 593191f22c6Ssthen verbose(VERB_QUERY, "subnetcache: forged data"); 5942be9e038Ssthen s_out->subnet_validdata = 0; 5952be9e038Ssthen (void)edns_opt_list_remove(&qstate->edns_opts_back_out, 5962be9e038Ssthen qstate->env->cfg->client_subnet_opcode); 5972be9e038Ssthen sq->subnet_sent = 0; 598d896b962Ssthen sq->subnet_sent_no_subnet = 0; 5992be9e038Ssthen return module_restart_next; 6002be9e038Ssthen } 6012be9e038Ssthen 6022be9e038Ssthen lock_rw_wrlock(&sne->biglock); 6033150e5f6Ssthen if(!sq->started_no_cache_store) { 6042be9e038Ssthen update_cache(qstate, id); 6053150e5f6Ssthen } 6062308e98cSsthen sne->num_msg_nocache++; 6072be9e038Ssthen lock_rw_unlock(&sne->biglock); 6082be9e038Ssthen 6092bdc0ed1Ssthen /* If there is an expired answer in the global cache, remove that, 6102bdc0ed1Ssthen * because expired answers would otherwise resurface once the ecs data 6112bdc0ed1Ssthen * expires, giving once in a while global data responses for ecs 6122bdc0ed1Ssthen * domains, with serve expired enabled. */ 6132bdc0ed1Ssthen if(qstate->env->cfg->serve_expired) { 6142bdc0ed1Ssthen msg_cache_remove(qstate->env, qstate->qinfo.qname, 6152bdc0ed1Ssthen qstate->qinfo.qname_len, qstate->qinfo.qtype, 6162bdc0ed1Ssthen qstate->qinfo.qclass, 0); 6172bdc0ed1Ssthen #ifdef USE_CACHEDB 6182bdc0ed1Ssthen if(qstate->env->cachedb_enabled) 6192bdc0ed1Ssthen cachedb_msg_remove(qstate); 6202bdc0ed1Ssthen #endif 6212bdc0ed1Ssthen } 6222bdc0ed1Ssthen 6232be9e038Ssthen if (sq->subnet_downstream) { 6242be9e038Ssthen /* Client wants to see the answer, echo option back 6252be9e038Ssthen * and adjust the scope. */ 6262be9e038Ssthen c_out->subnet_addr_fam = c_in->subnet_addr_fam; 6272be9e038Ssthen c_out->subnet_source_mask = c_in->subnet_source_mask; 6282be9e038Ssthen memcpy(&c_out->subnet_addr, &c_in->subnet_addr, INET6_SIZE); 629a3167c07Ssthen c_out->subnet_scope_mask = sq->max_scope; 6303150e5f6Ssthen /* Limit scope returned to client to scope used for caching. */ 6313150e5f6Ssthen if(c_out->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4) { 6323150e5f6Ssthen if(c_out->subnet_scope_mask > 6333150e5f6Ssthen qstate->env->cfg->max_client_subnet_ipv4) { 6343150e5f6Ssthen c_out->subnet_scope_mask = 6353150e5f6Ssthen qstate->env->cfg->max_client_subnet_ipv4; 6363150e5f6Ssthen } 6373150e5f6Ssthen } 6383150e5f6Ssthen else if(c_out->subnet_scope_mask > 6393150e5f6Ssthen qstate->env->cfg->max_client_subnet_ipv6) { 6403150e5f6Ssthen c_out->subnet_scope_mask = 6413150e5f6Ssthen qstate->env->cfg->max_client_subnet_ipv6; 6423150e5f6Ssthen } 6432be9e038Ssthen c_out->subnet_validdata = 1; 6442be9e038Ssthen } 6452be9e038Ssthen return module_finished; 6462be9e038Ssthen } 6472be9e038Ssthen 6482be9e038Ssthen /** Parse EDNS opt data containing ECS */ 6492be9e038Ssthen static int 6502be9e038Ssthen parse_subnet_option(struct edns_option* ecs_option, struct ecs_data* ecs) 6512be9e038Ssthen { 6522be9e038Ssthen memset(ecs, 0, sizeof(*ecs)); 6532be9e038Ssthen if (ecs_option->opt_len < 4) 6542be9e038Ssthen return 0; 6552be9e038Ssthen 6562be9e038Ssthen ecs->subnet_addr_fam = sldns_read_uint16(ecs_option->opt_data); 6572be9e038Ssthen ecs->subnet_source_mask = ecs_option->opt_data[2]; 6582be9e038Ssthen ecs->subnet_scope_mask = ecs_option->opt_data[3]; 659bdfc4d55Sflorian /* remaining bytes indicate address */ 6602be9e038Ssthen 6612be9e038Ssthen /* validate input*/ 6622be9e038Ssthen /* option length matches calculated length? */ 6632be9e038Ssthen if (ecs_option->opt_len != (size_t)((ecs->subnet_source_mask+7)/8 + 4)) 6642be9e038Ssthen return 0; 6652be9e038Ssthen if (ecs_option->opt_len - 4 > INET6_SIZE || ecs_option->opt_len == 0) 6662be9e038Ssthen return 0; 6672be9e038Ssthen if (ecs->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4) { 6682be9e038Ssthen if (ecs->subnet_source_mask > 32 || ecs->subnet_scope_mask > 32) 6692be9e038Ssthen return 0; 6702be9e038Ssthen } else if (ecs->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP6) { 6712be9e038Ssthen if (ecs->subnet_source_mask > 128 || 6722be9e038Ssthen ecs->subnet_scope_mask > 128) 6732be9e038Ssthen return 0; 6742be9e038Ssthen } else 6752be9e038Ssthen return 0; 6762be9e038Ssthen 6772be9e038Ssthen /* valid ECS data, write to ecs_data */ 6782be9e038Ssthen if (copy_clear(ecs->subnet_addr, INET6_SIZE, ecs_option->opt_data + 4, 6792be9e038Ssthen ecs_option->opt_len - 4, ecs->subnet_source_mask)) 6802be9e038Ssthen return 0; 6812be9e038Ssthen ecs->subnet_validdata = 1; 6822be9e038Ssthen return 1; 6832be9e038Ssthen } 6842be9e038Ssthen 6850bdb4f62Ssthen void 6862be9e038Ssthen subnet_option_from_ss(struct sockaddr_storage *ss, struct ecs_data* ecs, 6872be9e038Ssthen struct config_file* cfg) 6882be9e038Ssthen { 6892be9e038Ssthen void* sinaddr; 6902be9e038Ssthen 6912be9e038Ssthen /* Construct subnet option from original query */ 6922be9e038Ssthen if(((struct sockaddr_in*)ss)->sin_family == AF_INET) { 6932be9e038Ssthen ecs->subnet_source_mask = cfg->max_client_subnet_ipv4; 6942be9e038Ssthen ecs->subnet_addr_fam = EDNSSUBNET_ADDRFAM_IP4; 6952be9e038Ssthen sinaddr = &((struct sockaddr_in*)ss)->sin_addr; 6962be9e038Ssthen if (!copy_clear( ecs->subnet_addr, INET6_SIZE, 6972be9e038Ssthen (uint8_t *)sinaddr, INET_SIZE, 6982be9e038Ssthen ecs->subnet_source_mask)) { 6992be9e038Ssthen ecs->subnet_validdata = 1; 7002be9e038Ssthen } 7012be9e038Ssthen } 7022be9e038Ssthen #ifdef INET6 7032be9e038Ssthen else { 7042be9e038Ssthen ecs->subnet_source_mask = cfg->max_client_subnet_ipv6; 7052be9e038Ssthen ecs->subnet_addr_fam = EDNSSUBNET_ADDRFAM_IP6; 7062be9e038Ssthen sinaddr = &((struct sockaddr_in6*)ss)->sin6_addr; 7072be9e038Ssthen if (!copy_clear( ecs->subnet_addr, INET6_SIZE, 7082be9e038Ssthen (uint8_t *)sinaddr, INET6_SIZE, 7092be9e038Ssthen ecs->subnet_source_mask)) { 7102be9e038Ssthen ecs->subnet_validdata = 1; 7112be9e038Ssthen } 7122be9e038Ssthen } 7132be9e038Ssthen #else 7142be9e038Ssthen /* We don't know how to handle ip6, just pass */ 7152be9e038Ssthen #endif /* INET6 */ 7162be9e038Ssthen } 7172be9e038Ssthen 7182be9e038Ssthen int 7192be9e038Ssthen ecs_query_response(struct module_qstate* qstate, struct dns_msg* response, 7202be9e038Ssthen int id, void* ATTR_UNUSED(cbargs)) 7212be9e038Ssthen { 7222be9e038Ssthen struct subnet_qstate *sq; 7232be9e038Ssthen 7242be9e038Ssthen if(!response || !(sq=(struct subnet_qstate*)qstate->minfo[id])) 7252be9e038Ssthen return 1; 7262be9e038Ssthen 7272be9e038Ssthen if(sq->subnet_sent && 7282be9e038Ssthen FLAGS_GET_RCODE(response->rep->flags) == LDNS_RCODE_REFUSED) { 729bdfc4d55Sflorian /* REFUSED response to ECS query, remove ECS option. */ 7302be9e038Ssthen edns_opt_list_remove(&qstate->edns_opts_back_out, 7312be9e038Ssthen qstate->env->cfg->client_subnet_opcode); 7322be9e038Ssthen sq->subnet_sent = 0; 733d896b962Ssthen sq->subnet_sent_no_subnet = 0; 7342be9e038Ssthen memset(&sq->ecs_server_out, 0, sizeof(sq->ecs_server_out)); 735a3167c07Ssthen } else if (!sq->track_max_scope && 736a3167c07Ssthen FLAGS_GET_RCODE(response->rep->flags) == LDNS_RCODE_NOERROR && 737a3167c07Ssthen response->rep->an_numrrsets > 0 738a3167c07Ssthen ) { 739a3167c07Ssthen struct ub_packed_rrset_key* s = response->rep->rrsets[0]; 740a3167c07Ssthen if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME && 741a3167c07Ssthen query_dname_compare(qstate->qinfo.qname, 742a3167c07Ssthen s->rk.dname) == 0) { 743a3167c07Ssthen /* CNAME response for QNAME. From now on keep track of 744a3167c07Ssthen * longest received ECS prefix for all queries on this 745a3167c07Ssthen * qstate. */ 746a3167c07Ssthen sq->track_max_scope = 1; 747a3167c07Ssthen } 7482be9e038Ssthen } 7492be9e038Ssthen return 1; 7502be9e038Ssthen } 7512be9e038Ssthen 75245872187Ssthen /** verbose print edns subnet option in pretty print */ 75345872187Ssthen static void 75445872187Ssthen subnet_log_print(const char* s, struct edns_option* ecs_opt) 75545872187Ssthen { 75645872187Ssthen if(verbosity >= VERB_ALGO) { 75745872187Ssthen char buf[256]; 75845872187Ssthen char* str = buf; 75945872187Ssthen size_t str_len = sizeof(buf); 76045872187Ssthen if(!ecs_opt) { 76145872187Ssthen verbose(VERB_ALGO, "%s (null)", s); 76245872187Ssthen return; 76345872187Ssthen } 76445872187Ssthen (void)sldns_wire2str_edns_subnet_print(&str, &str_len, 76545872187Ssthen ecs_opt->opt_data, ecs_opt->opt_len); 76645872187Ssthen verbose(VERB_ALGO, "%s %s", s, buf); 76745872187Ssthen } 76845872187Ssthen } 76945872187Ssthen 7702be9e038Ssthen int 7712be9e038Ssthen ecs_edns_back_parsed(struct module_qstate* qstate, int id, 7722be9e038Ssthen void* ATTR_UNUSED(cbargs)) 7732be9e038Ssthen { 7742be9e038Ssthen struct subnet_qstate *sq; 7752be9e038Ssthen struct edns_option* ecs_opt; 7762be9e038Ssthen 7772be9e038Ssthen if(!(sq=(struct subnet_qstate*)qstate->minfo[id])) 7782be9e038Ssthen return 1; 7792be9e038Ssthen if((ecs_opt = edns_opt_list_find( 7802be9e038Ssthen qstate->edns_opts_back_in, 781a3167c07Ssthen qstate->env->cfg->client_subnet_opcode)) && 782a3167c07Ssthen parse_subnet_option(ecs_opt, &sq->ecs_server_in) && 783a3167c07Ssthen sq->subnet_sent && sq->ecs_server_in.subnet_validdata) { 78445872187Ssthen subnet_log_print("answer has edns subnet", ecs_opt); 7852be9e038Ssthen /* Only skip global cache store if we sent an ECS option 7862be9e038Ssthen * and received one back. Answers from non-whitelisted 787bdfc4d55Sflorian * servers will end up in global cache. Answers for 7882be9e038Ssthen * queries with 0 source will not (unless nameserver 7892be9e038Ssthen * does not support ECS). */ 7902be9e038Ssthen qstate->no_cache_store = 1; 791a3167c07Ssthen if(!sq->track_max_scope || (sq->track_max_scope && 792a3167c07Ssthen sq->ecs_server_in.subnet_scope_mask > 793a3167c07Ssthen sq->max_scope)) 794a3167c07Ssthen sq->max_scope = sq->ecs_server_in.subnet_scope_mask; 795d896b962Ssthen } else if(sq->subnet_sent_no_subnet) { 796d896b962Ssthen /* The answer can be stored as scope 0, not in global cache. */ 797d896b962Ssthen qstate->no_cache_store = 1; 7982be9e038Ssthen } 7992be9e038Ssthen 8002be9e038Ssthen return 1; 8012be9e038Ssthen } 8022be9e038Ssthen 8032be9e038Ssthen void 8042be9e038Ssthen subnetmod_operate(struct module_qstate *qstate, enum module_ev event, 8052be9e038Ssthen int id, struct outbound_entry* outbound) 8062be9e038Ssthen { 8072be9e038Ssthen struct subnet_env *sne = qstate->env->modinfo[id]; 8082be9e038Ssthen struct subnet_qstate *sq = (struct subnet_qstate*)qstate->minfo[id]; 8092be9e038Ssthen 810191f22c6Ssthen verbose(VERB_QUERY, "subnetcache[module %d] operate: extstate:%s " 8112be9e038Ssthen "event:%s", id, strextstate(qstate->ext_state[id]), 8122be9e038Ssthen strmodulevent(event)); 813191f22c6Ssthen log_query_info(VERB_QUERY, "subnetcache operate: query", &qstate->qinfo); 8142be9e038Ssthen 8152be9e038Ssthen if((event == module_event_new || event == module_event_pass) && 8162be9e038Ssthen sq == NULL) { 8172be9e038Ssthen struct edns_option* ecs_opt; 8182be9e038Ssthen if(!subnet_new_qstate(qstate, id)) { 8192be9e038Ssthen qstate->return_msg = NULL; 8202be9e038Ssthen qstate->ext_state[id] = module_finished; 8212be9e038Ssthen return; 8222be9e038Ssthen } 8232be9e038Ssthen 8242be9e038Ssthen sq = (struct subnet_qstate*)qstate->minfo[id]; 8252be9e038Ssthen 8262be9e038Ssthen if((ecs_opt = edns_opt_list_find( 8272be9e038Ssthen qstate->edns_opts_front_in, 8282be9e038Ssthen qstate->env->cfg->client_subnet_opcode))) { 8292be9e038Ssthen if(!parse_subnet_option(ecs_opt, &sq->ecs_client_in)) { 8302be9e038Ssthen /* Wrongly formatted ECS option. RFC mandates to 8312be9e038Ssthen * return FORMERROR. */ 8322be9e038Ssthen qstate->return_rcode = LDNS_RCODE_FORMERR; 8332be9e038Ssthen qstate->ext_state[id] = module_finished; 8342be9e038Ssthen return; 8352be9e038Ssthen } 83645872187Ssthen subnet_log_print("query has edns subnet", ecs_opt); 8372be9e038Ssthen sq->subnet_downstream = 1; 8382be9e038Ssthen } 8392be9e038Ssthen else if(qstate->mesh_info->reply_list) { 8402be9e038Ssthen subnet_option_from_ss( 84145872187Ssthen &qstate->mesh_info->reply_list->query_reply.client_addr, 8422be9e038Ssthen &sq->ecs_client_in, qstate->env->cfg); 8432be9e038Ssthen } 8448b7325afSsthen else if(qstate->client_addr.ss_family != AF_UNSPEC) { 8458b7325afSsthen subnet_option_from_ss( 8468b7325afSsthen &qstate->client_addr, 8478b7325afSsthen &sq->ecs_client_in, qstate->env->cfg); 8488b7325afSsthen } 8492be9e038Ssthen 8502be9e038Ssthen if(sq->ecs_client_in.subnet_validdata == 0) { 8512be9e038Ssthen /* No clients are interested in result or we could not 8522be9e038Ssthen * parse it, we don't do client subnet */ 8532be9e038Ssthen sq->ecs_server_out.subnet_validdata = 0; 854191f22c6Ssthen verbose(VERB_ALGO, "subnetcache: pass to next module"); 8552be9e038Ssthen qstate->ext_state[id] = module_wait_module; 8562be9e038Ssthen return; 8572be9e038Ssthen } 8582be9e038Ssthen 8593150e5f6Ssthen /* Limit to minimum allowed source mask */ 8603150e5f6Ssthen if(sq->ecs_client_in.subnet_source_mask != 0 && ( 8613150e5f6Ssthen (sq->ecs_client_in.subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4 && 8623150e5f6Ssthen sq->ecs_client_in.subnet_source_mask < qstate->env->cfg->min_client_subnet_ipv4) || 8633150e5f6Ssthen (sq->ecs_client_in.subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP6 && 8643150e5f6Ssthen sq->ecs_client_in.subnet_source_mask < qstate->env->cfg->min_client_subnet_ipv6))) { 8653150e5f6Ssthen qstate->return_rcode = LDNS_RCODE_REFUSED; 8663150e5f6Ssthen qstate->ext_state[id] = module_finished; 8673150e5f6Ssthen return; 8683150e5f6Ssthen } 8693150e5f6Ssthen 870d1e2768aSsthen if(!sq->started_no_cache_lookup && !qstate->blacklist) { 8712be9e038Ssthen lock_rw_wrlock(&sne->biglock); 8728b7325afSsthen if(qstate->mesh_info->reply_list && 8738b7325afSsthen lookup_and_reply(qstate, id, sq, 8748b7325afSsthen qstate->env->cfg->prefetch)) { 8752308e98cSsthen sne->num_msg_cache++; 8762be9e038Ssthen lock_rw_unlock(&sne->biglock); 877191f22c6Ssthen verbose(VERB_QUERY, "subnetcache: answered from cache"); 8782be9e038Ssthen qstate->ext_state[id] = module_finished; 8792be9e038Ssthen 8800bdb4f62Ssthen subnet_ecs_opt_list_append(&sq->ecs_client_out, 881d1e2768aSsthen &qstate->edns_opts_front_out, qstate, 882d1e2768aSsthen qstate->region); 88345872187Ssthen if(verbosity >= VERB_ALGO) { 88445872187Ssthen subnet_log_print("reply has edns subnet", 88545872187Ssthen edns_opt_list_find( 88645872187Ssthen qstate->edns_opts_front_out, 88745872187Ssthen qstate->env->cfg-> 88845872187Ssthen client_subnet_opcode)); 88945872187Ssthen } 8902be9e038Ssthen return; 8912be9e038Ssthen } 8922be9e038Ssthen lock_rw_unlock(&sne->biglock); 893d1e2768aSsthen } 8942be9e038Ssthen 8952be9e038Ssthen sq->ecs_server_out.subnet_addr_fam = 8962be9e038Ssthen sq->ecs_client_in.subnet_addr_fam; 8972be9e038Ssthen sq->ecs_server_out.subnet_source_mask = 8982be9e038Ssthen sq->ecs_client_in.subnet_source_mask; 8992be9e038Ssthen /* Limit source prefix to configured maximum */ 9002be9e038Ssthen if(sq->ecs_server_out.subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4 9012be9e038Ssthen && sq->ecs_server_out.subnet_source_mask > 9022be9e038Ssthen qstate->env->cfg->max_client_subnet_ipv4) 9032be9e038Ssthen sq->ecs_server_out.subnet_source_mask = 9042be9e038Ssthen qstate->env->cfg->max_client_subnet_ipv4; 9052be9e038Ssthen else if(sq->ecs_server_out.subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP6 9062be9e038Ssthen && sq->ecs_server_out.subnet_source_mask > 9072be9e038Ssthen qstate->env->cfg->max_client_subnet_ipv6) 9082be9e038Ssthen sq->ecs_server_out.subnet_source_mask = 9092be9e038Ssthen qstate->env->cfg->max_client_subnet_ipv6; 9102be9e038Ssthen /* Safe to copy completely, even if the source is limited by the 9110bdb4f62Ssthen * configuration. subnet_ecs_opt_list_append() will limit the address. 9122be9e038Ssthen * */ 9132be9e038Ssthen memcpy(&sq->ecs_server_out.subnet_addr, 9142be9e038Ssthen sq->ecs_client_in.subnet_addr, INET6_SIZE); 9152be9e038Ssthen sq->ecs_server_out.subnet_scope_mask = 0; 9162be9e038Ssthen sq->ecs_server_out.subnet_validdata = 1; 9172be9e038Ssthen if(sq->ecs_server_out.subnet_source_mask != 0 && 918bdfc4d55Sflorian qstate->env->cfg->client_subnet_always_forward && 9192be9e038Ssthen sq->subnet_downstream) 9202be9e038Ssthen /* ECS specific data required, do not look at the global 9212be9e038Ssthen * cache in other modules. */ 9222be9e038Ssthen qstate->no_cache_lookup = 1; 9232be9e038Ssthen 9242be9e038Ssthen /* pass request to next module */ 9252be9e038Ssthen verbose(VERB_ALGO, 926191f22c6Ssthen "subnetcache: not found in cache. pass to next module"); 9272be9e038Ssthen qstate->ext_state[id] = module_wait_module; 9282be9e038Ssthen return; 9292be9e038Ssthen } 9302be9e038Ssthen /* Query handed back by next module, we have a 'final' answer */ 9312be9e038Ssthen if(sq && event == module_event_moddone) { 9322be9e038Ssthen qstate->ext_state[id] = eval_response(qstate, id, sq); 9332308e98cSsthen if(qstate->ext_state[id] == module_finished && 9342308e98cSsthen qstate->return_msg) { 9350bdb4f62Ssthen subnet_ecs_opt_list_append(&sq->ecs_client_out, 936d1e2768aSsthen &qstate->edns_opts_front_out, qstate, 937d1e2768aSsthen qstate->region); 93845872187Ssthen if(verbosity >= VERB_ALGO) { 93945872187Ssthen subnet_log_print("reply has edns subnet", 94045872187Ssthen edns_opt_list_find( 94145872187Ssthen qstate->edns_opts_front_out, 94245872187Ssthen qstate->env->cfg-> 94345872187Ssthen client_subnet_opcode)); 94445872187Ssthen } 9452be9e038Ssthen } 9463150e5f6Ssthen qstate->no_cache_store = sq->started_no_cache_store; 947d1e2768aSsthen qstate->no_cache_lookup = sq->started_no_cache_lookup; 9482be9e038Ssthen return; 9492be9e038Ssthen } 9502be9e038Ssthen if(sq && outbound) { 9512be9e038Ssthen return; 9522be9e038Ssthen } 9532be9e038Ssthen /* We are being revisited */ 9542be9e038Ssthen if(event == module_event_pass || event == module_event_new) { 9552be9e038Ssthen /* Just pass it on, we already did the work */ 956191f22c6Ssthen verbose(VERB_ALGO, "subnetcache: pass to next module"); 9572be9e038Ssthen qstate->ext_state[id] = module_wait_module; 9582be9e038Ssthen return; 9592be9e038Ssthen } 9602be9e038Ssthen if(!sq && (event == module_event_moddone)) { 9612be9e038Ssthen /* during priming, module done but we never started */ 9622be9e038Ssthen qstate->ext_state[id] = module_finished; 9632be9e038Ssthen return; 9642be9e038Ssthen } 965191f22c6Ssthen log_err("subnetcache: bad event %s", strmodulevent(event)); 9662be9e038Ssthen qstate->ext_state[id] = module_error; 9672be9e038Ssthen return; 9682be9e038Ssthen } 9692be9e038Ssthen 9702be9e038Ssthen void 9712be9e038Ssthen subnetmod_clear(struct module_qstate *ATTR_UNUSED(qstate), 9722be9e038Ssthen int ATTR_UNUSED(id)) 9732be9e038Ssthen { 9742be9e038Ssthen /* qstate has no data outside region */ 9752be9e038Ssthen } 9762be9e038Ssthen 9772be9e038Ssthen void 9782be9e038Ssthen subnetmod_inform_super(struct module_qstate *ATTR_UNUSED(qstate), 9792be9e038Ssthen int ATTR_UNUSED(id), struct module_qstate *ATTR_UNUSED(super)) 9802be9e038Ssthen { 9812be9e038Ssthen /* Not used */ 9822be9e038Ssthen } 9832be9e038Ssthen 9842be9e038Ssthen size_t 9852be9e038Ssthen subnetmod_get_mem(struct module_env *env, int id) 9862be9e038Ssthen { 9872be9e038Ssthen struct subnet_env *sn_env = env->modinfo[id]; 9882be9e038Ssthen if (!sn_env) return 0; 9892be9e038Ssthen return sizeof(*sn_env) + 9902be9e038Ssthen slabhash_get_mem(sn_env->subnet_msg_cache) + 9912be9e038Ssthen ecs_whitelist_get_mem(sn_env->whitelist); 9922be9e038Ssthen } 9932be9e038Ssthen 9942be9e038Ssthen /** 9952be9e038Ssthen * The module function block 9962be9e038Ssthen */ 9972be9e038Ssthen static struct module_func_block subnetmod_block = { 998*98bc733bSsthen "subnetcache", 999*98bc733bSsthen NULL, NULL, &subnetmod_init, &subnetmod_deinit, &subnetmod_operate, 10002be9e038Ssthen &subnetmod_inform_super, &subnetmod_clear, &subnetmod_get_mem 10012be9e038Ssthen }; 10022be9e038Ssthen 10032be9e038Ssthen struct module_func_block* 10042be9e038Ssthen subnetmod_get_funcblock(void) 10052be9e038Ssthen { 10062be9e038Ssthen return &subnetmod_block; 10072be9e038Ssthen } 10082be9e038Ssthen 10092be9e038Ssthen /** Wrappers for static functions to unit test */ 10102be9e038Ssthen size_t 10112be9e038Ssthen unittest_wrapper_subnetmod_sizefunc(void *elemptr) 10122be9e038Ssthen { 10132be9e038Ssthen return sizefunc(elemptr); 10142be9e038Ssthen } 10152be9e038Ssthen 10162be9e038Ssthen #endif /* CLIENT_SUBNET */ 1017