From e816d085585b95c5f27ceaa5ea74d42f943375f7 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Mon, 3 Jan 2022 23:32:30 +0000 Subject: [PATCH] Fix massive confusion on server reload. The 2.86 upstream server rewrite severely broke re-reading of server configuration. It would get everyting right the first time, but on re-reading /etc/resolv.conf or --servers-file or setting things with DBUS, the results were just wrong. This should put things right again. --- src/domain-match.c | 154 +++++++++++++++++++++++++-------------------- 1 file changed, 85 insertions(+), 69 deletions(-) diff --git a/src/domain-match.c b/src/domain-match.c index 3a69aa1..f4fd093 100644 --- a/src/domain-match.c +++ b/src/domain-match.c @@ -37,7 +37,7 @@ static void build_server_array(void) if (serv->flags & SERV_WILDCARD) daemon->server_has_wildcard = 1; } - + for (serv = daemon->local_domains; serv; serv = serv->next) { count++; @@ -543,22 +543,35 @@ static int order_qsort(const void *a, const void *b) return rc; } +/* Must be called before add_update_server() to set daemon->servers_tail */ void mark_servers(int flag) { - struct server *serv; + struct server *serv, **up; /* mark everything with argument flag */ for (serv = daemon->servers; serv; serv = serv->next) - if (serv->flags & flag) - serv->flags |= SERV_MARK; - else - serv->flags &= ~SERV_MARK; - - for (serv = daemon->local_domains; serv; serv = serv->next) - if (serv->flags & flag) - serv->flags |= SERV_MARK; - else - serv->flags &= ~SERV_MARK; + { + if (serv->flags & flag) + serv->flags |= SERV_MARK; + else + serv->flags &= ~SERV_MARK; + } + + /* --address etc is different: since they are expected to be + 1) numerous and 2) not reloaded often. We just delete + and recreate. */ + if (flag) + for (serv = daemon->local_domains, up = &daemon->local_domains; serv; serv = serv->next) + { + if (serv->flags & flag) + { + *up = serv->next; + free(serv->domain); + free(serv); + } + else + up = &serv->next; + } } void cleanup_servers(void) @@ -566,7 +579,7 @@ void cleanup_servers(void) struct server *serv, *tmp, **up; /* unlink and free anything still marked. */ - for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp) + for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp) { tmp = serv->next; if (serv->flags & SERV_MARK) @@ -580,19 +593,6 @@ void cleanup_servers(void) up = &serv->next; } - for (serv = daemon->local_domains, up = &daemon->local_domains; serv; serv = tmp) - { - tmp = serv->next; - if (serv->flags & SERV_MARK) - { - *up = serv->next; - free(serv->domain); - free(serv); - } - else - up = &serv->next; - } - /* If we're delaying things, we don't call check_servers(), but reload_servers() may have deleted some servers, rendering the server_array invalid, so just rebuild that here. Once reload_servers() succeeds, @@ -630,56 +630,71 @@ int add_update_server(int flags, if (!alloc_domain) return 0; - /* See if there is a suitable candidate, and unmark - only do this for forwarding servers, not - address or local, to avoid delays on large numbers. */ + if (flags & SERV_IS_LOCAL) - for (serv = daemon->servers; serv; serv = serv->next) - if ((serv->flags & SERV_MARK) && - hostname_isequal(alloc_domain, serv->domain)) - break; - - if (serv) - { - free(alloc_domain); - alloc_domain = serv->domain; - } - else { size_t size; - if (flags & SERV_IS_LOCAL) - { - if (flags & SERV_6ADDR) - size = sizeof(struct serv_addr6); - else if (flags & SERV_4ADDR) - size = sizeof(struct serv_addr4); - else - size = sizeof(struct serv_local); - } + if (flags & SERV_6ADDR) + size = sizeof(struct serv_addr6); + else if (flags & SERV_4ADDR) + size = sizeof(struct serv_addr4); else - size = sizeof(struct server); + size = sizeof(struct serv_local); if (!(serv = whine_malloc(size))) { free(alloc_domain); return 0; } - - if (flags & SERV_IS_LOCAL) + + serv->next = daemon->local_domains; + daemon->local_domains = serv; + + if (flags & SERV_4ADDR) + ((struct serv_addr4*)serv)->addr = local_addr->addr4; + + if (flags & SERV_6ADDR) + ((struct serv_addr6*)serv)->addr = local_addr->addr6; + } + else + { + /* Upstream servers. See if there is a suitable candidate, if so unmark + and move to the end of the list, for order. The entry found may already + be at the end. */ + struct server **up, *tmp; + + for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp) { - serv->next = daemon->local_domains; - daemon->local_domains = serv; + tmp = serv->next; + if ((serv->flags & SERV_MARK) && + hostname_isequal(alloc_domain, serv->domain)) + { + /* Need to move down? */ + if (serv->next) + { + struct server *s; + *up = serv->next; + for (s = daemon->servers; s->next; s = s->next); + s->next = serv; + serv->next = NULL; + } + break; + } + } - if (flags & SERV_4ADDR) - ((struct serv_addr4*)serv)->addr = local_addr->addr4; - - if (flags & SERV_6ADDR) - ((struct serv_addr6*)serv)->addr = local_addr->addr6; + if (serv) + { + free(alloc_domain); + alloc_domain = serv->domain; } else { - struct server *s; + if (!(serv = whine_malloc(sizeof(struct server)))) + { + free(alloc_domain); + return 0; + } memset(serv, 0, sizeof(struct server)); @@ -688,23 +703,24 @@ int add_update_server(int flags, daemon->servers = serv; else { + struct server *s; for (s = daemon->servers; s->next; s = s->next); s->next = serv; } + } #ifdef HAVE_LOOP - serv->uid = rand32(); + serv->uid = rand32(); #endif - if (interface) - safe_strncpy(serv->interface, interface, sizeof(serv->interface)); - if (addr) - serv->addr = *addr; - if (source_addr) - serv->source_addr = *source_addr; - } + if (interface) + safe_strncpy(serv->interface, interface, sizeof(serv->interface)); + if (addr) + serv->addr = *addr; + if (source_addr) + serv->source_addr = *source_addr; } - + serv->flags = flags; serv->domain = alloc_domain; serv->domain_len = strlen(alloc_domain); -- 2.34.1