tree->node_count++;
node->scope = scope;
node->ttl = ttl;
+ node->only_match_scope_zero = 0;
node->edge[0] = NULL;
node->edge[1] = NULL;
node->parent_edge = NULL;
if (!node->elem) return;
tree->size_bytes -= tree->sizefunc(node->elem);
tree->delfunc(tree->env, node->elem);
+ node->only_match_scope_zero = 0;
node->elem = NULL;
}
void
addrtree_insert(struct addrtree *tree, const addrkey_t *addr,
addrlen_t sourcemask, addrlen_t scope, void *elem, time_t ttl,
- time_t now)
+ time_t now, int only_match_scope_zero)
{
struct addrnode *newnode, *node;
struct addredge *edge;
/* update this node's scope and data */
clean_node(tree, node);
node->ttl = ttl;
+ node->only_match_scope_zero = only_match_scope_zero;
node->elem = elem;
node->scope = scope;
tree->size_bytes += tree->sizefunc(elem);
newnode->elem = elem;
newnode->scope = scope;
newnode->ttl = ttl;
+ newnode->only_match_scope_zero = only_match_scope_zero;
}
tree->size_bytes += node_size(tree, newnode);
/* Current node more specific then question. */
log_assert(depth <= sourcemask);
/* does this node have data? if yes, see if we have a match */
- if (node->elem && node->ttl >= now) {
+ if (node->elem && node->ttl >= now &&
+ !(sourcemask != 0 && node->only_match_scope_zero)) {
/* saved at wrong depth */;
log_assert(node->scope >= depth);
if (depth == node->scope ||
#include "util/config_file.h"
#include "util/data/msgreply.h"
#include "sldns/sbuffer.h"
+#include "sldns/wire2str.h"
#include "iterator/iter_utils.h"
/** externally called */
struct slabhash *subnet_msg_cache = sne->subnet_msg_cache;
struct ecs_data *edns = &sq->ecs_client_in;
size_t i;
+ int only_match_scope_zero;
/* We already calculated hash upon lookup (lookup_and_reply) if we were
* allowed to look in the ECS cache */
reply_info_set_ttls(rep, *qstate->env->now);
rep->flags |= (BIT_RA | BIT_QR); /* fix flags to be sensible for */
rep->flags &= ~(BIT_AA | BIT_CD);/* a reply based on the cache */
+ if(edns->subnet_source_mask == 0 && edns->subnet_scope_mask == 0)
+ only_match_scope_zero = 1;
+ else only_match_scope_zero = 0;
addrtree_insert(tree, (addrkey_t*)edns->subnet_addr,
edns->subnet_source_mask, sq->max_scope, rep,
- rep->ttl, *qstate->env->now);
+ rep->ttl, *qstate->env->now, only_match_scope_zero);
lock_rw_unlock(&lru_entry->lock);
if (need_to_insert) {
return 1;
}
+/** verbose print edns subnet option in pretty print */
+static void
+subnet_log_print(const char* s, struct edns_option* ecs_opt)
+{
+ if(verbosity >= VERB_ALGO) {
+ char buf[256];
+ char* str = buf;
+ size_t str_len = sizeof(buf);
+ if(!ecs_opt) {
+ verbose(VERB_ALGO, "%s (null)", s);
+ return;
+ }
+ (void)sldns_wire2str_edns_subnet_print(&str, &str_len,
+ ecs_opt->opt_data, ecs_opt->opt_len);
+ verbose(VERB_ALGO, "%s %s", s, buf);
+ }
+}
+
int
ecs_edns_back_parsed(struct module_qstate* qstate, int id,
void* ATTR_UNUSED(cbargs))
qstate->env->cfg->client_subnet_opcode)) &&
parse_subnet_option(ecs_opt, &sq->ecs_server_in) &&
sq->subnet_sent && sq->ecs_server_in.subnet_validdata) {
+ subnet_log_print("answer has edns subnet", ecs_opt);
/* Only skip global cache store if we sent an ECS option
* and received one back. Answers from non-whitelisted
* servers will end up in global cache. Answers for
qstate->ext_state[id] = module_finished;
return;
}
+ subnet_log_print("query has edns subnet", ecs_opt);
sq->subnet_downstream = 1;
}
else if(qstate->mesh_info->reply_list) {
subnet_ecs_opt_list_append(&sq->ecs_client_out,
&qstate->edns_opts_front_out, qstate,
qstate->region);
+ if(verbosity >= VERB_ALGO) {
+ subnet_log_print("reply has edns subnet",
+ edns_opt_list_find(
+ qstate->edns_opts_front_out,
+ qstate->env->cfg->
+ client_subnet_opcode));
+ }
return;
}
lock_rw_unlock(&sne->biglock);
subnet_ecs_opt_list_append(&sq->ecs_client_out,
&qstate->edns_opts_front_out, qstate,
qstate->region);
+ if(verbosity >= VERB_ALGO) {
+ subnet_log_print("reply has edns subnet",
+ edns_opt_list_find(
+ qstate->edns_opts_front_out,
+ qstate->env->cfg->
+ client_subnet_opcode));
+ }
}
qstate->no_cache_store = sq->started_no_cache_store;
qstate->no_cache_lookup = sq->started_no_cache_lookup;
--- /dev/null
+; scope of 0, if the query also had scope of 0, do not answer this
+; to everyone, but only for scope 0 queries. Otherwise can answer cached.
+
+server:
+ target-fetch-policy: "0 0 0 0 0"
+ send-client-subnet: 1.2.3.4
+ module-config: "subnetcache validator iterator"
+ verbosity: 4
+ qname-minimisation: no
+
+stub-zone:
+ name: "."
+ stub-addr: 193.0.14.129
+
+stub-zone:
+ name: "example.com"
+ stub-addr: 1.2.3.4
+CONFIG_END
+
+SCENARIO_BEGIN Test subnet cache with scope zero queries and responses.
+
+; the upstream server.
+RANGE_BEGIN 0 100
+ ADDRESS 193.0.14.129
+
+ENTRY_BEGIN
+MATCH opcode qtype qname ednsdata
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS K.ROOT-SERVERS.NET.
+SECTION ADDITIONAL
+HEX_EDNSDATA_BEGIN
+ ;; we expect to receive empty
+HEX_EDNSDATA_END
+K.ROOT-SERVERS.NET. IN A 193.0.14.129
+ENTRY_END
+RANGE_END
+
+RANGE_BEGIN 0 11
+ ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+;copy_ednsdata_assume_clientsubnet
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.40
+SECTION AUTHORITY
+SECTION ADDITIONAL
+HEX_EDNSDATA_BEGIN
+ ; client is 127.0.0.1
+ 00 08 ; OPC
+ 00 07 ; option length
+ 00 01 ; Family
+ 18 11 ; source mask, scopemask
+ 7f 00 00 ; address
+HEX_EDNSDATA_END
+ENTRY_END
+RANGE_END
+
+RANGE_BEGIN 20 31
+ ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+;copy_ednsdata_assume_clientsubnet
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.41
+SECTION AUTHORITY
+SECTION ADDITIONAL
+HEX_EDNSDATA_BEGIN
+ ; client is 127.0.0.1
+ 00 08 ; OPC
+ 00 07 ; option length
+ 00 01 ; Family
+ 18 11 ; source mask, scopemask
+ 7f 01 00 ; address
+HEX_EDNSDATA_END
+ENTRY_END
+RANGE_END
+
+RANGE_BEGIN 40 51
+ ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+;copy_ednsdata_assume_clientsubnet
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.42
+SECTION AUTHORITY
+SECTION ADDITIONAL
+HEX_EDNSDATA_BEGIN
+ 00 08 ; OPC
+ 00 04 ; option length
+ 00 01 ; Family
+ 00 00 ; source mask, scopemask
+ ; address 0.0.0.0/0 scope 0
+HEX_EDNSDATA_END
+ENTRY_END
+RANGE_END
+
+RANGE_BEGIN 120 131
+ ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+;copy_ednsdata_assume_clientsubnet
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.43
+SECTION AUTHORITY
+SECTION ADDITIONAL
+HEX_EDNSDATA_BEGIN
+ 00 08 ; OPC
+ 00 07 ; option length
+ 00 01 ; Family
+ 18 00 ; source mask, scopemask
+ 7f 02 00 ; address 127.2.0.0/24 scope 0
+HEX_EDNSDATA_END
+ENTRY_END
+RANGE_END
+
+; query for 127.0.0.0/24
+STEP 1 QUERY
+ENTRY_BEGIN
+HEX_ANSWER_BEGIN
+ 00 00 01 00 00 01 00 00 ;ID 0
+ 00 00 00 01 03 77 77 77 ; www.example.com A? (DO)
+ 07 65 78 61 6d 70 6c 65
+ 03 63 6f 6d 00 00 01 00
+ 01 00 00 29 10 00 00 00
+ 80 00 00 0b
+
+ 00 08 00 07 ; OPC, optlen
+ 00 01 18 00 ; ip4, scope 24, source 0
+ 7f 00 00 ;127.0.0.0/24
+HEX_ANSWER_END
+ENTRY_END
+
+; answer is 10.20.30.40 for 127.0.0.0/24 scope 17
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ednsdata
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.40
+SECTION AUTHORITY
+SECTION ADDITIONAL
+HEX_EDNSDATA_BEGIN
+ ; client is 127.0.0.1
+ 00 08 ; OPC
+ 00 07 ; option length
+ 00 01 ; Family
+ 18 11 ; source mask, scopemask
+ 7f 00 00 ; address
+HEX_EDNSDATA_END
+ENTRY_END
+
+; query for 127.1.0.0/24
+STEP 20 QUERY
+ENTRY_BEGIN
+HEX_ANSWER_BEGIN
+ 00 00 01 00 00 01 00 00 ;ID 0
+ 00 00 00 01 03 77 77 77 ; www.example.com A? (DO)
+ 07 65 78 61 6d 70 6c 65
+ 03 63 6f 6d 00 00 01 00
+ 01 00 00 29 10 00 00 00
+ 80 00 00 0b
+
+ 00 08 00 07 ; OPC, optlen
+ 00 01 18 00 ; ip4, scope 24, source 0
+ 7f 01 00 ;127.1.0.0/24
+HEX_ANSWER_END
+ENTRY_END
+
+; answer is 10.20.30.41 for 127.1.0.0/24 scope 17
+STEP 30 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ednsdata
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.41
+SECTION AUTHORITY
+SECTION ADDITIONAL
+HEX_EDNSDATA_BEGIN
+ ; client is 127.1.0.1
+ 00 08 ; OPC
+ 00 07 ; option length
+ 00 01 ; Family
+ 18 11 ; source mask, scopemask
+ 7f 01 00 ; address
+HEX_EDNSDATA_END
+ENTRY_END
+
+; query for 0.0.0.0/0
+STEP 40 QUERY
+ENTRY_BEGIN
+HEX_ANSWER_BEGIN
+ 00 00 01 00 00 01 00 00 ;ID 0
+ 00 00 00 01 03 77 77 77 ; www.example.com A? (DO)
+ 07 65 78 61 6d 70 6c 65
+ 03 63 6f 6d 00 00 01 00
+ 01 00 00 29 10 00 00 00
+ 80 00 00 08
+
+ 00 08 00 04 ; OPC, optlen
+ 00 01 00 00 ; ip4, scope 0, source 0
+ ;0.0.0.0/0
+HEX_ANSWER_END
+ENTRY_END
+
+; answer is 10.20.30.42 for 0.0.0.0/0 scope 0
+STEP 50 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ednsdata
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.42
+SECTION AUTHORITY
+SECTION ADDITIONAL
+HEX_EDNSDATA_BEGIN
+ 00 08 ; OPC
+ 00 04 ; option length
+ 00 01 ; Family
+ 00 00 ; source mask, scopemask
+ ; address
+HEX_EDNSDATA_END
+ENTRY_END
+
+; query for 127.0.0.0/24, again, it should be in cache.
+; and not from the scope 0 answer.
+STEP 60 QUERY
+ENTRY_BEGIN
+HEX_ANSWER_BEGIN
+ 00 00 01 00 00 01 00 00 ;ID 0
+ 00 00 00 01 03 77 77 77 ; www.example.com A? (DO)
+ 07 65 78 61 6d 70 6c 65
+ 03 63 6f 6d 00 00 01 00
+ 01 00 00 29 10 00 00 00
+ 80 00 00 0b
+
+ 00 08 00 07 ; OPC, optlen
+ 00 01 18 00 ; ip4, scope 24, source 0
+ 7f 00 00 ;127.0.0.0/24
+HEX_ANSWER_END
+ENTRY_END
+
+; answer should be 10.20.30.40 for 127.0.0.0/24 scope 17
+STEP 70 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ednsdata
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.40
+SECTION AUTHORITY
+SECTION ADDITIONAL
+HEX_EDNSDATA_BEGIN
+ ; client is 127.0.0.1
+ 00 08 ; OPC
+ 00 07 ; option length
+ 00 01 ; Family
+ 18 11 ; source mask, scopemask
+ 7f 00 00 ; address
+HEX_EDNSDATA_END
+ENTRY_END
+
+; query for 127.1.0.0/24, again, it should be in cache.
+STEP 80 QUERY
+ENTRY_BEGIN
+HEX_ANSWER_BEGIN
+ 00 00 01 00 00 01 00 00 ;ID 0
+ 00 00 00 01 03 77 77 77 ; www.example.com A? (DO)
+ 07 65 78 61 6d 70 6c 65
+ 03 63 6f 6d 00 00 01 00
+ 01 00 00 29 10 00 00 00
+ 80 00 00 0b
+
+ 00 08 00 07 ; OPC, optlen
+ 00 01 18 00 ; ip4, scope 24, source 0
+ 7f 01 00 ;127.1.0.0/24
+HEX_ANSWER_END
+ENTRY_END
+
+; answer should be 10.20.30.41 for 127.1.0.0/24 scope 17
+STEP 90 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ednsdata
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.41
+SECTION AUTHORITY
+SECTION ADDITIONAL
+HEX_EDNSDATA_BEGIN
+ ; client is 127.1.0.1
+ 00 08 ; OPC
+ 00 07 ; option length
+ 00 01 ; Family
+ 18 11 ; source mask, scopemask
+ 7f 01 00 ; address
+HEX_EDNSDATA_END
+ENTRY_END
+
+; query for 0.0.0.0/0, again.
+STEP 100 QUERY
+ENTRY_BEGIN
+HEX_ANSWER_BEGIN
+ 00 00 01 00 00 01 00 00 ;ID 0
+ 00 00 00 01 03 77 77 77 ; www.example.com A? (DO)
+ 07 65 78 61 6d 70 6c 65
+ 03 63 6f 6d 00 00 01 00
+ 01 00 00 29 10 00 00 00
+ 80 00 00 08
+
+ 00 08 00 04 ; OPC, optlen
+ 00 01 00 00 ; ip4, scope 0, source 0
+ ;0.0.0.0/0
+HEX_ANSWER_END
+ENTRY_END
+
+; answer should be 10.20.30.42 for 0.0.0.0/0 scope 0
+STEP 110 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ednsdata
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.42
+SECTION AUTHORITY
+SECTION ADDITIONAL
+HEX_EDNSDATA_BEGIN
+ 00 08 ; OPC
+ 00 04 ; option length
+ 00 01 ; Family
+ 00 00 ; source mask, scopemask
+ ; address
+HEX_EDNSDATA_END
+ENTRY_END
+
+; now a query for a /24 that gets an answer for a /0.
+STEP 120 QUERY
+ENTRY_BEGIN
+HEX_ANSWER_BEGIN
+ 00 00 01 00 00 01 00 00 ;ID 0
+ 00 00 00 01 03 77 77 77 ; www.example.com A? (DO)
+ 07 65 78 61 6d 70 6c 65
+ 03 63 6f 6d 00 00 01 00
+ 01 00 00 29 10 00 00 00
+ 80 00 00 0b
+
+ 00 08 00 07 ; OPC, optlen
+ 00 01 18 00 ; ip4, scope 24, source 0
+ 7f 02 00 ;127.2.0.0/24
+HEX_ANSWER_END
+ENTRY_END
+
+; answer should be 10.20.30.43 for 127.2.0.0/24 scope 0
+STEP 130 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ednsdata
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.43
+SECTION AUTHORITY
+SECTION ADDITIONAL
+HEX_EDNSDATA_BEGIN
+ ; client is 127.2.0.1
+ 00 08 ; OPC
+ 00 07 ; option length
+ 00 01 ; Family
+ 18 00 ; source mask, scopemask
+ 7f 02 00 ; address
+HEX_EDNSDATA_END
+ENTRY_END
+
+; the scope 0 answer is now used to answer queries from
+; query for 127.0.0.0/24
+STEP 140 QUERY
+ENTRY_BEGIN
+HEX_ANSWER_BEGIN
+ 00 00 01 00 00 01 00 00 ;ID 0
+ 00 00 00 01 03 77 77 77 ; www.example.com A? (DO)
+ 07 65 78 61 6d 70 6c 65
+ 03 63 6f 6d 00 00 01 00
+ 01 00 00 29 10 00 00 00
+ 80 00 00 0b
+
+ 00 08 00 07 ; OPC, optlen
+ 00 01 18 00 ; ip4, scope 24, source 0
+ 7f 00 00 ;127.0.0.0/24
+HEX_ANSWER_END
+ENTRY_END
+
+STEP 150 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ednsdata
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.43
+SECTION AUTHORITY
+SECTION ADDITIONAL
+HEX_EDNSDATA_BEGIN
+ ; client is 127.0.0.1
+ 00 08 ; OPC
+ 00 07 ; option length
+ 00 01 ; Family
+ 18 00 ; source mask, scopemask
+ 7f 00 00 ; address
+HEX_EDNSDATA_END
+ENTRY_END
+
+SCENARIO_END