Compare commits

...

14 Commits

Author SHA1 Message Date
Andrew Doran e7d5fe17db DHCP client: make SendOption work for DHCPv6 too. 2020-05-11 16:31:08 +02:00
Lennart Poettering 2d5996c175
Merge pull request #15460 from elmarco/network-dhcp-resolve1
network: fallback on resolve1 DNS for DHCP
2020-05-11 16:16:06 +02:00
Zbigniew Jędrzejewski-Szmek 6b726e602e
Merge pull request #15768 from poettering/grnd-insecure
random-util: make use of GRND_INSECURE if we have it
2020-05-11 12:49:00 +02:00
Zbigniew Jędrzejewski-Szmek f1f7b08805
Merge pull request #15769 from poettering/man-tmpfiles-boot-override
man: document how "!" and conflicting lines play together in tmpfiles.d
2020-05-11 12:46:36 +02:00
Lennart Poettering 1e0d5eebf1 man: clarify that exit status name mappings are unaffected by SuccessExitStatus=
Fixes: #15757

(Note there's quite some confusion regarding "exit status" vs. "exit
code" in the docs here. We should clean this up fully one day. This
change tries to fix some occasions of the wrong use, but not all.)
2020-05-11 12:37:32 +02:00
Benjamin Dahlhoff 13c829c1bd
Added Chuwi Hibook Pro (Model: CWI526) (#15770) 2020-05-11 10:25:02 +02:00
Lennart Poettering ead2a4a231 tmpfiles: clarify that "!" lines are filtered before collisions are checked
Fixes: #15675
2020-05-10 11:45:52 +02:00
Lennart Poettering f742f9d317 man: mention the exclamation mark and minus sign literally, to make things searchable
I was looking for the explanation for the exclamation mark in the text,
and couldn't find it, searching for "!". Let's make this easier, and
indicate the character meant.
2020-05-10 11:44:53 +02:00
Lennart Poettering 82c8bda1f1 update TODO 2020-05-10 11:20:01 +02:00
Lennart Poettering 0497c4c28a random-util: make use of GRND_INSECURE when it is defined
kernel 5.6 added support for a new flag for getrandom(): GRND_INSECURE.
If we set it we can get some random data out of the kernel random pool,
even if it is not yet initializated. This is great for us to initialize
hash table seeds and such, where it is OK if they are crap initially. We
used RDRAND for these cases so far, but RDRAND is only available on
newer CPUs and some archs. Let's now use GRND_INSECURE for these cases
as well, which means we won't needlessly delay boot anymore even on
archs/CPUs that do not have RDRAND.

Of course we never set this flag when generating crypto keys or uuids.
Which makes it different from RDRAND for us (and is the reason I think
we should keep explicit RDRAND support in): RDRAND we don't trust enough
for crypto keys. But we do trust it enough for UUIDs.
2020-05-10 11:15:16 +02:00
Lennart Poettering e2b5546452 random-util: use ERRNO_IS_NOT_SUPPORTED() macro
Some container mgr or sandbox solution might block it with an unexpected
error code, hence let's be tolerant here.
2020-05-10 11:14:17 +02:00
Lennart Poettering 57ee010ff2 random-util: actually encode our expectations on RAND_MAX 2020-05-10 11:13:49 +02:00
Marc-André Lureau dd1d306058 network: fallback on resolved resolv.conf for DHCP server settings 2020-05-08 12:48:39 +02:00
Marc-André Lureau 2d95d81f7b shared: move in_addr_ifindex_name_from_string_auto() there 2020-05-07 22:36:52 +02:00
30 changed files with 444 additions and 168 deletions

2
TODO
View File

@ -22,8 +22,6 @@ Janitorial Clean-ups:
Features:
* random-util: make user of new GRND_INSECURE flag wherever possible
* nspawn: support time namespaces
* pid1: Move to tracking of main pid/control pid of units per pidfd

View File

@ -193,6 +193,10 @@ sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/07/201
sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/28/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnHampoo:rnCherryTrailCR:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
# Chuwi HiBook Pro (CWI526)
sensor:modalias:acpi:BOSC0200*:dmi:*:svnHampoo*:pnP1D6_C109K:*
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
# Chuwi CoreBook
# Chuwi CoreBook does not have its product name filled, so we
# match the entire dmi-alias

View File

@ -1748,6 +1748,14 @@
Defaults to false.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>SendOption=</varname></term>
<listitem>
<para>As in the <literal>[DHCPv4]</literal> section, however because DHCPv6 uses 16-bit fields to store
option numbers, the option number is an integer in the range 1..65536.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
@ -1985,7 +1993,7 @@
<para>Send a raw option with value via DHCPv4 server. Takes a DHCP option number, data type
and data (<literal><replaceable>option</replaceable>:<replaceable>type</replaceable>:<replaceable>value</replaceable></literal>).
The option number is an integer in the range 1..254. The type takes one of <literal>uint8</literal>,
<literal>uint16</literal>, <literal>uint32</literal>, <literal>ipv4address</literal>, or
<literal>uint16</literal>, <literal>uint32</literal>, <literal>ipv4address</literal>, <literal>ipv6address</literal>, or
<literal>string</literal>. Special characters in the data string may be escaped using
<ulink url="https://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences">C-style
escapes</ulink>. This setting can be specified multiple times. If an empty string is specified,

View File

@ -845,35 +845,41 @@
<varlistentry>
<term><varname>SuccessExitStatus=</varname></term>
<listitem><para>Takes a list of exit status definitions that, when returned by the main service
process, will be considered successful termination, in addition to the normal successful exit code 0
and the signals <constant>SIGHUP</constant>, <constant>SIGINT</constant>,
process, will be considered successful termination, in addition to the normal successful exit status
0 and the signals <constant>SIGHUP</constant>, <constant>SIGINT</constant>,
<constant>SIGTERM</constant>, and <constant>SIGPIPE</constant>. Exit status definitions can be
numeric exit codes, termination code names, or termination signal names, separated by spaces. See the
Process Exit Codes section in
numeric termination statuses, termination status names, or termination signal names, separated by
spaces. See the Process Exit Codes section in
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
a list of termination codes names (for this setting only the part without the
<literal>EXIT_</literal> or <literal>EX_</literal> prefix should be used). See
<citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
a list of termination status names (for this setting only the part without the
<literal>EXIT_</literal> or <literal>EX_</literal> prefix should be used). See <citerefentry
project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
a list of signal names.</para>
<para>This option may appear more than once, in which case the
list of successful exit statuses is merged. If the empty
string is assigned to this option, the list is reset, all
prior assignments of this option will have no
effect.</para>
<para>Note that this setting does not change the the mapping between numeric exit statuses and their
names, i.e. regardless how this setting is used 0 will still be mapped to <literal>SUCCESS</literal>
(and thus typically shown as <literal>0/SUCCESS</literal> in tool outputs) and 1 to
<literal>FAILURE</literal> (and thus typically shown as <literal>1/FAILURE</literal>), and so on. It
only controls what happens as effect of these exit statuses, and how it propagates to the state of
the service as a whole.</para>
<para>This option may appear more than once, in which case the list of successful exit statuses is
merged. If the empty string is assigned to this option, the list is reset, all prior assignments of
this option will have no effect.</para>
<example>
<title>A service with with the <varname>SuccessExitStatus=</varname> setting</title>
<programlisting>SuccessExitStatus=TEMPFAIL 250 SIGUSR1</programlisting>
<para>Exit codes 75 (<constant>TEMPFAIL</constant>), 250, and the termination signal
<para>Exit status 75 (<constant>TEMPFAIL</constant>), 250, and the termination signal
<constant>SIGKILL</constant> are considered clean service terminations.</para>
</example>
<para>Note: <command>systemd-analyze exit-status</command> may be used to list exit
codes and translate between numerical code values and names.</para></listitem>
<para>Note: <command>systemd-analyze exit-status</command> may be used to list exit statuses and
translate between numerical status values and names.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -121,16 +121,19 @@ A+ /path-or-glob/to/append/acls/recursively - - - - POSIX
<filename>/usr/lib/tmpfiles.d</filename> and <filename>/run/tmpfiles.d</filename>. Files in
<filename>/run/tmpfiles.d</filename> override files with the same name in
<filename>/usr/lib/tmpfiles.d</filename>. Packages should install their configuration files in
<filename>/usr/lib/tmpfiles.d</filename>. Files in <filename>/etc/tmpfiles.d</filename> are reserved for the local
administrator, who may use this logic to override the configuration files installed by vendor packages. All
configuration files are sorted by their filename in lexicographic order, regardless of which of the directories
they reside in. If multiple files specify the same path, the entry in the file with the lexicographically earliest
name will be applied. All other conflicting entries will be logged as errors. When two lines are prefix path and
suffix path of each other, then the prefix line is always created first, the suffix later (and if removal applies
to the line, the order is reversed: the suffix is removed first, the prefix later). Lines that take globs are
applied after those accepting no globs. If multiple operations shall be applied on the same file (such as ACL,
xattr, file attribute adjustments), these are always done in the same fixed order. Except for those cases, the
files/directories are processed in the order they are listed.</para>
<filename>/usr/lib/tmpfiles.d</filename>. Files in <filename>/etc/tmpfiles.d</filename> are reserved for
the local administrator, who may use this logic to override the configuration files installed by vendor
packages. All configuration files are sorted by their filename in lexicographic order, regardless of
which of the directories they reside in. If multiple files specify the same path, the entry in the file
with the lexicographically earliest name will be applied (note that lines suppressed due to the
<literal>!</literal> are filtered before application, meaning that if an early line carries the
exclamation mark and is suppressed because of that, a later line matching in path will be applied). All
other conflicting entries will be logged as errors. When two lines are prefix path and suffix path of
each other, then the prefix line is always created first, the suffix later (and if removal applies to the
line, the order is reversed: the suffix is removed first, the prefix later). Lines that take globs are
applied after those accepting no globs. If multiple operations shall be applied on the same file (such as
ACL, xattr, file attribute adjustments), these are always done in the same fixed order. Except for those
cases, the files/directories are processed in the order they are listed.</para>
<para>If the administrator wants to disable a configuration file
supplied by the vendor, the recommended way is to place a symlink
@ -154,8 +157,8 @@ L /tmp/foobar - - - - /dev/null</programlisting>
<refsect2>
<title>Type</title>
<para>The type consists of a single letter and optionally an
exclamation mark and/or minus sign.</para>
<para>The type consists of a single letter and optionally an exclamation mark (<literal>!</literal>)
and/or minus sign (<literal>-</literal>).</para>
<para>The following line types are understood:</para>
@ -453,13 +456,10 @@ L /tmp/foobar - - - - /dev/null</programlisting>
</varlistentry>
</variablelist>
<para>If the exclamation mark is used, this line is only safe to
execute during boot, and can break a running system. Lines
without the exclamation mark are presumed to be safe to execute
at any time, e.g. on package upgrades.
<command>systemd-tmpfiles</command> will execute line with an
exclamation mark only if option <option>--boot</option> is
given.</para>
<para>If the exclamation mark (<literal>!</literal>) is used, this line is only safe to execute during
boot, and can break a running system. Lines without the exclamation mark are presumed to be safe to
execute at any time, e.g. on package upgrades. <command>systemd-tmpfiles</command> will take lines with
an exclamation mark only into consideration, if the <option>--boot</option> option is given.</para>
<para>For example:
<programlisting># Make sure these are created by default so that nobody else can
@ -471,9 +471,8 @@ r! /tmp/.X[0-9]*-lock</programlisting>
running system, and will only be executed with
<option>--boot</option>.</para>
<para>If the minus sign is used, this line failing to run
successfully during create (and only create) will not cause
the execution of <command>systemd-tmpfiles</command> to return
<para>If the minus sign (<literal>-</literal>) is used, this line failing to run successfully during
create (and only create) will not cause the execution of <command>systemd-tmpfiles</command> to return
an error.</para>
<para>For example:

View File

@ -14,3 +14,7 @@
#ifndef GRND_RANDOM
#define GRND_RANDOM 0x0002
#endif
#ifndef GRND_INSECURE
#define GRND_INSECURE 0x0004
#endif

View File

@ -19,6 +19,7 @@
#endif
#include "alloc-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "io-util.h"
@ -207,7 +208,9 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
if (have_syscall != 0 && !HAS_FEATURE_MEMORY_SANITIZER) {
for (;;) {
r = getrandom(p, n, FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_NONBLOCK);
r = getrandom(p, n,
(FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_NONBLOCK) |
(FLAGS_SET(flags, RANDOM_ALLOW_INSECURE) ? GRND_INSECURE : 0));
if (r > 0) {
have_syscall = true;
@ -237,7 +240,7 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
have_syscall = true;
return -EIO;
} else if (errno == ENOSYS) {
} else if (ERRNO_IS_NOT_SUPPORTED(errno)) {
/* We lack the syscall, continue with reading from /dev/urandom. */
have_syscall = false;
break;
@ -263,6 +266,18 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
/* Use /dev/urandom instead */
break;
} else if (errno == EINVAL) {
/* Most likely: unknown flag. We know that GRND_INSECURE might cause this,
* hence try without. */
if (FLAGS_SET(flags, RANDOM_ALLOW_INSECURE)) {
flags = flags &~ RANDOM_ALLOW_INSECURE;
continue;
}
return -errno;
} else
return -errno;
}
@ -325,9 +340,11 @@ void initialize_srand(void) {
/* INT_MAX gives us only 31 bits, so use 24 out of that. */
#if RAND_MAX >= INT_MAX
assert_cc(RAND_MAX >= 16777215);
# define RAND_STEP 3
#else
/* SHORT_INT_MAX or lower gives at most 15 bits, we just just 8 out of that. */
/* SHORT_INT_MAX or lower gives at most 15 bits, we just use 8 out of that. */
assert_cc(RAND_MAX >= 255);
# define RAND_STEP 1
#endif
@ -392,7 +409,7 @@ void random_bytes(void *p, size_t n) {
* This function is hence not useful for generating UUIDs or cryptographic key material.
*/
if (genuine_random_bytes(p, n, RANDOM_EXTEND_WITH_PSEUDO|RANDOM_MAY_FAIL|RANDOM_ALLOW_RDRAND) >= 0)
if (genuine_random_bytes(p, n, RANDOM_EXTEND_WITH_PSEUDO|RANDOM_MAY_FAIL|RANDOM_ALLOW_RDRAND|RANDOM_ALLOW_INSECURE) >= 0)
return;
/* If for some reason some user made /dev/urandom unavailable to us, or the kernel has no entropy, use a PRNG instead. */

View File

@ -10,6 +10,7 @@ typedef enum RandomFlags {
RANDOM_BLOCK = 1 << 1, /* Rather block than return crap randomness (only if the kernel supports that) */
RANDOM_MAY_FAIL = 1 << 2, /* If we can't get any randomness at all, return early with -ENODATA */
RANDOM_ALLOW_RDRAND = 1 << 3, /* Allow usage of the CPU RNG */
RANDOM_ALLOW_INSECURE = 1 << 4, /* Allow usage of GRND_INSECURE flag to kernel's getrandom() API */
} RandomFlags;
int genuine_random_bytes(void *p, size_t n, RandomFlags flags); /* returns "genuine" randomness, optionally filled up with pseudo random, if not enough is available */

View File

@ -19,6 +19,7 @@ typedef enum DHCPRawOption {
DHCP_RAW_OPTION_DATA_UINT32,
DHCP_RAW_OPTION_DATA_STRING,
DHCP_RAW_OPTION_DATA_IPV4ADDRESS,
DHCP_RAW_OPTION_DATA_IPV6ADDRESS,
_DHCP_RAW_OPTION_DATA_MAX,
_DHCP_RAW_OPTION_DATA_INVALID,
} DHCPRawOption;

View File

@ -14,6 +14,16 @@
#include "macro.h"
#include "sparse-endian.h"
typedef struct sd_dhcp6_option {
unsigned n_ref;
uint16_t option;
void *data;
size_t length;
} sd_dhcp6_option;
extern const struct hash_ops dhcp6_option_hash_ops;
/* Common option header */
typedef struct DHCP6Option {
be16_t code;

View File

@ -597,3 +597,43 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char *
return idx;
}
static sd_dhcp6_option* dhcp6_option_free(sd_dhcp6_option *i) {
if (!i)
return NULL;
free(i->data);
return mfree(i);
}
int sd_dhcp6_option_new(uint16_t option, const void *data, size_t length, sd_dhcp6_option **ret) {
assert_return(ret, -EINVAL);
assert_return(length == 0 || data, -EINVAL);
_cleanup_free_ void *q = memdup(data, length);
if (!q)
return -ENOMEM;
sd_dhcp6_option *p = new(sd_dhcp6_option, 1);
if (!p)
return -ENOMEM;
*p = (sd_dhcp6_option) {
.n_ref = 1,
.option = option,
.length = length,
.data = TAKE_PTR(q),
};
*ret = p;
return 0;
}
DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_option, sd_dhcp6_option, dhcp6_option_free);
DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
dhcp6_option_hash_ops,
void,
trivial_hash_func,
trivial_compare_func,
sd_dhcp6_option,
sd_dhcp6_option_unref);

View File

@ -78,6 +78,7 @@ struct sd_dhcp6_client {
size_t duid_len;
usec_t information_request_time_usec;
usec_t information_refresh_time_usec;
OrderedHashmap *extra_options;
};
static const uint16_t default_req_opts[] = {
@ -447,6 +448,24 @@ int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
return 0;
}
int sd_dhcp6_client_add_option(sd_dhcp6_client *client, sd_dhcp6_option *v) {
int r;
assert_return(client, -EINVAL);
assert_return(v, -EINVAL);
r = ordered_hashmap_ensure_allocated(&client->extra_options, &dhcp6_option_hash_ops);
if (r < 0)
return r;
r = ordered_hashmap_put(client->extra_options, UINT_TO_PTR(v->option), v);
if (r < 0)
return r;
sd_dhcp6_option_ref(v);
return 0;
}
static void client_notify(sd_dhcp6_client *client, int event) {
assert(client);
@ -492,7 +511,9 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
_cleanup_free_ DHCP6Message *message = NULL;
struct in6_addr all_servers =
IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
struct sd_dhcp6_option *j;
size_t len, optlen = 512;
Iterator i;
uint8_t *opt;
int r;
usec_t elapsed_usec;
@ -672,6 +693,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
if (r < 0)
return r;
ORDERED_HASHMAP_FOREACH(j, client->extra_options, i) {
r = dhcp6_option_append(&opt, &optlen, j->option, j->length, j->data);
if (r < 0)
return r;
}
r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message,
len - optlen);
if (r < 0)
@ -1584,6 +1611,7 @@ static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) {
free(client->req_opts);
free(client->fqdn);
free(client->mudurl);
ordered_hashmap_free(client->extra_options);
return mfree(client);
}

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "dhcp-internal.h"
#include "dhcp6-internal.h"
#include "escape.h"
#include "in-addr-util.h"
#include "networkd-dhcp-common.h"
@ -320,13 +321,14 @@ int config_parse_dhcp_send_option(
void *data,
void *userdata) {
_cleanup_(sd_dhcp_option_unrefp) sd_dhcp_option *opt = NULL, *old = NULL;
_cleanup_(sd_dhcp_option_unrefp) sd_dhcp_option *opt4 = NULL, *old4 = NULL;
_cleanup_(sd_dhcp6_option_unrefp) sd_dhcp6_option *opt6 = NULL, *old6 = NULL;
_cleanup_free_ char *word = NULL, *q = NULL;
OrderedHashmap **options = data;
union in_addr_union addr;
DHCPOptionDataType type;
uint8_t u, uint8_data;
uint16_t uint16_data;
uint8_t u8, uint8_data;
uint16_t u16, uint16_data;
uint32_t uint32_data;
const void *udata;
const char *p;
@ -353,17 +355,31 @@ int config_parse_dhcp_send_option(
return 0;
}
r = safe_atou8(word, &u);
if (ltype == AF_INET6) {
r = safe_atou16(word, &u16);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Invalid DHCP option, ignoring assignment: %s", rvalue);
return 0;
}
if (u < 1 || u >= 255) {
if (u16 < 1 || u16 >= 65535) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"Invalid DHCP option, valid range is 1-65535, ignoring assignment: %s", rvalue);
return 0;
}
} else {
r = safe_atou8(word, &u8);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Invalid DHCP option, ignoring assignment: %s", rvalue);
return 0;
}
if (u8 < 1 || u8 >= 255) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"Invalid DHCP option, valid range is 1-254, ignoring assignment: %s", rvalue);
return 0;
}
}
word = mfree(word);
r = extract_first_word(&p, &word, ":", 0);
@ -387,7 +403,7 @@ int config_parse_dhcp_send_option(
r = safe_atou8(p, &uint8_data);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse DHCPv4 uint8 data, ignoring assignment: %s", p);
"Failed to parse DHCP uint8 data, ignoring assignment: %s", p);
return 0;
}
@ -399,7 +415,7 @@ int config_parse_dhcp_send_option(
r = safe_atou16(p, &uint16_data);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse DHCPv4 uint16 data, ignoring assignment: %s", p);
"Failed to parse DHCP uint16 data, ignoring assignment: %s", p);
return 0;
}
@ -411,7 +427,7 @@ int config_parse_dhcp_send_option(
r = safe_atou32(p, &uint32_data);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse DHCPv4 uint32 data, ignoring assignment: %s", p);
"Failed to parse DHCP uint32 data, ignoring assignment: %s", p);
return 0;
}
@ -424,7 +440,7 @@ int config_parse_dhcp_send_option(
r = in_addr_from_string(AF_INET, p, &addr);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse DHCPv4 ipv4address data, ignoring assignment: %s", p);
"Failed to parse DHCP ipv4address data, ignoring assignment: %s", p);
return 0;
}
@ -432,11 +448,23 @@ int config_parse_dhcp_send_option(
sz = sizeof(addr.in.s_addr);
break;
}
case DHCP_OPTION_DATA_IPV6ADDRESS: {
r = in_addr_from_string(AF_INET6, p, &addr);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse DHCP ipv6address data, ignoring assignment: %s", p);
return 0;
}
udata = &addr.in6;
sz = sizeof(addr.in6.s6_addr);
break;
}
case DHCP_OPTION_DATA_STRING:
sz = cunescape(p, UNESCAPE_ACCEPT_NUL, &q);
if (sz < 0) {
log_syntax(unit, LOG_ERR, filename, line, sz,
"Failed to decode DHCPv4 option data, ignoring assignment: %s", p);
"Failed to decode DHCP option data, ignoring assignment: %s", p);
}
udata = q;
@ -445,10 +473,32 @@ int config_parse_dhcp_send_option(
return -EINVAL;
}
r = sd_dhcp_option_new(u, udata, sz, &opt);
if (ltype == AF_INET6) {
r = sd_dhcp6_option_new(u16, udata, sz, &opt6);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to store DHCPv4 option '%s', ignoring assignment: %m", rvalue);
"Failed to store DHCP option '%s', ignoring assignment: %m", rvalue);
return 0;
}
r = ordered_hashmap_ensure_allocated(options, &dhcp6_option_hash_ops);
if (r < 0)
return log_oom();
/* Overwrite existing option */
old6 = ordered_hashmap_get(*options, UINT_TO_PTR(u16));
r = ordered_hashmap_replace(*options, UINT_TO_PTR(u16), opt6);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to store DHCP option '%s', ignoring assignment: %m", rvalue);
return 0;
}
TAKE_PTR(opt6);
} else {
r = sd_dhcp_option_new(u8, udata, sz, &opt4);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to store DHCP option '%s', ignoring assignment: %m", rvalue);
return 0;
}
@ -457,15 +507,15 @@ int config_parse_dhcp_send_option(
return log_oom();
/* Overwrite existing option */
old = ordered_hashmap_remove(*options, UINT_TO_PTR(u));
r = ordered_hashmap_put(*options, UINT_TO_PTR(u), opt);
old4 = ordered_hashmap_get(*options, UINT_TO_PTR(u8));
r = ordered_hashmap_replace(*options, UINT_TO_PTR(u8), opt4);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to store DHCPv4 option '%s', ignoring assignment: %m", rvalue);
"Failed to store DHCP option '%s', ignoring assignment: %m", rvalue);
return 0;
}
TAKE_PTR(opt);
TAKE_PTR(opt4);
}
return 0;
}
@ -486,6 +536,7 @@ static const char * const dhcp_option_data_type_table[_DHCP_OPTION_DATA_MAX] = {
[DHCP_OPTION_DATA_UINT32] = "uint32",
[DHCP_OPTION_DATA_STRING] = "string",
[DHCP_OPTION_DATA_IPV4ADDRESS] = "ipv4address",
[DHCP_OPTION_DATA_IPV6ADDRESS] = "ipv6address",
};
DEFINE_STRING_TABLE_LOOKUP(dhcp_option_data_type, DHCPOptionDataType);

