Browse Source

resolved: add daemon to manage resolv.conf

Also remove the equivalent functionality from networkd.
keep-around/964a6d9fb555cc86528eb1cc1f6d044f85584842
Tom Gundersen 9 years ago
parent
commit
091a364c80
  1. 1
      .gitignore
  2. 14
      Makefile-man.am
  3. 59
      Makefile.am
  4. 27
      configure.ac
  5. 91
      man/resolved.conf.xml
  6. 5
      man/systemd-networkd.service.xml
  7. 85
      man/systemd-resolved.service.xml
  8. 2
      src/network/.gitignore
  9. 11
      src/network/networkd-link.c
  10. 201
      src/network/networkd-manager.c
  11. 2
      src/network/networkd-network.c
  12. 8
      src/network/networkd.c
  13. 8
      src/network/networkd.h
  14. 2
      src/resolve/.gitignore
  15. 1
      src/resolve/Makefile
  16. 8
      src/resolve/resolved-gperf.gperf
  17. 320
      src/resolve/resolved-manager.c
  18. 86
      src/resolve/resolved.c
  19. 4
      src/resolve/resolved.conf.in
  20. 69
      src/resolve/resolved.h
  21. 1
      units/.gitignore
  22. 21
      units/systemd-resolved.service.in

1
.gitignore

@ -92,6 +92,7 @@
/systemd-remount-api-vfs
/systemd-remount-fs
/systemd-reply-password
/systemd-resolved
/systemd-rfkill
/systemd-run
/systemd-shutdown

14
Makefile-man.am

@ -1131,6 +1131,18 @@ man/systemd-readahead.html: man/systemd-readahead-replay.service.html
endif
if ENABLE_RESOLVED
MANPAGES += \
man/resolved.conf.5 \
man/systemd-resolved.service.8
MANPAGES_ALIAS += \
man/systemd-resolved.8
man/systemd-resolved.8: man/systemd-resolved.service.8
man/systemd-resolved.html: man/systemd-resolved.service.html
$(html-alias)
endif
if ENABLE_RFKILL
MANPAGES += \
man/systemd-rfkill@.service.8
@ -1483,6 +1495,7 @@ EXTRA_DIST += \
man/nss-myhostname.xml \
man/os-release.xml \
man/pam_systemd.xml \
man/resolved.conf.xml \
man/runlevel.xml \
man/sd-daemon.xml \
man/sd-id128.xml \
@ -1581,6 +1594,7 @@ EXTRA_DIST += \
man/systemd-random-seed.service.xml \
man/systemd-readahead-replay.service.xml \
man/systemd-remount-fs.service.xml \
man/systemd-resolved.service.xml \
man/systemd-rfkill@.service.xml \
man/systemd-run.xml \
man/systemd-shutdownd.service.xml \

59
Makefile.am

