From: Ralph Dolmans Date: Thu, 23 Jul 2020 15:17:44 +0000 (+0200) Subject: Start of EDNS client tags implementation. X-Git-Tag: release-1.12.0rc1~48^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=16029281a87bc6f79c8133a2eeecb18743bfdf91;p=thirdparty%2Funbound.git Start of EDNS client tags implementation. --- diff --git a/daemon/daemon.c b/daemon/daemon.c index 5d4279259..34f7bfda1 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -77,6 +77,7 @@ #include "util/storage/lookup3.h" #include "util/storage/slabhash.h" #include "util/tcp_conn_limit.h" +#include "util/edns.h" #include "services/listen_dnsport.h" #include "services/cache/rrset.h" #include "services/cache/infra.h" @@ -290,6 +291,15 @@ daemon_init(void) free(daemon); return NULL; } + if(!(daemon->env->edns_tags = edns_tags_create())) { + auth_zones_delete(daemon->env->auth_zones); + acl_list_delete(daemon->acl); + tcl_list_delete(daemon->tcl); + edns_known_options_delete(daemon->env); + free(daemon->env); + free(daemon); + return NULL; + } return daemon; } @@ -619,6 +629,10 @@ daemon_fork(struct daemon* daemon) &daemon->use_rpz)) fatal_exit("auth_zones could not be setup"); + /* Set-up EDNS tags */ + if(!edns_tags_apply_cfg(daemon->env->edns_tags, daemon->cfg)) + fatal_exit("Could not set up EDNS tags"); + /* setup modules */ daemon_setup_modules(daemon); @@ -750,6 +764,7 @@ daemon_delete(struct daemon* daemon) rrset_cache_delete(daemon->env->rrset_cache); infra_delete(daemon->env->infra_cache); edns_known_options_delete(daemon->env); + edns_tags_delete(daemon->env->edns_tags); auth_zones_delete(daemon->env->auth_zones); } ub_randfree(daemon->rand); diff --git a/services/outside_network.c b/services/outside_network.c index 44e01d745..b7ac5ef60 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -58,6 +58,7 @@ #include "util/net_help.h" #include "util/random.h" #include "util/fptr_wlist.h" +#include "util/edns.h" #include "sldns/sbuffer.h" #include "dnstap/dnstap.h" #ifdef HAVE_OPENSSL_SSL_H @@ -2111,9 +2112,20 @@ outnet_serviced_query(struct outside_network* outnet, { struct serviced_query* sq; struct service_callback* cb; + struct edns_tag_addr* client_tag_addr; + if(!inplace_cb_query_call(env, qinfo, flags, addr, addrlen, zone, zonelen, qstate, qstate->region)) return NULL; + + if((client_tag_addr = edns_tag_addr_lookup(env->edns_tags->client_tags, + addr, addrlen))) { + uint16_t client_tag = htons(client_tag_addr->tag_data); + edns_opt_list_append(&qstate->edns_opts_back_out, + LDNS_EDNS_CLIENT_TAG, 2, + (uint8_t*)&client_tag, qstate->region); + } + serviced_gen_query(buff, qinfo->qname, qinfo->qname_len, qinfo->qtype, qinfo->qclass, flags); sq = lookup_serviced(outnet, buff, dnssec, addr, addrlen, diff --git a/sldns/rrdef.h b/sldns/rrdef.h index 4e7fef574..e084f354a 100644 --- a/sldns/rrdef.h +++ b/sldns/rrdef.h @@ -426,7 +426,8 @@ enum sldns_enum_edns_option LDNS_EDNS_N3U = 7, /* RFC6975 */ LDNS_EDNS_CLIENT_SUBNET = 8, /* RFC7871 */ LDNS_EDNS_KEEPALIVE = 11, /* draft-ietf-dnsop-edns-tcp-keepalive*/ - LDNS_EDNS_PADDING = 12 /* RFC7830 */ + LDNS_EDNS_PADDING = 12, /* RFC7830 */ + LDNS_EDNS_CLIENT_TAG = 16 /* draft-bellis-dnsop-edns-tags-01 */ }; typedef enum sldns_enum_edns_option sldns_edns_option; diff --git a/util/edns.c b/util/edns.c index d19952df0..0ab00cf7c 100644 --- a/util/edns.c +++ b/util/edns.c @@ -47,6 +47,44 @@ #include "util/data/msgparse.h" #include "util/data/msgreply.h" +struct edns_tags* edns_tags_create(void) +{ + struct edns_tags* edns_tags = calloc(1, sizeof(struct edns_tags)); + if(!edns_tags) + return NULL; + if(!(edns_tags->region = regional_create())) { + edns_tags_delete(edns_tags); + return NULL; + } + return edns_tags; +} + +void edns_tags_delete(struct edns_tags* edns_tags) +{ + if(!edns_tags) + return; + regional_destroy(edns_tags->region); + free(edns_tags); +} + +int edns_tags_apply_cfg(struct edns_tags* edns_tags, + struct config_file* config) +{ + regional_free_all(edns_tags->region); + addr_tree_init(&edns_tags->client_tags); + + /* TODO walk over config, create and insert node. */ + + return 1; +} + +struct edns_tag_addr* +edns_tag_addr_lookup(rbtree_type tree, struct sockaddr_storage* addr, + socklen_t addrlen) +{ + return (struct edns_tag_addr*)addr_tree_lookup(&tree, addr, addrlen); +} + static int edns_keepalive(struct edns_data* edns_out, struct edns_data* edns_in, struct comm_point* c, struct regional* region) { diff --git a/util/edns.h b/util/edns.h index a4ee7def6..310ba1cd2 100644 --- a/util/edns.h +++ b/util/edns.h @@ -42,11 +42,66 @@ #ifndef UTIL_EDNS_H #define UTIL_EDNS_H +#include "util/storage/dnstree.h" + struct edns_data; struct config_file; struct comm_point; struct regional; +/** + * Structure containing all EDNS tags. + */ +struct edns_tags { + /** Tree of EDNS client tags to use in upstream queries, per address + * prefix. Contains nodes of type edns_tag_addr. */ + rbtree_type client_tags; + /** region to allocate tree nodes in */ + struct regional* region; +}; + +/** + * EDNS tag. Node of rbtree, containing tag and prefix. + */ +struct edns_tag_addr { + /** node in address tree, used for tree lookups. Need to be the first + * member of this struct. */ + struct addr_tree_node node; + /** tag data, in host byte ordering */ + uint16_t tag_data; +}; + +/** + * Create structure to hold EDNS tags + * @return: newly created edns_tags, NULL on alloc failure. + */ +struct edns_tags* edns_tags_create(void); + +/** Delete ENDS tags structure + * @param edns_tags: struct to delete + */ +void edns_tags_delete(struct edns_tags* edns_tags); + +/** + * Add configured EDNS tags + * @param edns_tags: edns tags to apply config to + * @param config: struct containing EDNS tags configuration + * @return 0 on error + */ +int edns_tags_apply_cfg(struct edns_tags* edns_tags, + struct config_file* config); + +/** + * Find tag for address. + * @param tree: tree containing EDNS tags per address prefix. + * @param addr: address to use for tree lookup + * @param addrlen: length of address + * @return: matching tree node, NULL otherwise + */ +struct edns_tag_addr* +edns_tag_addr_lookup(rbtree_type tree, struct sockaddr_storage* addr, + socklen_t addrlen); + /** * Apply common EDNS options. * diff --git a/util/module.h b/util/module.h index fa89c647e..1d696ed0a 100644 --- a/util/module.h +++ b/util/module.h @@ -520,6 +520,7 @@ struct module_env { struct edns_known_option* edns_known_options; /* Number of known edns options */ size_t edns_known_options_num; + struct edns_tags* edns_tags; /* Make every mesh state unique, do not aggregate mesh states. */ int unique_mesh;