Merge pull request #2437 from poettering/dnssec19

nineteenth dnssec patch
This commit is contained in:
Tom Gundersen 2016-01-26 18:07:19 +01:00
commit cfd77192c1
39 changed files with 723 additions and 464 deletions

View File

@ -24,7 +24,6 @@ right-away for being misfiled.
code. This is a requirement for all code we merge.
* Make sure to run "make check" locally, before posting your PR. We use a CI system, meaning we don't even look at your
PR, if the build and tests don't pass.
* If you need to update the code in a existing PR, please consider opening a new PR (mentioning in it which old PR it
replaces) and closing the old PR. This is much preferable over force-pushing a new patch set into the PR's branch, as
commit comments aren't lost that way. That said, we don't follow this rule ourselves quite often, hence this is

View File

@ -840,6 +840,7 @@ libbasic_la_SOURCES = \
src/basic/siphash24.h \
src/basic/set.h \
src/basic/ordered-set.h \
src/basic/ordered-set.c \
src/basic/bitmap.c \
src/basic/bitmap.h \
src/basic/fdset.c \

13
TODO
View File

@ -173,9 +173,9 @@ Features:
- use equvalent of cat() to insert existing config as a comment, prepended with #.
Upon editor exit, lines with one # are removed, lines with two # are left with one #, etc.
* exponential backoff in timesyncd and resolved when we cannot reach a server
* exponential backoff in timesyncd when we cannot reach a server
* timesyncd + resolved: add ugly bus calls to set NTP and DNS servers per-interface, for usage by NM
* timesyncd: add ugly bus calls to set NTP servers per-interface, for usage by NM
* extract_many_words() should probably be used by a lot of code that
currently uses FOREACH_WORD and friends. For example, most conf
@ -190,13 +190,7 @@ Features:
(throughout the codebase, not only PID1)
* resolved:
- put networkd events and rtnl events at a higher priority, so that
we always process them before we process client requests
- DNSSEC
- add display of private key types (http://tools.ietf.org/html/rfc4034#appendix-A.1.1)?
- synthesize negative cache entries from NSEC/NSEC3 and drop explicit negative caching of authenticated answers
- mDNS/DNS-SD
- mDNS RR resolving
- service registration
- service/domain/types browsing
- avahi compat
@ -204,7 +198,8 @@ Features:
- resolved should optionally register additional per-interface LLMNR
names, so that for the container case we can establish the same name
(maybe "host") for referencing the server, everywhere.
- add API so NM can push DNS server info into resolved
- enable DNSSEC by default
- allow clients to request DNSSEC for a single lookup even if DNSSEC is off (?)
* refcounting in sd-resolve is borked

View File

@ -294,15 +294,11 @@
<varlistentry>
<term><varname>RemoveIPC=</varname></term>
<listitem><para>Controls whether System V and POSIX IPC
objects belonging to the user shall be removed when the user
fully logs out. Takes a boolean argument. If enabled, the user
may not consume IPC resources after the last of the user's
sessions terminated. This covers System V semaphores, shared
memory and message queues, as well as POSIX shared memory and
message queues. Note that IPC objects of the root user are
excluded from the effect of this setting. Defaults to
<literal>yes</literal>.</para></listitem>
<listitem><para>Controls whether System V and POSIX IPC objects belonging to the user shall be removed when the
user fully logs out. Takes a boolean argument. If enabled, the user may not consume IPC resources after the
last of the user's sessions terminated. This covers System V semaphores, shared memory and message queues, as
well as POSIX shared memory and message queues. Note that IPC objects of the root user and other system users
are excluded from the effect of this setting. Defaults to <literal>yes</literal>.</para></listitem>
</varlistentry>
</variablelist>

View File

@ -72,40 +72,40 @@
<varlistentry>
<term><varname>DNS=</varname></term>
<listitem><para>A space-separated list of IPv4 and IPv6
addresses to be used as system DNS servers. DNS requests are
sent to one of the listed DNS servers in parallel to any
per-interface DNS servers acquired from
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
For compatibility reasons, if this setting is not specified,
the DNS servers listed in
<filename>/etc/resolv.conf</filename> are used instead, if
that file exists and any servers are configured in it. This
setting defaults to the empty list.</para></listitem>
<listitem><para>A space-separated list of IPv4 and IPv6 addresses to use as system DNS servers. DNS requests
are sent to one of the listed DNS servers in parallel to suitable per-link DNS servers acquired from
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> or
set at runtime by external applications. For compatibility reasons, if this setting is not specified, the DNS
servers listed in <filename>/etc/resolv.conf</filename> are used instead, if that file exists and any servers
are configured in it. This setting defaults to the empty list.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>FallbackDNS=</varname></term>
<listitem><para>A space-separated list of IPv4 and IPv6
addresses to be used as the fallback DNS servers. Any
per-interface DNS servers obtained from
<listitem><para>A space-separated list of IPv4 and IPv6 addresses to use as the fallback DNS servers. Any
per-link DNS servers obtained from
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
take precedence over this setting, as do any servers set via
<varname>DNS=</varname> above or
<filename>/etc/resolv.conf</filename>. This setting is hence
only used if no other DNS server information is known. If this
option is not given, a compiled-in list of DNS servers is used
instead.</para></listitem>
take precedence over this setting, as do any servers set via <varname>DNS=</varname> above or
<filename>/etc/resolv.conf</filename>. This setting is hence only used if no other DNS server information is
known. If this option is not given, a compiled-in list of DNS servers is used instead.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Domains=</varname></term>
<listitem><para>A space-separated list of search domains. For
compatibility reasons, if this setting is not specified, the
search domains listed in <filename>/etc/resolv.conf</filename>
are used instead, if that file exists and any domains are
configured in it. This setting defaults to the empty
list.</para></listitem>
<listitem><para>A space-separated list of domains. These domains are used as search suffixes when resolving
single-label host names (domain names which contain no dot), in order to qualify them into fully-qualified
domain names (FQDNs). Search domains are strictly processed in the order they are specified, until the name
with the suffix appended is found. For compatibility reasons, if this setting is not specified, the search
domains listed in <filename>/etc/resolv.conf</filename> are used instead, if that file exists and any domains
are configured in it. This setting defaults to the empty list.</para>
<para>Specified domain names may optionally be prefixed with <literal>~</literal>. In this case they do not
define a search path, but preferably direct DNS queries for the indicated domains to the DNS servers configured
with the system <varname>DNS=</varname> setting (see above), in case additional, suitable per-link DNS servers
are known. If no per-link DNS servers are known using the <literal>~</literal> syntax has no effect. Use the
construct <literal>~.</literal> (which is composed of <literal>~</literal> to indicate a routing domain and
<literal>.</literal> to indicate the DNS root domain that is the implied suffix of all DNS domains) to use the
system DNS server defined with <varname>DNS=</varname> preferably for all domains.</para></listitem>
</varlistentry>
<varlistentry>
@ -119,8 +119,8 @@
<literal>resolve</literal>, only resolution support is enabled,
but responding is disabled. Note that
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
also maintains per-interface LLMNR settings. LLMNR will be
enabled on an interface only if the per-interface and the
also maintains per-link LLMNR settings. LLMNR will be
enabled on a link only if the per-link and the
global setting is on.</para></listitem>
</varlistentry>
@ -181,9 +181,9 @@
<para>In addition to this global DNSSEC setting
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
also maintains per-interface DNSSEC settings. For system DNS
also maintains per-link DNSSEC settings. For system DNS
servers (see above), only the global DNSSEC setting is in
effect. For per-interface DNS servers the per-interface
effect. For per-link DNS servers the per-link
setting is in effect, unless it is unset in which case the
global setting is used instead.</para>

View File

@ -396,21 +396,37 @@
described in
<citerefentry project='man-pages'><refentrytitle>inet_pton</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
This option may be specified more than once. This setting is read by
<citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></para>
<citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Domains=</varname></term>
<listitem>
<para>The domains used for DNS resolution over this link. This setting is read by
<citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></para>
<para>The domains used for DNS host name resolution on this link. Takes a list of DNS domain names which
are used as search suffixes for extending single-label host names (host names containing no dots) to become
fully qualified domain names (FQDNs). If a single-label host name is resolved on this interface, each of
the specified search domains are appended to it in turn, converting it into a fully qualified domain name,
until one of them may be successfully resolved.</para>
<para>The specified domains are also used for routing of DNS queries: look-ups for host names ending in the
domains specified here are preferably routed to the DNS servers configured for this interface. If a domain
name is prefixed with <literal>~</literal>, the domain name becomes a pure "routing" domain, is used for
DNS query routing purposes only and is not used in the described domain search logic. By specifying a
routing domain of <literal>~.</literal> (the tilda indicating definition of a routing domain, the dot
referring to the DNS root domain which is the implied suffix of all valid DNS names) it is possible to
route all DNS traffic preferably to the DNS server specified for this interface. The route domain logic is
particularly useful on multi-homed hosts with DNS servers serving particular private DNS zones on each
interface.</para>
<para>This setting is read by
<citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>NTP=</varname></term>
<listitem>
<para>An NTP server address. This option may be specified more than once. This setting is read by
<citerefentry><refentrytitle>systemd-timesyncd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></para>
<citerefentry><refentrytitle>systemd-timesyncd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
</listitem>
</varlistentry>
<varlistentry>
@ -701,15 +717,20 @@
<varlistentry>
<term><varname>UseDomains=</varname></term>
<listitem>
<para>When true (not the default), the domain name
received from the DHCP server will be used for DNS
resolution over this link. When a name cannot be resolved
as specified, the domain name will be used a suffix and
name resolution of that will be attempted.</para>
<para>Takes a boolean argument, or a the special value <literal>route</literal>. When true, the domain name
received from the DHCP server will be used as DNS search domain over this link, similar to the effect of
the <option>Domains=</option> setting. If set to <literal>route</literal>, the domain name received from
the DHCP server will be used for routing DNS queries only, but not for searching, similar to the effect of
the <option>Domains=</option> setting when the argument is prefixed with <literal>~</literal>. Defaults to
false.</para>
<para>This corresponds to the <option>domain</option>
option in <citerefentry project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
and should not be enabled on untrusted networks.</para>
<para>It is recommended to enable this option only on trusted networks, as setting this affects resolution
of all host names, in particular to single-label names. It is generally safer to use the supplied domain
only as routing domain, rather than as search domain, in order to not have it affect local resolution of
single-label names.</para>
<para>When set to true, this setting corresponds to the <option>domain</option> option in <citerefentry
project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
</listitem>
</varlistentry>
<varlistentry>

View File

@ -1251,3 +1251,32 @@ int read_timestamp_file(const char *fn, usec_t *ret) {
*ret = (usec_t) t;
return 0;
}
int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space) {
int r;
assert(s);
/* Outputs the specified string with fputs(), but optionally prefixes it with a separator. The *space parameter
* when specified shall initially point to a boolean variable initialized to false. It is set to true after the
* first invocation. This call is supposed to be use in loops, where a separator shall be inserted between each
* element, but not before the first one. */
if (!f)
f = stdout;
if (space) {
if (!separator)
separator = " ";
if (*space) {
r = fputs(separator, f);
if (r < 0)
return r;
}
*space = true;
}
return fputs(s, f);
}

