summaryrefslogtreecommitdiff
path: root/daemon
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2022-10-16 19:24:20 +0000
committerCy Schubert <cy@FreeBSD.org>2022-10-16 19:24:20 +0000
commit643f9a0581e8aac7eb790ced1164748939829826 (patch)
tree426d366252d838c8c61b439342ab32eccd181425 /daemon
parent0dde6f4f8e604df8c6fbdab8b4aadb5ddf80c76f (diff)
Diffstat (limited to 'daemon')
-rw-r--r--daemon/acl_list.c447
-rw-r--r--daemon/acl_list.h39
-rw-r--r--daemon/daemon.c61
-rw-r--r--daemon/daemon.h2
-rw-r--r--daemon/remote.c6
-rw-r--r--daemon/stats.c27
-rw-r--r--daemon/worker.c152
-rw-r--r--daemon/worker.h4
8 files changed, 599 insertions, 139 deletions
diff --git a/daemon/acl_list.c b/daemon/acl_list.c
index aecb3e0c6437..f3961dbbb7ad 100644
--- a/daemon/acl_list.c
+++ b/daemon/acl_list.c
@@ -46,9 +46,10 @@
#include "util/config_file.h"
#include "util/net_help.h"
#include "services/localzone.h"
+#include "services/listen_dnsport.h"
#include "sldns/str2wire.h"
-struct acl_list*
+struct acl_list*
acl_list_create(void)
{
struct acl_list* acl = (struct acl_list*)calloc(1,
@@ -63,10 +64,10 @@ acl_list_create(void)
return acl;
}
-void
+void
acl_list_delete(struct acl_list* acl)
{
- if(!acl)
+ if(!acl)
return;
regional_destroy(acl->region);
free(acl);
@@ -74,8 +75,8 @@ acl_list_delete(struct acl_list* acl)
/** insert new address into acl_list structure */
static struct acl_addr*
-acl_list_insert(struct acl_list* acl, struct sockaddr_storage* addr,
- socklen_t addrlen, int net, enum acl_access control,
+acl_list_insert(struct acl_list* acl, struct sockaddr_storage* addr,
+ socklen_t addrlen, int net, enum acl_access control,
int complain_duplicates)
{
struct acl_addr* node = regional_alloc_zero(acl->region,
@@ -90,6 +91,31 @@ acl_list_insert(struct acl_list* acl, struct sockaddr_storage* addr,
return node;
}
+/** parse str to acl_access enum */
+static int
+parse_acl_access(const char* str, enum acl_access* control)
+{
+ if(strcmp(str, "allow") == 0)
+ *control = acl_allow;
+ else if(strcmp(str, "deny") == 0)
+ *control = acl_deny;
+ else if(strcmp(str, "refuse") == 0)
+ *control = acl_refuse;
+ else if(strcmp(str, "deny_non_local") == 0)
+ *control = acl_deny_non_local;
+ else if(strcmp(str, "refuse_non_local") == 0)
+ *control = acl_refuse_non_local;
+ else if(strcmp(str, "allow_snoop") == 0)
+ *control = acl_allow_snoop;
+ else if(strcmp(str, "allow_setrd") == 0)
+ *control = acl_allow_setrd;
+ else {
+ log_err("access control type %s unknown", str);
+ return 0;
+ }
+ return 1;
+}
+
/** apply acl_list string */
static int
acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2,
@@ -99,29 +125,14 @@ acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2,
int net;
socklen_t addrlen;
enum acl_access control;
- if(strcmp(s2, "allow") == 0)
- control = acl_allow;
- else if(strcmp(s2, "deny") == 0)
- control = acl_deny;
- else if(strcmp(s2, "refuse") == 0)
- control = acl_refuse;
- else if(strcmp(s2, "deny_non_local") == 0)
- control = acl_deny_non_local;
- else if(strcmp(s2, "refuse_non_local") == 0)
- control = acl_refuse_non_local;
- else if(strcmp(s2, "allow_snoop") == 0)
- control = acl_allow_snoop;
- else if(strcmp(s2, "allow_setrd") == 0)
- control = acl_allow_setrd;
- else {
- log_err("access control type %s unknown", str);
+ if(!parse_acl_access(s2, &control)) {
return 0;
}
if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
log_err("cannot parse access control: %s %s", str, s2);
return 0;
}
- if(!acl_list_insert(acl, &addr, addrlen, net, control,
+ if(!acl_list_insert(acl, &addr, addrlen, net, control,
complain_duplicates)) {
log_err("out of memory");
return 0;
@@ -131,19 +142,27 @@ acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2,
/** find or create node (NULL on parse or error) */
static struct acl_addr*
-acl_find_or_create(struct acl_list* acl, const char* str)
+acl_find_or_create_str2addr(struct acl_list* acl, const char* str,
+ int is_interface, int port)
{
struct acl_addr* node;
struct sockaddr_storage addr;
- int net;
socklen_t addrlen;
- if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
- log_err("cannot parse netblock: %s", str);
- return NULL;
+ int net = (str_is_ip6(str)?128:32);
+ if(is_interface) {
+ if(!extstrtoaddr(str, &addr, &addrlen, port)) {
+ log_err("cannot parse interface: %s", str);
+ return NULL;
+ }
+ } else {
+ if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
+ log_err("cannot parse netblock: %s", str);
+ return NULL;
+ }
}
/* find or create node */
if(!(node=(struct acl_addr*)addr_tree_find(&acl->tree, &addr,
- addrlen, net))) {
+ addrlen, net)) && !is_interface) {
/* create node, type 'allow' since otherwise tags are
* pointless, can override with specific access-control: cfg */
if(!(node=(struct acl_addr*)acl_list_insert(acl, &addr,
@@ -155,14 +174,65 @@ acl_find_or_create(struct acl_list* acl, const char* str)
return node;
}
+/** find or create node (NULL on error) */
+static struct acl_addr*
+acl_find_or_create(struct acl_list* acl, struct sockaddr_storage* addr,
+ socklen_t addrlen, enum acl_access control)
+{
+ struct acl_addr* node;
+ int net = (addr_is_ip6(addr, addrlen)?128:32);
+ /* find or create node */
+ if(!(node=(struct acl_addr*)addr_tree_find(&acl->tree, addr,
+ addrlen, net))) {
+ /* create node;
+ * can override with specific access-control: cfg */
+ if(!(node=(struct acl_addr*)acl_list_insert(acl, addr,
+ addrlen, net, control, 1))) {
+ log_err("out of memory");
+ return NULL;
+ }
+ }
+ return node;
+}
+
+/** apply acl_interface string */
+static int
+acl_interface_str_cfg(struct acl_list* acl_interface, const char* iface,
+ const char* s2, int port)
+{
+ struct acl_addr* node;
+ enum acl_access control;
+ if(!parse_acl_access(s2, &control)) {
+ return 0;
+ }
+ if(!(node=acl_find_or_create_str2addr(acl_interface, iface, 1, port))) {
+ log_err("cannot update ACL on non-configured interface: %s %d",
+ iface, port);
+ return 0;
+ }
+ node->control = control;
+ return 1;
+}
+
+struct acl_addr*
+acl_interface_insert(struct acl_list* acl_interface,
+ struct sockaddr_storage* addr, socklen_t addrlen,
+ enum acl_access control)
+{
+ return acl_find_or_create(acl_interface, addr, addrlen, control);
+}
+
/** apply acl_tag string */
static int
acl_list_tags_cfg(struct acl_list* acl, const char* str, uint8_t* bitmap,
- size_t bitmaplen)
+ size_t bitmaplen, int is_interface, int port)
{
struct acl_addr* node;
- if(!(node=acl_find_or_create(acl, str)))
+ if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
+ if(is_interface)
+ log_err("non-configured interface: %s", str);
return 0;
+ }
node->taglen = bitmaplen;
node->taglist = regional_alloc_init(acl->region, bitmap, bitmaplen);
if(!node->taglist) {
@@ -175,11 +245,14 @@ acl_list_tags_cfg(struct acl_list* acl, const char* str, uint8_t* bitmap,
/** apply acl_view string */
static int
acl_list_view_cfg(struct acl_list* acl, const char* str, const char* str2,
- struct views* vs)
+ struct views* vs, int is_interface, int port)
{
struct acl_addr* node;
- if(!(node=acl_find_or_create(acl, str)))
+ if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
+ if(is_interface)
+ log_err("non-configured interface: %s", str);
return 0;
+ }
node->view = views_find_view(vs, str2, 0 /* get read lock*/);
if(!node->view) {
log_err("no view with name: %s", str2);
@@ -192,13 +265,17 @@ acl_list_view_cfg(struct acl_list* acl, const char* str, const char* str2,
/** apply acl_tag_action string */
static int
acl_list_tag_action_cfg(struct acl_list* acl, struct config_file* cfg,
- const char* str, const char* tag, const char* action)
+ const char* str, const char* tag, const char* action,
+ int is_interface, int port)
{
struct acl_addr* node;
int tagid;
enum localzone_type t;
- if(!(node=acl_find_or_create(acl, str)))
+ if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
+ if(is_interface)
+ log_err("non-configured interface: %s", str);
return 0;
+ }
/* allocate array if not yet */
if(!node->tag_actions) {
node->tag_actions = (uint8_t*)regional_alloc_zero(acl->region,
@@ -281,13 +358,17 @@ check_data(const char* data, const struct config_strlist* head)
/** apply acl_tag_data string */
static int
acl_list_tag_data_cfg(struct acl_list* acl, struct config_file* cfg,
- const char* str, const char* tag, const char* data)
+ const char* str, const char* tag, const char* data,
+ int is_interface, int port)
{
struct acl_addr* node;
int tagid;
char* dupdata;
- if(!(node=acl_find_or_create(acl, str)))
+ if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
+ if(is_interface)
+ log_err("non-configured interface: %s", str);
return 0;
+ }
/* allocate array if not yet */
if(!node->tag_datas) {
node->tag_datas = (struct config_strlist**)regional_alloc_zero(
@@ -329,11 +410,11 @@ acl_list_tag_data_cfg(struct acl_list* acl, struct config_file* cfg,
}
/** read acl_list config */
-static int
-read_acl_list(struct acl_list* acl, struct config_file* cfg)
+static int
+read_acl_list(struct acl_list* acl, struct config_str2list* acls)
{
struct config_str2list* p;
- for(p = cfg->acls; p; p = p->next) {
+ for(p = acls; p; p = p->next) {
log_assert(p->str && p->str2);
if(!acl_list_str_cfg(acl, p->str, p->str2, 1))
return 0;
@@ -341,16 +422,17 @@ read_acl_list(struct acl_list* acl, struct config_file* cfg)
return 1;
}
-/** read acl tags config */
-static int
-read_acl_tags(struct acl_list* acl, struct config_file* cfg)
+/** read acl view config */
+static int
+read_acl_view(struct acl_list* acl, struct config_str2list** acl_view,
+ struct views* v)
{
- struct config_strbytelist* np, *p = cfg->acl_tags;
- cfg->acl_tags = NULL;
+ struct config_str2list* np, *p = *acl_view;
+ *acl_view = NULL;
while(p) {
log_assert(p->str && p->str2);
- if(!acl_list_tags_cfg(acl, p->str, p->str2, p->str2len)) {
- config_del_strbytelist(p);
+ if(!acl_list_view_cfg(acl, p->str, p->str2, v, 0, 0)) {
+ config_deldblstrlist(p);
return 0;
}
/* free the items as we go to free up memory */
@@ -363,15 +445,16 @@ read_acl_tags(struct acl_list* acl, struct config_file* cfg)
return 1;
}
-/** read acl view config */
-static int
-read_acl_view(struct acl_list* acl, struct config_file* cfg, struct views* v)
+/** read acl tags config */
+static int
+read_acl_tags(struct acl_list* acl, struct config_strbytelist** acl_tags)
{
- struct config_str2list* np, *p = cfg->acl_view;
- cfg->acl_view = NULL;
+ struct config_strbytelist* np, *p = *acl_tags;
+ *acl_tags = NULL;
while(p) {
log_assert(p->str && p->str2);
- if(!acl_list_view_cfg(acl, p->str, p->str2, v)) {
+ if(!acl_list_tags_cfg(acl, p->str, p->str2, p->str2len, 0, 0)) {
+ config_del_strbytelist(p);
return 0;
}
/* free the items as we go to free up memory */
@@ -385,16 +468,17 @@ read_acl_view(struct acl_list* acl, struct config_file* cfg, struct views* v)
}
/** read acl tag actions config */
-static int
-read_acl_tag_actions(struct acl_list* acl, struct config_file* cfg)
+static int
+read_acl_tag_actions(struct acl_list* acl, struct config_file* cfg,
+ struct config_str3list** acl_tag_actions)
{
struct config_str3list* p, *np;
- p = cfg->acl_tag_actions;
- cfg->acl_tag_actions = NULL;
+ p = *acl_tag_actions;
+ *acl_tag_actions = NULL;
while(p) {
log_assert(p->str && p->str2 && p->str3);
if(!acl_list_tag_action_cfg(acl, cfg, p->str, p->str2,
- p->str3)) {
+ p->str3, 0, 0)) {
config_deltrplstrlist(p);
return 0;
}
@@ -410,15 +494,17 @@ read_acl_tag_actions(struct acl_list* acl, struct config_file* cfg)
}
/** read acl tag datas config */
-static int
-read_acl_tag_datas(struct acl_list* acl, struct config_file* cfg)
+static int
+read_acl_tag_datas(struct acl_list* acl, struct config_file* cfg,
+ struct config_str3list** acl_tag_datas)
{
struct config_str3list* p, *np;
- p = cfg->acl_tag_datas;
- cfg->acl_tag_datas = NULL;
+ p = *acl_tag_datas;
+ *acl_tag_datas = NULL;
while(p) {
log_assert(p->str && p->str2 && p->str3);
- if(!acl_list_tag_data_cfg(acl, cfg, p->str, p->str2, p->str3)) {
+ if(!acl_list_tag_data_cfg(acl, cfg, p->str, p->str2, p->str3,
+ 0, 0)) {
config_deltrplstrlist(p);
return 0;
}
@@ -433,30 +519,27 @@ read_acl_tag_datas(struct acl_list* acl, struct config_file* cfg)
return 1;
}
-int
+int
acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg,
struct views* v)
{
regional_free_all(acl->region);
addr_tree_init(&acl->tree);
- if(!read_acl_list(acl, cfg))
+ if(!read_acl_list(acl, cfg->acls))
return 0;
- if(!read_acl_view(acl, cfg, v))
+ if(!read_acl_view(acl, &cfg->acl_view, v))
return 0;
- if(!read_acl_tags(acl, cfg))
+ if(!read_acl_tags(acl, &cfg->acl_tags))
return 0;
- if(!read_acl_tag_actions(acl, cfg))
+ if(!read_acl_tag_actions(acl, cfg, &cfg->acl_tag_actions))
return 0;
- if(!read_acl_tag_datas(acl, cfg))
+ if(!read_acl_tag_datas(acl, cfg, &cfg->acl_tag_datas))
return 0;
/* insert defaults, with '0' to ignore them if they are duplicates */
- if(!acl_list_str_cfg(acl, "0.0.0.0/0", "refuse", 0))
- return 0;
+ /* the 'refuse' defaults for /0 are now done per interface instead */
if(!acl_list_str_cfg(acl, "127.0.0.0/8", "allow", 0))
return 0;
if(cfg->do_ip6) {
- if(!acl_list_str_cfg(acl, "::0/0", "refuse", 0))
- return 0;
if(!acl_list_str_cfg(acl, "::1", "allow", 0))
return 0;
if(!acl_list_str_cfg(acl, "::ffff:127.0.0.1", "allow", 0))
@@ -466,7 +549,223 @@ acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg,
return 1;
}
-enum acl_access
+int
+acl_interface_compare(const void* k1, const void* k2)
+{
+ struct addr_tree_node* n1 = (struct addr_tree_node*)k1;
+ struct addr_tree_node* n2 = (struct addr_tree_node*)k2;
+ return sockaddr_cmp(&n1->addr, n1->addrlen, &n2->addr,
+ n2->addrlen);
+ /* We don't care about comparing node->net. All addresses in the
+ * acl_interface tree have either 32 (ipv4) or 128 (ipv6). */
+}
+
+void
+acl_interface_init(struct acl_list* acl_interface)
+{
+ regional_free_all(acl_interface->region);
+ /* We want comparison in the tree to include only address and port.
+ * We don't care about comparing node->net. All addresses in the
+ * acl_interface->tree should have either 32 (ipv4) or 128 (ipv6).
+ * Initialise with the appropriate compare function but keep treating
+ * it as an addr_tree. */
+ addr_tree_addrport_init(&acl_interface->tree);
+}
+
+static int
+read_acl_interface_action(struct acl_list* acl_interface,
+ struct config_str2list* acls, int port)
+{
+ struct config_str2list* p;
+ for(p = acls; p; p = p->next) {
+ char** resif = NULL;
+ int num_resif = 0;
+ int i;
+ log_assert(p->str && p->str2);
+ if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif))
+ return 0;
+ for(i = 0; i<num_resif; i++) {
+ if(!acl_interface_str_cfg(acl_interface, resif[i], p->str2, port)){
+ config_del_strarray(resif, num_resif);
+ return 0;
+ }
+ }
+ config_del_strarray(resif, num_resif);
+ }
+ return 1;
+}
+
+/** read acl view config for interface */
+static int
+read_acl_interface_view(struct acl_list* acl_interface,
+ struct config_str2list** acl_view,
+ struct views* v, int port)
+{
+ struct config_str2list* np, *p = *acl_view;
+ *acl_view = NULL;
+ while(p) {
+ char** resif = NULL;
+ int num_resif = 0;
+ int i;
+ log_assert(p->str && p->str2);
+ if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
+ config_deldblstrlist(p);
+ return 0;
+ }
+ for(i = 0; i<num_resif; i++) {
+ if(!acl_list_view_cfg(acl_interface, resif[i], p->str2,
+ v, 1, port)) {
+ config_del_strarray(resif, num_resif);
+ config_deldblstrlist(p);
+ return 0;
+ }
+ }
+ config_del_strarray(resif, num_resif);
+ /* free the items as we go to free up memory */
+ np = p->next;
+ free(p->str);
+ free(p->str2);
+ free(p);
+ p = np;
+ }
+ return 1;
+}
+
+/** read acl tags config for interface */
+static int
+read_acl_interface_tags(struct acl_list* acl_interface,
+ struct config_strbytelist** acl_tags, int port)
+{
+ struct config_strbytelist* np, *p = *acl_tags;
+ *acl_tags = NULL;
+ while(p) {
+ char** resif = NULL;
+ int num_resif = 0;
+ int i;
+ log_assert(p->str && p->str2);
+ if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
+ config_del_strbytelist(p);
+ return 0;
+ }
+ for(i = 0; i<num_resif; i++) {
+ if(!acl_list_tags_cfg(acl_interface, resif[i], p->str2,
+ p->str2len, 1, port)) {
+ config_del_strbytelist(p);
+ config_del_strarray(resif, num_resif);
+ return 0;
+ }
+ }
+ config_del_strarray(resif, num_resif);
+ /* free the items as we go to free up memory */
+ np = p->next;
+ free(p->str);
+ free(p->str2);
+ free(p);
+ p = np;
+ }
+ return 1;
+}
+
+/** read acl tag actions config for interface*/
+static int
+read_acl_interface_tag_actions(struct acl_list* acl_interface,
+ struct config_file* cfg,
+ struct config_str3list** acl_tag_actions, int port)
+{
+ struct config_str3list* p, *np;
+ p = *acl_tag_actions;
+ *acl_tag_actions = NULL;
+ while(p) {
+ char** resif = NULL;
+ int num_resif = 0;
+ int i;
+ log_assert(p->str && p->str2 && p->str3);
+ if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
+ config_deltrplstrlist(p);
+ return 0;
+ }
+ for(i = 0; i<num_resif; i++) {
+ if(!acl_list_tag_action_cfg(acl_interface, cfg,
+ resif[i], p->str2, p->str3, 1, port)) {
+ config_deltrplstrlist(p);
+ config_del_strarray(resif, num_resif);
+ return 0;
+ }
+ }
+ config_del_strarray(resif, num_resif);
+ /* free the items as we go to free up memory */
+ np = p->next;
+ free(p->str);
+ free(p->str2);
+ free(p->str3);
+ free(p);
+ p = np;
+ }
+ return 1;
+}
+
+/** read acl tag datas config for interface */
+static int
+read_acl_interface_tag_datas(struct acl_list* acl_interface,
+ struct config_file* cfg,
+ struct config_str3list** acl_tag_datas, int port)
+{
+ struct config_str3list* p, *np;
+ p = *acl_tag_datas;
+ *acl_tag_datas = NULL;
+ while(p) {
+ char** resif = NULL;
+ int num_resif = 0;
+ int i;
+ log_assert(p->str && p->str2 && p->str3);
+ if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
+ config_deltrplstrlist(p);
+ return 0;
+ }
+ for(i = 0; i<num_resif; i++) {
+ if(!acl_list_tag_data_cfg(acl_interface, cfg,
+ resif[i], p->str2, p->str3, 1, port)) {
+ config_deltrplstrlist(p);
+ config_del_strarray(resif, num_resif);
+ return 0;
+ }
+ }
+ config_del_strarray(resif, num_resif);
+ /* free the items as we go to free up memory */
+ np = p->next;
+ free(p->str);
+ free(p->str2);
+ free(p->str3);
+ free(p);
+ p = np;
+ }
+ return 1;
+}
+
+int
+acl_interface_apply_cfg(struct acl_list* acl_interface, struct config_file* cfg,
+ struct views* v)
+{
+ if(!read_acl_interface_action(acl_interface, cfg->interface_actions,
+ cfg->port))
+ return 0;
+ if(!read_acl_interface_view(acl_interface, &cfg->interface_view, v,
+ cfg->port))
+ return 0;
+ if(!read_acl_interface_tags(acl_interface, &cfg->interface_tags,
+ cfg->port))
+ return 0;
+ if(!read_acl_interface_tag_actions(acl_interface, cfg,
+ &cfg->interface_tag_actions, cfg->port))
+ return 0;
+ if(!read_acl_interface_tag_datas(acl_interface, cfg,
+ &cfg->interface_tag_datas, cfg->port))
+ return 0;
+ addr_tree_init_parents(&acl_interface->tree);
+ return 1;
+}
+
+enum acl_access
acl_get_control(struct acl_addr* acl)
{
if(acl) return acl->control;
@@ -481,7 +780,7 @@ acl_addr_lookup(struct acl_list* acl, struct sockaddr_storage* addr,
addr, addrlen);
}
-size_t
+size_t
acl_list_get_mem(struct acl_list* acl)
{
if(!acl) return 0;
diff --git a/daemon/acl_list.h b/daemon/acl_list.h
index c09e832a1def..c717179baf5e 100644
--- a/daemon/acl_list.h
+++ b/daemon/acl_list.h
@@ -36,7 +36,7 @@
/**
* \file
*
- * This file keeps track of the list of clients that are allowed to
+ * This file keeps track of the list of clients that are allowed to
* access the server.
*/
@@ -74,7 +74,7 @@ enum acl_access {
struct acl_list {
/** regional for allocation */
struct regional* region;
- /**
+ /**
* Tree of the addresses that are allowed/blocked.
* contents of type acl_addr.
*/
@@ -108,7 +108,7 @@ struct acl_addr {
};
/**
- * Create acl structure
+ * Create acl structure
* @return new structure or NULL on error.
*/
struct acl_list* acl_list_create(void);
@@ -120,6 +120,20 @@ struct acl_list* acl_list_create(void);
void acl_list_delete(struct acl_list* acl);
/**
+ * Insert interface in the acl_list. This should happen when the listening
+ * interface is setup.
+ * @param acl_interface: acl_list to insert to.
+ * @param addr: interface IP.
+ * @param addrlen: length of the interface IP.
+ * @param control: acl_access.
+ * @return new structure or NULL on error.
+ */
+struct acl_addr*
+acl_interface_insert(struct acl_list* acl_interface,
+ struct sockaddr_storage* addr, socklen_t addrlen,
+ enum acl_access control);
+
+/**
* Process access control config.
* @param acl: where to store.
* @param cfg: config options.
@@ -129,6 +143,25 @@ void acl_list_delete(struct acl_list* acl);
int acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg,
struct views* v);
+/** compare ACL interface "addr_tree" nodes (+port) */
+int acl_interface_compare(const void* k1, const void* k2);
+
+/**
+ * Initialise (also clean) the acl_interface struct.
+ * @param acl_interface: where to store.
+ */
+void acl_interface_init(struct acl_list* acl_interface);
+
+/**
+ * Process interface control config.
+ * @param acl_interface: where to store.
+ * @param cfg: config options.
+ * @param v: views structure
+ * @return 0 on error.
+ */
+int acl_interface_apply_cfg(struct acl_list* acl_interface, struct config_file* cfg,
+ struct views* v);
+
/**
* Lookup access control status for acl structure.
* @param acl: structure for acl storage.
diff --git a/daemon/daemon.c b/daemon/daemon.c
index 4ed531855ee6..71091133a487 100644
--- a/daemon/daemon.c
+++ b/daemon/daemon.c
@@ -96,6 +96,9 @@
#ifdef HAVE_SYSTEMD
#include <systemd/sd-daemon.h>
#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
/** How many quit requests happened. */
static int sig_record_quit = 0;
@@ -271,8 +274,17 @@ daemon_init(void)
free(daemon);
return NULL;
}
+ daemon->acl_interface = acl_list_create();
+ if(!daemon->acl_interface) {
+ acl_list_delete(daemon->acl);
+ edns_known_options_delete(daemon->env);
+ free(daemon->env);
+ free(daemon);
+ return NULL;
+ }
daemon->tcl = tcl_list_create();
if(!daemon->tcl) {
+ acl_list_delete(daemon->acl_interface);
acl_list_delete(daemon->acl);
edns_known_options_delete(daemon->env);
free(daemon->env);
@@ -284,6 +296,7 @@ daemon_init(void)
log_err("gettimeofday: %s", strerror(errno));
daemon->time_last_stat = daemon->time_boot;
if((daemon->env->auth_zones = auth_zones_create()) == 0) {
+ acl_list_delete(daemon->acl_interface);
acl_list_delete(daemon->acl);
tcl_list_delete(daemon->tcl);
edns_known_options_delete(daemon->env);
@@ -293,6 +306,7 @@ daemon_init(void)
}
if(!(daemon->env->edns_strings = edns_strings_create())) {
auth_zones_delete(daemon->env->auth_zones);
+ acl_list_delete(daemon->acl_interface);
acl_list_delete(daemon->acl);
tcl_list_delete(daemon->tcl);
edns_known_options_delete(daemon->env);
@@ -303,6 +317,29 @@ daemon_init(void)
return daemon;
}
+static int setup_acl_for_ports(struct acl_list* list,
+ struct listen_port* port_list)
+{
+ struct acl_addr* acl_node;
+ struct addrinfo* addr;
+ for(; port_list; port_list=port_list->next) {
+ if(!port_list->socket) {
+ /* This is mainly for testbound where port_list is
+ * empty. */
+ continue;
+ }
+ addr = port_list->socket->addr;
+ if(!(acl_node = acl_interface_insert(list,
+ (struct sockaddr_storage*)addr->ai_addr,
+ (socklen_t)addr->ai_addrlen,
+ acl_refuse))) {
+ return 0;
+ }
+ port_list->socket->acl = acl_node;
+ }
+ return 1;
+}
+
int
daemon_open_shared_ports(struct daemon* daemon)
{
@@ -320,6 +357,8 @@ daemon_open_shared_ports(struct daemon* daemon)
free(daemon->ports);
daemon->ports = NULL;
}
+ /* clean acl_interface */
+ acl_interface_init(daemon->acl_interface);
if(!resolve_interface_names(daemon->cfg->ifs,
daemon->cfg->num_ifs, NULL, &resif, &num_resif))
return 0;
@@ -329,7 +368,8 @@ daemon_open_shared_ports(struct daemon* daemon)
daemon->reuseport = 1;
#endif
/* try to use reuseport */
- p0 = listening_ports_open(daemon->cfg, resif, num_resif, &daemon->reuseport);
+ p0 = listening_ports_open(daemon->cfg, resif, num_resif,
+ &daemon->reuseport);
if(!p0) {
listening_ports_free(p0);
config_del_strarray(resif, num_resif);
@@ -350,6 +390,12 @@ daemon_open_shared_ports(struct daemon* daemon)
return 0;
}
daemon->ports[0] = p0;
+ if(!setup_acl_for_ports(daemon->acl_interface,
+ daemon->ports[0])) {
+ listening_ports_free(p0);
+ config_del_strarray(resif, num_resif);
+ return 0;
+ }
if(daemon->reuseport) {
/* continue to use reuseport */
for(i=1; i<daemon->num_ports; i++) {
@@ -365,6 +411,15 @@ daemon_open_shared_ports(struct daemon* daemon)
config_del_strarray(resif, num_resif);
return 0;
}
+ if(!setup_acl_for_ports(daemon->acl_interface,
+ daemon->ports[i])) {
+ for(i=0; i<daemon->num_ports; i++)
+ listening_ports_free(daemon->ports[i]);
+ free(daemon->ports);
+ daemon->ports = NULL;
+ config_del_strarray(resif, num_resif);
+ return 0;
+ }
}
}
config_del_strarray(resif, num_resif);
@@ -604,6 +659,9 @@ daemon_fork(struct daemon* daemon)
if(!acl_list_apply_cfg(daemon->acl, daemon->cfg, daemon->views))
fatal_exit("Could not setup access control list");
+ if(!acl_interface_apply_cfg(daemon->acl_interface, daemon->cfg,
+ daemon->views))
+ fatal_exit("Could not setup interface control list");
if(!tcl_list_apply_cfg(daemon->tcl, daemon->cfg))
fatal_exit("Could not setup TCP connection limits");
if(daemon->cfg->dnscrypt) {
@@ -780,6 +838,7 @@ daemon_delete(struct daemon* daemon)
ub_randfree(daemon->rand);
alloc_clear(&daemon->superalloc);
acl_list_delete(daemon->acl);
+ acl_list_delete(daemon->acl_interface);
tcl_list_delete(daemon->tcl);
listen_desetup_locks();
free(daemon->chroot);
diff --git a/daemon/daemon.h b/daemon/daemon.h
index 3effbafb7918..58713e9ce466 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -113,6 +113,8 @@ struct daemon {
struct module_stack mods;
/** access control, which client IPs are allowed to connect */
struct acl_list* acl;
+ /** access control, which interfaces are allowed to connect */
+ struct acl_list* acl_interface;
/** TCP connection limit, limit connections from client IPs */
struct tcl_list* tcl;
/** local authority zones */
diff --git a/daemon/remote.c b/daemon/remote.c
index ec7a4d5d93f4..7d4a414002ac 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -494,8 +494,8 @@ int remote_accept_callback(struct comm_point* c, void* arg, int err,
n->c->do_not_close = 0;
comm_point_stop_listening(n->c);
comm_point_start_listening(n->c, -1, REMOTE_CONTROL_TCP_TIMEOUT);
- memcpy(&n->c->repinfo.addr, &addr, addrlen);
- n->c->repinfo.addrlen = addrlen;
+ memcpy(&n->c->repinfo.remote_addr, &addr, addrlen);
+ n->c->repinfo.remote_addrlen = addrlen;
if(rc->use_cert) {
n->shake_state = rc_hs_read;
n->ssl = SSL_new(rc->ctx);
@@ -3304,7 +3304,7 @@ remote_handshake_later(struct daemon_remote* rc, struct rc_state* s,
if(r == 0)
log_err("remote control connection closed prematurely");
log_addr(VERB_OPS, "failed connection from",
- &s->c->repinfo.addr, s->c->repinfo.addrlen);
+ &s->c->repinfo.remote_addr, s->c->repinfo.remote_addrlen);
log_crypto_err("remote control failed ssl");
clean_point(rc, s);
}
diff --git a/daemon/stats.c b/daemon/stats.c
index 57c42827161c..6b3834977844 100644
--- a/daemon/stats.c
+++ b/daemon/stats.c
@@ -70,6 +70,9 @@
#include <openssl/ssl.h>
#endif
+/** How long to wait for threads to transmit statistics, in msec. */
+#define STATS_THREAD_WAIT 60000
+
/** add timers and the values do not overflow or become negative */
static void
stats_timeval_add(long long* d_sec, long long* d_usec, long long add_sec, long long add_usec)
@@ -380,6 +383,28 @@ void server_stats_obtain(struct worker* worker, struct worker* who,
worker_send_cmd(who, worker_cmd_stats);
else worker_send_cmd(who, worker_cmd_stats_noreset);
verbose(VERB_ALGO, "wait for stats reply");
+ if(tube_wait_timeout(worker->cmd, STATS_THREAD_WAIT) == 0) {
+ verbose(VERB_OPS, "no response from thread %d"
+#ifdef HAVE_GETTID
+ " LWP %u"
+#endif
+#if defined(HAVE_PTHREAD) && defined(SIZEOF_PTHREAD_T) && defined(SIZEOF_UNSIGNED_LONG)
+# if SIZEOF_PTHREAD_T == SIZEOF_UNSIGNED_LONG
+ " pthread 0x%lx"
+# endif
+#endif
+ ,
+ who->thread_num
+#ifdef HAVE_GETTID
+ , (unsigned)who->thread_tid
+#endif
+#if defined(HAVE_PTHREAD) && defined(SIZEOF_PTHREAD_T) && defined(SIZEOF_UNSIGNED_LONG)
+# if SIZEOF_PTHREAD_T == SIZEOF_UNSIGNED_LONG
+ , (unsigned long)*((unsigned long*)&who->thr_id)
+# endif
+#endif
+ );
+ }
if(!tube_read_msg(worker->cmd, &reply, &len, 0))
fatal_exit("failed to read stats over cmd channel");
if(len != (uint32_t)sizeof(*s))
@@ -496,7 +521,7 @@ void server_stats_insquery(struct ub_server_stats* stats, struct comm_point* c,
stats->qhttps++;
}
}
- if(repinfo && addr_is_ip6(&repinfo->addr, repinfo->addrlen))
+ if(repinfo && addr_is_ip6(&repinfo->remote_addr, repinfo->remote_addrlen))
stats->qipv6++;
if( (flags&BIT_QR) )
stats->qbit_QR++;
diff --git a/daemon/worker.c b/daemon/worker.c
index 010c4dc0a281..caefad621409 100644
--- a/daemon/worker.c
+++ b/daemon/worker.c
@@ -547,7 +547,8 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
static int
apply_respip_action(struct worker* worker, const struct query_info* qinfo,
struct respip_client_info* cinfo, struct reply_info* rep,
- struct comm_reply* repinfo, struct ub_packed_rrset_key** alias_rrset,
+ struct sockaddr_storage* addr, socklen_t addrlen,
+ struct ub_packed_rrset_key** alias_rrset,
struct reply_info** encode_repp, struct auth_zones* az)
{
struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL};
@@ -574,7 +575,7 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
if(actinfo.addrinfo) {
respip_inform_print(&actinfo, qinfo->qname,
qinfo->qtype, qinfo->qclass, qinfo->local_alias,
- repinfo);
+ addr, addrlen);
if(worker->stats.extended && actinfo.rpz_used) {
if(actinfo.rpz_disabled)
@@ -703,7 +704,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
*alias_rrset = NULL; /* avoid confusion if caller set it to non-NULL */
if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
!partial_rep && !apply_respip_action(worker, qinfo, cinfo, rep,
- repinfo, alias_rrset,
+ &repinfo->client_addr, repinfo->client_addrlen, alias_rrset,
&encode_rep, worker->env.auth_zones)) {
goto bail_out;
} else if(partial_rep &&
@@ -991,12 +992,14 @@ answer_chaos(struct worker* w, struct query_info* qinfo,
* @param w: worker
* @param qinfo: query info. Pointer into packet buffer.
* @param edns: edns info from query.
- * @param repinfo: reply info with source address.
+ * @param addr: client address.
+ * @param addrlen: client address length.
* @param pkt: packet buffer.
*/
static void
-answer_notify(struct worker* w, struct query_info* qinfo,
- struct edns_data* edns, sldns_buffer* pkt, struct comm_reply* repinfo)
+answer_notify(struct worker* w, struct query_info* qinfo,
+ struct edns_data* edns, sldns_buffer* pkt,
+ struct sockaddr_storage* addr, socklen_t addrlen)
{
int refused = 0;
int rcode = LDNS_RCODE_NOERROR;
@@ -1005,8 +1008,8 @@ answer_notify(struct worker* w, struct query_info* qinfo,
if(!w->env.auth_zones) return;
has_serial = auth_zone_parse_notify_serial(pkt, &serial);
if(auth_zones_notify(w->env.auth_zones, &w->env, qinfo->qname,
- qinfo->qname_len, qinfo->qclass, &repinfo->addr,
- repinfo->addrlen, has_serial, serial, &refused)) {
+ qinfo->qname_len, qinfo->qclass, addr,
+ addrlen, has_serial, serial, &refused)) {
rcode = LDNS_RCODE_NOERROR;
} else {
if(refused)
@@ -1031,7 +1034,7 @@ answer_notify(struct worker* w, struct query_info* qinfo,
"servfail for NOTIFY %sfor %s from", sr, zname);
else snprintf(buf, sizeof(buf),
"received NOTIFY %sfor %s from", sr, zname);
- log_addr(VERB_DETAIL, buf, &repinfo->addr, repinfo->addrlen);
+ log_addr(VERB_DETAIL, buf, addr, addrlen);
}
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
@@ -1051,8 +1054,8 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
{
if(acl == deny) {
if(verbosity >= VERB_ALGO) {
- log_acl_action("dropped", &repinfo->addr,
- repinfo->addrlen, acl, acladdr);
+ log_acl_action("dropped", &repinfo->client_addr,
+ repinfo->client_addrlen, acl, acladdr);
log_buf(VERB_ALGO, "dropped", c->buffer);
}
comm_point_drop_reply(repinfo);
@@ -1063,8 +1066,8 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
size_t opt_rr_mark;
if(verbosity >= VERB_ALGO) {
- log_acl_action("refused", &repinfo->addr,
- repinfo->addrlen, acl, acladdr);
+ log_acl_action("refused", &repinfo->client_addr,
+ repinfo->client_addrlen, acl, acladdr);
log_buf(VERB_ALGO, "refuse", c->buffer);
}
@@ -1224,12 +1227,24 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
}
static int
-deny_refuse_all(struct comm_point* c, enum acl_access acl,
+deny_refuse_all(struct comm_point* c, enum acl_access* acl,
struct worker* worker, struct comm_reply* repinfo,
- struct acl_addr* acladdr, int ede)
+ struct acl_addr** acladdr, int ede, int check_proxy)
{
- return deny_refuse(c, acl, acl_deny, acl_refuse, worker, repinfo,
- acladdr, ede);
+ if(check_proxy) {
+ *acladdr = acl_addr_lookup(worker->daemon->acl,
+ &repinfo->remote_addr, repinfo->remote_addrlen);
+ } else {
+ *acladdr = acl_addr_lookup(worker->daemon->acl,
+ &repinfo->client_addr, repinfo->client_addrlen);
+ }
+ /* If there is no ACL based on client IP use the interface ACL. */
+ if(!(*acladdr) && c->socket) {
+ *acladdr = c->socket->acl;
+ }
+ *acl = acl_get_control(*acladdr);
+ return deny_refuse(c, *acl, acl_deny, acl_refuse, worker, repinfo,
+ *acladdr, ede);
}
static int
@@ -1241,7 +1256,7 @@ deny_refuse_non_local(struct comm_point* c, enum acl_access acl,
worker, repinfo, acladdr, ede);
}
-int
+int
worker_handle_request(struct comm_point* c, void* arg, int error,
struct comm_reply* repinfo)
{
@@ -1286,16 +1301,16 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
if(worker_check_request(c->buffer, worker) != 0) {
verbose(VERB_ALGO,
"dnscrypt: worker check request: bad query.");
- log_addr(VERB_CLIENT,"from",&repinfo->addr,
- repinfo->addrlen);
+ log_addr(VERB_CLIENT,"from",&repinfo->client_addr,
+ repinfo->client_addrlen);
comm_point_drop_reply(repinfo);
return 0;
}
if(!query_info_parse(&qinfo, c->buffer)) {
verbose(VERB_ALGO,
"dnscrypt: worker parse request: formerror.");
- log_addr(VERB_CLIENT, "from", &repinfo->addr,
- repinfo->addrlen);
+ log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
+ repinfo->client_addrlen);
comm_point_drop_reply(repinfo);
return 0;
}
@@ -1323,25 +1338,30 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
* sending src (client)/dst (local service) addresses over DNSTAP from incoming request handler
*/
if(worker->dtenv.log_client_query_messages) {
- log_addr(VERB_ALGO, "request from client", &repinfo->addr, repinfo->addrlen);
+ log_addr(VERB_ALGO, "request from client", &repinfo->client_addr, repinfo->client_addrlen);
log_addr(VERB_ALGO, "to local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen);
- dt_msg_send_client_query(&worker->dtenv, &repinfo->addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->buffer);
+ dt_msg_send_client_query(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->buffer);
}
#endif
- acladdr = acl_addr_lookup(worker->daemon->acl, &repinfo->addr,
- repinfo->addrlen);
- acl = acl_get_control(acladdr);
-
- if((ret=deny_refuse_all(c, acl, worker, repinfo, acladdr,
- worker->env.cfg->ede)) != -1)
- {
+ /* Check deny/refuse ACLs */
+ if(repinfo->is_proxied) {
+ if((ret=deny_refuse_all(c, &acl, worker, repinfo, &acladdr,
+ worker->env.cfg->ede, 1)) != -1) {
+ if(ret == 1)
+ goto send_reply;
+ return ret;
+ }
+ }
+ if((ret=deny_refuse_all(c, &acl, worker, repinfo, &acladdr,
+ worker->env.cfg->ede, 0)) != -1) {
if(ret == 1)
goto send_reply;
return ret;
}
+
if((ret=worker_check_request(c->buffer, worker)) != 0) {
verbose(VERB_ALGO, "worker check request: bad query.");
- log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
+ log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen);
if(ret != -1) {
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret);
@@ -1353,20 +1373,24 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
worker->stats.num_queries++;
- /* check if this query should be dropped based on source ip rate limiting */
- if(!infra_ip_ratelimit_inc(worker->env.infra_cache, repinfo,
+ /* check if this query should be dropped based on source ip rate limiting
+ * NOTE: we always check the repinfo->client_address. IP ratelimiting is
+ * implicitly disabled for proxies. */
+ if(!infra_ip_ratelimit_inc(worker->env.infra_cache,
+ &repinfo->client_addr, repinfo->client_addrlen,
*worker->env.now,
worker->env.cfg->ip_ratelimit_backoff, c->buffer)) {
/* See if we are passed through with slip factor */
if(worker->env.cfg->ip_ratelimit_factor != 0 &&
ub_random_max(worker->env.rnd,
- worker->env.cfg->ip_ratelimit_factor) == 0) {
-
+ worker->env.cfg->ip_ratelimit_factor) == 0) {
char addrbuf[128];
- addr_to_str(&repinfo->addr, repinfo->addrlen,
- addrbuf, sizeof(addrbuf));
- verbose(VERB_QUERY, "ip_ratelimit allowed through for ip address %s because of slip in ip_ratelimit_factor",
- addrbuf);
+ addr_to_str(&repinfo->client_addr,
+ repinfo->client_addrlen, addrbuf,
+ sizeof(addrbuf));
+ verbose(VERB_QUERY, "ip_ratelimit allowed through for "
+ "ip address %s because of slip in "
+ "ip_ratelimit_factor", addrbuf);
} else {
worker->stats.num_queries_ip_ratelimited++;
comm_point_drop_reply(repinfo);
@@ -1377,7 +1401,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
/* see if query is in the cache */
if(!query_info_parse(&qinfo, c->buffer)) {
verbose(VERB_ALGO, "worker parse request: formerror.");
- log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
+ log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
+ repinfo->client_addrlen);
memset(&qinfo, 0, sizeof(qinfo)); /* zero qinfo.qname */
if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) {
comm_point_drop_reply(repinfo);
@@ -1391,13 +1416,14 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
}
if(worker->env.cfg->log_queries) {
char ip[128];
- addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip));
+ addr_to_str(&repinfo->client_addr, repinfo->client_addrlen, ip, sizeof(ip));
log_query_in(ip, qinfo.qname, qinfo.qtype, qinfo.qclass);
}
if(qinfo.qtype == LDNS_RR_TYPE_AXFR ||
qinfo.qtype == LDNS_RR_TYPE_IXFR) {
verbose(VERB_ALGO, "worker request: refused zone transfer.");
- log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
+ log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
+ repinfo->client_addrlen);
sldns_buffer_rewind(c->buffer);
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
@@ -1414,7 +1440,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
qinfo.qtype == LDNS_RR_TYPE_MAILB ||
(qinfo.qtype >= 128 && qinfo.qtype <= 248)) {
verbose(VERB_ALGO, "worker request: formerror for meta-type.");
- log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
+ log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
+ repinfo->client_addrlen);
if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) {
comm_point_drop_reply(repinfo);
return 0;
@@ -1432,7 +1459,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
worker->scratchpad)) != 0) {
struct edns_data reply_edns;
verbose(VERB_ALGO, "worker parse edns: formerror.");
- log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
+ log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
+ repinfo->client_addrlen);
memset(&reply_edns, 0, sizeof(reply_edns));
reply_edns.edns_present = 1;
reply_edns.udp_size = EDNS_ADVERTISED_SIZE;
@@ -1454,7 +1482,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
edns.opt_list_inplace_cb_out = NULL;
edns.padding_block_size = 0;
verbose(VERB_ALGO, "query with bad edns version.");
- log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
+ log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
+ repinfo->client_addrlen);
error_encode(c->buffer, EDNS_RCODE_BADVERS&0xf, &qinfo,
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
sldns_buffer_read_u16_at(c->buffer, 2), NULL);
@@ -1468,7 +1497,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
worker->daemon->cfg->harden_short_bufsize) {
verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored",
(int)edns.udp_size);
- log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
+ log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
+ repinfo->client_addrlen);
edns.udp_size = NORMAL_UDP_SIZE;
}
}
@@ -1477,12 +1507,14 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
verbose(VERB_QUERY,
"worker request: max UDP reply size modified"
" (%d to max-udp-size)", (int)edns.udp_size);
- log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
+ log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
+ repinfo->client_addrlen);
edns.udp_size = worker->daemon->cfg->max_udp_size;
}
if(edns.udp_size < LDNS_HEADER_SIZE) {
verbose(VERB_ALGO, "worker request: edns is too small.");
- log_addr(VERB_CLIENT, "from", &repinfo->addr, repinfo->addrlen);
+ log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
+ repinfo->client_addrlen);
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_TC_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
@@ -1506,7 +1538,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
}
if(LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) ==
LDNS_PACKET_NOTIFY) {
- answer_notify(worker, &qinfo, &edns, c->buffer, repinfo);
+ answer_notify(worker, &qinfo, &edns, c->buffer,
+ &repinfo->client_addr, repinfo->client_addrlen);
regional_free_all(worker->scratchpad);
goto send_reply;
}
@@ -1582,7 +1615,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
sldns_buffer_read_u16_at(c->buffer, 2), &edns);
regional_free_all(worker->scratchpad);
log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from",
- &repinfo->addr, repinfo->addrlen);
+ &repinfo->client_addr, repinfo->client_addrlen);
goto send_reply;
}
@@ -1722,9 +1755,9 @@ lookup_cache:
if(verbosity >= VERB_CLIENT) {
if(c->type == comm_udp)
log_addr(VERB_CLIENT, "udp request from",
- &repinfo->addr, repinfo->addrlen);
+ &repinfo->client_addr, repinfo->client_addrlen);
else log_addr(VERB_CLIENT, "tcp request from",
- &repinfo->addr, repinfo->addrlen);
+ &repinfo->client_addr, repinfo->client_addrlen);
}
/* grab a work request structure for this new request */
@@ -1756,8 +1789,8 @@ send_reply_rc:
*/
if(worker->dtenv.log_client_response_messages) {
log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen);
- log_addr(VERB_ALGO, "response to client", &repinfo->addr, repinfo->addrlen);
- dt_msg_send_client_response(&worker->dtenv, &repinfo->addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->buffer);
+ log_addr(VERB_ALGO, "response to client", &repinfo->client_addr, repinfo->client_addrlen);
+ dt_msg_send_client_response(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->buffer);
}
#endif
if(worker->env.cfg->log_replies)
@@ -1769,10 +1802,12 @@ send_reply_rc:
/* log original qname, before the local alias was
* used to resolve that CNAME to something else */
qinfo.qname = qinfo.local_alias->rrset->rk.dname;
- log_reply_info(NO_VERBOSE, &qinfo, &repinfo->addr, repinfo->addrlen,
+ log_reply_info(NO_VERBOSE, &qinfo,
+ &repinfo->client_addr, repinfo->client_addrlen,
tv, 1, c->buffer);
} else {
- log_reply_info(NO_VERBOSE, &qinfo, &repinfo->addr, repinfo->addrlen,
+ log_reply_info(NO_VERBOSE, &qinfo,
+ &repinfo->client_addr, repinfo->client_addrlen,
tv, 1, c->buffer);
}
}
@@ -1904,6 +1939,9 @@ worker_init(struct worker* worker, struct config_file *cfg,
#else
void* dtenv = NULL;
#endif
+#ifdef HAVE_GETTID
+ worker->thread_tid = gettid();
+#endif
worker->need_to_exit = 0;
worker->base = comm_base_create(do_sigs);
if(!worker->base) {
diff --git a/daemon/worker.h b/daemon/worker.h
index 3887d0405ae6..3fb52abd9d87 100644
--- a/daemon/worker.h
+++ b/daemon/worker.h
@@ -86,6 +86,10 @@ struct worker {
struct daemon* daemon;
/** thread id */
ub_thread_type thr_id;
+#ifdef HAVE_GETTID
+ /** thread tid, the LWP id. */
+ pid_t thread_tid;
+#endif
/** pipe, for commands for this worker */
struct tube* cmd;
/** the event base this worker works with */