aboutsummaryrefslogtreecommitdiff
path: root/edns-subnet/subnet-whitelist.c
diff options
context:
space:
mode:
Diffstat (limited to 'edns-subnet/subnet-whitelist.c')
-rw-r--r--edns-subnet/subnet-whitelist.c120
1 files changed, 87 insertions, 33 deletions
diff --git a/edns-subnet/subnet-whitelist.c b/edns-subnet/subnet-whitelist.c
index 1cfdb4be3c5a..1ea7fb1b2591 100644
--- a/edns-subnet/subnet-whitelist.c
+++ b/edns-subnet/subnet-whitelist.c
@@ -50,42 +50,44 @@
#include "util/config_file.h"
#include "util/net_help.h"
#include "util/storage/dnstree.h"
+#include "sldns/str2wire.h"
+#include "util/data/dname.h"
-struct ednssubnet_upstream*
-upstream_create(void)
+struct ecs_whitelist*
+ecs_whitelist_create(void)
{
- struct ednssubnet_upstream* upstream =
- (struct ednssubnet_upstream*)calloc(1,
- sizeof(struct ednssubnet_upstream));
- if(!upstream)
+ struct ecs_whitelist* whitelist =
+ (struct ecs_whitelist*)calloc(1,
+ sizeof(struct ecs_whitelist));
+ if(!whitelist)
return NULL;
- upstream->region = regional_create();
- if(!upstream->region) {
- upstream_delete(upstream);
+ whitelist->region = regional_create();
+ if(!whitelist->region) {
+ ecs_whitelist_delete(whitelist);
return NULL;
}
- return upstream;
+ return whitelist;
}
void
-upstream_delete(struct ednssubnet_upstream* upstream)
+ecs_whitelist_delete(struct ecs_whitelist* whitelist)
{
- if(!upstream)
+ if(!whitelist)
return;
- regional_destroy(upstream->region);
- free(upstream);
+ regional_destroy(whitelist->region);
+ free(whitelist);
}
-/** insert new address into upstream structure */
+/** insert new address into whitelist structure */
static int
-upstream_insert(struct ednssubnet_upstream* upstream,
+upstream_insert(struct ecs_whitelist* whitelist,
struct sockaddr_storage* addr, socklen_t addrlen, int net)
{
struct addr_tree_node* node = (struct addr_tree_node*)regional_alloc(
- upstream->region, sizeof(*node));
+ whitelist->region, sizeof(*node));
if(!node)
return 0;
- if(!addr_tree_insert(&upstream->tree, node, addr, addrlen, net)) {
+ if(!addr_tree_insert(&whitelist->upstream, node, addr, addrlen, net)) {
verbose(VERB_QUERY,
"duplicate send-client-subnet address ignored.");
}
@@ -94,7 +96,7 @@ upstream_insert(struct ednssubnet_upstream* upstream,
/** apply edns-subnet string */
static int
-upstream_str_cfg(struct ednssubnet_upstream* upstream, const char* str)
+upstream_str_cfg(struct ecs_whitelist* whitelist, const char* str)
{
struct sockaddr_storage addr;
int net;
@@ -104,7 +106,7 @@ upstream_str_cfg(struct ednssubnet_upstream* upstream, const char* str)
log_err("cannot parse send-client-subnet netblock: %s", str);
return 0;
}
- if(!upstream_insert(upstream, &addr, addrlen, net)) {
+ if(!upstream_insert(whitelist, &addr, addrlen, net)) {
log_err("out of memory");
return 0;
}
@@ -113,41 +115,93 @@ upstream_str_cfg(struct ednssubnet_upstream* upstream, const char* str)
/** read client_subnet config */
static int
-read_upstream(struct ednssubnet_upstream* upstream, struct config_file* cfg)
+read_upstream(struct ecs_whitelist* whitelist, struct config_file* cfg)
{
struct config_strlist* p;
for(p = cfg->client_subnet; p; p = p->next) {
log_assert(p->str);
- if(!upstream_str_cfg(upstream, p->str))
+ if(!upstream_str_cfg(whitelist, p->str))
return 0;
}
return 1;
}
+/** read client_subnet_zone config */
+static int
+read_names(struct ecs_whitelist* whitelist, struct config_file* cfg)
+{
+ /* parse names, report errors, insert into tree */
+ struct config_strlist* p;
+ struct name_tree_node* n;
+ uint8_t* nm, *nmr;
+ size_t nm_len;
+ int nm_labs;
+
+ for(p = cfg->client_subnet_zone; p; p = p->next) {
+ log_assert(p->str);
+ nm = sldns_str2wire_dname(p->str, &nm_len);
+ if(!nm) {
+ log_err("cannot parse client-subnet-zone: %s", p->str);
+ return 0;
+ }
+ nm_labs = dname_count_size_labels(nm, &nm_len);
+ nmr = (uint8_t*)regional_alloc_init(whitelist->region, nm,
+ nm_len);
+ free(nm);
+ if(!nmr) {
+ log_err("out of memory");
+ return 0;
+ }
+ n = (struct name_tree_node*)regional_alloc(whitelist->region,
+ sizeof(*n));
+ if(!n) {
+ log_err("out of memory");
+ return 0;
+ }
+ if(!name_tree_insert(&whitelist->dname, n, nmr, nm_len, nm_labs,
+ LDNS_RR_CLASS_IN)) {
+ verbose(VERB_QUERY, "ignoring duplicate "
+ "client-subnet-zone: %s", p->str);
+ }
+ }
+ return 1;
+}
+
int
-upstream_apply_cfg(struct ednssubnet_upstream* upstream,
+ecs_whitelist_apply_cfg(struct ecs_whitelist* whitelist,
struct config_file* cfg)
{
- regional_free_all(upstream->region);
- addr_tree_init(&upstream->tree);
- if(!read_upstream(upstream, cfg))
+ regional_free_all(whitelist->region);
+ addr_tree_init(&whitelist->upstream);
+ name_tree_init(&whitelist->dname);
+ if(!read_upstream(whitelist, cfg))
+ return 0;
+ if(!read_names(whitelist, cfg))
return 0;
- addr_tree_init_parents(&upstream->tree);
+ addr_tree_init_parents(&whitelist->upstream);
+ name_tree_init_parents(&whitelist->dname);
return 1;
}
int
-upstream_is_whitelisted(struct ednssubnet_upstream* upstream,
- struct sockaddr_storage* addr, socklen_t addrlen)
+ecs_is_whitelisted(struct ecs_whitelist* whitelist,
+ struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* qname,
+ size_t qname_len, uint16_t qclass)
{
- return addr_tree_lookup(&upstream->tree, addr, addrlen) != NULL;
+ int labs;
+ if(addr_tree_lookup(&whitelist->upstream, addr, addrlen))
+ return 1;
+ /* Not in upstream whitelist, check dname whitelist. */
+ labs = dname_count_labels(qname);
+ return name_tree_lookup(&whitelist->dname, qname, qname_len, labs,
+ qclass) != NULL;
}
size_t
-upstream_get_mem(struct ednssubnet_upstream* upstream)
+ecs_whitelist_get_mem(struct ecs_whitelist* whitelist)
{
- if(!upstream) return 0;
- return sizeof(*upstream) + regional_get_mem(upstream->region);
+ if(!whitelist) return 0;
+ return sizeof(*whitelist) + regional_get_mem(whitelist->region);
}
#endif /* CLIENT_SUBNET */