1 /*
2 * edns-subnet/subnetmod.c - edns subnet module. Must be called before validator
3 * and iterator.
4 *
5 * Copyright (c) 2013, NLnet Labs. All rights reserved.
6 *
7 * This software is open source.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 *
16 * Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 *
20 * Neither the name of the NLNET LABS nor the names of its contributors may
21 * be used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
30 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36 /**
37 * \file
38 * subnet module for unbound.
39 */
40
41 #include "config.h"
42
43 #ifdef CLIENT_SUBNET /* keeps splint happy */
44
45 #include "edns-subnet/subnetmod.h"
46 #include "edns-subnet/edns-subnet.h"
47 #include "edns-subnet/addrtree.h"
48 #include "edns-subnet/subnet-whitelist.h"
49
50 #include "services/mesh.h"
51 #include "services/cache/dns.h"
52 #include "util/module.h"
53 #include "util/regional.h"
54 #include "util/fptr_wlist.h"
55 #include "util/storage/slabhash.h"
56 #include "util/config_file.h"
57 #include "util/data/msgreply.h"
58 #include "sldns/sbuffer.h"
59 #include "sldns/wire2str.h"
60 #include "iterator/iter_utils.h"
61 #ifdef USE_CACHEDB
62 #include "cachedb/cachedb.h"
63 #endif
64
65 /** externally called */
66 void
subnet_data_delete(void * d,void * ATTR_UNUSED (arg))67 subnet_data_delete(void *d, void *ATTR_UNUSED(arg))
68 {
69 struct subnet_msg_cache_data *r;
70 r = (struct subnet_msg_cache_data*)d;
71 addrtree_delete(r->tree4);
72 addrtree_delete(r->tree6);
73 free(r);
74 }
75
76 /** externally called */
77 size_t
msg_cache_sizefunc(void * k,void * d)78 msg_cache_sizefunc(void *k, void *d)
79 {
80 struct msgreply_entry *q = (struct msgreply_entry*)k;
81 struct subnet_msg_cache_data *r = (struct subnet_msg_cache_data*)d;
82 size_t s = sizeof(struct msgreply_entry)
83 + sizeof(struct subnet_msg_cache_data)
84 + q->key.qname_len + lock_get_mem(&q->entry.lock);
85 s += addrtree_size(r->tree4);
86 s += addrtree_size(r->tree6);
87 return s;
88 }
89
90 /** new query for ecs module */
91 static int
subnet_new_qstate(struct module_qstate * qstate,int id)92 subnet_new_qstate(struct module_qstate *qstate, int id)
93 {
94 struct subnet_qstate *sq = (struct subnet_qstate*)regional_alloc(
95 qstate->region, sizeof(struct subnet_qstate));
96 if(!sq)
97 return 0;
98 qstate->minfo[id] = sq;
99 memset(sq, 0, sizeof(*sq));
100 sq->started_no_cache_store = qstate->no_cache_store;
101 sq->started_no_cache_lookup = qstate->no_cache_lookup;
102 return 1;
103 }
104
105 /** Add ecs struct to edns list, after parsing it to wire format. */
106 void
subnet_ecs_opt_list_append(struct ecs_data * ecs,struct edns_option ** list,struct module_qstate * qstate,struct regional * region)107 subnet_ecs_opt_list_append(struct ecs_data* ecs, struct edns_option** list,
108 struct module_qstate *qstate, struct regional *region)
109 {
110 size_t sn_octs, sn_octs_remainder;
111 sldns_buffer* buf = qstate->env->scratch_buffer;
112
113 if(ecs->subnet_validdata) {
114 log_assert(ecs->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4 ||
115 ecs->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP6);
116 log_assert(ecs->subnet_addr_fam != EDNSSUBNET_ADDRFAM_IP4 ||
117 ecs->subnet_source_mask <= INET_SIZE*8);
118 log_assert(ecs->subnet_addr_fam != EDNSSUBNET_ADDRFAM_IP6 ||
119 ecs->subnet_source_mask <= INET6_SIZE*8);
120
121 sn_octs = ecs->subnet_source_mask / 8;
122 sn_octs_remainder =
123 (size_t)((ecs->subnet_source_mask % 8)>0?1:0);
124
125 log_assert(sn_octs + sn_octs_remainder <= INET6_SIZE);
126
127 sldns_buffer_clear(buf);
128 sldns_buffer_write_u16(buf, ecs->subnet_addr_fam);
129 sldns_buffer_write_u8(buf, ecs->subnet_source_mask);
130 sldns_buffer_write_u8(buf, ecs->subnet_scope_mask);
131 sldns_buffer_write(buf, ecs->subnet_addr, sn_octs);
132 if(sn_octs_remainder)
133 sldns_buffer_write_u8(buf, ecs->subnet_addr[sn_octs] &
134 ~(0xFF >> (ecs->subnet_source_mask % 8)));
135 sldns_buffer_flip(buf);
136
137 edns_opt_list_append(list,
138 qstate->env->cfg->client_subnet_opcode,
139 sn_octs + sn_octs_remainder + 4,
140 sldns_buffer_begin(buf), region);
141 }
142 }
143
ecs_whitelist_check(struct query_info * qinfo,uint16_t ATTR_UNUSED (flags),struct module_qstate * qstate,struct sockaddr_storage * addr,socklen_t addrlen,uint8_t * ATTR_UNUSED (zone),size_t ATTR_UNUSED (zonelen),struct regional * region,int id,void * ATTR_UNUSED (cbargs))144 int ecs_whitelist_check(struct query_info* qinfo,
145 uint16_t ATTR_UNUSED(flags), struct module_qstate* qstate,
146 struct sockaddr_storage* addr, socklen_t addrlen,
147 uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen),
148 struct regional *region, int id, void* ATTR_UNUSED(cbargs))
149 {
150 struct subnet_qstate *sq;
151 struct subnet_env *sn_env;
152
153 if(!(sq=(struct subnet_qstate*)qstate->minfo[id]))
154 return 1;
155 sn_env = (struct subnet_env*)qstate->env->modinfo[id];
156
157 /* Cache by default, might be disabled after parsing EDNS option
158 * received from nameserver. */
159 if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL, NULL, 0)
160 && sq->ecs_client_in.subnet_validdata) {
161 qstate->no_cache_store = 0;
162 }
163
164 sq->subnet_sent_no_subnet = 0;
165 if(sq->ecs_server_out.subnet_validdata && ((sq->subnet_downstream &&
166 qstate->env->cfg->client_subnet_always_forward) ||
167 ecs_is_whitelisted(sn_env->whitelist,
168 addr, addrlen, qinfo->qname, qinfo->qname_len,
169 qinfo->qclass))) {
170 /* Address on whitelist or client query contains ECS option, we
171 * want to sent out ECS. Only add option if it is not already
172 * set. */
173 if(!edns_opt_list_find(qstate->edns_opts_back_out,
174 qstate->env->cfg->client_subnet_opcode)) {
175 /* if the client is not wanting an EDNS subnet option,
176 * omit it and store that we omitted it but actually
177 * are doing EDNS subnet to the server. */
178 if(sq->ecs_server_out.subnet_source_mask == 0) {
179 sq->subnet_sent_no_subnet = 1;
180 sq->subnet_sent = 0;
181 return 1;
182 }
183 subnet_ecs_opt_list_append(&sq->ecs_server_out,
184 &qstate->edns_opts_back_out, qstate, region);
185 }
186 sq->subnet_sent = 1;
187 }
188 else {
189 /* Outgoing ECS option is set, but we don't want to sent it to
190 * this address, remove option. */
191 if(edns_opt_list_find(qstate->edns_opts_back_out,
192 qstate->env->cfg->client_subnet_opcode)) {
193 edns_opt_list_remove(&qstate->edns_opts_back_out,
194 qstate->env->cfg->client_subnet_opcode);
195 }
196 sq->subnet_sent = 0;
197 }
198 return 1;
199 }
200
201
202 void
subnet_markdel(void * key)203 subnet_markdel(void* key)
204 {
205 struct msgreply_entry *e = (struct msgreply_entry*)key;
206 e->key.qtype = 0;
207 e->key.qclass = 0;
208 }
209
210 int
subnetmod_init(struct module_env * env,int id)211 subnetmod_init(struct module_env *env, int id)
212 {
213 struct subnet_env *sn_env = (struct subnet_env*)calloc(1,
214 sizeof(struct subnet_env));
215 if(!sn_env) {
216 log_err("malloc failure");
217 return 0;
218 }
219 alloc_init(&sn_env->alloc, NULL, 0);
220 env->modinfo[id] = (void*)sn_env;
221
222 /* Warn that serve-expired and prefetch do not work with the subnet
223 * module cache. */
224 if(env->cfg->serve_expired)
225 log_warn(
226 "subnetcache: serve-expired is set but not working "
227 "for data originating from the subnet module cache.");
228 if(env->cfg->prefetch)
229 log_warn(
230 "subnetcache: prefetch is set but not working "
231 "for data originating from the subnet module cache.");
232 /* Copy msg_cache settings */
233 sn_env->subnet_msg_cache = slabhash_create(env->cfg->msg_cache_slabs,
234 HASH_DEFAULT_STARTARRAY, env->cfg->msg_cache_size,
235 msg_cache_sizefunc, query_info_compare, query_entry_delete,
236 subnet_data_delete, NULL);
237 slabhash_setmarkdel(sn_env->subnet_msg_cache, &subnet_markdel);
238 if(!sn_env->subnet_msg_cache) {
239 log_err("subnetcache: could not create cache");
240 free(sn_env);
241 env->modinfo[id] = NULL;
242 return 0;
243 }
244 /* whitelist for edns subnet capable servers */
245 sn_env->whitelist = ecs_whitelist_create();
246 if(!sn_env->whitelist ||
247 !ecs_whitelist_apply_cfg(sn_env->whitelist, env->cfg)) {
248 log_err("subnetcache: could not create ECS whitelist");
249 slabhash_delete(sn_env->subnet_msg_cache);
250 free(sn_env);
251 env->modinfo[id] = NULL;
252 return 0;
253 }
254
255 verbose(VERB_QUERY, "subnetcache: option registered (%d)",
256 env->cfg->client_subnet_opcode);
257 /* Create new mesh state for all queries. */
258 env->unique_mesh = 1;
259 if(!edns_register_option(env->cfg->client_subnet_opcode,
260 env->cfg->client_subnet_always_forward /* bypass cache */,
261 1 /* no aggregation */, env)) {
262 log_err("subnetcache: could not register opcode");
263 ecs_whitelist_delete(sn_env->whitelist);
264 slabhash_delete(sn_env->subnet_msg_cache);
265 free(sn_env);
266 env->modinfo[id] = NULL;
267 return 0;
268 }
269 inplace_cb_register((void*)ecs_whitelist_check, inplace_cb_query, NULL,
270 env, id);
271 inplace_cb_register((void*)ecs_edns_back_parsed,
272 inplace_cb_edns_back_parsed, NULL, env, id);
273 inplace_cb_register((void*)ecs_query_response,
274 inplace_cb_query_response, NULL, env, id);
275 lock_rw_init(&sn_env->biglock);
276 return 1;
277 }
278
279 void
subnetmod_deinit(struct module_env * env,int id)280 subnetmod_deinit(struct module_env *env, int id)
281 {
282 struct subnet_env *sn_env;
283 if(!env || !env->modinfo[id])
284 return;
285 sn_env = (struct subnet_env*)env->modinfo[id];
286 lock_rw_destroy(&sn_env->biglock);
287 inplace_cb_delete(env, inplace_cb_edns_back_parsed, id);
288 inplace_cb_delete(env, inplace_cb_query, id);
289 inplace_cb_delete(env, inplace_cb_query_response, id);
290 ecs_whitelist_delete(sn_env->whitelist);
291 slabhash_delete(sn_env->subnet_msg_cache);
292 alloc_clear(&sn_env->alloc);
293 free(sn_env);
294 env->modinfo[id] = NULL;
295 }
296
297 /** Tells client that upstream has no/improper support */
298 static void
cp_edns_bad_response(struct ecs_data * target,struct ecs_data * source)299 cp_edns_bad_response(struct ecs_data *target, struct ecs_data *source)
300 {
301 target->subnet_scope_mask = 0;
302 target->subnet_source_mask = source->subnet_source_mask;
303 target->subnet_addr_fam = source->subnet_addr_fam;
304 memcpy(target->subnet_addr, source->subnet_addr, INET6_SIZE);
305 target->subnet_validdata = 1;
306 }
307
308 static void
delfunc(void * envptr,void * elemptr)309 delfunc(void *envptr, void *elemptr) {
310 struct reply_info *elem = (struct reply_info *)elemptr;
311 struct subnet_env *env = (struct subnet_env *)envptr;
312 reply_info_parsedelete(elem, &env->alloc);
313 }
314
315 static size_t
sizefunc(void * elemptr)316 sizefunc(void *elemptr) {
317 struct reply_info *elem = (struct reply_info *)elemptr;
318 size_t s = sizeof (struct reply_info) - sizeof (struct rrset_ref)
319 + elem->rrset_count * sizeof (struct rrset_ref)
320 + elem->rrset_count * sizeof (struct ub_packed_rrset_key *);
321 size_t i;
322 for (i = 0; i < elem->rrset_count; i++) {
323 struct ub_packed_rrset_key *key = elem->rrsets[i];
324 struct packed_rrset_data *data = key->entry.data;
325 s += ub_rrset_sizefunc(key, data);
326 }
327 if(elem->reason_bogus_str)
328 s += strlen(elem->reason_bogus_str)+1;
329 return s;
330 }
331
332 /**
333 * Select tree from cache entry based on edns data.
334 * If for address family not present it will create a new one.
335 * NULL on failure to create. */
336 static struct addrtree*
get_tree(struct subnet_msg_cache_data * data,struct ecs_data * edns,struct subnet_env * env,struct config_file * cfg)337 get_tree(struct subnet_msg_cache_data *data, struct ecs_data *edns,
338 struct subnet_env *env, struct config_file* cfg)
339 {
340 struct addrtree *tree;
341 if (edns->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4) {
342 if (!data->tree4)
343 data->tree4 = addrtree_create(
344 cfg->max_client_subnet_ipv4, &delfunc,
345 &sizefunc, env, cfg->max_ecs_tree_size_ipv4);
346 tree = data->tree4;
347 } else {
348 if (!data->tree6)
349 data->tree6 = addrtree_create(
350 cfg->max_client_subnet_ipv6, &delfunc,
351 &sizefunc, env, cfg->max_ecs_tree_size_ipv6);
352 tree = data->tree6;
353 }
354 return tree;
355 }
356
357 static void
update_cache(struct module_qstate * qstate,int id)358 update_cache(struct module_qstate *qstate, int id)
359 {
360 struct msgreply_entry *mrep_entry;
361 struct addrtree *tree;
362 struct reply_info *rep;
363 struct query_info qinf;
364 struct subnet_env *sne = qstate->env->modinfo[id];
365 struct subnet_qstate *sq = (struct subnet_qstate*)qstate->minfo[id];
366 struct slabhash *subnet_msg_cache = sne->subnet_msg_cache;
367 struct ecs_data *edns = &sq->ecs_client_in;
368 size_t i;
369 int only_match_scope_zero, diff_size;
370
371 /* We already calculated hash upon lookup (lookup_and_reply) if we were
372 * allowed to look in the ECS cache */
373 hashvalue_type h = qstate->minfo[id] &&
374 ((struct subnet_qstate*)qstate->minfo[id])->qinfo_hash_calculated?
375 ((struct subnet_qstate*)qstate->minfo[id])->qinfo_hash :
376 query_info_hash(&qstate->qinfo, qstate->query_flags);
377 /* Step 1, general qinfo lookup */
378 struct lruhash_entry* lru_entry = slabhash_lookup(subnet_msg_cache, h,
379 &qstate->qinfo, 1);
380 int need_to_insert = (lru_entry == NULL);
381 if (!lru_entry) {
382 void* data = calloc(1,
383 sizeof(struct subnet_msg_cache_data));
384 if(!data) {
385 log_err("malloc failed");
386 return;
387 }
388 qinf = qstate->qinfo;
389 qinf.qname = memdup(qstate->qinfo.qname,
390 qstate->qinfo.qname_len);
391 if(!qinf.qname) {
392 free(data);
393 log_err("memdup failed");
394 return;
395 }
396 mrep_entry = query_info_entrysetup(&qinf, data, h);
397 free(qinf.qname); /* if qname 'consumed', it is set to NULL */
398 if (!mrep_entry) {
399 free(data);
400 log_err("query_info_entrysetup failed");
401 return;
402 }
403 lru_entry = &mrep_entry->entry;
404 lock_rw_wrlock(&lru_entry->lock);
405 }
406 /* lru_entry->lock is locked regardless of how we got here,
407 * either from the slabhash_lookup, or above in the new allocated */
408 /* Step 2, find the correct tree */
409 if (!(tree = get_tree(lru_entry->data, edns, sne, qstate->env->cfg))) {
410 lock_rw_unlock(&lru_entry->lock);
411 log_err("subnetcache: cache insertion failed");
412 return;
413 }
414 lock_quick_lock(&sne->alloc.lock);
415 rep = reply_info_copy(qstate->return_msg->rep, &sne->alloc, NULL);
416 lock_quick_unlock(&sne->alloc.lock);
417 if (!rep) {
418 lock_rw_unlock(&lru_entry->lock);
419 log_err("subnetcache: cache insertion failed");
420 return;
421 }
422
423 /* store RRsets */
424 for(i=0; i<rep->rrset_count; i++) {
425 rep->ref[i].key = rep->rrsets[i];
426 rep->ref[i].id = rep->rrsets[i]->id;
427 }
428 reply_info_set_ttls(rep, *qstate->env->now);
429 reply_info_sortref(rep);
430 rep->flags |= (BIT_RA | BIT_QR); /* fix flags to be sensible for */
431 rep->flags &= ~(BIT_AA | BIT_CD);/* a reply based on the cache */
432 if(edns->subnet_source_mask == 0 && edns->subnet_scope_mask == 0)
433 only_match_scope_zero = 1;
434 else only_match_scope_zero = 0;
435 diff_size = (int)tree->size_bytes;
436 addrtree_insert(tree, (addrkey_t*)edns->subnet_addr,
437 edns->subnet_source_mask, sq->max_scope, rep,
438 rep->ttl, *qstate->env->now, only_match_scope_zero);
439 diff_size = (int)tree->size_bytes - diff_size;
440
441 lock_rw_unlock(&lru_entry->lock);
442 if (need_to_insert) {
443 slabhash_insert(subnet_msg_cache, h, lru_entry, lru_entry->data,
444 NULL);
445 } else {
446 slabhash_update_space_used(subnet_msg_cache, h, NULL,
447 diff_size);
448 }
449 }
450
451 /** Lookup in cache and reply true iff reply is sent. */
452 static int
lookup_and_reply(struct module_qstate * qstate,int id,struct subnet_qstate * sq,int prefetch)453 lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq, int prefetch)
454 {
455 struct lruhash_entry *e;
456 struct module_env *env = qstate->env;
457 struct subnet_env *sne = (struct subnet_env*)env->modinfo[id];
458 hashvalue_type h = query_info_hash(&qstate->qinfo, qstate->query_flags);
459 struct subnet_msg_cache_data *data;
460 struct ecs_data *ecs = &sq->ecs_client_in;
461 struct addrtree *tree;
462 struct addrnode *node;
463 uint8_t scope;
464
465 memset(&sq->ecs_client_out, 0, sizeof(sq->ecs_client_out));
466
467 if (sq) {
468 sq->qinfo_hash = h; /* Might be useful on cache miss */
469 sq->qinfo_hash_calculated = 1;
470 }
471 e = slabhash_lookup(sne->subnet_msg_cache, h, &qstate->qinfo, 1);
472 if (!e) return 0; /* qinfo not in cache */
473 data = e->data;
474 tree = (ecs->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4)?
475 data->tree4 : data->tree6;
476 if (!tree) { /* qinfo in cache but not for this family */
477 lock_rw_unlock(&e->lock);
478 return 0;
479 }
480 node = addrtree_find(tree, (addrkey_t*)ecs->subnet_addr,
481 ecs->subnet_source_mask, *env->now);
482 if (!node) { /* plain old cache miss */
483 lock_rw_unlock(&e->lock);
484 return 0;
485 }
486
487 qstate->return_msg = tomsg(NULL, &qstate->qinfo,
488 (struct reply_info *)node->elem, qstate->region, *env->now, 0,
489 env->scratch);
490 scope = (uint8_t)node->scope;
491 lock_rw_unlock(&e->lock);
492
493 if (!qstate->return_msg) { /* Failed allocation or expired TTL */
494 return 0;
495 }
496
497 if (sq->subnet_downstream) { /* relay to interested client */
498 sq->ecs_client_out.subnet_scope_mask = scope;
499 sq->ecs_client_out.subnet_addr_fam = ecs->subnet_addr_fam;
500 sq->ecs_client_out.subnet_source_mask = ecs->subnet_source_mask;
501 memcpy(&sq->ecs_client_out.subnet_addr, &ecs->subnet_addr,
502 INET6_SIZE);
503 sq->ecs_client_out.subnet_validdata = 1;
504 }
505
506 if (prefetch && *qstate->env->now >= ((struct reply_info *)node->elem)->prefetch_ttl) {
507 qstate->need_refetch = 1;
508 }
509 return 1;
510 }
511
512 /**
513 * Test first bits of addresses for equality. Caller is responsible
514 * for making sure that both a and b are at least net/8 octets long.
515 * @param a: first address.
516 * @param a: seconds address.
517 * @param net: Number of bits to test.
518 * @return: 1 if equal, 0 otherwise.
519 */
520 static int
common_prefix(uint8_t * a,uint8_t * b,uint8_t net)521 common_prefix(uint8_t *a, uint8_t *b, uint8_t net)
522 {
523 size_t n = (size_t)net / 8;
524 return !memcmp(a, b, n) && ((net % 8) == 0 || a[n] == b[n]);
525 }
526
527 /**
528 * Create sub request that looks up the query.
529 * @param qstate: query state
530 * @param sq: subnet qstate
531 * @return false on failure.
532 */
533 static int
generate_sub_request(struct module_qstate * qstate,struct subnet_qstate * sq)534 generate_sub_request(struct module_qstate *qstate, struct subnet_qstate* sq)
535 {
536 struct module_qstate* subq = NULL;
537 uint16_t qflags = 0; /* OPCODE QUERY, no flags */
538 int prime = 0;
539 int valrec = 0;
540 struct query_info qinf;
541 qinf.qname = qstate->qinfo.qname;
542 qinf.qname_len = qstate->qinfo.qname_len;
543 qinf.qtype = qstate->qinfo.qtype;
544 qinf.qclass = qstate->qinfo.qclass;
545 qinf.local_alias = NULL;
546
547 qflags |= BIT_RD;
548 if((qstate->query_flags & BIT_CD)!=0) {
549 qflags |= BIT_CD;
550 valrec = 1;
551 }
552
553 fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
554 if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime, valrec,
555 &subq)) {
556 return 0;
557 }
558 if(subq) {
559 /* It is possible to access the subquery module state. */
560 if(sq->ecs_client_in.subnet_source_mask == 0 &&
561 edns_opt_list_find(qstate->edns_opts_front_in,
562 qstate->env->cfg->client_subnet_opcode)) {
563 subq->no_cache_store = 1;
564 }
565 }
566 return 1;
567 }
568
569 /**
570 * Perform the query without subnet
571 * @param qstate: query state
572 * @param sq: subnet qstate
573 * @return module state
574 */
575 static enum module_ext_state
generate_lookup_without_subnet(struct module_qstate * qstate,struct subnet_qstate * sq)576 generate_lookup_without_subnet(struct module_qstate *qstate,
577 struct subnet_qstate* sq)
578 {
579 verbose(VERB_ALGO, "subnetcache: make subquery to look up without subnet");
580 if(!generate_sub_request(qstate, sq)) {
581 verbose(VERB_ALGO, "Could not generate sub query");
582 qstate->return_rcode = LDNS_RCODE_FORMERR;
583 qstate->return_msg = NULL;
584 return module_finished;
585 }
586 sq->wait_subquery = 1;
587 return module_wait_subquery;
588 }
589
590 static enum module_ext_state
eval_response(struct module_qstate * qstate,int id,struct subnet_qstate * sq)591 eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
592 {
593 struct subnet_env *sne = qstate->env->modinfo[id];
594
595 struct ecs_data *c_in = &sq->ecs_client_in; /* rcvd from client */
596 struct ecs_data *c_out = &sq->ecs_client_out;/* will send to client */
597 struct ecs_data *s_in = &sq->ecs_server_in; /* rcvd from auth */
598 struct ecs_data *s_out = &sq->ecs_server_out;/* sent to auth */
599
600 memset(c_out, 0, sizeof(*c_out));
601
602 if (!qstate->return_msg) {
603 /* already an answer and its not a message, but retain
604 * the actual rcode, instead of module_error, so send
605 * module_finished */
606 return module_finished;
607 }
608
609 /* We have not asked for subnet data */
610 if (!sq->subnet_sent && !sq->subnet_sent_no_subnet) {
611 if (s_in->subnet_validdata)
612 verbose(VERB_QUERY, "subnetcache: received spurious data");
613 if (sq->subnet_downstream) /* Copy back to client */
614 cp_edns_bad_response(c_out, c_in);
615 return module_finished;
616 }
617
618 /* subnet sent but nothing came back */
619 if (!s_in->subnet_validdata && !sq->subnet_sent_no_subnet) {
620 /* The authority indicated no support for edns subnet. As a
621 * consequence the answer ended up in the regular cache. It
622 * is still useful to put it in the edns subnet cache for
623 * when a client explicitly asks for subnet specific answer. */
624 verbose(VERB_QUERY, "subnetcache: Authority indicates no support");
625 return generate_lookup_without_subnet(qstate, sq);
626 }
627
628 /* Purposefully there was no sent subnet, and there is consequently
629 * no subnet in the answer. If there was, use the subnet in the answer
630 * anyway. But if there is not, treat it as a prefix 0 answer. */
631 if(sq->subnet_sent_no_subnet && !s_in->subnet_validdata) {
632 /* Fill in 0.0.0.0/0 scope 0, or ::0/0 scope 0, for caching. */
633 s_in->subnet_addr_fam = s_out->subnet_addr_fam;
634 s_in->subnet_source_mask = 0;
635 s_in->subnet_scope_mask = 0;
636 memset(s_in->subnet_addr, 0, INET6_SIZE);
637 s_in->subnet_validdata = 1;
638 }
639
640 /* Being here means we have asked for and got a subnet specific
641 * answer. Also, the answer from the authority is not yet cached
642 * anywhere. */
643
644 /* can we accept response? */
645 if(s_out->subnet_addr_fam != s_in->subnet_addr_fam ||
646 s_out->subnet_source_mask != s_in->subnet_source_mask ||
647 !common_prefix(s_out->subnet_addr, s_in->subnet_addr,
648 s_out->subnet_source_mask))
649 {
650 /* we can not accept, perform query without option */
651 verbose(VERB_QUERY, "subnetcache: forged data");
652 s_out->subnet_validdata = 0;
653 (void)edns_opt_list_remove(&qstate->edns_opts_back_out,
654 qstate->env->cfg->client_subnet_opcode);
655 sq->subnet_sent = 0;
656 sq->subnet_sent_no_subnet = 0;
657 return generate_lookup_without_subnet(qstate, sq);
658 }
659
660 lock_rw_wrlock(&sne->biglock);
661 if(!sq->started_no_cache_store) {
662 update_cache(qstate, id);
663 }
664 sne->num_msg_nocache++;
665 lock_rw_unlock(&sne->biglock);
666
667 /* If there is an expired answer in the global cache, remove that,
668 * because expired answers would otherwise resurface once the ecs data
669 * expires, giving once in a while global data responses for ecs
670 * domains, with serve expired enabled. */
671 if(qstate->env->cfg->serve_expired) {
672 msg_cache_remove(qstate->env, qstate->qinfo.qname,
673 qstate->qinfo.qname_len, qstate->qinfo.qtype,
674 qstate->qinfo.qclass, 0);
675 #ifdef USE_CACHEDB
676 if(qstate->env->cachedb_enabled)
677 cachedb_msg_remove(qstate);
678 #endif
679 }
680
681 if (sq->subnet_downstream) {
682 /* Client wants to see the answer, echo option back
683 * and adjust the scope. */
684 c_out->subnet_addr_fam = c_in->subnet_addr_fam;
685 c_out->subnet_source_mask = c_in->subnet_source_mask;
686 memcpy(&c_out->subnet_addr, &c_in->subnet_addr, INET6_SIZE);
687 c_out->subnet_scope_mask = sq->max_scope;
688 /* Limit scope returned to client to scope used for caching. */
689 if(c_out->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4) {
690 if(c_out->subnet_scope_mask >
691 qstate->env->cfg->max_client_subnet_ipv4) {
692 c_out->subnet_scope_mask =
693 qstate->env->cfg->max_client_subnet_ipv4;
694 }
695 }
696 else if(c_out->subnet_scope_mask >
697 qstate->env->cfg->max_client_subnet_ipv6) {
698 c_out->subnet_scope_mask =
699 qstate->env->cfg->max_client_subnet_ipv6;
700 }
701 c_out->subnet_validdata = 1;
702 }
703 return module_finished;
704 }
705
706 /** Parse EDNS opt data containing ECS */
707 static int
parse_subnet_option(struct edns_option * ecs_option,struct ecs_data * ecs)708 parse_subnet_option(struct edns_option* ecs_option, struct ecs_data* ecs)
709 {
710 memset(ecs, 0, sizeof(*ecs));
711 if (ecs_option->opt_len < 4)
712 return 0;
713
714 ecs->subnet_addr_fam = sldns_read_uint16(ecs_option->opt_data);
715 ecs->subnet_source_mask = ecs_option->opt_data[2];
716 ecs->subnet_scope_mask = ecs_option->opt_data[3];
717 /* remaining bytes indicate address */
718
719 /* validate input*/
720 /* option length matches calculated length? */
721 if (ecs_option->opt_len != (size_t)((ecs->subnet_source_mask+7)/8 + 4))
722 return 0;
723 if (ecs_option->opt_len - 4 > INET6_SIZE || ecs_option->opt_len == 0)
724 return 0;
725 if (ecs->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4) {
726 if (ecs->subnet_source_mask > 32 || ecs->subnet_scope_mask > 32)
727 return 0;
728 } else if (ecs->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP6) {
729 if (ecs->subnet_source_mask > 128 ||
730 ecs->subnet_scope_mask > 128)
731 return 0;
732 } else
733 return 0;
734
735 /* valid ECS data, write to ecs_data */
736 if (copy_clear(ecs->subnet_addr, INET6_SIZE, ecs_option->opt_data + 4,
737 ecs_option->opt_len - 4, ecs->subnet_source_mask))
738 return 0;
739 ecs->subnet_validdata = 1;
740 return 1;
741 }
742
743 void
subnet_option_from_ss(struct sockaddr_storage * ss,struct ecs_data * ecs,struct config_file * cfg)744 subnet_option_from_ss(struct sockaddr_storage *ss, struct ecs_data* ecs,
745 struct config_file* cfg)
746 {
747 void* sinaddr;
748
749 /* Construct subnet option from original query */
750 if(((struct sockaddr_in*)ss)->sin_family == AF_INET) {
751 ecs->subnet_source_mask = cfg->max_client_subnet_ipv4;
752 ecs->subnet_addr_fam = EDNSSUBNET_ADDRFAM_IP4;
753 sinaddr = &((struct sockaddr_in*)ss)->sin_addr;
754 if (!copy_clear( ecs->subnet_addr, INET6_SIZE,
755 (uint8_t *)sinaddr, INET_SIZE,
756 ecs->subnet_source_mask)) {
757 ecs->subnet_validdata = 1;
758 }
759 }
760 #ifdef INET6
761 else {
762 ecs->subnet_source_mask = cfg->max_client_subnet_ipv6;
763 ecs->subnet_addr_fam = EDNSSUBNET_ADDRFAM_IP6;
764 sinaddr = &((struct sockaddr_in6*)ss)->sin6_addr;
765 if (!copy_clear( ecs->subnet_addr, INET6_SIZE,
766 (uint8_t *)sinaddr, INET6_SIZE,
767 ecs->subnet_source_mask)) {
768 ecs->subnet_validdata = 1;
769 }
770 }
771 #else
772 /* We don't know how to handle ip6, just pass */
773 #endif /* INET6 */
774 }
775
776 int
ecs_query_response(struct module_qstate * qstate,struct dns_msg * response,int id,void * ATTR_UNUSED (cbargs))777 ecs_query_response(struct module_qstate* qstate, struct dns_msg* response,
778 int id, void* ATTR_UNUSED(cbargs))
779 {
780 struct subnet_qstate *sq;
781
782 if(!response || !(sq=(struct subnet_qstate*)qstate->minfo[id]))
783 return 1;
784
785 if(sq->subnet_sent &&
786 FLAGS_GET_RCODE(response->rep->flags) == LDNS_RCODE_REFUSED) {
787 /* REFUSED response to ECS query, remove ECS option. */
788 edns_opt_list_remove(&qstate->edns_opts_back_out,
789 qstate->env->cfg->client_subnet_opcode);
790 sq->subnet_sent = 0;
791 sq->subnet_sent_no_subnet = 0;
792 memset(&sq->ecs_server_out, 0, sizeof(sq->ecs_server_out));
793 } else if (!sq->track_max_scope &&
794 FLAGS_GET_RCODE(response->rep->flags) == LDNS_RCODE_NOERROR &&
795 response->rep->an_numrrsets > 0
796 ) {
797 struct ub_packed_rrset_key* s = response->rep->rrsets[0];
798 if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME &&
799 query_dname_compare(qstate->qinfo.qname,
800 s->rk.dname) == 0) {
801 /* CNAME response for QNAME. From now on keep track of
802 * longest received ECS prefix for all queries on this
803 * qstate. */
804 sq->track_max_scope = 1;
805 }
806 }
807 return 1;
808 }
809
810 /** verbose print edns subnet option in pretty print */
811 static void
subnet_log_print(const char * s,struct edns_option * ecs_opt)812 subnet_log_print(const char* s, struct edns_option* ecs_opt)
813 {
814 if(verbosity >= VERB_ALGO) {
815 char buf[256];
816 char* str = buf;
817 size_t str_len = sizeof(buf);
818 if(!ecs_opt) {
819 verbose(VERB_ALGO, "%s (null)", s);
820 return;
821 }
822 (void)sldns_wire2str_edns_subnet_print(&str, &str_len,
823 ecs_opt->opt_data, ecs_opt->opt_len);
824 verbose(VERB_ALGO, "%s %s", s, buf);
825 }
826 }
827
828 int
ecs_edns_back_parsed(struct module_qstate * qstate,int id,void * ATTR_UNUSED (cbargs))829 ecs_edns_back_parsed(struct module_qstate* qstate, int id,
830 void* ATTR_UNUSED(cbargs))
831 {
832 struct subnet_qstate *sq;
833 struct edns_option* ecs_opt;
834
835 if(!(sq=(struct subnet_qstate*)qstate->minfo[id]))
836 return 1;
837 if((ecs_opt = edns_opt_list_find(
838 qstate->edns_opts_back_in,
839 qstate->env->cfg->client_subnet_opcode)) &&
840 parse_subnet_option(ecs_opt, &sq->ecs_server_in) &&
841 sq->subnet_sent && sq->ecs_server_in.subnet_validdata) {
842 subnet_log_print("answer has edns subnet", ecs_opt);
843 /* Only skip global cache store if we sent an ECS option
844 * and received one back. Answers from non-whitelisted
845 * servers will end up in global cache. Answers for
846 * queries with 0 source will not (unless nameserver
847 * does not support ECS). */
848 qstate->no_cache_store = 1;
849 if(!sq->track_max_scope || (sq->track_max_scope &&
850 sq->ecs_server_in.subnet_scope_mask >
851 sq->max_scope))
852 sq->max_scope = sq->ecs_server_in.subnet_scope_mask;
853 } else if(sq->subnet_sent_no_subnet) {
854 /* The answer can be stored as scope 0, not in global cache. */
855 qstate->no_cache_store = 1;
856 } else if(sq->subnet_sent) {
857 /* Need another query to be able to store in global cache. */
858 qstate->no_cache_store = 1;
859 }
860
861 return 1;
862 }
863
864 void
subnetmod_operate(struct module_qstate * qstate,enum module_ev event,int id,struct outbound_entry * outbound)865 subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
866 int id, struct outbound_entry* outbound)
867 {
868 struct subnet_env *sne = qstate->env->modinfo[id];
869 struct subnet_qstate *sq = (struct subnet_qstate*)qstate->minfo[id];
870
871 verbose(VERB_QUERY, "subnetcache[module %d] operate: extstate:%s "
872 "event:%s", id, strextstate(qstate->ext_state[id]),
873 strmodulevent(event));
874 log_query_info(VERB_QUERY, "subnetcache operate: query", &qstate->qinfo);
875
876 if(sq && sq->wait_subquery_done) {
877 /* The subquery lookup returned. */
878 if(sq->ecs_client_in.subnet_source_mask == 0 &&
879 edns_opt_list_find(qstate->edns_opts_front_in,
880 qstate->env->cfg->client_subnet_opcode)) {
881 if(!sq->started_no_cache_store &&
882 qstate->return_msg) {
883 lock_rw_wrlock(&sne->biglock);
884 update_cache(qstate, id);
885 lock_rw_unlock(&sne->biglock);
886 }
887 if (sq->subnet_downstream)
888 cp_edns_bad_response(&sq->ecs_client_out,
889 &sq->ecs_client_in);
890 /* It is a scope zero lookup, append edns subnet
891 * option to the querier. */
892 subnet_ecs_opt_list_append(&sq->ecs_client_out,
893 &qstate->edns_opts_front_out, qstate,
894 qstate->region);
895 }
896 sq->wait_subquery_done = 0;
897 qstate->ext_state[id] = module_finished;
898 qstate->no_cache_store = sq->started_no_cache_store;
899 qstate->no_cache_lookup = sq->started_no_cache_lookup;
900 return;
901 }
902 if((event == module_event_new || event == module_event_pass) &&
903 sq == NULL) {
904 struct edns_option* ecs_opt;
905 if(!subnet_new_qstate(qstate, id)) {
906 qstate->return_msg = NULL;
907 qstate->ext_state[id] = module_finished;
908 return;
909 }
910
911 sq = (struct subnet_qstate*)qstate->minfo[id];
912 if(sq->wait_subquery)
913 return; /* Wait for that subquery to return */
914
915 if((ecs_opt = edns_opt_list_find(
916 qstate->edns_opts_front_in,
917 qstate->env->cfg->client_subnet_opcode))) {
918 if(!parse_subnet_option(ecs_opt, &sq->ecs_client_in)) {
919 /* Wrongly formatted ECS option. RFC mandates to
920 * return FORMERROR. */
921 qstate->return_rcode = LDNS_RCODE_FORMERR;
922 qstate->ext_state[id] = module_finished;
923 return;
924 }
925 subnet_log_print("query has edns subnet", ecs_opt);
926 sq->subnet_downstream = 1;
927 }
928 else if(qstate->mesh_info->reply_list) {
929 subnet_option_from_ss(
930 &qstate->mesh_info->reply_list->query_reply.client_addr,
931 &sq->ecs_client_in, qstate->env->cfg);
932 }
933 else if(qstate->client_addr.ss_family != AF_UNSPEC) {
934 subnet_option_from_ss(
935 &qstate->client_addr,
936 &sq->ecs_client_in, qstate->env->cfg);
937 }
938
939 if(sq->ecs_client_in.subnet_validdata == 0) {
940 /* No clients are interested in result or we could not
941 * parse it, we don't do client subnet */
942 sq->ecs_server_out.subnet_validdata = 0;
943 if(edns_opt_list_find(qstate->edns_opts_front_in,
944 qstate->env->cfg->client_subnet_opcode)) {
945 /* aggregated this deaggregated state */
946 qstate->ext_state[id] =
947 generate_lookup_without_subnet(
948 qstate, sq);
949 return;
950 }
951 verbose(VERB_ALGO, "subnetcache: pass to next module");
952 qstate->ext_state[id] = module_wait_module;
953 return;
954 }
955
956 /* Limit to minimum allowed source mask */
957 if(sq->ecs_client_in.subnet_source_mask != 0 && (
958 (sq->ecs_client_in.subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4 &&
959 sq->ecs_client_in.subnet_source_mask < qstate->env->cfg->min_client_subnet_ipv4) ||
960 (sq->ecs_client_in.subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP6 &&
961 sq->ecs_client_in.subnet_source_mask < qstate->env->cfg->min_client_subnet_ipv6))) {
962 qstate->return_rcode = LDNS_RCODE_REFUSED;
963 qstate->ext_state[id] = module_finished;
964 return;
965 }
966
967 if(!sq->started_no_cache_lookup && !qstate->blacklist) {
968 lock_rw_wrlock(&sne->biglock);
969 if(qstate->mesh_info->reply_list &&
970 lookup_and_reply(qstate, id, sq,
971 qstate->env->cfg->prefetch)) {
972 sne->num_msg_cache++;
973 lock_rw_unlock(&sne->biglock);
974 verbose(VERB_QUERY, "subnetcache: answered from cache");
975 qstate->ext_state[id] = module_finished;
976
977 subnet_ecs_opt_list_append(&sq->ecs_client_out,
978 &qstate->edns_opts_front_out, qstate,
979 qstate->region);
980 if(verbosity >= VERB_ALGO) {
981 subnet_log_print("reply has edns subnet",
982 edns_opt_list_find(
983 qstate->edns_opts_front_out,
984 qstate->env->cfg->
985 client_subnet_opcode));
986 }
987 return;
988 }
989 lock_rw_unlock(&sne->biglock);
990 }
991 if(sq->ecs_client_in.subnet_source_mask == 0 &&
992 edns_opt_list_find(qstate->edns_opts_front_in,
993 qstate->env->cfg->client_subnet_opcode)) {
994 /* client asked for resolution without edns subnet */
995 qstate->ext_state[id] = generate_lookup_without_subnet(
996 qstate, sq);
997 return;
998 }
999
1000 sq->ecs_server_out.subnet_addr_fam =
1001 sq->ecs_client_in.subnet_addr_fam;
1002 sq->ecs_server_out.subnet_source_mask =
1003 sq->ecs_client_in.subnet_source_mask;
1004 /* Limit source prefix to configured maximum */
1005 if(sq->ecs_server_out.subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4
1006 && sq->ecs_server_out.subnet_source_mask >
1007 qstate->env->cfg->max_client_subnet_ipv4)
1008 sq->ecs_server_out.subnet_source_mask =
1009 qstate->env->cfg->max_client_subnet_ipv4;
1010 else if(sq->ecs_server_out.subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP6
1011 && sq->ecs_server_out.subnet_source_mask >
1012 qstate->env->cfg->max_client_subnet_ipv6)
1013 sq->ecs_server_out.subnet_source_mask =
1014 qstate->env->cfg->max_client_subnet_ipv6;
1015 /* Safe to copy completely, even if the source is limited by the
1016 * configuration. subnet_ecs_opt_list_append() will limit the address.
1017 * */
1018 memcpy(&sq->ecs_server_out.subnet_addr,
1019 sq->ecs_client_in.subnet_addr, INET6_SIZE);
1020 sq->ecs_server_out.subnet_scope_mask = 0;
1021 sq->ecs_server_out.subnet_validdata = 1;
1022 if(sq->ecs_server_out.subnet_source_mask != 0 &&
1023 qstate->env->cfg->client_subnet_always_forward &&
1024 sq->subnet_downstream)
1025 /* ECS specific data required, do not look at the global
1026 * cache in other modules. */
1027 qstate->no_cache_lookup = 1;
1028
1029 /* pass request to next module */
1030 verbose(VERB_ALGO,
1031 "subnetcache: not found in cache. pass to next module");
1032 qstate->ext_state[id] = module_wait_module;
1033 return;
1034 }
1035 if(sq && sq->wait_subquery)
1036 return; /* Wait for that subquery to return */
1037 /* Query handed back by next module, we have a 'final' answer */
1038 if(sq && event == module_event_moddone) {
1039 qstate->ext_state[id] = eval_response(qstate, id, sq);
1040 if(qstate->ext_state[id] == module_finished &&
1041 qstate->return_msg) {
1042 subnet_ecs_opt_list_append(&sq->ecs_client_out,
1043 &qstate->edns_opts_front_out, qstate,
1044 qstate->region);
1045 if(verbosity >= VERB_ALGO) {
1046 subnet_log_print("reply has edns subnet",
1047 edns_opt_list_find(
1048 qstate->edns_opts_front_out,
1049 qstate->env->cfg->
1050 client_subnet_opcode));
1051 }
1052 }
1053 qstate->no_cache_store = sq->started_no_cache_store;
1054 qstate->no_cache_lookup = sq->started_no_cache_lookup;
1055 return;
1056 }
1057 if(sq && outbound) {
1058 return;
1059 }
1060 /* We are being revisited */
1061 if(event == module_event_pass || event == module_event_new) {
1062 /* Just pass it on, we already did the work */
1063 verbose(VERB_ALGO, "subnetcache: pass to next module");
1064 qstate->ext_state[id] = module_wait_module;
1065 return;
1066 }
1067 if(!sq && (event == module_event_moddone)) {
1068 /* during priming, module done but we never started */
1069 qstate->ext_state[id] = module_finished;
1070 return;
1071 }
1072 log_err("subnetcache: bad event %s", strmodulevent(event));
1073 qstate->ext_state[id] = module_error;
1074 return;
1075 }
1076
1077 void
subnetmod_clear(struct module_qstate * ATTR_UNUSED (qstate),int ATTR_UNUSED (id))1078 subnetmod_clear(struct module_qstate *ATTR_UNUSED(qstate),
1079 int ATTR_UNUSED(id))
1080 {
1081 /* qstate has no data outside region */
1082 }
1083
1084 void
subnetmod_inform_super(struct module_qstate * qstate,int id,struct module_qstate * super)1085 subnetmod_inform_super(struct module_qstate *qstate, int id,
1086 struct module_qstate *super)
1087 {
1088 struct subnet_qstate* super_sq =
1089 (struct subnet_qstate*)super->minfo[id];
1090 log_query_info(VERB_ALGO, "subnetcache inform_super: query",
1091 &super->qinfo);
1092 super_sq->wait_subquery = 0;
1093 super_sq->wait_subquery_done = 1;
1094 if(qstate->return_rcode != LDNS_RCODE_NOERROR ||
1095 !qstate->return_msg) {
1096 super->return_msg = NULL;
1097 super->return_rcode = LDNS_RCODE_SERVFAIL;
1098 return;
1099 }
1100 super->return_rcode = LDNS_RCODE_NOERROR;
1101 super->return_msg = dns_copy_msg(qstate->return_msg, super->region);
1102 if(!super->return_msg) {
1103 log_err("subnetcache: copy response, out of memory");
1104 super->return_rcode = LDNS_RCODE_SERVFAIL;
1105 }
1106 }
1107
1108 size_t
subnetmod_get_mem(struct module_env * env,int id)1109 subnetmod_get_mem(struct module_env *env, int id)
1110 {
1111 struct subnet_env *sn_env = env->modinfo[id];
1112 if (!sn_env) return 0;
1113 return sizeof(*sn_env) +
1114 slabhash_get_mem(sn_env->subnet_msg_cache) +
1115 ecs_whitelist_get_mem(sn_env->whitelist);
1116 }
1117
1118 /**
1119 * The module function block
1120 */
1121 static struct module_func_block subnetmod_block = {
1122 "subnetcache",
1123 NULL, NULL, &subnetmod_init, &subnetmod_deinit, &subnetmod_operate,
1124 &subnetmod_inform_super, &subnetmod_clear, &subnetmod_get_mem
1125 };
1126
1127 struct module_func_block*
subnetmod_get_funcblock(void)1128 subnetmod_get_funcblock(void)
1129 {
1130 return &subnetmod_block;
1131 }
1132
1133 /** Wrappers for static functions to unit test */
1134 size_t
unittest_wrapper_subnetmod_sizefunc(void * elemptr)1135 unittest_wrapper_subnetmod_sizefunc(void *elemptr)
1136 {
1137 return sizefunc(elemptr);
1138 }
1139
1140 #endif /* CLIENT_SUBNET */
1141