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