mirror of
https://github.com/systemd/systemd.git
synced 2024-11-05 06:52:22 +03:00
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.
This commit is contained in:
parent
afe7fd56f5
commit
5cb36f41f0
@ -94,19 +94,26 @@ int config_parse_dnsv(
|
|||||||
else
|
else
|
||||||
l = &m->dns_servers;
|
l = &m->dns_servers;
|
||||||
|
|
||||||
/* Empty assignment means clear the list */
|
|
||||||
if (isempty(rvalue)) {
|
if (isempty(rvalue)) {
|
||||||
|
|
||||||
|
/* Empty assignment means clear the list */
|
||||||
while (*l)
|
while (*l)
|
||||||
dns_server_free(*l);
|
dns_server_free(*l);
|
||||||
|
|
||||||
return 0;
|
} else {
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r = manager_parse_dns_server(m, ltype, rvalue);
|
/* If we have a manual setting, then we stop reading
|
||||||
if (r < 0) {
|
* /etc/resolv.conf */
|
||||||
log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse DNS server string '%s'. Ignoring.", rvalue);
|
if (ltype == DNS_SERVER_SYSTEM)
|
||||||
return 0;
|
m->read_resolv_conf = false;
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -150,13 +150,13 @@ static int link_update_dns_servers(Link *l) {
|
|||||||
|
|
||||||
assert(l);
|
assert(l);
|
||||||
|
|
||||||
LIST_FOREACH(servers, s, l->dns_servers)
|
|
||||||
s->marked = true;
|
|
||||||
|
|
||||||
r = sd_network_get_dns(l->ifindex, &nameservers);
|
r = sd_network_get_dns(l->ifindex, &nameservers);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto clear;
|
goto clear;
|
||||||
|
|
||||||
|
LIST_FOREACH(servers, s, l->dns_servers)
|
||||||
|
s->marked = true;
|
||||||
|
|
||||||
STRV_FOREACH(nameserver, nameservers) {
|
STRV_FOREACH(nameserver, nameservers) {
|
||||||
union in_addr_union a;
|
union in_addr_union a;
|
||||||
int family;
|
int family;
|
||||||
|
@ -184,7 +184,6 @@ fail:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int manager_rtnl_listen(Manager *m) {
|
static int manager_rtnl_listen(Manager *m) {
|
||||||
_cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
|
_cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
|
||||||
sd_rtnl_message *i;
|
sd_rtnl_message *i;
|
||||||
@ -410,6 +409,7 @@ int manager_new(Manager **ret) {
|
|||||||
m->hostname_fd = -1;
|
m->hostname_fd = -1;
|
||||||
|
|
||||||
m->llmnr_support = SUPPORT_YES;
|
m->llmnr_support = SUPPORT_YES;
|
||||||
|
m->read_resolv_conf = true;
|
||||||
|
|
||||||
r = manager_parse_dns_server(m, DNS_SERVER_FALLBACK, DNS_SERVERS);
|
r = manager_parse_dns_server(m, DNS_SERVER_FALLBACK, DNS_SERVERS);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -520,6 +520,110 @@ Manager *manager_free(Manager *m) {
|
|||||||
return NULL;
|
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) {
|
static void write_resolve_conf_server(DnsServer *s, FILE *f, unsigned *count) {
|
||||||
_cleanup_free_ char *t = NULL;
|
_cleanup_free_ char *t = NULL;
|
||||||
int r;
|
int r;
|
||||||
@ -553,6 +657,9 @@ int manager_write_resolv_conf(Manager *m) {
|
|||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
|
/* Read the system /etc/resolv.conf first */
|
||||||
|
manager_read_resolv_conf(m);
|
||||||
|
|
||||||
r = fopen_temporary(path, &f, &temp_path);
|
r = fopen_temporary(path, &f, &temp_path);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -953,11 +1060,11 @@ bool manager_known_dns_server(Manager *m, int family, const union in_addr_union
|
|||||||
assert(in_addr);
|
assert(in_addr);
|
||||||
|
|
||||||
LIST_FOREACH(servers, s, m->dns_servers)
|
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;
|
return true;
|
||||||
|
|
||||||
LIST_FOREACH(servers, s, m->fallback_dns_servers)
|
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 true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -985,6 +1092,9 @@ DnsServer *manager_get_dns_server(Manager *m) {
|
|||||||
Link *l;
|
Link *l;
|
||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
|
/* Try to read updates resolv.conf */
|
||||||
|
manager_read_resolv_conf(m);
|
||||||
|
|
||||||
if (!m->current_dns_server)
|
if (!m->current_dns_server)
|
||||||
manager_set_dns_server(m, m->dns_servers);
|
manager_set_dns_server(m, m->dns_servers);
|
||||||
|
|
||||||
|
@ -78,6 +78,9 @@ struct Manager {
|
|||||||
LIST_HEAD(DnsServer, fallback_dns_servers);
|
LIST_HEAD(DnsServer, fallback_dns_servers);
|
||||||
DnsServer *current_dns_server;
|
DnsServer *current_dns_server;
|
||||||
|
|
||||||
|
bool read_resolv_conf;
|
||||||
|
usec_t resolv_conf_mtime;
|
||||||
|
|
||||||
LIST_HEAD(DnsScope, dns_scopes);
|
LIST_HEAD(DnsScope, dns_scopes);
|
||||||
DnsScope *unicast_scope;
|
DnsScope *unicast_scope;
|
||||||
|
|
||||||
@ -111,6 +114,7 @@ struct Manager {
|
|||||||
int manager_new(Manager **ret);
|
int manager_new(Manager **ret);
|
||||||
Manager* manager_free(Manager *m);
|
Manager* manager_free(Manager *m);
|
||||||
|
|
||||||
|
int manager_read_resolv_conf(Manager *m);
|
||||||
int manager_write_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);
|
bool manager_known_dns_server(Manager *m, int family, const union in_addr_union *in_addr);
|
||||||
|
@ -140,26 +140,38 @@ char* endswith(const char *s, const char *postfix) {
|
|||||||
return (char*) s + sl - pl;
|
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;
|
size_t sl, wl;
|
||||||
|
const char *p;
|
||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
assert(word);
|
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);
|
sl = strlen(s);
|
||||||
wl = strlen(word);
|
wl = strlen(word);
|
||||||
|
|
||||||
if (sl < wl)
|
if (sl < wl)
|
||||||
return false;
|
return NULL;
|
||||||
|
|
||||||
if (wl == 0)
|
if (wl == 0)
|
||||||
return true;
|
return (char*) s;
|
||||||
|
|
||||||
if (memcmp(s, word, wl) != 0)
|
if (memcmp(s, word, wl) != 0)
|
||||||
return false;
|
return NULL;
|
||||||
|
|
||||||
return s[wl] == 0 ||
|
p = s + wl;
|
||||||
strchr(WHITESPACE, s[wl]);
|
if (*p == 0)
|
||||||
|
return (char*) p;
|
||||||
|
|
||||||
|
if (!strchr(WHITESPACE, *p))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
p += strspn(p, WHITESPACE);
|
||||||
|
return (char*) p;
|
||||||
}
|
}
|
||||||
|
|
||||||
int close_nointr(int fd) {
|
int close_nointr(int fd) {
|
||||||
|
@ -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_;
|
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 close_nointr(int fd);
|
||||||
int safe_close(int fd);
|
int safe_close(int fd);
|
||||||
|
Loading…
Reference in New Issue
Block a user