@ -4193,6 +4193,51 @@ EXTRA_DIST += \
endif
# ------------------------------------------------------------------------------
if ENABLE_RESOLVED
systemd_resolved_SOURCES = \
src/resolve/resolved.h \
src/resolve/resolved.c \
src/resolve/resolved-manager.c
nodist_systemd_resolved_SOURCES = \
src/resolve/resolved-gperf.c
EXTRA_DIST += \
src/resolve/resolved-gperf.gperf
CLEANFILES += \
src/resolve/resolved-gperf.c
systemd_resolved_LDADD = \
libsystemd-label.la \
libsystemd-internal.la \
libsystemd-shared.la \
libsystemd-network.la
rootlibexec_PROGRAMS += \
systemd-resolved
nodist_systemunit_DATA += \
units/systemd-resolved.service
EXTRA_DIST += \
units/systemd-resolved.service.in
GENERAL_ALIASES += \
$(systemunitdir)/systemd-resolved.service $(pkgsysconfdir)/system/multi-user.target.wants/systemd-resolved.service
nodist_pkgsysconf_DATA += \
src/resolve/resolved.conf
EXTRA_DIST += \
src/resolve/resolved.conf.in
CLEANFILES += \
src/resolve/resolved.conf
endif
# ------------------------------------------------------------------------------
if ENABLE_NETWORKD
rootlibexec_PROGRAMS += \
@ -4225,8 +4270,7 @@ libsystemd_networkd_core_la_SOURCES = \
nodist_libsystemd_networkd_core_la_SOURCES = \
src/network/networkd-network-gperf.c \
src/network/networkd-netdev-gperf.c \
src/network/networkd-gperf.c
src/network/networkd-netdev-gperf.c
libsystemd_networkd_core_la_LIBADD = \
libudev-internal.la \
@ -4272,22 +4316,15 @@ GENERAL_ALIASES += \
$(systemunitdir)/systemd-networkd.service $(pkgsysconfdir)/system/multi-user.target.wants/systemd-networkd.service \
$(systemunitdir)/systemd-networkd.service $(pkgsysconfdir)/system/network-online.target.wants/systemd-networkd-wait-online.service
nodist_pkgsysconf_DATA += \
src/network/networkd.conf
EXTRA_DIST += \
src/network/networkd-network-gperf.gperf \
src/network/networkd-netdev-gperf.gperf \
src/network/networkd-gperf.gperf \
units/systemd-networkd.service.in \
units/systemd-networkd-wait-online.service.in \
src/network/networkd.conf.in
units/systemd-networkd-wait-online.service.in
CLEANFILES += \
src/network/networkd-network-gperf.c \
src/network/networkd-netdev-gperf.c \
src/network/networkd-gperf.c \
src/network/networkd.conf
src/network/networkd-netdev-gperf.c
endif
# ------------------------------------------------------------------------------

27
configure.ac

