resolved-resolv-conf.c revision 9176a57c101d51b4a7fb4141240b5ce03abac57d
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen This file is part of systemd.
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen Copyright 2014 Tom Gundersen <teg@jklm.no>
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen systemd is free software; you can redistribute it and/or modify it
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen under the terms of the GNU Lesser General Public License as published by
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen (at your option) any later version.
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen systemd is distributed in the hope that it will be useful, but
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen Lesser General Public License for more details.
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen You should have received a copy of the GNU Lesser General Public License
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /* Reads the system /etc/resolv.conf, if it exists and is not
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen * symlinked to our own resolv.conf instance */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = log_warning_errno(errno, "Failed to stat /etc/resolv.conf: %m");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /* Have we already seen the file? */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /* Is it symlinked to our own file? */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (stat("/run/systemd/resolve/resolv.conf", &own) >= 0 &&
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = log_warning_errno(errno, "Failed to open /etc/resolv.conf: %m");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = log_error_errno(errno, "Failed to stat open file: %m");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen dns_search_domain_mark_all(m->search_domains);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen FOREACH_LINE(line, f, r = -errno; goto clear) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen const char *a;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = manager_add_dns_server_by_string(m, DNS_SERVER_SYSTEM, a);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_warning_errno(r, "Failed to parse DNS server address '%s', ignoring.", a);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen if (!a) /* We treat "domain" lines, and "search" lines as equivalent, and add both to our list. */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = manager_parse_search_domains_and_warn(m, a);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_warning_errno(r, "Failed to parse search domain string '%s', ignoring.", a);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /* Flush out all servers and search domains that are still
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen * marked. Those are then ones that didn't appear in the new
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen dns_search_domain_unlink_marked(m->search_domains);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /* Whenever /etc/resolv.conf changes, start using the first
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen * DNS server of it. This is useful to deal with broken
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen * network managing implementations (like NetworkManager),
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen * that when connecting to a VPN place both the VPN DNS
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen * servers and the local ones in /etc/resolv.conf. Without
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen * resetting the DNS server to use back to the first entry we
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen * will continue to use the local one thus being unable to
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen * resolve VPN domains. */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen dns_search_domain_unlink_all(m->search_domains);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = in_addr_to_string(s->family, &s->address, &t);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen log_warning_errno(r, "Invalid DNS address. Ignoring: %m");
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen fputs("# Too many DNS servers configured, the following entries may be ignored.\n", f);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen fputs(" # Too many search domains configured, remaining ones ignored.", f);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen fputs(" # Total length of all search domains is too long, remaining ones ignored.", f);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersenstatic int write_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *domains) {
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "# Third party programs must not access this file directly, but\n"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "# only through the symlink at /etc/resolv.conf. To manage\n"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "# resolv.conf(5) in a different way, replace the symlink by a\n"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen "# static file or a different symlink.\n\n", f);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen unsigned count = 0;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen write_resolv_conf_search(domain, f, &count, &length);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen #define PRIVATE_RESOLV_CONF "/run/systemd/resolve/resolv.conf"
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen _cleanup_ordered_set_free_ OrderedSet *dns = NULL, *domains = NULL;
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /* Read the system /etc/resolv.conf first */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen /* Add the full list to a set, to filter out duplicates */
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = manager_compile_search_domains(m, &domains);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = fopen_temporary_label(PRIVATE_RESOLV_CONF, PRIVATE_RESOLV_CONF, &f, &temp_path);
e3dca0089b7b50e2ec21409d1292727921d06102Tom Gundersen r = write_resolv_conf_contents(f, dns, domains);