aboutsummaryrefslogtreecommitdiff
path: root/services
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2018-05-12 11:53:39 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2018-05-12 11:53:39 +0000
commit6cacf549d3c2d5bddb0dcadd620e1db2897c7f26 (patch)
treee187e7d708a063f1628697fe779e2bb101d451b8 /services
parentfbdb9ac866a647da0919b224f05cca039afc02fa (diff)
downloadsrc-6cacf549d3c2d5bddb0dcadd620e1db2897c7f26.tar.gz
src-6cacf549d3c2d5bddb0dcadd620e1db2897c7f26.zip
Vendor import of Unbound 1.6.2.vendor/unbound/1.6.2
Notes
Notes: svn path=/vendor/unbound/dist/; revision=333532 svn path=/vendor/unbound/1.6.2/; revision=333533; tag=vendor/unbound/1.6.2
Diffstat (limited to 'services')
-rw-r--r--services/cache/dns.c8
-rw-r--r--services/cache/dns.h14
-rw-r--r--services/listen_dnsport.c73
-rw-r--r--services/listen_dnsport.h13
-rw-r--r--services/localzone.c56
-rw-r--r--services/localzone.h108
-rw-r--r--services/mesh.c144
-rw-r--r--services/mesh.h22
-rw-r--r--services/modstack.c14
-rw-r--r--services/view.c5
-rw-r--r--services/view.h3
11 files changed, 394 insertions, 66 deletions
diff --git a/services/cache/dns.c b/services/cache/dns.c
index 7beb76164986..a8fde9f2890e 100644
--- a/services/cache/dns.c
+++ b/services/cache/dns.c
@@ -479,8 +479,7 @@ gen_dns_msg(struct regional* region, struct query_info* q, size_t num)
return msg;
}
-/** generate dns_msg from cached message */
-static struct dns_msg*
+struct dns_msg*
tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
struct regional* region, time_t now, struct regional* scratch)
{
@@ -525,8 +524,11 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
return NULL;
}
}
- rrset_array_unlock_touch(env->rrset_cache, scratch, r->ref,
+ if(env)
+ rrset_array_unlock_touch(env->rrset_cache, scratch, r->ref,
r->rrset_count);
+ else
+ rrset_array_unlock(r->ref, r->rrset_count);
return msg;
}
diff --git a/services/cache/dns.h b/services/cache/dns.h
index 15a4a236b028..0dfb68874403 100644
--- a/services/cache/dns.h
+++ b/services/cache/dns.h
@@ -126,6 +126,20 @@ struct delegpt* dns_cache_find_delegation(struct module_env* env,
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
struct regional* region, struct dns_msg** msg, time_t timenow);
+/**
+ * generate dns_msg from cached message
+ * @param env: module environment with the DNS cache. NULL if the LRU from cache
+ * does not need to be touched.
+ * @param q: query info, contains qname that will make up the dns message.
+ * @param r: reply info that, together with qname, will make up the dns message.
+ * @param region: where to allocate dns message.
+ * @param now: the time now, for check if TTL on cache entry is ok.
+ * @param scratch: where to allocate temporary data.
+ * */
+struct dns_msg* tomsg(struct module_env* env, struct query_info* q,
+ struct reply_info* r, struct regional* region, time_t now,
+ struct regional* scratch);
+
/**
* Find cached message
* @param env: module environment with the DNS cache.
diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c
index 0132ce45f781..37ee9a6b9b46 100644
--- a/services/listen_dnsport.c
+++ b/services/listen_dnsport.c
@@ -1056,15 +1056,25 @@ set_recvpktinfo(int s, int family)
* @param tcp_mss: maximum segment size of tcp socket. default if zero.
* @param freebind: set IP_FREEBIND socket option.
* @param use_systemd: if true, fetch sockets from systemd.
+ * @param dnscrypt_port: dnscrypt service port number
* @return: returns false on error.
*/
static int
ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
struct addrinfo *hints, const char* port, struct listen_port** list,
size_t rcv, size_t snd, int ssl_port, int* reuseport, int transparent,
- int tcp_mss, int freebind, int use_systemd)
+ int tcp_mss, int freebind, int use_systemd, int dnscrypt_port)
{
int s, noip6=0;
+#ifdef USE_DNSCRYPT
+ int is_dnscrypt = ((strchr(ifname, '@') &&
+ atoi(strchr(ifname, '@')+1) == dnscrypt_port) ||
+ (!strchr(ifname, '@') && atoi(port) == dnscrypt_port));
+#else
+ int is_dnscrypt = 0;
+ (void)dnscrypt_port;
+#endif
+
if(!do_udp && !do_tcp)
return 0;
if(do_auto) {
@@ -1086,7 +1096,8 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
#endif
return 0;
}
- if(!port_insert(list, s, listen_type_udpancil)) {
+ if(!port_insert(list, s,
+ is_dnscrypt?listen_type_udpancil_dnscrypt:listen_type_udpancil)) {
#ifndef USE_WINSOCK
close(s);
#else
@@ -1105,7 +1116,8 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
}
return 0;
}
- if(!port_insert(list, s, listen_type_udp)) {
+ if(!port_insert(list, s,
+ is_dnscrypt?listen_type_udp_dnscrypt:listen_type_udp)) {
#ifndef USE_WINSOCK
close(s);
#else
@@ -1130,7 +1142,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
if(is_ssl)
verbose(VERB_ALGO, "setup TCP for SSL service");
if(!port_insert(list, s, is_ssl?listen_type_ssl:
- listen_type_tcp)) {
+ (is_dnscrypt?listen_type_tcp_dnscrypt:listen_type_tcp))) {
#ifndef USE_WINSOCK
close(s);
#else
@@ -1172,6 +1184,9 @@ listen_create(struct comm_base* base, struct listen_port* ports,
return NULL;
front->cps = NULL;
front->udp_buff = sldns_buffer_new(bufsize);
+#ifdef USE_DNSCRYPT
+ front->dnscrypt_udp_buff = NULL;
+#endif
if(!front->udp_buff) {
free(front);
return NULL;
@@ -1180,17 +1195,20 @@ listen_create(struct comm_base* base, struct listen_port* ports,
/* create comm points as needed */
while(ports) {
struct comm_point* cp = NULL;
- if(ports->ftype == listen_type_udp)
+ if(ports->ftype == listen_type_udp ||
+ ports->ftype == listen_type_udp_dnscrypt)
cp = comm_point_create_udp(base, ports->fd,
front->udp_buff, cb, cb_arg);
- else if(ports->ftype == listen_type_tcp)
+ else if(ports->ftype == listen_type_tcp ||
+ ports->ftype == listen_type_tcp_dnscrypt)
cp = comm_point_create_tcp(base, ports->fd,
tcp_accept_count, bufsize, cb, cb_arg);
else if(ports->ftype == listen_type_ssl) {
cp = comm_point_create_tcp(base, ports->fd,
tcp_accept_count, bufsize, cb, cb_arg);
cp->ssl = sslctx;
- } else if(ports->ftype == listen_type_udpancil)
+ } else if(ports->ftype == listen_type_udpancil ||
+ ports->ftype == listen_type_udpancil_dnscrypt)
cp = comm_point_create_udp_ancil(base, ports->fd,
front->udp_buff, cb, cb_arg);
if(!cp) {
@@ -1200,6 +1218,21 @@ listen_create(struct comm_base* base, struct listen_port* ports,
}
cp->dtenv = dtenv;
cp->do_not_close = 1;
+#ifdef USE_DNSCRYPT
+ if (ports->ftype == listen_type_udp_dnscrypt ||
+ ports->ftype == listen_type_tcp_dnscrypt ||
+ ports->ftype == listen_type_udpancil_dnscrypt) {
+ cp->dnscrypt = 1;
+ cp->dnscrypt_buffer = sldns_buffer_new(bufsize);
+ if(!cp->dnscrypt_buffer) {
+ log_err("can't alloc dnscrypt_buffer");
+ comm_point_delete(cp);
+ listen_delete(front);
+ return NULL;
+ }
+ front->dnscrypt_udp_buff = cp->dnscrypt_buffer;
+ }
+#endif
if(!listen_cp_insert(cp, front)) {
log_err("malloc failed");
comm_point_delete(cp);
@@ -1235,6 +1268,12 @@ listen_delete(struct listen_dnsport* front)
if(!front)
return;
listen_list_delete(front->cps);
+#ifdef USE_DNSCRYPT
+ if(front->dnscrypt_udp_buff &&
+ front->udp_buff != front->dnscrypt_udp_buff) {
+ sldns_buffer_free(front->dnscrypt_udp_buff);
+ }
+#endif
sldns_buffer_free(front->udp_buff);
free(front);
}
@@ -1278,7 +1317,8 @@ listening_ports_open(struct config_file* cfg, int* reuseport)
cfg->so_rcvbuf, cfg->so_sndbuf,
cfg->ssl_port, reuseport,
cfg->ip_transparent,
- cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd)) {
+ cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd,
+ cfg->dnscrypt_port)) {
listening_ports_free(list);
return NULL;
}
@@ -1291,7 +1331,8 @@ listening_ports_open(struct config_file* cfg, int* reuseport)
cfg->so_rcvbuf, cfg->so_sndbuf,
cfg->ssl_port, reuseport,
cfg->ip_transparent,
- cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd)) {
+ cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd,
+ cfg->dnscrypt_port)) {
listening_ports_free(list);
return NULL;
}
@@ -1306,7 +1347,8 @@ listening_ports_open(struct config_file* cfg, int* reuseport)
cfg->so_rcvbuf, cfg->so_sndbuf,
cfg->ssl_port, reuseport,
cfg->ip_transparent,
- cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd)) {
+ cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd,
+ cfg->dnscrypt_port)) {
listening_ports_free(list);
return NULL;
}
@@ -1319,7 +1361,8 @@ listening_ports_open(struct config_file* cfg, int* reuseport)
cfg->so_rcvbuf, cfg->so_sndbuf,
cfg->ssl_port, reuseport,
cfg->ip_transparent,
- cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd)) {
+ cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd,
+ cfg->dnscrypt_port)) {
listening_ports_free(list);
return NULL;
}
@@ -1347,10 +1390,16 @@ void listening_ports_free(struct listen_port* list)
size_t listen_get_mem(struct listen_dnsport* listen)
{
+ struct listen_list* p;
size_t s = sizeof(*listen) + sizeof(*listen->base) +
sizeof(*listen->udp_buff) +
sldns_buffer_capacity(listen->udp_buff);
- struct listen_list* p;
+#ifdef USE_DNSCRYPT
+ s += sizeof(*listen->dnscrypt_udp_buff);
+ if(listen->udp_buff != listen->dnscrypt_udp_buff){
+ s += sldns_buffer_capacity(listen->dnscrypt_udp_buff);
+ }
+#endif
for(p = listen->cps; p; p = p->next) {
s += sizeof(*p);
s += comm_point_get_mem(p->com);
diff --git a/services/listen_dnsport.h b/services/listen_dnsport.h
index 93d2ef7148e2..fac0f7970924 100644
--- a/services/listen_dnsport.h
+++ b/services/listen_dnsport.h
@@ -59,7 +59,9 @@ struct listen_dnsport {
/** buffer shared by UDP connections, since there is only one
datagram at any time. */
struct sldns_buffer* udp_buff;
-
+#ifdef USE_DNSCRYPT
+ struct sldns_buffer* dnscrypt_udp_buff;
+#endif
/** list of comm points used to get incoming events */
struct listen_list* cps;
};
@@ -85,7 +87,14 @@ enum listen_type {
/** udp ipv6 (v4mapped) for use with ancillary data */
listen_type_udpancil,
/** ssl over tcp type */
- listen_type_ssl
+ listen_type_ssl,
+ /** udp type + dnscrypt*/
+ listen_type_udp_dnscrypt,
+ /** tcp type + dnscrypt */
+ listen_type_tcp_dnscrypt,
+ /** udp ipv6 (v4mapped) for use with ancillary data + dnscrypt*/
+ listen_type_udpancil_dnscrypt
+
};
/**
diff --git a/services/localzone.c b/services/localzone.c
index d813ab586172..dcce46e863e4 100644
--- a/services/localzone.c
+++ b/services/localzone.c
@@ -229,9 +229,8 @@ lz_enter_zone(struct local_zones* zones, const char* name, const char* type,
return z;
}
-/** return name and class and rdata of rr; parses string */
-static int
-get_rr_content(const char* str, uint8_t** nm, uint16_t* type,
+int
+rrstr_get_rr_content(const char* str, uint8_t** nm, uint16_t* type,
uint16_t* dclass, time_t* ttl, uint8_t* rr, size_t len,
uint8_t** rdata, size_t* rdata_len)
{
@@ -353,8 +352,8 @@ new_local_rrset(struct regional* region, struct local_data* node,
}
/** insert RR into RRset data structure; Wastes a couple of bytes */
-static int
-insert_rr(struct regional* region, struct packed_rrset_data* pd,
+int
+rrset_insert_rr(struct regional* region, struct packed_rrset_data* pd,
uint8_t* rdata, size_t rdata_len, time_t ttl, const char* rrstr)
{
size_t* oldlen = pd->rr_len;
@@ -456,8 +455,8 @@ lz_enter_rr_into_zone(struct local_zone* z, const char* rrstr)
uint8_t rr[LDNS_RR_BUF_SIZE];
uint8_t* rdata;
size_t rdata_len;
- if(!get_rr_content(rrstr, &nm, &rrtype, &rrclass, &ttl, rr, sizeof(rr),
- &rdata, &rdata_len)) {
+ if(!rrstr_get_rr_content(rrstr, &nm, &rrtype, &rrclass, &ttl, rr,
+ sizeof(rr), &rdata, &rdata_len)) {
log_err("bad local-data: %s", rrstr);
return 0;
}
@@ -513,7 +512,7 @@ lz_enter_rr_into_zone(struct local_zone* z, const char* rrstr)
verbose(VERB_ALGO, "ignoring duplicate RR: %s", rrstr);
return 1;
}
- return insert_rr(z->region, pd, rdata, rdata_len, ttl, rrstr);
+ return rrset_insert_rr(z->region, pd, rdata, rdata_len, ttl, rrstr);
}
/** enter a data RR into auth data; a zone for it must exist */
@@ -1233,9 +1232,10 @@ local_error_encode(struct query_info* qinfo, struct module_env* env,
}
/** find local data tag string match for the given type in the list */
-static int
-find_tag_datas(struct query_info* qinfo, struct config_strlist* list,
- struct ub_packed_rrset_key* r, struct regional* temp)
+int
+local_data_find_tag_datas(const struct query_info* qinfo,
+ struct config_strlist* list, struct ub_packed_rrset_key* r,
+ struct regional* temp)
{
struct config_strlist* p;
char buf[65536];
@@ -1312,13 +1312,24 @@ find_tag_datas(struct query_info* qinfo, struct config_strlist* list,
sldns_wirerr_get_rdatawl(rr, len, 1),
d->rr_len[d->count]);
if(!d->rr_data[d->count])
- if(!d) return 0; /* out of memory */
+ return 0; /* out of memory */
d->count++;
}
+ if(r->rk.dname)
+ return 1;
+ return 0;
+}
+
+static int
+find_tag_datas(struct query_info* qinfo, struct config_strlist* list,
+ struct ub_packed_rrset_key* r, struct regional* temp)
+{
+ int result = local_data_find_tag_datas(qinfo, list, r, temp);
+
/* If we've found a non-exact alias type of local data, make a shallow
* copy of the RRset and remember it in qinfo to complete the alias
* chain later. */
- if(r->rk.dname && qinfo->qtype != LDNS_RR_TYPE_CNAME &&
+ if(result && qinfo->qtype != LDNS_RR_TYPE_CNAME &&
r->rk.type == htons(LDNS_RR_TYPE_CNAME)) {
qinfo->local_alias =
regional_alloc_zero(temp, sizeof(struct local_rrset));
@@ -1329,9 +1340,7 @@ find_tag_datas(struct query_info* qinfo, struct config_strlist* list,
if(!qinfo->local_alias->rrset)
return 0; /* out of memory */
}
- if(r->rk.dname)
- return 1;
- return 0;
+ return result;
}
/** answer local data match */
@@ -1497,8 +1506,6 @@ lz_type(uint8_t *taglist, size_t taglen, uint8_t *taglist2, size_t taglen2,
struct comm_reply* repinfo, struct rbtree_type* override_tree,
int* tag, char** tagname, int num_tags)
{
- size_t i, j;
- uint8_t tagmatch;
struct local_zone_override* lzo;
if(repinfo && override_tree) {
lzo = (struct local_zone_override*)addr_tree_lookup(
@@ -1511,6 +1518,19 @@ lz_type(uint8_t *taglist, size_t taglen, uint8_t *taglist2, size_t taglen2,
}
if(!taglist || !taglist2)
return lzt;
+ return local_data_find_tag_action(taglist, taglen, taglist2, taglen2,
+ tagactions, tagactionssize, lzt, tag, tagname, num_tags);
+}
+
+enum localzone_type
+local_data_find_tag_action(const uint8_t* taglist, size_t taglen,
+ const uint8_t* taglist2, size_t taglen2, const uint8_t* tagactions,
+ size_t tagactionssize, enum localzone_type lzt, int* tag,
+ char* const* tagname, int num_tags)
+{
+ size_t i, j;
+ uint8_t tagmatch;
+
for(i=0; i<taglen && i<taglen2; i++) {
tagmatch = (taglist[i] & taglist2[i]);
for(j=0; j<8 && tagmatch>0; j++) {
diff --git a/services/localzone.h b/services/localzone.h
index bf9c9bf489cb..658f28024ef4 100644
--- a/services/localzone.h
+++ b/services/localzone.h
@@ -46,6 +46,7 @@
#include "util/storage/dnstree.h"
#include "util/module.h"
#include "services/view.h"
+struct packed_rrset_data;
struct ub_packed_rrset_key;
struct regional;
struct config_file;
@@ -389,4 +390,111 @@ void local_zones_del_data(struct local_zones* zones,
*/
int parse_dname(const char* str, uint8_t** res, size_t* len, int* labs);
+/**
+ * Find local data tag string match for the given type (in qinfo) in the list.
+ * If found, 'r' will be filled with corresponding rrset information.
+ * @param qinfo: contains name, type, and class for the data
+ * @param list: stores local tag data to be searched
+ * @param r: rrset key to be filled for matched data
+ * @param temp: region to allocate rrset in 'r'
+ * @return 1 if a match is found and rrset is built; otherwise 0 including
+ * errors.
+ */
+int local_data_find_tag_datas(const struct query_info* qinfo,
+ struct config_strlist* list, struct ub_packed_rrset_key* r,
+ struct regional* temp);
+
+/**
+ * See if two sets of tag lists (in the form of bitmap) have the same tag that
+ * has an action. If so, '*tag' will be set to the found tag index, and the
+ * corresponding action will be returned in the form of local zone type.
+ * Otherwise the passed type (lzt) will be returned as the default action.
+ * Pointers except tagactions must not be NULL.
+ * @param taglist: 1st list of tags
+ * @param taglen: size of taglist in bytes
+ * @param taglist2: 2nd list of tags
+ * @param taglen2: size of taglist2 in bytes
+ * @param tagactions: local data actions for tags. May be NULL.
+ * @param tagactionssize: length of the tagactions.
+ * @param lzt: default action (local zone type) if no tag action is found.
+ * @param tag: see above.
+ * @param tagname: array of tag name strings (for debug output).
+ * @param num_tags: number of items in tagname array.
+ * @return found tag action or the default action.
+ */
+enum localzone_type local_data_find_tag_action(const uint8_t* taglist,
+ size_t taglen, const uint8_t* taglist2, size_t taglen2,
+ const uint8_t* tagactions, size_t tagactionssize,
+ enum localzone_type lzt, int* tag, char* const* tagname, int num_tags);
+
+/**
+ * Parses resource record string into wire format, also returning its field values.
+ * @param str: input resource record
+ * @param nm: domain name field
+ * @param type: record type field
+ * @param dclass: record class field
+ * @param ttl: ttl field
+ * @param rr: buffer for the parsed rr in wire format
+ * @param len: buffer length
+ * @param rdata: rdata field
+ * @param rdata_len: rdata field length
+ * @return 1 on success; 0 otherwise.
+ */
+int rrstr_get_rr_content(const char* str, uint8_t** nm, uint16_t* type,
+ uint16_t* dclass, time_t* ttl, uint8_t* rr, size_t len,
+ uint8_t** rdata, size_t* rdata_len);
+
+/**
+ * Insert specified rdata into the specified resource record.
+ * @param region: allocator
+ * @param pd: data portion of the destination resource record
+ * @param rdata: source rdata
+ * @param rdata_len: source rdata length
+ * @param ttl: time to live
+ * @param rrstr: resource record in text form (for logging)
+ * @return 1 on success; 0 otherwise.
+ */
+int rrset_insert_rr(struct regional* region, struct packed_rrset_data* pd,
+ uint8_t* rdata, size_t rdata_len, time_t ttl, const char* rrstr);
+
+/**
+ * Valid response ip actions for the IP-response-driven-action feature;
+ * defined here instead of in the respip module to enable sharing of enum
+ * values with the localzone_type enum.
+ * Note that these values except 'none' are the same as localzone types of
+ * the 'same semantics'. It's intentional as we use these values via
+ * access-control-tags, which can be shared for both response ip actions and
+ * local zones.
+ */
+enum respip_action {
+ /** no respip action */
+ respip_none = local_zone_unset,
+ /** don't answer */
+ respip_deny = local_zone_deny,
+ /** redirect as per provided data */
+ respip_redirect = local_zone_redirect,
+ /** log query source and answer query */
+ respip_inform = local_zone_inform,
+ /** log query source and don't answer query */
+ respip_inform_deny = local_zone_inform_deny,
+ /** resolve normally, even when there is response-ip data */
+ respip_always_transparent = local_zone_always_transparent,
+ /** answer with 'refused' response */
+ respip_always_refuse = local_zone_always_refuse,
+ /** answer with 'no such domain' response */
+ respip_always_nxdomain = local_zone_always_nxdomain,
+
+ /* The rest of the values are only possible as
+ * access-control-tag-action */
+
+ /** serves response data (if any), else, drops queries. */
+ respip_refuse = local_zone_refuse,
+ /** serves response data, else, nodata answer. */
+ respip_static = local_zone_static,
+ /** gives response data (if any), else nodata answer. */
+ respip_transparent = local_zone_transparent,
+ /** gives response data (if any), else nodata answer. */
+ respip_typetransparent = local_zone_typetransparent,
+};
+
#endif /* SERVICES_LOCALZONE_H */
diff --git a/services/mesh.c b/services/mesh.c
index f5a193ac2d48..0cb134ade85f 100644
--- a/services/mesh.c
+++ b/services/mesh.c
@@ -59,6 +59,7 @@
#include "sldns/wire2str.h"
#include "services/localzone.h"
#include "util/data/dname.h"
+#include "respip/respip.h"
/** subtract timers and the values do not overflow or become negative */
static void
@@ -124,11 +125,64 @@ timeval_smaller(const struct timeval* x, const struct timeval* y)
#endif
}
+/*
+ * Compare two response-ip client info entries for the purpose of mesh state
+ * compare. It returns 0 if ci_a and ci_b are considered equal; otherwise
+ * 1 or -1 (they mean 'ci_a is larger/smaller than ci_b', respectively, but
+ * in practice it should be only used to mean they are different).
+ * We cannot share the mesh state for two queries if different response-ip
+ * actions can apply in the end, even if those queries are otherwise identical.
+ * For this purpose we compare tag lists and tag action lists; they should be
+ * identical to share the same state.
+ * For tag data, we don't look into the data content, as it can be
+ * expensive; unless tag data are not defined for both or they point to the
+ * exact same data in memory (i.e., they come from the same ACL entry), we
+ * consider these data different.
+ * Likewise, if the client info is associated with views, we don't look into
+ * the views. They are considered different unless they are exactly the same
+ * even if the views only differ in the names.
+ */
+static int
+client_info_compare(const struct respip_client_info* ci_a,
+ const struct respip_client_info* ci_b)
+{
+ int cmp;
+
+ if(!ci_a && !ci_b)
+ return 0;
+ if(ci_a && !ci_b)
+ return -1;
+ if(!ci_a && ci_b)
+ return 1;
+ if(ci_a->taglen != ci_b->taglen)
+ return (ci_a->taglen < ci_b->taglen) ? -1 : 1;
+ cmp = memcmp(ci_a->taglist, ci_b->taglist, ci_a->taglen);
+ if(cmp != 0)
+ return cmp;
+ if(ci_a->tag_actions_size != ci_b->tag_actions_size)
+ return (ci_a->tag_actions_size < ci_b->tag_actions_size) ?
+ -1 : 1;
+ cmp = memcmp(ci_a->tag_actions, ci_b->tag_actions,
+ ci_a->tag_actions_size);
+ if(cmp != 0)
+ return cmp;
+ if(ci_a->tag_datas != ci_b->tag_datas)
+ return ci_a->tag_datas < ci_b->tag_datas ? -1 : 1;
+ if(ci_a->view != ci_b->view)
+ return ci_a->view < ci_b->view ? -1 : 1;
+ /* For the unbound daemon these should be non-NULL and identical,
+ * but we check that just in case. */
+ if(ci_a->respip_set != ci_b->respip_set)
+ return ci_a->respip_set < ci_b->respip_set ? -1 : 1;
+ return 0;
+}
+
int
mesh_state_compare(const void* ap, const void* bp)
{
struct mesh_state* a = (struct mesh_state*)ap;
struct mesh_state* b = (struct mesh_state*)bp;
+ int cmp;
if(a->unique < b->unique)
return -1;
@@ -155,7 +209,10 @@ mesh_state_compare(const void* ap, const void* bp)
if(!(a->s.query_flags&BIT_CD) && (b->s.query_flags&BIT_CD))
return 1;
- return query_info_compare(&a->s.qinfo, &b->s.qinfo);
+ cmp = query_info_compare(&a->s.qinfo, &b->s.qinfo);
+ if(cmp != 0)
+ return cmp;
+ return client_info_compare(a->s.client_info, b->s.client_info);
}
int
@@ -287,16 +344,16 @@ int mesh_make_new_space(struct mesh_area* mesh, sldns_buffer* qbuf)
}
void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
- uint16_t qflags, struct edns_data* edns, struct comm_reply* rep,
- uint16_t qid)
+ struct respip_client_info* cinfo, uint16_t qflags,
+ struct edns_data* edns, struct comm_reply* rep, uint16_t qid)
{
struct mesh_state* s = NULL;
- int unique = edns_unique_mesh_state(edns->opt_list, mesh->env);
+ int unique = unique_mesh_state(edns->opt_list, mesh->env);
int was_detached = 0;
int was_noreply = 0;
int added = 0;
if(!unique)
- s = mesh_area_find(mesh, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
+ s = mesh_area_find(mesh, cinfo, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
/* does this create a new reply state? */
if(!s || s->list_select == mesh_no_list) {
if(!mesh_make_new_space(mesh, rep->c->buffer)) {
@@ -323,7 +380,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
#ifdef UNBOUND_DEBUG
struct rbnode_type* n;
#endif
- s = mesh_state_create(mesh->env, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
+ s = mesh_state_create(mesh->env, qinfo, cinfo,
+ qflags&(BIT_RD|BIT_CD), 0, 0);
if(!s) {
log_err("mesh_state_create: out of memory; SERVFAIL");
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL,
@@ -412,12 +470,13 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qid, mesh_cb_func_type cb, void* cb_arg)
{
struct mesh_state* s = NULL;
- int unique = edns_unique_mesh_state(edns->opt_list, mesh->env);
+ int unique = unique_mesh_state(edns->opt_list, mesh->env);
int was_detached = 0;
int was_noreply = 0;
int added = 0;
if(!unique)
- s = mesh_area_find(mesh, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
+ s = mesh_area_find(mesh, NULL, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
+
/* there are no limits on the number of callbacks */
/* see if it already exists, if not, create one */
@@ -425,7 +484,8 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
#ifdef UNBOUND_DEBUG
struct rbnode_type* n;
#endif
- s = mesh_state_create(mesh->env, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
+ s = mesh_state_create(mesh->env, qinfo, NULL,
+ qflags&(BIT_RD|BIT_CD), 0, 0);
if(!s) {
return 0;
}
@@ -476,8 +536,8 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags, time_t leeway)
{
- struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags&(BIT_RD|BIT_CD),
- 0, 0);
+ struct mesh_state* s = mesh_area_find(mesh, NULL, qinfo,
+ qflags&(BIT_RD|BIT_CD), 0, 0);
#ifdef UNBOUND_DEBUG
struct rbnode_type* n;
#endif
@@ -497,7 +557,8 @@ void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
return;
}
- s = mesh_state_create(mesh->env, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
+ s = mesh_state_create(mesh->env, qinfo, NULL,
+ qflags&(BIT_RD|BIT_CD), 0, 0);
if(!s) {
log_err("prefetch mesh_state_create: out of memory");
return;
@@ -546,7 +607,8 @@ void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
struct mesh_state*
mesh_state_create(struct module_env* env, struct query_info* qinfo,
- uint16_t qflags, int prime, int valrec)
+ struct respip_client_info* cinfo, uint16_t qflags, int prime,
+ int valrec)
{
struct regional* region = alloc_reg_obtain(env->alloc);
struct mesh_state* mstate;
@@ -582,6 +644,14 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo,
alloc_reg_release(env->alloc, region);
return NULL;
}
+ if(cinfo) {
+ mstate->s.client_info = regional_alloc_init(region, cinfo,
+ sizeof(*cinfo));
+ if(!mstate->s.client_info) {
+ alloc_reg_release(env->alloc, region);
+ return NULL;
+ }
+ }
/* remove all weird bits from qflags */
mstate->s.query_flags = (qflags & (BIT_RD|BIT_CD));
mstate->s.is_priming = prime;
@@ -756,7 +826,8 @@ int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo,
{
/* find it, if not, create it */
struct mesh_area* mesh = qstate->env->mesh;
- struct mesh_state* sub = mesh_area_find(mesh, qinfo, qflags, prime, valrec);
+ struct mesh_state* sub = mesh_area_find(mesh, NULL, qinfo, qflags,
+ prime, valrec);
int was_detached;
if(mesh_detect_cycle_found(qstate, sub)) {
verbose(VERB_ALGO, "attach failed, cycle detected");
@@ -767,7 +838,8 @@ int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo,
struct rbnode_type* n;
#endif
/* create a new one */
- sub = mesh_state_create(qstate->env, qinfo, qflags, prime, valrec);
+ sub = mesh_state_create(qstate->env, qinfo, NULL, qflags, prime,
+ valrec);
if(!sub) {
log_err("mesh_attach_sub: out of memory");
return 0;
@@ -1035,8 +1107,25 @@ void mesh_query_done(struct mesh_state* mstate)
struct reply_info* rep = (mstate->s.return_msg?
mstate->s.return_msg->rep:NULL);
for(r = mstate->reply_list; r; r = r->next) {
- mesh_send_reply(mstate, mstate->s.return_rcode, rep, r, prev);
- prev = r;
+ /* if a response-ip address block has been stored the
+ * information should be logged for each client. */
+ if(mstate->s.respip_action_info &&
+ mstate->s.respip_action_info->addrinfo) {
+ respip_inform_print(mstate->s.respip_action_info->addrinfo,
+ r->qname, mstate->s.qinfo.qtype,
+ mstate->s.qinfo.qclass, r->local_alias,
+ &r->query_reply);
+ }
+
+ /* if this query is determined to be dropped during the
+ * mesh processing, this is the point to take that action. */
+ if(mstate->s.is_drop)
+ comm_point_drop_reply(&r->query_reply);
+ else {
+ mesh_send_reply(mstate, mstate->s.return_rcode, rep,
+ r, prev);
+ prev = r;
+ }
}
mstate->replies_sent = 1;
for(c = mstate->cb_list; c; c = c->next) {
@@ -1060,7 +1149,8 @@ void mesh_walk_supers(struct mesh_area* mesh, struct mesh_state* mstate)
}
struct mesh_state* mesh_area_find(struct mesh_area* mesh,
- struct query_info* qinfo, uint16_t qflags, int prime, int valrec)
+ struct respip_client_info* cinfo, struct query_info* qinfo,
+ uint16_t qflags, int prime, int valrec)
{
struct mesh_state key;
struct mesh_state* result;
@@ -1074,6 +1164,7 @@ struct mesh_state* mesh_area_find(struct mesh_area* mesh,
* aggregate the state. Thus unique is set to NULL. (default when we
* desire aggregation).*/
key.unique = NULL;
+ key.s.client_info = cinfo;
result = (struct mesh_state*)rbtree_search(&mesh->all, &key);
return result;
@@ -1224,11 +1315,16 @@ mesh_continue(struct mesh_area* mesh, struct mesh_state* mstate,
return mesh_continue(mesh, mstate, module_error, ev);
}
if(s == module_restart_next) {
- fptr_ok(fptr_whitelist_mod_clear(
- mesh->mods.mod[mstate->s.curmod]->clear));
- (*mesh->mods.mod[mstate->s.curmod]->clear)
- (&mstate->s, mstate->s.curmod);
- mstate->s.minfo[mstate->s.curmod] = NULL;
+ int curmod = mstate->s.curmod;
+ for(; mstate->s.curmod < mesh->mods.num;
+ mstate->s.curmod++) {
+ fptr_ok(fptr_whitelist_mod_clear(
+ mesh->mods.mod[mstate->s.curmod]->clear));
+ (*mesh->mods.mod[mstate->s.curmod]->clear)
+ (&mstate->s, mstate->s.curmod);
+ mstate->s.minfo[mstate->s.curmod] = NULL;
+ }
+ mstate->s.curmod = curmod;
}
*ev = module_event_pass;
return 1;
@@ -1378,7 +1474,7 @@ mesh_detect_cycle(struct module_qstate* qstate, struct query_info* qinfo,
struct mesh_area* mesh = qstate->env->mesh;
struct mesh_state* dep_m = NULL;
if(!mesh_state_is_unique(qstate->mesh_info))
- dep_m = mesh_area_find(mesh, qinfo, flags, prime, valrec);
+ dep_m = mesh_area_find(mesh, NULL, qinfo, flags, prime, valrec);
return mesh_detect_cycle_found(qstate, dep_m);
}
diff --git a/services/mesh.h b/services/mesh.h
index 435f89c689d5..1c77945320e3 100644
--- a/services/mesh.h
+++ b/services/mesh.h
@@ -59,6 +59,7 @@ struct query_info;
struct reply_info;
struct outbound_entry;
struct timehist;
+struct respip_client_info;
/**
* Maximum number of mesh state activations. Any more is likely an
@@ -274,14 +275,18 @@ void mesh_delete(struct mesh_area* mesh);
*
* @param mesh: the mesh.
* @param qinfo: query from client.
+ * @param cinfo: additional information associated with the query client.
+ * 'cinfo' itself is ephemeral but data pointed to by its members
+ * can be assumed to be valid and unchanged until the query processing is
+ * completed.
* @param qflags: flags from client query.
* @param edns: edns data from client query.
* @param rep: where to reply to.
* @param qid: query id to reply with.
*/
void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
- uint16_t qflags, struct edns_data* edns, struct comm_reply* rep,
- uint16_t qid);
+ struct respip_client_info* cinfo, uint16_t qflags,
+ struct edns_data* edns, struct comm_reply* rep, uint16_t qid);
/**
* New query with callback. Create new query state if needed, and
@@ -409,14 +414,16 @@ void mesh_state_delete(struct module_qstate* qstate);
* Does not put the mesh state into rbtrees and so on.
* @param env: module environment to set.
* @param qinfo: query info that the mesh is for.
+ * @param cinfo: control info for the query client (can be NULL).
* @param qflags: flags for query (RD / CD flag).
* @param prime: if true, it is a priming query, set is_priming on mesh state.
* @param valrec: if true, it is a validation recursion query, and sets
* is_valrec on the mesh state.
* @return: new mesh state or NULL on allocation error.
*/
-struct mesh_state* mesh_state_create(struct module_env* env,
- struct query_info* qinfo, uint16_t qflags, int prime, int valrec);
+struct mesh_state* mesh_state_create(struct module_env* env,
+ struct query_info* qinfo, struct respip_client_info* cinfo,
+ uint16_t qflags, int prime, int valrec);
/**
* Check if the mesh state is unique.
@@ -451,14 +458,17 @@ void mesh_delete_all(struct mesh_area* mesh);
* Find a mesh state in the mesh area. Pass relevant flags.
*
* @param mesh: the mesh area to look in.
+ * @param cinfo: if non-NULL client specific info that may affect IP-based
+ * actions that apply to the query result.
* @param qinfo: what query
* @param qflags: if RD / CD bit is set or not.
* @param prime: if it is a priming query.
* @param valrec: if it is a validation-recursion query.
* @return: mesh state or NULL if not found.
*/
-struct mesh_state* mesh_area_find(struct mesh_area* mesh,
- struct query_info* qinfo, uint16_t qflags, int prime, int valrec);
+struct mesh_state* mesh_area_find(struct mesh_area* mesh,
+ struct respip_client_info* cinfo, struct query_info* qinfo,
+ uint16_t qflags, int prime, int valrec);
/**
* Setup attachment super/sub relation between super and sub mesh state.
diff --git a/services/modstack.c b/services/modstack.c
index 70e066670d5d..9bebd3a5634c 100644
--- a/services/modstack.c
+++ b/services/modstack.c
@@ -46,6 +46,7 @@
#include "dns64/dns64.h"
#include "iterator/iterator.h"
#include "validator/validator.h"
+#include "respip/respip.h"
#ifdef WITH_PYTHONMODULE
#include "pythonmod/pythonmod.h"
@@ -53,6 +54,9 @@
#ifdef USE_CACHEDB
#include "cachedb/cachedb.h"
#endif
+#ifdef CLIENT_SUBNET
+#include "edns-subnet/subnetmod.h"
+#endif
/** count number of modules (words) in the string */
static int
@@ -127,6 +131,10 @@ module_list_avail(void)
#ifdef USE_CACHEDB
"cachedb",
#endif
+#ifdef CLIENT_SUBNET
+ "subnetcache",
+#endif
+ "respip",
"validator",
"iterator",
NULL};
@@ -148,6 +156,10 @@ module_funcs_avail(void)
#ifdef USE_CACHEDB
&cachedb_get_funcblock,
#endif
+#ifdef CLIENT_SUBNET
+ &subnetmod_get_funcblock,
+#endif
+ &respip_get_funcblock,
&val_get_funcblock,
&iter_get_funcblock,
NULL};
@@ -216,7 +228,7 @@ int
modstack_find(struct module_stack* stack, const char* name)
{
int i;
- for(i=0; i<stack->num; i++) {
+ for(i=0; i<stack->num; i++) {
if(strcmp(stack->mod[i]->name, name) == 0)
return i;
}
diff --git a/services/view.c b/services/view.c
index c9dfc3c87383..33f4f4986ba7 100644
--- a/services/view.c
+++ b/services/view.c
@@ -66,6 +66,10 @@ views_create(void)
return v;
}
+/** This prototype is defined in in respip.h, but we want to avoid
+ * unnecessary dependencies */
+void respip_set_delete(struct respip_set *set);
+
void
view_delete(struct view* v)
{
@@ -73,6 +77,7 @@ view_delete(struct view* v)
return;
lock_rw_destroy(&v->lock);
local_zones_delete(v->local_zones);
+ respip_set_delete(v->respip_set);
free(v->name);
free(v);
}
diff --git a/services/view.h b/services/view.h
index ce4b69d6c510..e0b346419e9b 100644
--- a/services/view.h
+++ b/services/view.h
@@ -47,6 +47,7 @@
struct regional;
struct config_file;
struct config_view;
+struct respip_set;
/**
@@ -71,6 +72,8 @@ struct view {
char* name;
/** view specific local authority zones */
struct local_zones* local_zones;
+ /** response-ip configuration data for this view */
+ struct respip_set* respip_set;
/** Fallback to global local_zones when there is no match in the view
* specific tree. 1 for yes, 0 for no */
int isfirst;