View File

@ -82,3 +82,5 @@ int tempfn_random_child(const char *p, const char *extra, char **ret);
int write_timestamp_file_atomic(const char *fn, usec_t n);
int read_timestamp_file(const char *fn, usec_t *ret);
int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space);

64
src/basic/ordered-set.c Normal file
View File

@ -0,0 +1,64 @@
/***
This file is part of systemd.
Copyright 2016 Lennart Poettering
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 "ordered-set.h"
#include "strv.h"
int ordered_set_consume(OrderedSet *s, void *p) {
int r;
r = ordered_set_put(s, p);
if (r <= 0)
free(p);
return r;
}
int ordered_set_put_strdup(OrderedSet *s, const char *p) {
char *c;
int r;
assert(s);
assert(p);
c = strdup(p);
if (!c)
return -ENOMEM;
r = ordered_set_consume(s, c);
if (r == -EEXIST)
return 0;
return r;
}
int ordered_set_put_strdupv(OrderedSet *s, char **l) {
int n = 0, r;
char **i;
STRV_FOREACH(i, l) {
r = ordered_set_put_strdup(s, *i);
if (r < 0)
return r;
n += r;
}
return n;
}

View File

@ -62,9 +62,15 @@ static inline bool ordered_set_iterate(OrderedSet *s, Iterator *i, void **value)
return ordered_hashmap_iterate((OrderedHashmap*) s, i, value, NULL);
}
int ordered_set_consume(OrderedSet *s, void *p);
int ordered_set_put_strdup(OrderedSet *s, const char *p);
int ordered_set_put_strdupv(OrderedSet *s, char **l);
#define ORDERED_SET_FOREACH(e, s, i) \
for ((i) = ITERATOR_FIRST; ordered_set_iterate((s), &(i), (void**)&(e)); )
DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedSet*, ordered_set_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedSet*, ordered_set_free_free);
#define _cleanup_ordered_set_free_ _cleanup_(ordered_set_freep)
#define _cleanup_ordered_set_free_free_ _cleanup_(ordered_set_free_freep)

View File

@ -29,6 +29,7 @@
#include "alloc-util.h"
#include "escape.h"
#include "extract-word.h"
#include "fileio.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
@ -871,3 +872,22 @@ rollback:
nl[k] = NULL;
return -ENOMEM;
}
int fputstrv(FILE *f, char **l, const char *separator, bool *space) {
bool b = false;
char **s;
int r;
/* Like fputs(), but for strv, and with a less stupid argument order */
if (!space)
space = &b;
STRV_FOREACH(s, l) {
r = fputs_with_space(f, *s, separator, space);
if (r < 0)
return r;
}
return 0;
}

View File

@ -169,3 +169,5 @@ char ***strv_free_free(char ***l);
char **strv_skip(char **l, size_t n);
int strv_extend_n(char ***l, const char *value, size_t n);
int fputstrv(FILE *f, char **l, const char *separator, bool *space);

View File

