diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2022-01-03 23:32:30 +0000 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2022-01-03 23:32:30 +0000 |
commit | 553c4c99cca173e9964d0edbd0676ed96c30f62b (patch) | |
tree | c3fc1857b9eb7d98606c2bb399536b5b4449753b | |
parent | 4165c1331bf2e82a5f6afeab3e7fb94aecf2b9d6 (diff) | |
download | dnsmasq-553c4c99cca173e9964d0edbd0676ed96c30f62b.tar.gz |
Fix massive confusion on server reload.v2.87test5
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.
-rw-r--r-- | src/domain-match.c | 157 |
1 files changed, 88 insertions, 69 deletions
diff --git a/src/domain-match.c b/src/domain-match.c index b457f5b..4e01092 100644 --- a/src/domain-match.c +++ b/src/domain-match.c @@ -542,22 +542,39 @@ 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; + daemon->servers_tail = NULL; + /* 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; + { + 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; + daemon->servers_tail = serv; + } + + /* --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) @@ -565,7 +582,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, daemon->servers_tail = NULL; serv; serv = tmp) { tmp = serv->next; if (serv->flags & SERV_MARK) @@ -581,19 +598,6 @@ void cleanup_servers(void) daemon->servers_tail = serv; } } - - 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; - } } int add_update_server(int flags, @@ -626,36 +630,17 @@ 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 + + if (flags & SERV_IS_LOCAL) { 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))) { @@ -663,19 +648,53 @@ int add_update_server(int flags, 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) + { + *up = serv->next; + daemon->servers_tail->next = serv; + daemon->servers_tail = 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 { + if (!(serv = whine_malloc(sizeof(struct server)))) + { + free(alloc_domain); + return 0; + } + memset(serv, 0, sizeof(struct server)); /* Add to the end of the chain, for order */ @@ -684,20 +703,20 @@ int add_update_server(int flags, else daemon->servers = serv; daemon->servers_tail = 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); |