[systemd-commits] 3 commits - TODO src/resolve src/shared
Lennart Poettering
lennart at kemper.freedesktop.org
Fri Aug 1 09:10:12 PDT 2014
TODO | 1
src/resolve/resolved-conf.c | 21 +++--
src/resolve/resolved-dns-scope.c | 8 -
src/resolve/resolved-dns-scope.h | 2
src/resolve/resolved-dns-server.c | 6 -
src/resolve/resolved-dns-transaction.c | 11 ++
src/resolve/resolved-link.c | 15 ++-
src/resolve/resolved-link.h | 2
src/resolve/resolved-manager.c | 133 ++++++++++++++++++++++++++++++---
src/resolve/resolved-manager.h | 7 +
src/shared/util.c | 24 ++++-
src/shared/util.h | 2
12 files changed, 191 insertions(+), 41 deletions(-)
New commits:
commit 035d56dc32fd1947cd3eafbb55d15aad888e4f34
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Aug 1 18:09:51 2014 +0200
update TODO
diff --git a/TODO b/TODO
index ec5cf2d..1dbb9ff 100644
--- a/TODO
+++ b/TODO
@@ -45,7 +45,6 @@ Features:
- edns0
- dname
- cname on PTR (?)
- - read /etc/resolv.conf if it is not pointing to our own
* Ignore .busname units on classic D-Bus boots, systemd-resolved cannot be started on kdbus
without the active policy and should get a Wants=org.freedesktop.resolve1.busname to
commit 2c27fbca2d88214bd305272308a370a962818f1e
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Aug 1 18:09:07 2014 +0200
resolved: flush cache each time we change to a different DNS server
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index 42a2fc4..291d035 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -85,7 +85,7 @@ DnsScope* dns_scope_free(DnsScope *s) {
return NULL;
}
-DnsServer *dns_scope_get_server(DnsScope *s) {
+DnsServer *dns_scope_get_dns_server(DnsScope *s) {
assert(s);
if (s->protocol != DNS_PROTOCOL_DNS)
@@ -133,7 +133,7 @@ int dns_scope_send(DnsScope *s, DnsPacket *p) {
if (DNS_PACKET_QDCOUNT(p) > 1)
return -ENOTSUP;
- srv = dns_scope_get_server(s);
+ srv = dns_scope_get_dns_server(s);
if (!srv)
return -ESRCH;
@@ -197,7 +197,7 @@ int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *add
if (family == AF_UNSPEC) {
DnsServer *srv;
- srv = dns_scope_get_server(s);
+ srv = dns_scope_get_dns_server(s);
if (!srv)
return -ESRCH;
@@ -384,7 +384,7 @@ int dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union
if (s->link)
return !!link_find_dns_server(s->link, family, address);
else
- return manager_known_dns_server(s->manager, family, address);
+ return !!manager_find_dns_server(s->manager, family, address);
}
static int dns_scope_make_reply_packet(
diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h
index 8f42068..313c617 100644
--- a/src/resolve/resolved-dns-scope.h
+++ b/src/resolve/resolved-dns-scope.h
@@ -70,7 +70,7 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, const char *domain);
int dns_scope_good_key(DnsScope *s, DnsResourceKey *key);
int dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union *address);
-DnsServer *dns_scope_get_server(DnsScope *s);
+DnsServer *dns_scope_get_dns_server(DnsScope *s);
void dns_scope_next_dns_server(DnsScope *s);
int dns_scope_llmnr_membership(DnsScope *s, bool b);
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index 2c41337..30d9c8b 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -64,7 +64,7 @@ int dns_server_new(
if (type != DNS_SERVER_FALLBACK &&
s->manager->current_dns_server &&
s->manager->current_dns_server->type == DNS_SERVER_FALLBACK)
- s->manager->current_dns_server = NULL;
+ manager_set_dns_server(s->manager, NULL);
if (ret)
*ret = s;
@@ -88,10 +88,10 @@ DnsServer* dns_server_free(DnsServer *s) {
}
if (s->link && s->link->current_dns_server == s)
- s->link->current_dns_server = NULL;
+ link_set_dns_server(s->link, NULL);
if (s->manager && s->manager->current_dns_server == s)
- s->manager->current_dns_server = NULL;
+ manager_set_dns_server(s->manager, NULL);
free(s);
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index faa1de9..48da432 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -465,12 +465,19 @@ int dns_transaction_go(DnsTransaction *t) {
t->cached = dns_answer_unref(t->cached);
t->cached_rcode = 0;
- /* First, let's try the cache */
+ /* Before trying the cache, let's make sure we figured out a
+ * server to use. Should this cause a change of server this
+ * might flush the cache. */
+ dns_scope_get_dns_server(t->scope);
+
+ /* Let's then prune all outdated entries */
dns_cache_prune(&t->scope->cache);
+
r = dns_cache_lookup(&t->scope->cache, t->question, &t->cached_rcode, &t->cached);
if (r < 0)
return r;
if (r > 0) {
+ log_debug("Cache hit!");
if (t->cached_rcode == DNS_RCODE_SUCCESS)
dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);
else
@@ -478,6 +485,8 @@ int dns_transaction_go(DnsTransaction *t) {
return 0;
}
+ log_debug("Cache miss!");
+
/* Otherwise, we need to ask the network */
r = dns_transaction_make_packet(t);
if (r == -EDOM) {
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
index 7418ea1..2c02f09 100644
--- a/src/resolve/resolved-link.c
+++ b/src/resolve/resolved-link.c
@@ -248,7 +248,7 @@ DnsServer* link_find_dns_server(Link *l, int family, const union in_addr_union *
return NULL;
}
-static DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
+DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
assert(l);
if (l->current_dns_server == s)
@@ -259,10 +259,13 @@ static DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
in_addr_to_string(s->family, &s->address, &ip);
log_info("Switching to DNS server %s for interface %s.", strna(ip), l->name);
- } else
- log_info("No DNS server set for interface %s.", l->name);
+ }
l->current_dns_server = s;
+
+ if (l->unicast_scope)
+ dns_cache_flush(&l->unicast_scope->cache);
+
return s;
}
diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h
index d29311e..38bb392 100644
--- a/src/resolve/resolved-link.h
+++ b/src/resolve/resolved-link.h
@@ -77,6 +77,8 @@ int link_update_monitor(Link *l);
bool link_relevant(Link *l, int family);
LinkAddress* link_find_address(Link *l, int family, const union in_addr_union *in_addr);
void link_add_rrs(Link *l, bool force_remove);
+
+DnsServer* link_set_dns_server(Link *l, DnsServer *s);
DnsServer* link_find_dns_server(Link *l, int family, const union in_addr_union *in_addr);
DnsServer* link_get_dns_server(Link *l);
void link_next_dns_server(Link *l);
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index ba2380d..5ed7a9f 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -1053,7 +1053,7 @@ int manager_send(Manager *m, int fd, int ifindex, int family, const union in_add
return -EAFNOSUPPORT;
}
-bool manager_known_dns_server(Manager *m, int family, const union in_addr_union *in_addr) {
+DnsServer* manager_find_dns_server(Manager *m, int family, const union in_addr_union *in_addr) {
DnsServer *s;
assert(m);
@@ -1061,16 +1061,16 @@ bool manager_known_dns_server(Manager *m, int family, const union in_addr_union
LIST_FOREACH(servers, s, m->dns_servers)
if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
- return true;
+ return s;
LIST_FOREACH(servers, s, m->fallback_dns_servers)
if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
- return true;
+ return s;
- return false;
+ return NULL;
}
-static DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
+DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
assert(m);
if (m->current_dns_server == s)
@@ -1081,10 +1081,13 @@ static DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
in_addr_to_string(s->family, &s->address, &ip);
log_info("Switching to system DNS server %s.", strna(ip));
- } else
- log_info("No system DNS server set.");
+ }
m->current_dns_server = s;
+
+ if (m->unicast_scope)
+ dns_cache_flush(&m->unicast_scope->cache);
+
return s;
}
diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h
index 7bb18c0..31d670d 100644
--- a/src/resolve/resolved-manager.h
+++ b/src/resolve/resolved-manager.h
@@ -117,7 +117,8 @@ Manager* manager_free(Manager *m);
int manager_read_resolv_conf(Manager *m);
int manager_write_resolv_conf(Manager *m);
-bool manager_known_dns_server(Manager *m, int family, const union in_addr_union *in_addr);
+DnsServer *manager_set_dns_server(Manager *m, DnsServer *s);
+DnsServer *manager_find_dns_server(Manager *m, int family, const union in_addr_union *in_addr);
DnsServer *manager_get_dns_server(Manager *m);
void manager_next_dns_server(Manager *m);
commit 5cb36f41f01cf4b1f4395abfffd1b33116591e58
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Aug 1 17:03:28 2014 +0200
resolved: read the system /etc/resolv.conf unless we wrote it ourselves
This way we integrate nicely with foreign network management stacks,
such as NM.
diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c
index 0def80e..ae3773f 100644
--- a/src/resolve/resolved-conf.c
+++ b/src/resolve/resolved-conf.c
@@ -94,20 +94,27 @@ int config_parse_dnsv(
else
l = &m->dns_servers;
- /* Empty assignment means clear the list */
if (isempty(rvalue)) {
+
+ /* Empty assignment means clear the list */
while (*l)
dns_server_free(*l);
- return 0;
- }
+ } else {
- r = manager_parse_dns_server(m, ltype, rvalue);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse DNS server string '%s'. Ignoring.", rvalue);
- return 0;
+ /* Otherwise add to the list */
+ r = manager_parse_dns_server(m, ltype, rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse DNS server string '%s'. Ignoring.", rvalue);
+ return 0;
+ }
}
+ /* If we have a manual setting, then we stop reading
+ * /etc/resolv.conf */
+ if (ltype == DNS_SERVER_SYSTEM)
+ m->read_resolv_conf = false;
+
return 0;
}
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
index 93ccc04..7418ea1 100644
--- a/src/resolve/resolved-link.c
+++ b/src/resolve/resolved-link.c
@@ -150,13 +150,13 @@ static int link_update_dns_servers(Link *l) {
assert(l);
- LIST_FOREACH(servers, s, l->dns_servers)
- s->marked = true;
-
r = sd_network_get_dns(l->ifindex, &nameservers);
if (r < 0)
goto clear;
+ LIST_FOREACH(servers, s, l->dns_servers)
+ s->marked = true;
+
STRV_FOREACH(nameserver, nameservers) {
union in_addr_union a;
int family;
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 1e86c10..ba2380d 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -184,7 +184,6 @@ fail:
return 0;
}
-
static int manager_rtnl_listen(Manager *m) {
_cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
sd_rtnl_message *i;
@@ -410,6 +409,7 @@ int manager_new(Manager **ret) {
m->hostname_fd = -1;
m->llmnr_support = SUPPORT_YES;
+ m->read_resolv_conf = true;
r = manager_parse_dns_server(m, DNS_SERVER_FALLBACK, DNS_SERVERS);
if (r < 0)
@@ -520,6 +520,110 @@ Manager *manager_free(Manager *m) {
return NULL;
}
+int manager_read_resolv_conf(Manager *m) {
+ _cleanup_fclose_ FILE *f = NULL;
+ struct stat st, own;
+ char line[LINE_MAX];
+ DnsServer *s, *nx;
+ usec_t t;
+ int r;
+
+ assert(m);
+
+ /* Reads the system /etc/resolv.conf, if it exists and is not
+ * symlinked to our own resolv.conf instance */
+
+ if (!m->read_resolv_conf)
+ return 0;
+
+ r = stat("/etc/resolv.conf", &st);
+ if (r < 0) {
+ if (errno != ENOENT)
+ log_warning("Failed to open /etc/resolv.conf: %m");
+ r = -errno;
+ goto clear;
+ }
+
+ /* Have we already seen the file? */
+ t = timespec_load(&st.st_mtim);
+ if (t == m->resolv_conf_mtime)
+ return 0;
+
+ m->resolv_conf_mtime = t;
+
+ /* Is it symlinked to our own file? */
+ if (stat("/run/systemd/resolve/resolv.conf", &own) >= 0 &&
+ st.st_dev == own.st_dev &&
+ st.st_ino == own.st_ino) {
+ r = 0;
+ goto clear;
+ }
+
+ f = fopen("/etc/resolv.conf", "re");
+ if (!f) {
+ if (errno != ENOENT)
+ log_warning("Failed to open /etc/resolv.conf: %m");
+ r = -errno;
+ goto clear;
+ }
+
+ if (fstat(fileno(f), &st) < 0) {
+ log_error("Failed to stat open file: %m");
+ r = -errno;
+ goto clear;
+ }
+
+ LIST_FOREACH(servers, s, m->dns_servers)
+ s->marked = true;
+
+ FOREACH_LINE(line, f, r = -errno; goto clear) {
+ union in_addr_union address;
+ int family;
+ char *l;
+ const char *a;
+
+ truncate_nl(line);
+
+ l = strstrip(line);
+ if (*l == '#' || *l == ';')
+ continue;
+
+ a = first_word(l, "nameserver");
+ if (!a)
+ continue;
+
+ r = in_addr_from_string_auto(a, &family, &address);
+ if (r < 0) {
+ log_warning("Failed to parse name server %s.", a);
+ continue;
+ }
+
+ LIST_FOREACH(servers, s, m->dns_servers)
+ if (s->family == family && in_addr_equal(family, &s->address, &address) > 0)
+ break;
+
+ if (s)
+ s->marked = false;
+ else {
+ r = dns_server_new(m, NULL, DNS_SERVER_SYSTEM, NULL, family, &address);
+ if (r < 0)
+ goto clear;
+ }
+ }
+
+ LIST_FOREACH_SAFE(servers, s, nx, m->dns_servers)
+ if (s->marked)
+ dns_server_free(s);
+
+ return 0;
+
+clear:
+ while (m->dns_servers)
+ dns_server_free(m->dns_servers);
+
+ return r;
+}
+
static void write_resolve_conf_server(DnsServer *s, FILE *f, unsigned *count) {
_cleanup_free_ char *t = NULL;
int r;
@@ -553,6 +657,9 @@ int manager_write_resolv_conf(Manager *m) {
assert(m);
+ /* Read the system /etc/resolv.conf first */
+ manager_read_resolv_conf(m);
+
r = fopen_temporary(path, &f, &temp_path);
if (r < 0)
return r;
@@ -953,11 +1060,11 @@ bool manager_known_dns_server(Manager *m, int family, const union in_addr_union
assert(in_addr);
LIST_FOREACH(servers, s, m->dns_servers)
- if (s->family == family && in_addr_equal(family, &s->address, in_addr))
+ if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
return true;
LIST_FOREACH(servers, s, m->fallback_dns_servers)
- if (s->family == family && in_addr_equal(family, &s->address, in_addr))
+ if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
return true;
return false;
@@ -985,6 +1092,9 @@ DnsServer *manager_get_dns_server(Manager *m) {
Link *l;
assert(m);
+ /* Try to read updates resolv.conf */
+ manager_read_resolv_conf(m);
+
if (!m->current_dns_server)
manager_set_dns_server(m, m->dns_servers);
diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h
index 03386f0..7bb18c0 100644
--- a/src/resolve/resolved-manager.h
+++ b/src/resolve/resolved-manager.h
@@ -78,6 +78,9 @@ struct Manager {
LIST_HEAD(DnsServer, fallback_dns_servers);
DnsServer *current_dns_server;
+ bool read_resolv_conf;
+ usec_t resolv_conf_mtime;
+
LIST_HEAD(DnsScope, dns_scopes);
DnsScope *unicast_scope;
@@ -111,6 +114,7 @@ struct Manager {
int manager_new(Manager **ret);
Manager* manager_free(Manager *m);
+int manager_read_resolv_conf(Manager *m);
int manager_write_resolv_conf(Manager *m);
bool manager_known_dns_server(Manager *m, int family, const union in_addr_union *in_addr);
diff --git a/src/shared/util.c b/src/shared/util.c
index 4c30a98..e2c955b 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -140,26 +140,38 @@ char* endswith(const char *s, const char *postfix) {
return (char*) s + sl - pl;
}
-bool first_word(const char *s, const char *word) {
+char* first_word(const char *s, const char *word) {
size_t sl, wl;
+ const char *p;
assert(s);
assert(word);
+ /* Checks if the string starts with the specified word, either
+ * followed by NUL or by whitespace. Returns a pointer to the
+ * NUL or the first character after the whitespace. */
+
sl = strlen(s);
wl = strlen(word);
if (sl < wl)
- return false;
+ return NULL;
if (wl == 0)
- return true;
+ return (char*) s;
if (memcmp(s, word, wl) != 0)
- return false;
+ return NULL;
+
+ p = s + wl;
+ if (*p == 0)
+ return (char*) p;
+
+ if (!strchr(WHITESPACE, *p))
+ return NULL;
- return s[wl] == 0 ||
- strchr(WHITESPACE, s[wl]);
+ p += strspn(p, WHITESPACE);
+ return (char*) p;
}
int close_nointr(int fd) {
diff --git a/src/shared/util.h b/src/shared/util.h
index 4529480..fd999bd 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -169,7 +169,7 @@ static inline const char *startswith_no_case(const char *s, const char *prefix)
char *endswith(const char *s, const char *postfix) _pure_;
-bool first_word(const char *s, const char *word) _pure_;
+char *first_word(const char *s, const char *word) _pure_;
int close_nointr(int fd);
int safe_close(int fd);
More information about the systemd-commits
mailing list