@ -794,6 +794,8 @@ int main(int argc, char* argv[]) {
IOVEC_SET_STRING(iovec[j++], core_timestamp);
IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
assert_cc(2 == LOG_CRIT);
IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
/* Vacuum before we write anything again */

View File

@ -372,6 +372,7 @@ static int fill_iovec_perror_and_send(const char *message, int skip, struct iove
xsprintf(error, "ERRNO=%i", _saved_errno_);
assert_cc(3 == LOG_ERR);
IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
IOVEC_SET_STRING(iov[skip+1], buffer);
IOVEC_SET_STRING(iov[skip+2], error);

View File

@ -397,8 +397,8 @@ static void process_audit_string(Server *s, int type, const char *data, size_t s
sprintf(id_field, "_AUDIT_ID=%" PRIu64, id);
IOVEC_SET_STRING(iov[n_iov++], id_field);
assert_cc(32 == LOG_AUTH);
IOVEC_SET_STRING(iov[n_iov++], "SYSLOG_FACILITY=32");
assert_cc(4 == LOG_FAC(LOG_AUTH));
IOVEC_SET_STRING(iov[n_iov++], "SYSLOG_FACILITY=4");
IOVEC_SET_STRING(iov[n_iov++], "SYSLOG_IDENTIFIER=audit");
type_name = audit_type_name_alloca(type);

View File

@ -866,10 +866,12 @@ void server_driver_message(Server *s, sd_id128_t message_id, const char *format,
assert(s);
assert(format);
assert_cc(3 == LOG_FAC(LOG_DAEMON));
IOVEC_SET_STRING(iovec[n++], "SYSLOG_FACILITY=3");
IOVEC_SET_STRING(iovec[n++], "SYSLOG_IDENTIFIER=systemd-journald");
IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=driver");
assert_cc(6 == LOG_INFO);
IOVEC_SET_STRING(iovec[n++], "PRIORITY=6");
if (!sd_id128_equal(message_id, SD_ID128_NULL)) {

View File

@ -353,6 +353,38 @@ static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
return 0;
}
static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) {
_cleanup_free_ char *name = NULL, *normalized = NULL;
int r;
assert(option);
assert(ret);
r = lease_parse_string(option, len, &name);
if (r < 0)
return r;
if (!name) {
*ret = mfree(*ret);
return 0;
}
r = dns_name_normalize(name, &normalized);
if (r < 0)
return r;
if (is_localhost(normalized))
return -EINVAL;
if (dns_name_is_root(normalized))
return -EINVAL;
free(*ret);
*ret = normalized;
normalized = NULL;
return 0;
}
static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) {
assert(option);
assert(ret);
@ -547,59 +579,23 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
log_debug_errno(r, "Failed to parse MTU, ignoring: %m");
break;
case SD_DHCP_OPTION_DOMAIN_NAME: {
_cleanup_free_ char *domainname = NULL, *normalized = NULL;
r = lease_parse_string(option, len, &domainname);
case SD_DHCP_OPTION_DOMAIN_NAME:
r = lease_parse_domain(option, len, &lease->domainname);
if (r < 0) {
log_debug_errno(r, "Failed to parse domain name, ignoring: %m");
return 0;
}
r = dns_name_normalize(domainname, &normalized);
if (r < 0) {
log_debug_errno(r, "Failed to normalize domain name '%s': %m", domainname);
return 0;
}
if (is_localhost(normalized)) {
log_debug_errno(r, "Detected 'localhost' as suggested domain name, ignoring.");
break;
}
free(lease->domainname);
lease->domainname = normalized;
normalized = NULL;
break;
}
case SD_DHCP_OPTION_HOST_NAME: {
_cleanup_free_ char *hostname = NULL, *normalized = NULL;
r = lease_parse_string(option, len, &hostname);
case SD_DHCP_OPTION_HOST_NAME:
r = lease_parse_domain(option, len, &lease->hostname);
if (r < 0) {
log_debug_errno(r, "Failed to parse host name, ignoring: %m");
return 0;
}
r = dns_name_normalize(hostname, &normalized);
if (r < 0) {
log_debug_errno(r, "Failed to normalize host name '%s', ignoring: %m", hostname);
return 0;
}
if (is_localhost(normalized)) {
log_debug_errno(r, "Detected 'localhost' as suggested host name, ignoring.");
return 0;
}
free(lease->hostname);
lease->hostname = normalized;
normalized = NULL;
break;
}
case SD_DHCP_OPTION_ROOT_PATH:
r = lease_parse_string(option, len, &lease->root_path);

View File

@ -95,10 +95,14 @@ _public_ int sd_network_get_ntp(char ***ret) {
return network_get_strv("NTP", ret);
}
_public_ int sd_network_get_domains(char ***ret) {
_public_ int sd_network_get_search_domains(char ***ret) {
return network_get_strv("DOMAINS", ret);
}
_public_ int sd_network_get_route_domains(char ***ret) {
return network_get_strv("ROUTE_DOMAINS", ret);
}
static int network_link_get_string(int ifindex, const char *field, char **ret) {
_cleanup_free_ char *s = NULL, *p = NULL;
int r;
@ -222,10 +226,14 @@ _public_ int sd_network_link_get_ntp(int ifindex, char ***ret) {
return network_link_get_strv(ifindex, "NTP", ret);
}
_public_ int sd_network_link_get_domains(int ifindex, char ***ret) {
_public_ int sd_network_link_get_search_domains(int ifindex, char ***ret) {
return network_link_get_strv(ifindex, "DOMAINS", ret);
}
_public_ int sd_network_link_get_route_domains(int ifindex, char ***ret) {
return network_link_get_strv(ifindex, "ROUTE_DOMAINS", ret);
}
_public_ int sd_network_link_get_carrier_bound_to(int ifindex, char ***ret) {
return network_link_get_strv(ifindex, "CARRIER_BOUND_TO", ret);
}
@ -234,26 +242,6 @@ _public_ int sd_network_link_get_carrier_bound_by(int ifindex, char ***ret) {
return network_link_get_strv(ifindex, "CARRIER_BOUND_BY", ret);
}
_public_ int sd_network_link_get_wildcard_domain(int ifindex) {
_cleanup_free_ char *p = NULL, *s = NULL;
int r;
assert_return(ifindex > 0, -EINVAL);
if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
return -ENOMEM;
r = parse_env_file(p, NEWLINE, "WILDCARD_DOMAIN", &s, NULL);
if (r == -ENOENT)
return -ENODATA;
if (r < 0)
return r;
if (isempty(s))
return -ENODATA;
return parse_boolean(s);
}
static inline int MONITOR_TO_FD(sd_network_monitor *m) {
return (int) (unsigned long) m - 1;
}

View File

@ -490,6 +490,9 @@ static int dump_addresses(
static void dump_list(const char *prefix, char **l) {
char **i;
if (strv_isempty(l))
return;
STRV_FOREACH(i, l) {
printf("%*s%s\n",
(int) strlen(prefix),
@ -502,7 +505,7 @@ static int link_status_one(
sd_netlink *rtnl,
sd_hwdb *hwdb,
const char *name) {
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL;
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
@ -552,7 +555,6 @@ static int link_status_one(
return rtnl_log_parse_error(r);
have_mac = sd_netlink_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
if (have_mac) {
const uint8_t *p;
bool all_zeroes = true;
@ -567,44 +569,35 @@ static int link_status_one(
have_mac = false;
}
sd_netlink_message_read_u32(reply, IFLA_MTU, &mtu);
(void) sd_netlink_message_read_u32(reply, IFLA_MTU, &mtu);
sd_network_link_get_operational_state(ifindex, &operational_state);
(void) sd_network_link_get_operational_state(ifindex, &operational_state);
operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
sd_network_link_get_setup_state(ifindex, &setup_state);
(void) sd_network_link_get_setup_state(ifindex, &setup_state);
setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
sd_network_link_get_dns(ifindex, &dns);
sd_network_link_get_domains(ifindex, &domains);
r = sd_network_link_get_wildcard_domain(ifindex);
if (r > 0) {
char *wildcard;
wildcard = strdup("*");
if (!wildcard)
return log_oom();
if (strv_consume(&domains, wildcard) < 0)
return log_oom();
}
(void) sd_network_link_get_dns(ifindex, &dns);
(void) sd_network_link_get_search_domains(ifindex, &search_domains);
(void) sd_network_link_get_route_domains(ifindex, &route_domains);
(void) sd_network_link_get_ntp(ifindex, &ntp);
sprintf(devid, "n%i", ifindex);
(void)sd_device_new_from_device_id(&d, devid);
(void) sd_device_new_from_device_id(&d, devid);
if (d) {
(void)sd_device_get_property_value(d, "ID_NET_LINK_FILE", &link);
(void)sd_device_get_property_value(d, "ID_NET_DRIVER", &driver);
(void)sd_device_get_property_value(d, "ID_PATH", &path);
(void) sd_device_get_property_value(d, "ID_NET_LINK_FILE", &link);
(void) sd_device_get_property_value(d, "ID_NET_DRIVER", &driver);
(void) sd_device_get_property_value(d, "ID_PATH", &path);
r = sd_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE", &vendor);
if (r < 0)
(void)sd_device_get_property_value(d, "ID_VENDOR", &vendor);
(void) sd_device_get_property_value(d, "ID_VENDOR", &vendor);
r = sd_device_get_property_value(d, "ID_MODEL_FROM_DATABASE", &model);
if (r < 0)
(void)sd_device_get_property_value(d, "ID_MODEL", &model);
(void) sd_device_get_property_value(d, "ID_MODEL", &model);
}
link_get_type_string(iftype, d, &t);
@ -653,20 +646,14 @@ static int link_status_one(
dump_addresses(rtnl, " Address: ", ifindex);
dump_gateways(rtnl, hwdb, " Gateway: ", ifindex);
if (!strv_isempty(dns))
dump_list(" DNS: ", dns);
if (!strv_isempty(domains))
dump_list(" Domain: ", domains);
dump_list(" DNS: ", dns);
dump_list(" Search Domains: ", search_domains);
dump_list(" Route Domains: ", route_domains);
(void) sd_network_link_get_ntp(ifindex, &ntp);
if (!strv_isempty(ntp))
dump_list(" NTP: ", ntp);
dump_list(" NTP: ", ntp);
if (!strv_isempty(carrier_bound_to))
dump_list("Carrier Bound To: ", carrier_bound_to);
if (!strv_isempty(carrier_bound_by))
dump_list("Carrier Bound By: ", carrier_bound_by);
dump_list("Carrier Bound To: ", carrier_bound_to);
dump_list("Carrier Bound By: ", carrier_bound_by);
(void) sd_network_link_get_timezone(ifindex, &tz);
if (tz)
@ -691,30 +678,30 @@ static int link_status(int argc, char *argv[], void *userdata) {
if (argc <= 1 && !arg_all) {
_cleanup_free_ char *operational_state = NULL;
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains;
const char *on_color_operational, *off_color_operational;
sd_network_get_operational_state(&operational_state);
operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
printf("%s%s%s State: %s%s%s\n",
printf("%s%s%s State: %s%s%s\n",
on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational,
on_color_operational, strna(operational_state), off_color_operational);
dump_addresses(rtnl, " Address: ", 0);
dump_gateways(rtnl, hwdb, " Gateway: ", 0);
dump_addresses(rtnl, " Address: ", 0);
dump_gateways(rtnl, hwdb, " Gateway: ", 0);
sd_network_get_dns(&dns);
if (!strv_isempty(dns))
dump_list(" DNS: ", dns);
dump_list(" DNS: ", dns);
sd_network_get_domains(&domains);
if (!strv_isempty(domains))
dump_list(" Domain: ", domains);
sd_network_get_search_domains(&search_domains);
dump_list("Search Domains: ", search_domains);
sd_network_get_route_domains(&route_domains);
dump_list(" Route Domains: ", route_domains);
sd_network_get_ntp(&ntp);
if (!strv_isempty(ntp))
dump_list(" NTP: ", ntp);
dump_list(" NTP: ", ntp);
return 0;
}

View File

@ -158,7 +158,7 @@ static int dhcp_lease_lost(Link *link) {
log_link_warning(link, "DHCP lease lost");
if (link->network->dhcp_routes) {
if (link->network->dhcp_use_routes) {
_cleanup_free_ sd_dhcp_route **routes = NULL;
int n, i;
@ -223,7 +223,7 @@ static int dhcp_lease_lost(Link *link) {
}
}
if (link->network->dhcp_mtu) {
if (link->network->dhcp_use_mtu) {
uint16_t mtu;
r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
@ -238,11 +238,11 @@ static int dhcp_lease_lost(Link *link) {
}
}
if (link->network->dhcp_hostname) {
if (link->network->dhcp_use_hostname) {
const char *hostname = NULL;
if (link->network->hostname)
hostname = link->network->hostname;
if (link->network->dhcp_hostname)
hostname = link->network->dhcp_hostname;
else
(void) sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
@ -412,7 +412,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
link->dhcp_lease = sd_dhcp_lease_ref(lease);
link_dirty(link);
if (link->network->dhcp_mtu) {
if (link->network->dhcp_use_mtu) {
uint16_t mtu;
r = sd_dhcp_lease_get_mtu(lease, &mtu);
@ -423,11 +423,11 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
}
}
if (link->network->dhcp_hostname) {
if (link->network->dhcp_use_hostname) {
const char *hostname = NULL;
if (link->network->hostname)
hostname = link->network->hostname;
if (link->network->dhcp_hostname)
hostname = link->network->dhcp_hostname;
else
(void) sd_dhcp_lease_get_hostname(lease, &hostname);
@ -438,7 +438,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
}
}
if (link->network->dhcp_timezone) {
if (link->network->dhcp_use_timezone) {
const char *tz = NULL;
(void) sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
@ -571,14 +571,14 @@ int dhcp4_configure(Link *link) {
return r;
}
if (link->network->dhcp_mtu) {
if (link->network->dhcp_use_mtu) {
r = sd_dhcp_client_set_request_option(link->dhcp_client,
SD_DHCP_OPTION_INTERFACE_MTU);
if (r < 0)
return r;
}
if (link->network->dhcp_routes) {
if (link->network->dhcp_use_routes) {
r = sd_dhcp_client_set_request_option(link->dhcp_client,
SD_DHCP_OPTION_STATIC_ROUTE);
if (r < 0)
@ -589,7 +589,7 @@ int dhcp4_configure(Link *link) {
return r;
}
/* Always acquire the timezone and NTP*/
/* Always acquire the timezone and NTP */
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
if (r < 0)
return r;
@ -598,18 +598,18 @@ int dhcp4_configure(Link *link) {
if (r < 0)
return r;
if (link->network->dhcp_sendhost) {
if (link->network->dhcp_send_hostname) {
_cleanup_free_ char *hostname = NULL;
const char *hn = NULL;
if (!link->network->hostname) {
if (!link->network->dhcp_hostname) {
hostname = gethostname_malloc();
if (!hostname)
return -ENOMEM;
hn = hostname;
} else
hn = link->network->hostname;
hn = link->network->dhcp_hostname;
if (!is_localhost(hn)) {
r = sd_dhcp_client_set_hostname(link->dhcp_client, hn);

View File

@ -767,7 +767,7 @@ static int link_push_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) {
addresses[n_addresses++] = ia;
}
if (link->network->dhcp_dns &&
if (link->network->dhcp_use_dns &&
link->dhcp_lease) {
const struct in_addr *da = NULL;
int n;
@ -812,7 +812,7 @@ static int link_push_ntp_to_dhcp_server(Link *link, sd_dhcp_server *s) {
addresses[n_addresses++] = ia;
}
if (link->network->dhcp_ntp &&
if (link->network->dhcp_use_ntp &&
link->dhcp_lease) {
const struct in_addr *da = NULL;
int n;
@ -2729,9 +2729,10 @@ int link_save(Link *link) {
admin_state, oper_state);
if (link->network) {
char **address, **domain;
bool space;
sd_dhcp6_lease *dhcp6_lease = NULL;
const char *dhcp_domainname = NULL;
char **dhcp6_domains = NULL;
if (link->dhcp6_client) {
r = sd_dhcp6_client_get_lease(link->dhcp6_client, &dhcp6_lease);
@ -2743,14 +2744,9 @@ int link_save(Link *link) {
fputs("DNS=", f);
space = false;
STRV_FOREACH(address, link->network->dns) {
if (space)
fputc(' ', f);
fputs(*address, f);
space = true;
}
fputstrv(f, link->network->dns, NULL, &space);
if (link->network->dhcp_dns &&
if (link->network->dhcp_use_dns &&
link->dhcp_lease) {
const struct in_addr *addresses;
@ -2763,7 +2759,7 @@ int link_save(Link *link) {
}
}
if (link->network->dhcp_dns && dhcp6_lease) {
if (link->network->dhcp_use_dns && dhcp6_lease) {
struct in6_addr *in6_addrs;
r = sd_dhcp6_lease_get_dns(dhcp6_lease, &in6_addrs);
@ -2778,14 +2774,9 @@ int link_save(Link *link) {
fputs("NTP=", f);
space = false;
STRV_FOREACH(address, link->network->ntp) {
if (space)
fputc(' ', f);
fputs(*address, f);
space = true;
}
fputstrv(f, link->network->ntp, NULL, &space);
if (link->network->dhcp_ntp &&
if (link->network->dhcp_use_ntp &&
link->dhcp_lease) {
const struct in_addr *addresses;
@ -2798,10 +2789,9 @@ int link_save(Link *link) {
}
}
if (link->network->dhcp_ntp && dhcp6_lease) {
if (link->network->dhcp_use_ntp && dhcp6_lease) {
struct in6_addr *in6_addrs;
char **hosts;
char **hostname;
r = sd_dhcp6_lease_get_ntp_addrs(dhcp6_lease,
&in6_addrs);
@ -2813,58 +2803,41 @@ int link_save(Link *link) {
}
r = sd_dhcp6_lease_get_ntp_fqdn(dhcp6_lease, &hosts);
if (r > 0) {
STRV_FOREACH(hostname, hosts) {
if (space)
fputc(' ', f);
fputs(*hostname, f);
space = true;
}
}
if (r > 0)
fputstrv(f, hosts, NULL, &space);
}
fputc('\n', f);
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
if (link->dhcp_lease)
(void) sd_dhcp_lease_get_domainname(link->dhcp_lease, &dhcp_domainname);
if (dhcp6_lease)
(void) sd_dhcp6_lease_get_domains(dhcp6_lease, &dhcp6_domains);
}
fputs("DOMAINS=", f);
space = false;
STRV_FOREACH(domain, link->network->domains) {
if (space)
fputc(' ', f);
fputs(*domain, f);
space = true;
}
fputstrv(f, link->network->search_domains, NULL, &space);
if (link->network->dhcp_domains &&
link->dhcp_lease) {
const char *domainname;
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES && dhcp_domainname)
fputs_with_space(f, dhcp_domainname, NULL, &space);
r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
if (r >= 0) {
if (space)
fputc(' ', f);
fputs(domainname, f);
space = true;
}
}
if (link->network->dhcp_domains && dhcp6_lease) {
char **domains;
r = sd_dhcp6_lease_get_domains(dhcp6_lease, &domains);
if (r >= 0) {
STRV_FOREACH(domain, domains) {
if (space)
fputc(' ', f);
fputs(*domain, f);
space = true;
}
}
}
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES && dhcp6_domains)
fputstrv(f, dhcp6_domains, NULL, &space);
fputc('\n', f);
fprintf(f, "WILDCARD_DOMAIN=%s\n",
yes_no(link->network->wildcard_domain));
fputs("ROUTE_DOMAINS=", f);
fputstrv(f, link->network->route_domains, NULL, NULL);
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE && dhcp_domainname)
fputs_with_space(f, dhcp_domainname, NULL, &space);
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE && dhcp6_domains)
fputstrv(f, dhcp6_domains, NULL, &space);
fputc('\n', f);
fprintf(f, "LLMNR=%s\n",
resolve_support_to_string(link->network->llmnr));
@ -2880,12 +2853,8 @@ int link_save(Link *link) {
fputs("DNSSEC_NTA=", f);
space = false;
SET_FOREACH(n, link->network->dnssec_negative_trust_anchors, i) {
if (space)
fputc(' ', f);
fputs(n, f);
space = true;
}
SET_FOREACH(n, link->network->dnssec_negative_trust_anchors, i)
fputs_with_space(f, n, NULL, &space);
fputc('\n', f);
}
@ -2925,12 +2894,8 @@ int link_save(Link *link) {
bool space = false;
fputs("CARRIER_BOUND_TO=", f);
HASHMAP_FOREACH(carrier, link->bound_to_links, i) {
if (space)
fputc(' ', f);
fputs(carrier->ifname, f);
space = true;
}
HASHMAP_FOREACH(carrier, link->bound_to_links, i)
fputs_with_space(f, carrier->ifname, NULL, &space);
fputc('\n', f);
}
@ -2940,12 +2905,8 @@ int link_save(Link *link) {
bool space = false;
fputs("CARRIER_BOUND_BY=", f);
HASHMAP_FOREACH(carrier, link->bound_by_links, i) {
if (space)
fputc(' ', f);
fputs(carrier->ifname, f);
space = true;
}
HASHMAP_FOREACH(carrier, link->bound_by_links, i)
fputs_with_space(f, carrier->ifname, NULL, &space);
fputc('\n', f);
}

View File

@ -29,12 +29,14 @@
#include "bus-util.h"
#include "conf-parser.h"
#include "def.h"
#include "dns-domain.h"
#include "fd-util.h"
#include "fileio.h"
#include "libudev-private.h"
#include "local-addresses.h"
#include "netlink-util.h"
#include "networkd.h"
#include "ordered-set.h"
#include "path-util.h"
#include "set.h"
#include "udev-util.h"
@ -776,7 +778,7 @@ static int manager_connect_rtnl(Manager *m) {
return 0;
}
static int set_put_in_addr(Set *s, const struct in_addr *address) {
static int ordered_set_put_in_addr(OrderedSet *s, const struct in_addr *address) {
char *p;
int r;
@ -786,21 +788,21 @@ static int set_put_in_addr(Set *s, const struct in_addr *address) {
if (r < 0)
return r;
r = set_consume(s, p);
r = ordered_set_consume(s, p);
if (r == -EEXIST)
return 0;
return r;
}
static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) {
static int ordered_set_put_in_addrv(OrderedSet *s, const struct in_addr *addresses, int n) {
int r, i, c = 0;
assert(s);
assert(n <= 0 || addresses);
for (i = 0; i < n; i++) {
r = set_put_in_addr(s, addresses+i);
r = ordered_set_put_in_addr(s, addresses+i);
if (r < 0)
return r;
@ -810,27 +812,24 @@ static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) {
return c;
}
static void print_string_set(FILE *f, const char *field, Set *s) {
static void print_string_set(FILE *f, const char *field, OrderedSet *s) {
bool space = false;
Iterator i;
char *p;
if (set_isempty(s))
if (ordered_set_isempty(s))
return;
fputs(field, f);
SET_FOREACH(p, s, i) {
if (space)
fputc(' ', f);
fputs(p, f);
space = true;
}
ORDERED_SET_FOREACH(p, s, i)
fputs_with_space(f, p, NULL, &space);
fputc('\n', f);
}
static int manager_save(Manager *m) {
_cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL;
_cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *search_domains = NULL, *route_domains = NULL;
Link *link;
Iterator i;
_cleanup_free_ char *temp_path = NULL;
@ -843,16 +842,20 @@ static int manager_save(Manager *m) {
assert(m->state_file);
/* We add all NTP and DNS server to a set, to filter out duplicates */
dns = set_new(&string_hash_ops);
dns = ordered_set_new(&string_hash_ops);
if (!dns)
return -ENOMEM;
ntp = set_new(&string_hash_ops);
ntp = ordered_set_new(&string_hash_ops);
if (!ntp)
return -ENOMEM;
domains = set_new(&string_hash_ops);
if (!domains)
search_domains = ordered_set_new(&dns_name_hash_ops);
if (!search_domains)
return -ENOMEM;
route_domains = ordered_set_new(&dns_name_hash_ops);
if (!route_domains)
return -ENOMEM;
HASHMAP_FOREACH(link, m->links, i) {
@ -866,15 +869,19 @@ static int manager_save(Manager *m) {
continue;
/* First add the static configured entries */
r = set_put_strdupv(dns, link->network->dns);
r = ordered_set_put_strdupv(dns, link->network->dns);
if (r < 0)
return r;
r = set_put_strdupv(ntp, link->network->ntp);
r = ordered_set_put_strdupv(ntp, link->network->ntp);
if (r < 0)
return r;
r = set_put_strdupv(domains, link->network->domains);
r = ordered_set_put_strdupv(search_domains, link->network->search_domains);
if (r < 0)
return r;
r = ordered_set_put_strdupv(route_domains, link->network->route_domains);
if (r < 0)
return r;
@ -882,36 +889,41 @@ static int manager_save(Manager *m) {
continue;
/* Secondly, add the entries acquired via DHCP */
if (link->network->dhcp_dns) {
if (link->network->dhcp_use_dns) {
const struct in_addr *addresses;
r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
if (r > 0) {
r = set_put_in_addrv(dns, addresses, r);
r = ordered_set_put_in_addrv(dns, addresses, r);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
return r;
}
if (link->network->dhcp_ntp) {
if (link->network->dhcp_use_ntp) {
const struct in_addr *addresses;
r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
if (r > 0) {
r = set_put_in_addrv(ntp, addresses, r);
r = ordered_set_put_in_addrv(ntp, addresses, r);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
return r;
}
if (link->network->dhcp_domains) {
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
const char *domainname;
r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
if (r >= 0) {
r = set_put_strdup(domains, domainname);
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES)
r = ordered_set_put_strdup(search_domains, domainname);
else
r = ordered_set_put_strdup(route_domains, domainname);
if (r < 0)
return r;
} else if (r != -ENODATA)
@ -934,7 +946,8 @@ static int manager_save(Manager *m) {
print_string_set(f, "DNS=", dns);
print_string_set(f, "NTP=", ntp);
print_string_set(f, "DOMAINS=", domains);
print_string_set(f, "DOMAINS=", search_domains);
print_string_set(f, "ROUTE_DOMAINS=", route_domains);
r = fflush_and_check(f);
if (r < 0)

View File

@ -43,7 +43,7 @@ Network.IPv6Token, config_parse_ipv6token,
Network.LLDP, config_parse_bool, 0, offsetof(Network, lldp)
Network.Address, config_parse_address, 0, 0
Network.Gateway, config_parse_gateway, 0, 0
Network.Domains, config_parse_domains, 0, offsetof(Network, domains)
Network.Domains, config_parse_domains, 0, 0
Network.DNS, config_parse_strv, 0, offsetof(Network, dns)
Network.LLMNR, config_parse_resolve_support, 0, offsetof(Network, llmnr)
Network.MulticastDNS, config_parse_resolve_support, 0, offsetof(Network, mdns)
@ -68,19 +68,19 @@ Route.Metric, config_parse_route_priority,
Route.Scope, config_parse_route_scope, 0, 0
Route.PreferredSource, config_parse_preferred_src, 0, 0
DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier)
DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns)
DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_ntp)
DHCP.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu)
DHCP.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname)
DHCP.UseDomains, config_parse_bool, 0, offsetof(Network, dhcp_domains)
DHCP.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_routes)
DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_sendhost)
DHCP.Hostname, config_parse_hostname, 0, offsetof(Network, hostname)
DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_use_dns)
DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_use_ntp)
DHCP.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_use_mtu)
DHCP.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_use_hostname)
DHCP.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains)
DHCP.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_use_routes)
DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_send_hostname)
DHCP.Hostname, config_parse_hostname, 0, offsetof(Network, dhcp_hostname)
DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast)
DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical)
DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)
DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_timezone)
DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone)
DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec)
DHCPServer.DefaultLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec)
DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_dns)
@ -101,9 +101,9 @@ BridgeFDB.MACAddress, config_parse_fdb_hwaddr,
BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0
/* backwards compatibility: do not add new entries to this section */
Network.IPv4LL, config_parse_ipv4ll, 0, offsetof(Network, link_local)
DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns)
DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu)
DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname)
DHCP.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains)
DHCPv4.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains)
DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_use_dns)
DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_use_mtu)
DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_use_hostname)
DHCP.UseDomainName, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains)
DHCPv4.UseDomainName, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains)
DHCPv4.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical)

View File

@ -105,11 +105,11 @@ static int network_load_one(Manager *manager, const char *filename) {
*d = '\0';
network->dhcp = ADDRESS_FAMILY_NO;
network->dhcp_ntp = true;
network->dhcp_dns = true;
network->dhcp_hostname = true;
network->dhcp_routes = true;
network->dhcp_sendhost = true;
network->dhcp_use_ntp = true;
network->dhcp_use_dns = true;
network->dhcp_use_hostname = true;
network->dhcp_use_routes = true;
network->dhcp_send_hostname = true;
network->dhcp_route_metric = DHCP_ROUTE_METRIC;
network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
@ -227,13 +227,14 @@ void network_free(Network *network) {
free(network->description);
free(network->dhcp_vendor_class_identifier);
free(network->hostname);
free(network->dhcp_hostname);
free(network->mac);
strv_free(network->ntp);
strv_free(network->dns);
strv_free(network->domains);
strv_free(network->search_domains);
strv_free(network->route_domains);
strv_free(network->bind_carrier);
netdev_unref(network->bridge);
@ -384,7 +385,10 @@ int network_apply(Manager *manager, Network *network, Link *link) {
route->protocol = RTPROT_STATIC;
}
if (network->dns || network->ntp || network->domains) {
if (!strv_isempty(network->dns) ||
!strv_isempty(network->ntp) ||
!strv_isempty(network->search_domains) ||
!strv_isempty(network->route_domains)) {
manager_dirty(manager);
link_dirty(link);
}
@ -469,49 +473,85 @@ int config_parse_netdev(const char *unit,
return 0;
}
int config_parse_domains(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) {
Network *network = userdata;
char ***domains = data;
char **domain;
int config_parse_domains(
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) {
const char *p;
Network *n = data;
int r;
r = config_parse_strv(unit, filename, line, section, section_line,
lvalue, ltype, rvalue, domains, userdata);
if (r < 0)
return r;
assert(n);
assert(lvalue);
assert(rvalue);
strv_uniq(*domains);
network->wildcard_domain = !!strv_find(*domains, "*");
if (isempty(rvalue)) {
n->search_domains = strv_free(n->search_domains);
n->route_domains = strv_free(n->route_domains);
return 0;
}
STRV_FOREACH(domain, *domains) {
if (is_localhost(*domain))
log_syntax(unit, LOG_ERR, filename, line, 0, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
else {
r = dns_name_is_valid(*domain);
if (r <= 0 && !streq(*domain, "*")) {
if (r < 0)
log_error_errno(r, "Failed to validate domain name: %s: %m", *domain);
if (r == 0)
log_warning("Domain name is not valid, ignoring assignment: %s", *domain);
} else
p = rvalue;
for (;;) {
_cleanup_free_ char *w = NULL, *normalized = NULL;
const char *domain;
bool is_route;
r = extract_first_word(&p, &w, NULL, 0);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract search or route domain, ignoring: %s", rvalue);
break;
}
if (r == 0)
break;
is_route = w[0] == '~';
domain = is_route ? w + 1 : w;
if (dns_name_is_root(domain) || streq(domain, "*")) {
/* If the root domain appears as is, or the special token "*" is found, we'll consider this as
* routing domain, unconditionally. */
is_route = true;
domain = "."; /* make sure we don't allow empty strings, thus write the root domain as "." */
} else {
r = dns_name_normalize(domain, &normalized);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "'%s' is not a valid domain name, ignoring.", domain);
continue;
}
domain = normalized;
if (is_localhost(domain)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "'localhost' domain names may not be configure as search or route domains, ignoring assignment: %s", domain);
continue;
}
}
strv_remove(*domains, *domain);
if (is_route) {
r = strv_extend(&n->route_domains, domain);
if (r < 0)
return log_oom();
/* We removed one entry, make sure we don't skip the next one */
domain--;
} else {
r = strv_extend(&n->search_domains, domain);
if (r < 0)
return log_oom();
}
}
strv_uniq(n->route_domains);
strv_uniq(n->search_domains);
return 0;
}
@ -930,7 +970,7 @@ int config_parse_dnssec_negative_trust_anchors(
Network *n = data;
int r;
assert(filename);
assert(n);
assert(lvalue);
assert(rvalue);
@ -965,3 +1005,13 @@ int config_parse_dnssec_negative_trust_anchors(
return 0;
}
DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting");
static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
[DHCP_USE_DOMAINS_NO] = "no",
[DHCP_USE_DOMAINS_ROUTE] = "route",
[DHCP_USE_DOMAINS_YES] = "yes",
};
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);

View File

@ -52,6 +52,14 @@ typedef enum IPv6PrivacyExtensions {
_IPV6_PRIVACY_EXTENSIONS_INVALID = -1,
} IPv6PrivacyExtensions;
typedef enum DHCPUseDomains {
DHCP_USE_DOMAINS_NO,
DHCP_USE_DOMAINS_YES,
DHCP_USE_DOMAINS_ROUTE,
_DHCP_USE_DOMAINS_MAX,
_DHCP_USE_DOMAINS_INVALID = -1,
} DHCPUseDomains;
struct Network {
Manager *manager;
@ -79,17 +87,17 @@ struct Network {
AddressFamilyBoolean dhcp;
DCHPClientIdentifier dhcp_client_identifier;
char *dhcp_vendor_class_identifier;
char *hostname;
bool dhcp_dns;
bool dhcp_ntp;
bool dhcp_mtu;
bool dhcp_hostname;
bool dhcp_domains;
bool dhcp_sendhost;
char *dhcp_hostname;
bool dhcp_use_dns;
bool dhcp_use_ntp;
bool dhcp_use_mtu;
bool dhcp_use_hostname;
DHCPUseDomains dhcp_use_domains;
bool dhcp_send_hostname;
bool dhcp_broadcast;
bool dhcp_critical;
bool dhcp_routes;
bool dhcp_timezone;
bool dhcp_use_routes;
bool dhcp_use_timezone;
unsigned dhcp_route_metric;
/* DHCP Server Support */
@ -141,8 +149,7 @@ struct Network {
Hashmap *routes_by_section;
Hashmap *fdb_entries_by_section;
bool wildcard_domain;
char **domains, **dns, **ntp, **bind_carrier;
char **search_domains, **route_domains, **dns, **ntp, **bind_carrier;
ResolveSupport llmnr;
ResolveSupport mdns;
@ -175,6 +182,7 @@ int config_parse_timezone(const char *unit, const char *filename, unsigned line,
int config_parse_dhcp_server_dns(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);
int config_parse_dhcp_server_ntp(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);
int config_parse_dnssec_negative_trust_anchors(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);
int config_parse_dhcp_use_domains(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);
/* Legacy IPv4LL support */
int config_parse_ipv4ll(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);
@ -188,3 +196,6 @@ int network_object_find(sd_bus *bus, const char *path, const char *interface, vo
const char* ipv6_privacy_extensions_to_string(IPv6PrivacyExtensions i) _const_;
IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_;
const char* dhcp_use_domains_to_string(DHCPUseDomains p) _const_;
DHCPUseDomains dhcp_use_domains_from_string(const char *s) _pure_;

View File

@ -1217,19 +1217,19 @@ static int bus_property_get_search_domains(
assert(reply);
assert(m);
r = sd_bus_message_open_container(reply, 'a', "(is)");
r = sd_bus_message_open_container(reply, 'a', "(isb)");
if (r < 0)
return r;
LIST_FOREACH(domains, d, m->search_domains) {
r = sd_bus_message_append(reply, "(is)", 0, d->name);
r = sd_bus_message_append(reply, "(isb)", 0, d->name, d->route_only);
if (r < 0)
return r;
}
HASHMAP_FOREACH(l, m->links, i) {
LIST_FOREACH(domains, d, l->search_domains) {
r = sd_bus_message_append(reply, "is", l->ifindex, d->name);
r = sd_bus_message_append(reply, "(isb)", l->ifindex, d->name, d->route_only);
if (r < 0)
return r;
}
@ -1450,7 +1450,7 @@ static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), 0),
SD_BUS_PROPERTY("DNS", "a(iiay)", bus_property_get_dns_servers, 0, 0),
SD_BUS_PROPERTY("Domains", "a(is)", bus_property_get_search_domains, 0, 0),
SD_BUS_PROPERTY("SearchDomains", "a(isb)", bus_property_get_search_domains, 0, 0),
SD_BUS_PROPERTY("TransactionStatistics", "(tt)", bus_property_get_transaction_statistics, 0, 0),
SD_BUS_PROPERTY("CacheStatistics", "(ttt)", bus_property_get_cache_statistics, 0, 0),
SD_BUS_PROPERTY("DNSSECStatistics", "(tttt)", bus_property_get_dnssec_statistics, 0, 0),
@ -1463,7 +1463,7 @@ static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, 0),
SD_BUS_METHOD("GetLink", "i", "o", bus_method_get_link, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, 0),
SD_BUS_METHOD("SetLinkDomains", "ias", NULL, bus_method_set_link_search_domains, 0),
SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_search_domains, 0),
SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, 0),
SD_BUS_METHOD("SetLinkMulticastDNS", "is", NULL, bus_method_set_link_mdns, 0),
SD_BUS_METHOD("SetLinkDNSSEC", "is", NULL, bus_method_set_link_dnssec, 0),

View File

@ -80,20 +80,34 @@ int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, con
int manager_add_search_domain_by_string(Manager *m, const char *domain) {
DnsSearchDomain *d;
bool route_only;
int r;
assert(m);
assert(domain);
route_only = *domain == '~';
if (route_only)
domain++;
if (dns_name_is_root(domain) || streq(domain, "*")) {
route_only = true;
domain = ".";
}
r = dns_search_domain_find(m->search_domains, domain, &d);
if (r < 0)
return r;
if (r > 0) {
if (r > 0)
dns_search_domain_move_back_and_unmark(d);
return 0;
else {
r = dns_search_domain_new(m, &d, DNS_SEARCH_DOMAIN_SYSTEM, NULL, domain);
if (r < 0)
return r;
}
return dns_search_domain_new(m, NULL, DNS_SEARCH_DOMAIN_SYSTEM, NULL, domain);
d->route_only = route_only;
return 0;
}
int manager_parse_search_domains_and_warn(Manager *m, const char *string) {

View File

@ -28,18 +28,6 @@
#include "resolved-dns-packet.h"
#include "string-table.h"
/* Open question:
*
* How does the DNSSEC canonical form of a hostname with a label
* containing a dot look like, the way DNS-SD does it?
*
* TODO:
*
* - enable by default
* - Allow clients to request DNSSEC even if DNSSEC is off
* - make sure when getting an NXDOMAIN response through CNAME, we still process the first CNAMEs in the packet
* */
#define VERIFY_RRS_MAX 256
#define MAX_KEY_SIZE (32*1024)

View File

@ -93,17 +93,20 @@ static int dns_query_candidate_next_search_domain(DnsQueryCandidate *c) {
assert(c);
if (c->search_domain && c->search_domain->linked) {
if (c->search_domain && c->search_domain->linked)
next = c->search_domain->domains_next;
else
next = dns_scope_get_search_domains(c->scope);
for (;;) {
if (!next) /* We hit the end of the list */
return 0;
} else {
next = dns_scope_get_search_domains(c->scope);
if (!next->route_only)
break;
if (!next) /* OK, there's nothing. */
return 0;
/* Skip over route-only domains */
next = next->domains_next;
}
dns_search_domain_unref(c->search_domain);

View File

@ -42,9 +42,6 @@ int dns_search_domain_new(
if (r < 0)
return r;
if (dns_name_is_root(normalized))
return -EINVAL;
if (l) {
if (l->n_search_domains >= LINK_SEARCH_DOMAINS_MAX)
return -E2BIG;

View File

@ -44,6 +44,7 @@ struct DnsSearchDomain {
char *name;
bool marked:1;
bool route_only:1;
bool linked:1;
LIST_FIELDS(DnsSearchDomain, domains);

View File

@ -732,6 +732,55 @@ fail:
dns_transaction_complete(t, DNS_TRANSACTION_ERRNO);
}
static int dns_transaction_has_positive_answer(DnsTransaction *t, DnsAnswerFlags *flags) {
int r;
assert(t);
/* Checks whether the answer is positive, i.e. either a direct
* answer to the question, or a CNAME/DNAME for it */
r = dns_answer_match_key(t->answer, t->key, flags);
if (r != 0)
return r;
r = dns_answer_find_cname_or_dname(t->answer, t->key, NULL, flags);
if (r != 0)
return r;
return false;
}
static int dns_transaction_fix_rcode(DnsTransaction *t) {
int r;
assert(t);
/* Fix up the RCODE to SUCCESS if we get at least one matching RR in a response. Note that this contradicts the
* DNS RFCs a bit. Specifically, RFC 6604 Section 3 clarifies that the RCODE shall say something about a
* CNAME/DNAME chain element coming after the last chain element contained in the message, and not the first
* one included. However, it also indicates that not all DNS servers implement this correctly. Moreover, when
* using DNSSEC we usually only can prove the first element of a CNAME/DNAME chain anyway, hence let's settle
* on always processing the RCODE as referring to the immediate look-up we do, i.e. the first element of a
* CNAME/DNAME chain. This way, we uniformly handle CNAME/DNAME chains, regardless if the DNS server
* incorrectly implements RCODE, whether DNSSEC is in use, or whether the DNS server only supplied us with an
* incomplete CNAME/DNAME chain.
*
* Or in other words: if we get at least one positive reply in a message we patch NXDOMAIN to become SUCCESS,
* and then rely on the CNAME chasing logic to figure out that there's actually a CNAME error with a new
* lookup. */
if (t->answer_rcode != DNS_RCODE_NXDOMAIN)
return 0;
r = dns_transaction_has_positive_answer(t, NULL);
if (r <= 0)
return r;
t->answer_rcode = DNS_RCODE_SUCCESS;
return 0;
}
void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
usec_t ts;
int r;
@ -923,6 +972,10 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
t->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
t->answer_authenticated = false;
r = dns_transaction_fix_rcode(t);
if (r < 0)
goto fail;
/* Block GC while starting requests for additional DNSSEC RRs */
t->block_gc++;
r = dns_transaction_request_dnssec_keys(t);
@ -1635,25 +1688,6 @@ static int dns_transaction_request_dnssec_rr(DnsTransaction *t, DnsResourceKey *
return 1;
}
static int dns_transaction_has_positive_answer(DnsTransaction *t, DnsAnswerFlags *flags) {
int r;
assert(t);
/* Checks whether the answer is positive, i.e. either a direct
* answer to the question, or a CNAME/DNAME for it */
r = dns_answer_match_key(t->answer, t->key, flags);
if (r != 0)
return r;
r = dns_answer_find_cname_or_dname(t->answer, t->key, NULL, flags);
if (r != 0)
return r;
return false;
}
static int dns_transaction_negative_trust_anchor_lookup(DnsTransaction *t, const char *name) {
int r;

View File

@ -75,12 +75,12 @@ static int property_get_domains(
assert(reply);
assert(l);
r = sd_bus_message_open_container(reply, 'a', "s");
r = sd_bus_message_open_container(reply, 'a', "(sb)");
if (r < 0)
return r;
LIST_FOREACH(domains, d, l->search_domains) {
r = sd_bus_message_append(reply, "s", d->name);
r = sd_bus_message_append(reply, "(sb)", d->name, d->route_only);
if (r < 0)
return r;
}
@ -242,47 +242,71 @@ clear:
}
int bus_link_method_set_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char **domains = NULL;
Link *l = userdata;
char **i;
int r;
assert(message);
assert(l);
r = sd_bus_message_read_strv(message, &domains);
r = sd_bus_message_enter_container(message, 'a', "(sb)");
if (r < 0)
return r;
STRV_FOREACH(i, domains) {
for (;;) {
const char *name;
int route_only;
r = dns_name_is_valid(*i);
r = sd_bus_message_read(message, "(sb)", &name, &route_only);
if (r < 0)
return r;
if (r == 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", *i);
if (dns_name_is_root(*i))
break;
r = dns_name_is_valid(name);
if (r < 0)
return r;
if (r == 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name);
if (!route_only && dns_name_is_root(name))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain");
}
dns_search_domain_mark_all(l->search_domains);
STRV_FOREACH(i, domains) {
DnsSearchDomain *d;
r = sd_bus_message_rewind(message, false);
if (r < 0)
return r;
r = dns_search_domain_find(l->search_domains, *i, &d);
for (;;) {
DnsSearchDomain *d;
const char *name;
int route_only;
r = sd_bus_message_read(message, "(sb)", &name, &route_only);
if (r < 0)
goto clear;
if (r == 0)
break;
r = dns_search_domain_find(l->search_domains, name, &d);
if (r < 0)
goto clear;
if (r > 0)
dns_search_domain_move_back_and_unmark(d);
else {
r = dns_search_domain_new(l->manager, NULL, DNS_SEARCH_DOMAIN_LINK, l, *i);
r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name);
if (r < 0)
goto clear;
}
d->route_only = route_only;
}
r = sd_bus_message_exit_container(message);
if (r < 0)
goto clear;
dns_search_domain_unlink_marked(l->search_domains);
return sd_bus_reply_method_return(message, NULL);
@ -430,7 +454,7 @@ const sd_bus_vtable link_vtable[] = {
SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask, 0, 0),
SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns, 0, 0),
SD_BUS_PROPERTY("Domains", "as", property_get_domains, 0, 0),
SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0),
SD_BUS_PROPERTY("LLMNR", "s", property_get_resolve_support, offsetof(Link, llmnr_support), 0),
SD_BUS_PROPERTY("MulticastDNS", "s", property_get_resolve_support, offsetof(Link, mdns_support), 0),
SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, offsetof(Link, dnssec_mode), 0),
@ -438,7 +462,7 @@ const sd_bus_vtable link_vtable[] = {
SD_BUS_PROPERTY("DNSSECSupport", "b", property_get_dnssec_supported, 0, 0),
SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, 0),
SD_BUS_METHOD("SetDomains", "as", NULL, bus_link_method_set_search_domains, 0),
SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_search_domains, 0),
SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, 0),
SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, 0),
SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, 0),

View File

@ -377,38 +377,60 @@ clear:
return r;
}
static int link_update_search_domains(Link *l) {
_cleanup_strv_free_ char **domains = NULL;
char **i;
static int link_update_search_domain_one(Link *l, const char *name, bool route_only) {
DnsSearchDomain *d;
int r;
r = dns_search_domain_find(l->search_domains, name, &d);
if (r < 0)
return r;
if (r > 0)
dns_search_domain_move_back_and_unmark(d);
else {
r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name);
if (r < 0)
return r;
}
d->route_only = route_only;
return 0;
}
static int link_update_search_domains(Link *l) {
_cleanup_strv_free_ char **sdomains = NULL, **rdomains = NULL;
char **i;
int r, q;
assert(l);
r = sd_network_link_get_domains(l->ifindex, &domains);
if (r == -ENODATA) {
r = sd_network_link_get_search_domains(l->ifindex, &sdomains);
if (r < 0 && r != -ENODATA)
goto clear;
q = sd_network_link_get_route_domains(l->ifindex, &rdomains);
if (q < 0 && q != -ENODATA) {
r = q;
goto clear;
}
if (r == -ENODATA && q == -ENODATA) {
/* networkd knows nothing about this interface, and that's fine. */
r = 0;
goto clear;
}
if (r < 0)
goto clear;
dns_search_domain_mark_all(l->search_domains);
STRV_FOREACH(i, domains) {
DnsSearchDomain *d;
r = dns_search_domain_find(l->search_domains, *i, &d);
STRV_FOREACH(i, sdomains) {
r = link_update_search_domain_one(l, *i, false);
if (r < 0)
goto clear;
}
if (r > 0)
dns_search_domain_move_back_and_unmark(d);
else {
r = dns_search_domain_new(l->manager, NULL, DNS_SEARCH_DOMAIN_LINK, l, *i);
if (r < 0)
goto clear;
}
STRV_FOREACH(i, rdomains) {
r = link_update_search_domain_one(l, *i, true);
if (r < 0)
goto clear;
}
dns_search_domain_unlink_marked(l->search_domains);

View File

@ -206,7 +206,7 @@ static int manager_rtnl_listen(Manager *m) {
if (r < 0)
return r;
r = sd_netlink_attach_event(m->rtnl, m->event, 0);
r = sd_netlink_attach_event(m->rtnl, m->event, SD_EVENT_PRIORITY_IMPORTANT);
if (r < 0)
return r;
@ -314,6 +314,10 @@ static int manager_network_monitor_listen(Manager *m) {
if (r < 0)
return r;
r = sd_event_source_set_priority(m->network_event_source, SD_EVENT_PRIORITY_IMPORTANT+5);
if (r < 0)
return r;
(void) sd_event_source_set_description(m->network_event_source, "network-monitor");
return 0;

View File

@ -74,6 +74,7 @@ struct Manager {
LIST_HEAD(DnsSearchDomain, search_domains);
unsigned n_search_domains;
bool permit_domain_search;
bool need_builtin_fallbacks:1;

View File

@ -405,11 +405,17 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded,
int dns_name_concat(const char *a, const char *b, char **_ret) {
_cleanup_free_ char *ret = NULL;
size_t n = 0, allocated = 0;
const char *p = a;
const char *p;
bool first = true;
int r;
assert(a);
if (a)
p = a;
else if (b) {
p = b;
b = NULL;
} else
goto finish;
for (;;) {
char label[DNS_LABEL_MAX];
@ -457,12 +463,21 @@ int dns_name_concat(const char *a, const char *b, char **_ret) {
n += r;
}
finish:
if (n > DNS_HOSTNAME_MAX)
return -EINVAL;
if (_ret) {
if (!GREEDY_REALLOC(ret, allocated, n + 1))
return -ENOMEM;
if (n == 0) {
/* Nothing appended? If so, generate at least a single dot, to indicate the DNS root domain */
if (!GREEDY_REALLOC(ret, allocated, 2))
return -ENOMEM;
ret[n++] = '.';
} else {
if (!GREEDY_REALLOC(ret, allocated, n + 1))
return -ENOMEM;
}
ret[n] = 0;
*_ret = ret;

View File

@ -64,8 +64,11 @@ int sd_network_get_dns(char ***dns);
* representations of IP addresses */
int sd_network_get_ntp(char ***ntp);
/* Get the search/routing domains for all links. */
int sd_network_get_domains(char ***domains);
/* Get the search domains for all links. */
int sd_network_get_search_domains(char ***domains);
/* Get the search domains for all links. */
int sd_network_get_route_domains(char ***domains);
/* Get setup state from ifindex.
* Possible states:
@ -134,8 +137,11 @@ int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char ***nta);
int sd_network_link_get_lldp(int ifindex, char **lldp);
/* Get the DNS domain names for a given link. */
int sd_network_link_get_domains(int ifindex, char ***domains);
/* Get the search DNS domain names for a given link. */
int sd_network_link_get_search_domains(int ifindex, char ***domains);
/* Get the route DNS domain names for a given link. */
int sd_network_link_get_route_domains(int ifindex, char ***domains);
/* Get the CARRIERS to which current link is bound to. */
int sd_network_link_get_carrier_bound_to(int ifindex, char ***carriers);
@ -146,10 +152,6 @@ int sd_network_link_get_carrier_bound_by(int ifindex, char ***carriers);
/* Get the timezone that was learnt on a specific link. */
int sd_network_link_get_timezone(int ifindex, char **timezone);
/* Returns whether or not domains that don't match any link should be resolved
* on this link. 1 for yes, 0 for no and negative value for error */
int sd_network_link_get_wildcard_domain(int ifindex);
/* Monitor object */
typedef struct sd_network_monitor sd_network_monitor;

View File

@ -186,7 +186,7 @@ static void test_dns_name_normalize_one(const char *what, const char *expect, in
}
static void test_dns_name_normalize(void) {
test_dns_name_normalize_one("", "", 0);
test_dns_name_normalize_one("", ".", 0);
test_dns_name_normalize_one("f", "f", 0);
test_dns_name_normalize_one("f.waldi", "f.waldi", 0);
test_dns_name_normalize_one("f \\032.waldi", "f\\032\\032.waldi", 0);
@ -194,7 +194,7 @@ static void test_dns_name_normalize(void) {
test_dns_name_normalize_one("..", NULL, -EINVAL);
test_dns_name_normalize_one(".foobar", NULL, -EINVAL);
test_dns_name_normalize_one("foobar.", "foobar", 0);
test_dns_name_normalize_one(".", "", 0);
test_dns_name_normalize_one(".", ".", 0);
}
static void test_dns_name_equal_one(const char *a, const char *b, int ret) {
@ -340,10 +340,18 @@ static void test_dns_name_concat_one(const char *a, const char *b, int r, const
}
static void test_dns_name_concat(void) {
test_dns_name_concat_one("", "", 0, ".");
test_dns_name_concat_one(".", "", 0, ".");
test_dns_name_concat_one("", ".", 0, ".");
test_dns_name_concat_one(".", ".", 0, ".");
test_dns_name_concat_one("foo", "bar", 0, "foo.bar");
test_dns_name_concat_one("foo.foo", "bar.bar", 0, "foo.foo.bar.bar");
test_dns_name_concat_one("foo", NULL, 0, "foo");
test_dns_name_concat_one("foo", ".", 0, "foo");
test_dns_name_concat_one("foo.", "bar.", 0, "foo.bar");
test_dns_name_concat_one(NULL, NULL, 0, ".");
test_dns_name_concat_one(NULL, ".", 0, ".");
test_dns_name_concat_one(NULL, "foo", 0, "foo");
}
static void test_dns_name_is_valid_one(const char *s, int ret) {
@ -429,7 +437,7 @@ static void test_dns_service_join_one(const char *a, const char *b, const char *
assert_se(dns_service_split(t, &x, &y, &z) >= 0);
assert_se(streq_ptr(a, x));
assert_se(streq_ptr(b, y));
assert_se(streq_ptr(c, z));
assert_se(dns_name_equal(c, z) > 0);
}
static void test_dns_service_join(void) {
@ -460,18 +468,18 @@ static void test_dns_service_split_one(const char *joined, const char *a, const
if (y) {
assert_se(dns_service_join(x, y, z, &t) == 0);
assert_se(streq_ptr(joined, t));
assert_se(dns_name_equal(joined, t) > 0);
} else
assert_se(!x && streq_ptr(z, joined));
assert_se(!x && dns_name_equal(z, joined) > 0);
}
static void test_dns_service_split(void) {
test_dns_service_split_one("", NULL, NULL, "", 0);
test_dns_service_split_one("", NULL, NULL, ".", 0);
test_dns_service_split_one("foo", NULL, NULL, "foo", 0);
test_dns_service_split_one("foo.bar", NULL, NULL, "foo.bar", 0);
test_dns_service_split_one("_foo.bar", NULL, NULL, "_foo.bar", 0);
test_dns_service_split_one("_foo._bar", NULL, "_foo._bar", "", 0);
test_dns_service_split_one("_meh._foo._bar", "_meh", "_foo._bar", "", 0);
test_dns_service_split_one("_foo._bar", NULL, "_foo._bar", ".", 0);
test_dns_service_split_one("_meh._foo._bar", "_meh", "_foo._bar", ".", 0);
test_dns_service_split_one("Wuff\\032Wuff._foo._bar.waldo.com", "Wuff Wuff", "_foo._bar", "waldo.com", 0);
}
@ -490,7 +498,7 @@ static void test_dns_name_change_suffix(void) {
test_dns_name_change_suffix_one("foo.bar.waldi.quux", "quux", "piff.paff", 1, "foo.bar.waldi.piff.paff");
test_dns_name_change_suffix_one("foo.bar.waldi.quux", "", "piff.paff", 1, "foo.bar.waldi.quux.piff.paff");
test_dns_name_change_suffix_one("", "", "piff.paff", 1, "piff.paff");
test_dns_name_change_suffix_one("", "", "", 1, "");
test_dns_name_change_suffix_one("", "", "", 1, ".");
test_dns_name_change_suffix_one("a", "b", "c", 0, NULL);
}