View File

@ -21,6 +21,7 @@ typedef enum DHCPOptionDataType {
DHCP_OPTION_DATA_UINT32,
DHCP_OPTION_DATA_STRING,
DHCP_OPTION_DATA_IPV4ADDRESS,
DHCP_OPTION_DATA_IPV6ADDRESS,
_DHCP_OPTION_DATA_MAX,
_DHCP_OPTION_DATA_INVALID,
} DHCPOptionDataType;

View File

@ -2,14 +2,17 @@
#include "sd-dhcp-server.h"
#include "fd-util.h"
#include "fileio.h"
#include "networkd-dhcp-server.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "parse-util.h"
#include "strv.h"
#include "socket-netlink.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
static Address* link_find_dhcp_server_address(Link *link) {
Address *address;
@ -174,6 +177,87 @@ static int link_push_uplink_to_dhcp_server(
return sd_dhcp_server_set_servers(s, what, addresses, n_addresses);
}
static int dhcp4_server_parse_dns_server_string_and_warn(Link *l, const char *string, struct in_addr **addresses, size_t *n_allocated, size_t *n_addresses) {
for (;;) {
_cleanup_free_ char *word = NULL, *server_name = NULL;
union in_addr_union address;
int family, r, ifindex = 0;
r = extract_first_word(&string, &word, NULL, 0);
if (r < 0)
return r;
if (r == 0)
break;
r = in_addr_ifindex_name_from_string_auto(word, &family, &address, &ifindex, &server_name);
if (r < 0) {
log_warning_errno(r, "Failed to parse DNS server address '%s', ignoring: %m", word);
continue;
}
/* Only look for IPv4 addresses */
if (family != AF_INET)
continue;
/* Never propagate obviously borked data */
if (in4_addr_is_null(&address.in) || in4_addr_is_localhost(&address.in))
continue;
if (!GREEDY_REALLOC(*addresses, *n_allocated, *n_addresses + 1))
return log_oom();
(*addresses)[(*n_addresses)++] = address.in;
}
return 0;
}
static int dhcp4_server_set_dns_from_resolve_conf(Link *link) {
_cleanup_free_ struct in_addr *addresses = NULL;
size_t n_addresses = 0, n_allocated = 0;
_cleanup_fclose_ FILE *f = NULL;
int n = 0, r;
f = fopen(PRIVATE_UPLINK_RESOLV_CONF, "re");
if (!f) {
if (errno == ENOENT)
return 0;
return log_warning_errno(errno, "Failed to open " PRIVATE_UPLINK_RESOLV_CONF ": %m");
}
for (;;) {
_cleanup_free_ char *line = NULL;
const char *a;
char *l;
r = read_line(f, LONG_LINE_MAX, &line);
if (r < 0)
return log_error_errno(r, "Failed to read " PRIVATE_UPLINK_RESOLV_CONF ": %m");
if (r == 0)
break;
n++;
l = strstrip(line);
if (IN_SET(*l, '#', ';', 0))
continue;
a = first_word(l, "nameserver");
if (!a)
continue;
r = dhcp4_server_parse_dns_server_string_and_warn(link, a, &addresses, &n_allocated, &n_addresses);
if (r < 0)
log_warning_errno(r, "Failed to parse DNS server address '%s', ignoring.", a);
}
if (n_addresses <= 0)
return 0;
return sd_dhcp_server_set_dns(link->dhcp_server, addresses, n_addresses);
}
int dhcp4_server_configure(Link *link) {
bool acquired_uplink = false;
sd_dhcp_option *p;
@ -267,8 +351,10 @@ int dhcp4_server_configure(Link *link) {
"Not emitting %s on link, couldn't find suitable uplink.",
dhcp_lease_info_to_string(n));
r = 0;
} else
} else if (uplink->network)
r = link_push_uplink_to_dhcp_server(uplink, n, link->dhcp_server);
else if (n == SD_DHCP_LEASE_DNS_SERVERS)
r = dhcp4_server_set_dns_from_resolve_conf(link);
}
if (r < 0)
log_link_warning_errno(link, r,

View File

@ -620,7 +620,9 @@ static int dhcp6_set_hostname(sd_dhcp6_client *client, Link *link) {
int dhcp6_configure(Link *link) {
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
sd_dhcp6_option *send_option;
const DUID *duid;
Iterator i;
int r;
assert(link);
@ -662,6 +664,14 @@ int dhcp6_configure(Link *link) {
if (r < 0)
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set DUID: %m");
ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp6_client_send_options, i) {
r = sd_dhcp6_client_add_option(client, send_option);
if (r == -EEXIST)
continue;
if (r < 0)
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set option: %m");
}
r = dhcp6_set_hostname(client, link);
if (r < 0)
return r;

View File

@ -185,7 +185,7 @@ DHCPv4.SendRelease, config_parse_bool,
DHCPv4.SendDecline, config_parse_bool, 0, offsetof(Network, dhcp_send_decline)
DHCPv4.BlackList, config_parse_dhcp_black_listed_ip_address, 0, 0
DHCPv4.IPServiceType, config_parse_dhcp_ip_service_type, 0, offsetof(Network, ip_service_type)
DHCPv4.SendOption, config_parse_dhcp_send_option, 0, offsetof(Network, dhcp_client_send_options)
DHCPv4.SendOption, config_parse_dhcp_send_option, AF_INET, offsetof(Network, dhcp_client_send_options)
DHCPv4.SendVendorOption, config_parse_dhcp_send_option, 0, offsetof(Network, dhcp_client_send_vendor_options)
DHCPv4.RouteMTUBytes, config_parse_mtu, AF_INET, offsetof(Network, dhcp_route_mtu)
DHCPv6.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp6_use_dns)
@ -195,6 +195,7 @@ DHCPv6.MUDURL, config_parse_dhcp6_mud_url,
DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information)
DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_hint, 0, 0
DHCPv6.WithoutRA, config_parse_bool, 0, offsetof(Network, dhcp6_without_ra)
DHCPv6.SendOption, config_parse_dhcp_send_option, AF_INET6, offsetof(Network, dhcp6_client_send_options)
IPv6AcceptRA.UseAutonomousPrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_autonomous_prefix)
IPv6AcceptRA.UseOnLinkPrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_onlink_prefix)
IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns)