@ -879,25 +879,33 @@ fi
AM_CONDITIONAL(ENABLE_POLKIT, [test "x$have_polkit" = "xyes"])
# ------------------------------------------------------------------------------
have_networkd=no
AC_ARG_ENABLE(networkd, AS_HELP_STRING([--disable-networkd], [disable networkd]))
if test "x$enable_networkd" != "xno"; then
AC_DEFINE(ENABLE_NETWORKD, 1, [Define if networkd support is to be enabled])
have_networkd=yes
have_resolved=no
AC_ARG_ENABLE(resolved, AS_HELP_STRING([--disable-resolved], [disable resolve daemon]))
if test "x$enable_resolved" != "xno"; then
have_resolved=yes
fi
AS_IF([test "x$have_networkd" = "xyes" -a "x$have_kmod" != "xyes"],
[AC_MSG_ERROR([networkd requires kmod])])
AM_CONDITIONAL(ENABLE_NETWORKD, [test "x$have_networkd" = "xyes"])
AM_CONDITIONAL(ENABLE_RESOLVED, [test "$have_resolved" = "yes"])
AC_ARG_WITH(dns-servers,
AS_HELP_STRING([--with-dns-servers=DNSSERVERS],
[Space-separated list of default DNS servers]),
[DNS_SERVERS="$withval"],
[NTP_SERVERS="$withval"],
[DNS_SERVERS="8.8.8.8 8.8.4.4 2001:4860:4860::8888 2001:4860:4860::8844"])
AC_DEFINE_UNQUOTED(DNS_SERVERS, ["$DNS_SERVERS"], [Default DNS Servers])
AC_SUBST(DNS_SERVERS)
# ------------------------------------------------------------------------------
have_networkd=no
AC_ARG_ENABLE(networkd, AS_HELP_STRING([--disable-networkd], [disable networkd]))
if test "x$enable_networkd" != "xno"; then
AC_DEFINE(ENABLE_NETWORKD, 1, [Define if networkd support is to be enabled])
have_networkd=yes
fi
AS_IF([test "x$have_networkd" = "xyes" -a "x$have_kmod" != "xyes"],
[AC_MSG_ERROR([networkd requires kmod])])
AM_CONDITIONAL(ENABLE_NETWORKD, [test "x$have_networkd" = "xyes"])
# ------------------------------------------------------------------------------
have_efi=no
AC_ARG_ENABLE(efi, AS_HELP_STRING([--disable-efi], [disable EFI support]))
@ -1201,6 +1209,7 @@ AC_MSG_RESULT([
time epoch: ${TIME_EPOCH}
localed: ${have_localed}
networkd: ${have_networkd}
resolved: ${have_resolved}
default DNS servers: ${DNS_SERVERS}
coredump: ${have_coredump}
polkit: ${have_polkit}

91
man/resolved.conf.xml

@ -0,0 +1,91 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<?xml-stylesheet type="text/xsl" href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!--
This file is part of systemd.
Copyright 2014 Tom Gundersen
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="resolved.conf" conditional='ENABLE_RESOLVED'>
<refentryinfo>
<title>resolved.conf</title>
<productname>systemd</productname>
<authorgroup>
<author>
<contrib>Developer</contrib>
<firstname>Tom</firstname>
<surname>Gundersen</surname>
<email>teg@jklm.no</email>
</author>
</authorgroup>
</refentryinfo>
<refmeta>
<refentrytitle>resolved.conf</refentrytitle>
<manvolnum>5</manvolnum>
</refmeta>
<refnamediv>
<refname>resolved.conf</refname>
<refpurpose>Network Name Resolution configuration file</refpurpose>
</refnamediv>
<refsynopsisdiv>
<para><filename>/etc/systemd/resolved.conf</filename></para>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>When starting, systemd-resolved will read the
configuration file <filename>resolved.conf</filename>.
This configuration file determines the fallback DNS
servers.</para>
</refsect1>
<refsect1>
<title>Options</title>
<variablelist class='network-directives'>
<varlistentry>
<term><varname>DNS=</varname></term>
<listitem><para>A space separated list of IPv4 and IPv6
addresses to be used as the fallback DNS servers. Note that
the servers obtained from
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
take precedence. If this option is not given, a compiled-in
list of DNS servers is used instead.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

5
man/systemd-networkd.service.xml

@ -72,11 +72,6 @@
restarting networkd does not cut the network connection, and, in particular,
that it is safe to transition between the initrd and the real root,
and back.</para>
<para>Nameservers configured in networkd, or received over DHCP
are exposed in <filename>/run/systemd/network/resolv.conf</filename>.
This file should not be used directly, but only through a symlink
from <filename>/etc/resolv.conf</filename>.</para>
</refsect1>
<refsect1><title>Configuration Files</title>

85
man/systemd-resolved.service.xml

@ -0,0 +1,85 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!--
This file is part of systemd.
Copyright 2014 Tom Gundersen
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="systemd-resolved.service" conditional='ENABLE_RESOLVED'>
<refentryinfo>
<title>systemd-resolved.service</title>
<productname>systemd</productname>
<authorgroup>
<author>
<contrib>Developer</contrib>
<firstname>Tom</firstname>
<surname>Gundersen</surname>
<email>teg@jklm.no</email>
</author>
</authorgroup>
</refentryinfo>
<refmeta>
<refentrytitle>systemd-resolved.service</refentrytitle>
<manvolnum>8</manvolnum>
</refmeta>
<refnamediv>
<refname>systemd-resolved.service</refname>
<refname>systemd-resolved</refname>
<refpurpose>Network Name Resolution manager</refpurpose>
</refnamediv>
<refsynopsisdiv>
<para><filename>systemd-resolved.service</filename></para>
<para><filename>/usr/lib/systemd/systemd-resolved</filename></para>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para><command>systemd-networkd</command> is a system
service that manages network name resolution. It does so by
generating <filename>/run/systemd/network/resolv.conf</filename>,
which may be symlinked from <filename>/etc/resolv.conf</filename>.
The contents is generated from the global settings in
<citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
the per-link static settings in <filename>.network</filename> files,
and the per-link dynamic settings received over DHCP. See
<citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for more details.</para>
<para>Note that <filename>/run/systemd/network/resolv.conf</filename>
should not be used directly, but only through a symlink from
<filename>/etc/resolv.conf</filename>.</para>
</refsect1>
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

2
src/network/.gitignore

@ -1,4 +1,2 @@
/networkd-network-gperf.c
/networkd-netdev-gperf.c
/networkd-gperf.c
/networkd.conf

11
src/network/networkd-link.c

@ -854,8 +854,6 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
struct in_addr netmask;
struct in_addr gateway;
unsigned prefixlen;
struct in_addr *nameservers;
size_t nameservers_size;
int r;
assert(client);
@ -920,15 +918,6 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
link->dhcp_lease = lease;
if (link->network->dhcp_dns) {
r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size);
if (r >= 0) {
r = manager_update_resolv_conf(link->manager);
if (r < 0)
log_error_link(link, "Failed to update resolv.conf");
}
}
if (link->network->dhcp_mtu) {
uint16_t mtu;

201
src/network/networkd-manager.c

@ -19,7 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <resolv.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <libkmod.h>
@ -76,95 +76,6 @@ static int setup_signals(Manager *m) {
return 0;
}
static int set_fallback_dns(Manager *m, const char *string) {
char *word, *state;
size_t length;
int r;
assert(m);
assert(string);
FOREACH_WORD_QUOTED(word, length, string, state) {
_cleanup_address_free_ Address *address = NULL;
Address *tail;
_cleanup_free_ char *addrstr = NULL;
r = address_new_dynamic(&address);
if (r < 0)
return r;
addrstr = strndup(word, length);
if (!addrstr)
return -ENOMEM;
r = net_parse_inaddr(addrstr, &address->family, &address->in_addr);
if (r < 0) {
log_debug("Ignoring invalid DNS address '%s'", addrstr);
continue;
}
LIST_FIND_TAIL(addresses, m->fallback_dns, tail);
LIST_INSERT_AFTER(addresses, m->fallback_dns, tail, address);
address = NULL;
}
return 0;
}
int config_parse_dnsv(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Manager *m = userdata;
Address *address;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(m);
while ((address = m->fallback_dns)) {
LIST_REMOVE(addresses, m->fallback_dns, address);
address_free(address);
}
set_fallback_dns(m, rvalue);
return 0;
}
static int manager_parse_config_file(Manager *m) {
static const char fn[] = "/etc/systemd/networkd.conf";
_cleanup_fclose_ FILE *f = NULL;
int r;
assert(m);
f = fopen(fn, "re");
if (!f) {
if (errno == ENOENT)
return 0;
log_warning("Failed to open configuration file %s: %m", fn);
return -errno;
}
r = config_parse(NULL, fn, f, "Network\0", config_item_perf_lookup,
(void*) networkd_gperf_lookup, false, false, m);
if (r < 0)
log_warning("Failed to parse configuration file: %s", strerror(-r));
return r;
}
int manager_new(Manager **ret) {
_cleanup_manager_free_ Manager *m = NULL;
int r;
@ -177,14 +88,6 @@ int manager_new(Manager **ret) {
if (!m->state_file)
return -ENOMEM;
r = set_fallback_dns(m, DNS_SERVERS);
if (r < 0)
return r;
r = manager_parse_config_file(m);
if (r < 0)
return r;
r = sd_event_default(&m->event);
if (r < 0)
return r;
@ -241,7 +144,6 @@ void manager_free(Manager *m) {
Network *network;
NetDev *netdev;
Link *link;
Address *address;
if (!m)
return;
@ -257,11 +159,6 @@ void manager_free(Manager *m) {
sd_event_source_unref(m->sigint_event_source);
sd_event_unref(m->event);
while ((address = m->fallback_dns)) {
LIST_REMOVE(addresses, m->fallback_dns, address);
address_free(address);
}
while ((link = hashmap_first(m->links)))
link_unref(link);
hashmap_free(m->links);
@ -522,102 +419,6 @@ int manager_bus_listen(Manager *m) {
return 0;
}
static void append_dns(FILE *f, struct in_addr *dns, unsigned char family, unsigned *count) {
char buf[INET6_ADDRSTRLEN];
const char *address;
address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN);
if (!address) {
log_warning("Invalid DNS address. Ignoring.");
return;
}
if (*count == MAXNS)
fputs("# Too many DNS servers configured, the following entries "
"will be ignored\n", f);
fprintf(f, "nameserver %s\n", address);
(*count) ++;
}
int manager_update_resolv_conf(Manager *m) {
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
Link *link;
Iterator i;
unsigned count = 0;
const char *domainname = NULL;
int r;
assert(m);
r = fopen_temporary("/run/systemd/network/resolv.conf", &f, &temp_path);
if (r < 0)
return r;
fchmod(fileno(f), 0644);
fputs("# This file is managed by systemd-networkd(8). Do not edit.\n#\n"
"# Third party programs must not access this file directly, but\n"
"# only through the symlink at /etc/resolv.conf. To manage\n"
"# resolv.conf(5) in a different way, replace the symlink by a\n"
"# static file or a different symlink.\n\n", f);
HASHMAP_FOREACH(link, m->links, i) {
if (link->dhcp_lease) {
struct in_addr *nameservers;
size_t nameservers_size;
if (link->network->dhcp_dns) {
r = sd_dhcp_lease_get_dns(link->dhcp_lease, &nameservers, &nameservers_size);
if (r >= 0) {
unsigned j;
for (j = 0; j < nameservers_size; j++)
append_dns(f, &nameservers[j], AF_INET, &count);
}
}
if (link->network->dhcp_domainname && !domainname) {
r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
if (r >= 0)
fprintf(f, "domain %s\n", domainname);
}
}
}
HASHMAP_FOREACH(link, m->links, i) {
if (link->network && link->network->dns) {
Address *address;
LIST_FOREACH(addresses, address, link->network->dns) {
append_dns(f, &address->in_addr.in,
address->family, &count);
}
}
}
if (!count) {
Address *address;
LIST_FOREACH(addresses, address, m->fallback_dns)
append_dns(f, &address->in_addr.in,
address->family, &count);
}
fflush(f);
if (ferror(f) || rename(temp_path, "/run/systemd/network/resolv.conf") < 0) {
r = -errno;
unlink("/run/systemd/network/resolv.conf");
unlink(temp_path);
return r;
}
return 0;
}
int manager_save(Manager *m) {
Link *link;
Iterator i;

2
src/network/networkd-network.c

@ -235,7 +235,7 @@ int network_apply(Manager *manager, Network *network, Link *link) {
link->network = network;
if (network->dns) {
r = manager_update_resolv_conf(manager);
r = link_save(link);
if (r < 0)
return r;
}

8
src/network/networkd.c

@ -93,14 +93,6 @@ int main(int argc, char *argv[]) {
goto out;
}
/* write out empty resolv.conf to avoid a
* dangling symlink */
r = manager_update_resolv_conf(m);
if (r < 0) {
log_error("Could not create resolv.conf: %s", strerror(-r));
goto out;
}
sd_notify(false,
"READY=1\n"
"STATUS=Processing requests...");

8
src/network/networkd.h

@ -256,7 +256,6 @@ struct Manager {
Hashmap *links;
Hashmap *netdevs;
LIST_HEAD(Network, networks);
LIST_HEAD(Address, fallback_dns);
usec_t network_dirs_ts_usec;
struct kmod_ctx *kmod_ctx;
@ -278,18 +277,11 @@ int manager_rtnl_listen(Manager *m);
int manager_udev_listen(Manager *m);
int manager_bus_listen(Manager *m);
int manager_update_resolv_conf(Manager *m);
int manager_save(Manager *m);
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
#define _cleanup_manager_free_ _cleanup_(manager_freep)
const struct ConfigPerfItem* networkd_gperf_lookup(const char *key, unsigned length);
int config_parse_dnsv(const char *unit, const char *filename, unsigned line,
const char *section, unsigned section_line, const char *lvalue,
int ltype, const char *rvalue, void *data, void *userdata);
/* NetDev */
int netdev_load(Manager *manager);

2
src/resolve/.gitignore

@ -0,0 +1,2 @@
/resolved-gperf.c
/resolved.conf

1
src/resolve/Makefile

@ -0,0 +1 @@
../Makefile

8
src/network/networkd-gperf.gperf → src/resolve/resolved-gperf.gperf

@ -1,17 +1,17 @@
%{
#include <stddef.h>
#include "conf-parser.h"
#include "networkd.h"
#include "resolved.h"
%}
struct ConfigPerfItem;
%null_strings
%language=ANSI-C
%define slot-name section_and_lvalue
%define hash-function-name networkd_gperf_hash
%define lookup-function-name networkd_gperf_lookup
%define hash-function-name resolved_gperf_hash
%define lookup-function-name resolved_gperf_lookup
%readonly-tables
%omit-struct-type
%struct-type
%includes
%%
Network.DNS, config_parse_dnsv, 0, offsetof(Manager, fallback_dns)
Resolve.DNS, config_parse_dnsv, 0, offsetof(Manager, fallback_dns)

320
src/resolve/resolved-manager.c

@ -0,0 +1,320 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2014 Tom Gundersen <teg@jklm.no>
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <arpa/inet.h>
#include <resolv.h>
#include <linux/if.h>
#include "resolved.h"
#include "event-util.h"
#include "network-util.h"
#include "sd-dhcp-lease.h"
#include "dhcp-lease-internal.h"
#include "network-internal.h"
#include "conf-parser.h"
#include "mkdir.h"
static int set_fallback_dns(Manager *m, const char *string) {
char *word, *state;
size_t length;
int r;
assert(m);
assert(string);
FOREACH_WORD_QUOTED(word, length, string, state) {
_cleanup_free_ Address *address = NULL;
Address *tail;
_cleanup_free_ char *addrstr = NULL;
address = new0(Address, 1);
if (!address)
return -ENOMEM;
addrstr = strndup(word, length);
if (!addrstr)
return -ENOMEM;
r = net_parse_inaddr(addrstr, &address->family, &address->in_addr);
if (r < 0) {
log_debug("Ignoring invalid DNS address '%s'", addrstr);
continue;
}
LIST_FIND_TAIL(addresses, m->fallback_dns, tail);
LIST_INSERT_AFTER(addresses, m->fallback_dns, tail, address);
address = NULL;
}
return 0;
}
int config_parse_dnsv(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Manager *m = userdata;
Address *address;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(m);
while ((address = m->fallback_dns)) {
LIST_REMOVE(addresses, m->fallback_dns, address);
free(address);
}
set_fallback_dns(m, rvalue);
return 0;
}
static int manager_parse_config_file(Manager *m) {
static const char fn[] = "/etc/systemd/resolved.conf";
_cleanup_fclose_ FILE *f = NULL;
int r;
assert(m);
f = fopen(fn, "re");
if (!f) {
if (errno == ENOENT)
return 0;
log_warning("Failed to open configuration file %s: %m", fn);
return -errno;
}
r = config_parse(NULL, fn, f, "Resolve\0", config_item_perf_lookup,
(void*) resolved_gperf_lookup, false, false, m);
if (r < 0)
log_warning("Failed to parse configuration file: %s", strerror(-r));
return r;
}
int manager_new(Manager **ret) {
_cleanup_manager_free_ Manager *m = NULL;
int r;
m = new0(Manager, 1);
if (!m)
return -ENOMEM;
r = set_fallback_dns(m, DNS_SERVERS);
if (r < 0)
return r;
r = manager_parse_config_file(m);
if (r < 0)
return r;
r = sd_event_default(&m->event);
if (r < 0)
return r;
sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
sd_event_set_watchdog(m->event, true);
*ret = m;
m = NULL;
return 0;
}
void manager_free(Manager *m) {
Address *address;
if (!m)
return;
sd_event_unref(m->event);
while ((address = m->fallback_dns)) {
LIST_REMOVE(addresses, m->fallback_dns, address);
free(address);
}
free(m);
}
static void append_dns(FILE *f, void *dns, unsigned char family, unsigned *count) {
char buf[INET6_ADDRSTRLEN];
const char *address;
assert(f);
assert(dns);
assert(count);
address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN);
if (!address) {
log_warning("Invalid DNS address. Ignoring.");
return;
}
if (*count == MAXNS)
fputs("# Too many DNS servers configured, the following entries "
"may be ignored\n", f);
fprintf(f, "nameserver %s\n", address);
(*count) ++;
}
int manager_update_resolv_conf(Manager *m) {
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ unsigned *indices = NULL;
Address *address;
unsigned count = 0;
int n, r, i;
assert(m);
r = fopen_temporary("/run/systemd/network/resolv.conf", &f, &temp_path);
if (r < 0)
return r;
fchmod(fileno(f), 0644);
fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n"
"# Third party programs must not access this file directly, but\n"
"# only through the symlink at /etc/resolv.conf. To manage\n"
"# resolv.conf(5) in a different way, replace the symlink by a\n"
"# static file or a different symlink.\n\n", f);
n = sd_network_get_ifindices(&indices);
if (n < 0)
n = 0;
for (i = 0; i < n; i++) {
_cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
struct in_addr *nameservers;
struct in6_addr *nameservers6;
size_t nameservers_size;
r = sd_network_dhcp_use_dns(indices[i]);
if (r > 0) {
r = sd_network_get_dhcp_lease(indices[i], &lease);
if (r >= 0) {
r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size);
if (r >= 0) {
unsigned j;
for (j = 0; j < nameservers_size; j++)
append_dns(f, &nameservers[j], AF_INET, &count);
}
}
}
r = sd_network_get_dns(indices[i], &nameservers, &nameservers_size);
if (r >= 0) {
unsigned j;
for (j = 0; j < nameservers_size; j++)
append_dns(f, &nameservers[j], AF_INET, &count);
free(nameservers);
}
r = sd_network_get_dns6(indices[i], &nameservers6, &nameservers_size);
if (r >= 0) {
unsigned j;
for (j = 0; j < nameservers_size; j++)
append_dns(f, &nameservers6[j], AF_INET6, &count);
free(nameservers6);
}
}
LIST_FOREACH(addresses, address, m->fallback_dns)
append_dns(f, &address->in_addr, address->family, &count);
fflush(f);
if (ferror(f) || rename(temp_path, "/run/systemd/network/resolv.conf") < 0) {
r = -errno;
unlink("/run/systemd/network/resolv.conf");
unlink(temp_path);
return r;
}
return 0;
}
static int manager_network_event_handler(sd_event_source *s, int fd, uint32_t revents,
void *userdata) {
Manager *m = userdata;
int r;
assert(m);
r = manager_update_resolv_conf(m);
if (r < 0)
log_warning("Could not update resolv.conf: %s", strerror(-r));
sd_network_monitor_flush(m->network_monitor);
return 0;
}
int manager_network_monitor_listen(Manager *m) {
_cleanup_event_source_unref_ sd_event_source *event_source = NULL;
_cleanup_network_monitor_unref_ sd_network_monitor *monitor = NULL;
int r, fd, events;
r = sd_network_monitor_new(NULL, &monitor);
if (r < 0)
return r;
fd = sd_network_monitor_get_fd(monitor);
if (fd < 0)
return fd;
events = sd_network_monitor_get_events(monitor);
if (events < 0)
return events;
r = sd_event_add_io(m->event, &event_source, fd, events,
&manager_network_event_handler, m);
if (r < 0)
return r;
m->network_monitor = monitor;
m->network_event_source = event_source;
monitor = NULL;
event_source = NULL;
return 0;
}

86
src/resolve/resolved.c

@ -0,0 +1,86 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2014 Tom Gundersen <teg@jklm.no>
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "sd-event.h"
#include "sd-daemon.h"
#include "resolved.h"
#include "mkdir.h"
int main(int argc, char *argv[]) {
_cleanup_manager_free_ Manager *m = NULL;
int r;
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
log_open();
umask(0022);
if (argc != 1) {
log_error("This program takes no arguments.");
r = -EINVAL;
goto out;
}
/* Always create the directory where resolv.conf will live */
r = mkdir_label("/run/systemd/network", 0755);
if (r < 0)
log_error("Could not create runtime directory: %s",
strerror(-r));
r = manager_new(&m);
if (r < 0) {
log_error("Could not create manager: %s", strerror(-r));
goto out;
}
r = manager_network_monitor_listen(m);
if (r < 0) {
log_error("Could not listen for network events: %s", strerror(-r));
goto out;
}
/* write out default resolv.conf to avoid a
* dangling symlink */
r = manager_update_resolv_conf(m);
if (r < 0) {
log_error("Could not create resolv.conf: %s", strerror(-r));
goto out;
}
sd_notify(false,
"READY=1\n"
"STATUS=Processing requests...");
r = sd_event_loop(m->event);
if (r < 0) {
log_error("Event loop failed: %s", strerror(-r));
goto out;
}
out:
sd_notify(false,
"STATUS=Shutting down...");
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}

4
src/network/networkd.conf.in → src/resolve/resolved.conf.in

@ -5,7 +5,7 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# See networkd.conf(5) for details
# See resolved.conf(5) for details
[Network]
[Resolve]
#DNS=@DNS_SERVERS@

69
src/resolve/resolved.h

@ -0,0 +1,69 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Tom Gundersen <teg@jklm.no>
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include "sd-event.h"
#include "sd-network.h"
#include "util.h"
#include "list.h"
typedef struct Address Address;
typedef struct Manager Manager;
struct Address {
unsigned char family;
union {
struct in_addr in;
struct in6_addr in6;
} in_addr;
LIST_FIELDS(Address, addresses);
};
struct Manager {
sd_event *event;
LIST_HEAD(Address, fallback_dns);
/* network */
sd_event_source *network_event_source;
sd_network_monitor *network_monitor;
};
/* Manager */
int manager_new(Manager **ret);
void manager_free(Manager *m);
int manager_update_resolv_conf(Manager *m);
int manager_network_monitor_listen(Manager *m);
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
#define _cleanup_manager_free_ _cleanup_(manager_freep)
const struct ConfigPerfItem* resolved_gperf_lookup(const char *key, unsigned length);
int config_parse_dnsv(const char *unit, const char *filename, unsigned line,
const char *section, unsigned section_line, const char *lvalue,
int ltype, const char *rvalue, void *data, void *userdata);

1
units/.gitignore

@ -49,6 +49,7 @@
/systemd-readahead-replay.service
/systemd-reboot.service
/systemd-remount-fs.service
/systemd-resolved.service
/systemd-rfkill@.service
/systemd-shutdownd.service
/systemd-suspend.service

21
units/systemd-resolved.service.in

@ -0,0 +1,21 @@
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Network Name Resolution
Documentation=man:systemd-resolved.service(8)
After=systemd-networkd.service network.service
[Service]
Type=notify
Restart=always
RestartSec=0
ExecStart=@rootlibexecdir@/systemd-resolved
CapabilityBoundingSet=
[Install]
WantedBy=multi-user.target
Loading…
Cancel
Save