View File

@ -133,6 +133,7 @@ struct Network {
uint8_t dhcp6_pd_length;
char *dhcp6_mudurl;
struct in6_addr dhcp6_pd_address;
OrderedHashmap *dhcp6_client_send_options;
/* DHCP Server Support */
bool dhcp_server;

View File

@ -64,8 +64,6 @@ systemd_resolved_sources = files('''
resolved-etc-hosts.h
resolved-etc-hosts.c
resolved-dnstls.h
resolved-util.c
resolved-util.h
'''.split())
resolvectl_sources = files('''
@ -230,10 +228,4 @@ tests += [
[],
[],
'ENABLE_RESOLVE', 'manual'],
[['src/resolve/test-resolved-util.c',
'src/resolve/resolved-util.c',
'src/resolve/resolved-util.h'],
[],
[]],
]

View File

@ -8,10 +8,10 @@
#include "parse-util.h"
#include "resolved-conf.h"
#include "resolved-dnssd.h"
#include "resolved-util.h"
#include "resolved-manager.h"
#include "resolved-dns-search-domain.h"
#include "dns-domain.h"
#include "socket-netlink.h"
#include "specifier.h"
#include "string-table.h"
#include "string-util.h"

View File

@ -1,36 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "alloc-util.h"
#include "macro.h"
#include "resolved-util.h"
#include "socket-netlink.h"
int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name) {
_cleanup_free_ char *buf = NULL, *name = NULL;
const char *m;
int r;
assert(s);
m = strchr(s, '#');
if (m) {
name = strdup(m+1);
if (!name)
return -ENOMEM;
buf = strndup(s, m - s);
if (!buf)
return -ENOMEM;
s = buf;
}
r = in_addr_ifindex_from_string_auto(s, family, ret, ifindex);
if (r < 0)
return r;
if (server_name)
*server_name = TAKE_PTR(name);
return r;
}

View File

@ -1,6 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include "in-addr-util.h"
int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name);

View File

@ -1,32 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "log.h"
#include "resolved-util.h"
#include "string-util.h"
#include "tests.h"
static void test_in_addr_ifindex_name_from_string_auto_one(const char *a, const char *expected) {
int family, ifindex;
union in_addr_union ua;
_cleanup_free_ char *server_name = NULL;
assert_se(in_addr_ifindex_name_from_string_auto(a, &family, &ua, &ifindex, &server_name) >= 0);
assert_se(streq_ptr(server_name, expected));
}
static void test_in_addr_ifindex_name_from_string_auto(void) {
log_info("/* %s */", __func__);
test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1", NULL);
test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1#test.com", "test.com");
test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19", NULL);
test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19#another.test.com", "another.test.com");
}
int main(int argc, char **argv) {
test_setup_logging(LOG_DEBUG);
test_in_addr_ifindex_name_from_string_auto();
return 0;
}

View File

@ -362,3 +362,33 @@ int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_u
return r;
}
int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name) {
_cleanup_free_ char *buf = NULL, *name = NULL;
const char *m;
int r;
assert(s);
m = strchr(s, '#');
if (m) {
name = strdup(m+1);
if (!name)
return -ENOMEM;
buf = strndup(s, m - s);
if (!buf)
return -ENOMEM;
s = buf;
}
r = in_addr_ifindex_from_string_auto(s, family, ret, ifindex);
if (r < 0)
return r;
if (server_name)
*server_name = TAKE_PTR(name);
return r;
}

View File

@ -21,3 +21,4 @@ bool socket_address_is(const SocketAddress *a, const char *s, int type);
bool socket_address_is_netlink(const SocketAddress *a, const char *s);
int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex);
int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name);

View File

@ -24,6 +24,7 @@
#include <sys/types.h>
#include "sd-dhcp6-lease.h"
#include "sd-dhcp6-option.h"
#include "sd-event.h"
#include "_sd-common.h"
@ -142,6 +143,8 @@ int sd_dhcp6_client_get_lease(
sd_dhcp6_client *client,
sd_dhcp6_lease **ret);
int sd_dhcp6_client_add_option(sd_dhcp6_client *client, sd_dhcp6_option *v);
int sd_dhcp6_client_stop(sd_dhcp6_client *client);
int sd_dhcp6_client_start(sd_dhcp6_client *client);
int sd_dhcp6_client_is_running(sd_dhcp6_client *client);

View File

@ -0,0 +1,37 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#ifndef foosddhcp6optionhfoo
#define foosddhcp6optionhfoo
/***
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 <inttypes.h>
#include <sys/types.h>
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
typedef struct sd_dhcp6_option sd_dhcp6_option;
int sd_dhcp6_option_new(uint16_t option, const void *data, size_t length, sd_dhcp6_option **ret);
sd_dhcp6_option *sd_dhcp6_option_ref(sd_dhcp6_option *ra);
sd_dhcp6_option *sd_dhcp6_option_unref(sd_dhcp6_option *ra);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp6_option, sd_dhcp6_option_unref);
_SD_END_DECLARATIONS;
#endif

View File

@ -58,6 +58,7 @@ int main(int argc, char **argv) {
test_genuine_random_bytes(0);
test_genuine_random_bytes(RANDOM_BLOCK);
test_genuine_random_bytes(RANDOM_ALLOW_RDRAND);
test_genuine_random_bytes(RANDOM_ALLOW_INSECURE);
test_pseudo_random_bytes();

View File

@ -245,6 +245,24 @@ static void test_in_addr_ifindex_from_string_auto(void) {
assert_se(in_addr_ifindex_from_string_auto("fe80::19%thisinterfacecantexist", &family, &ua, &ifindex) == -ENODEV);
}
static void test_in_addr_ifindex_name_from_string_auto_one(const char *a, const char *expected) {
int family, ifindex;
union in_addr_union ua;
_cleanup_free_ char *server_name = NULL;
assert_se(in_addr_ifindex_name_from_string_auto(a, &family, &ua, &ifindex, &server_name) >= 0);
assert_se(streq_ptr(server_name, expected));
}
static void test_in_addr_ifindex_name_from_string_auto(void) {
log_info("/* %s */", __func__);
test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1", NULL);
test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1#test.com", "test.com");
test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19", NULL);
test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19#another.test.com", "another.test.com");
}
static void test_sockaddr_equal(void) {
union sockaddr_union a = {
.in.sin_family = AF_INET,
@ -676,6 +694,7 @@ int main(int argc, char *argv[]) {
test_in_addr_to_string();
test_in_addr_ifindex_to_string();
test_in_addr_ifindex_from_string_auto();
test_in_addr_ifindex_name_from_string_auto();
test_sockaddr_equal();

View File

@ -112,6 +112,7 @@ ForceDHCPv6PDOtherInformation=
PrefixDelegationHint=
WithoutRA=
MUDURL=
SendOption=
[Route]
Destination=
Protocol=