summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS14
-rw-r--r--TODO4
-rw-r--r--docs/.gitignore1
-rw-r--r--man/sd_bus_default.xml2
-rw-r--r--man/systemd.network.xml17
-rw-r--r--src/basic/fileio.c11
-rw-r--r--src/basic/fileio.h2
-rw-r--r--src/basic/process-util.c3
-rw-r--r--src/bus-proxyd/proxy.c18
-rw-r--r--src/core/job.c4
-rw-r--r--src/core/service.c2
-rw-r--r--src/libsystemd-network/sd-lldp.c2
-rw-r--r--src/libsystemd-terminal/grdev-drm.c4
-rw-r--r--src/libsystemd/sd-bus/bus-control.c29
-rw-r--r--src/libsystemd/sd-bus/kdbus.h1
-rw-r--r--src/libsystemd/sd-netlink/netlink-internal.h2
-rw-r--r--src/login/71-seat.rules.in2
-rw-r--r--src/network/networkd-link.c75
-rw-r--r--src/network/networkd-network-gperf.gperf131
-rw-r--r--src/network/networkd-network.c58
-rw-r--r--src/network/networkd.h18
-rw-r--r--src/nspawn/nspawn.c48
-rw-r--r--src/test/test-pty.c2
23 files changed, 350 insertions, 100 deletions
diff --git a/NEWS b/NEWS
index 03f8676589..f5173e0fd6 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
systemd System and Service Manager
CHANGES WITH 222:
+
* udev does not longer support the WAIT_FOR_SYSFS= key in udev rules.
There are no known issues with current sysfs, and udev does not need
or should be used to work around such bugs.
@@ -14,17 +15,22 @@ CHANGES WITH 222:
accelerometer/orientation data with this systemd version.
Please upgrade iio-sensor-proxy to version 1.0.
+ * networkd gained a new configuration option IPv6PrivacyExtensions=
+ which enables IPv6 privacy extensions (RFC 4941, "Privacy Extensions
+ for Stateless Address") on selected networks.
+
Contributions from: Abdo Roig-Maranges, Andrew Eikum, Bastien Nocera,
Cédric Delmas, Christian Hesse, Christos Trochalakis, Daniel Mack,
daurnimator, David Herrmann, Dimitri John Ledkov, Eric Biggers, Eric
Cook, Felipe Sateler, Geert Jansen, Gerd Hoffmann, Gianpaolo Macario,
- Greg Kroah-Hartman, Iago López Galeiras, Jan Alexander Steffens,
- Jan Engelhardt, Jay Strict, Kay Sievers, Lennart Poettering,
+ Greg Kroah-Hartman, Iago López Galeiras, Jan Alexander Steffens
+ (heftig), Jan Engelhardt, Jay Strict, Kay Sievers, Lennart Poettering,
Markus Knetschke, Martin Pitt, Michael Biebl, Michael Marineau, Michal
Sekletar, Miguel Bernal Marin, Peter Hutterer, Richard Maw, rinrinne,
- Tom Gundersen, Vedran Miletić, WaLyong Cho, Zbigniew Jędrzejewski-Szmek
+ Susant Sahani, Tom Gundersen, Torstein Husebø, Vedran Miletić, WaLyong
+ Cho, Zbigniew Jędrzejewski-Szmek
- -- Berlin, 2015-07-XX
+ -- Berlin, 2015-07-06
CHANGES WITH 221:
diff --git a/TODO b/TODO
index 386599bc10..2904e2b445 100644
--- a/TODO
+++ b/TODO
@@ -26,6 +26,8 @@ External:
Features:
+* consider throwing a warning if a service declares it wants to be "Before=" a .device unit.
+
* "systemctl edit" should know a mode to create a new unit file
* there's probably something wrong with having user mounts below /sys,
@@ -49,8 +51,6 @@ Features:
* install: include generator dirs in unit file search paths
-* networkd: add support for configuring ipv6 privacy extensions
-
* introduce an NSS module that uses machined info to give container UIDs pretty names when user namespacing is used.
* stop using off_t, it's a crazy type. Use uint64_t instead.
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 0000000000..35b5e99aee
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1 @@
+/html
diff --git a/man/sd_bus_default.xml b/man/sd_bus_default.xml
index c5a1b530f9..95b347bdfd 100644
--- a/man/sd_bus_default.xml
+++ b/man/sd_bus_default.xml
@@ -182,7 +182,7 @@
processes at this time.</para>
<para>These calls allocate a bus connection object and initiate
- the connection ot a well-known bus of some form. An alternative to
+ the connection to a well-known bus of some form. An alternative to
using these high-level calls is to create an unconnected bus
object with
<citerefentry><refentrytitle>sd_bus_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 71ced09696..ff01da6249 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -392,6 +392,23 @@
<literal>no</literal>.</para></listitem>
</varlistentry>
<varlistentry>
+ <term><varname>IPv6PrivacyExtensions=</varname></term>
+ <listitem><para>Configures use of stateless temporary
+ addresses that change over time (see <ulink
+ url="https://tools.ietf.org/html/rfc4941">RFC 4941</ulink>,
+ Privacy Extensions for Stateless Address Autoconfiguration
+ in IPv6). Takes a boolean or the special values
+ <literal>prefer-public</literal> and
+ <literal>kernel</literal>. When true enables the privacy
+ extensions and prefers temporary addresses over public
+ addresses. When <literal>prefer-public</literal> enables the
+ privacy extensions, but prefers public addresses over
+ temporary addresses. When false, the privacy extensions
+ remain disabled. When <literal>kernel</literal> the kernel's
+ default setting will be left in place. Defaults to
+ <literal>no</literal>.</para></listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>Bridge=</varname></term>
<listitem>
<para>The name of the bridge to add the link to.</para>
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index ff6b1a7ed7..00fb6f8b5c 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -134,6 +134,17 @@ int read_one_line_file(const char *fn, char **line) {
return 0;
}
+int verify_one_line_file(const char *fn, const char *line) {
+ _cleanup_free_ char *value = NULL;
+ int r;
+
+ r = read_one_line_file(fn, &value);
+ if (r < 0)
+ return r;
+
+ return streq(value, line);
+}
+
int read_full_stream(FILE *f, char **contents, size_t *size) {
size_t n, l;
_cleanup_free_ char *buf = NULL;
diff --git a/src/basic/fileio.h b/src/basic/fileio.h
index 5ae51c1e28..91d4a0d2d5 100644
--- a/src/basic/fileio.h
+++ b/src/basic/fileio.h
@@ -34,6 +34,8 @@ int read_one_line_file(const char *fn, char **line);
int read_full_file(const char *fn, char **contents, size_t *size);
int read_full_stream(FILE *f, char **contents, size_t *size);
+int verify_one_line_file(const char *fn, const char *line);
+
int parse_env_file(const char *fname, const char *separator, ...) _sentinel_;
int load_env_file(FILE *f, const char *fname, const char *separator, char ***l);
int load_env_file_pairs(FILE *f, const char *fname, const char *separator, char ***l);
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index cfc876567d..2c05f2fee4 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -329,6 +329,9 @@ int get_process_environ(pid_t pid, char **env) {
sz += cescape_char(c, outcome + sz);
}
+ if (sz == 0)
+ return -ENOENT;
+
outcome[sz] = '\0';
*env = outcome;
outcome = NULL;
diff --git a/src/bus-proxyd/proxy.c b/src/bus-proxyd/proxy.c
index c0055d3788..189ee969c7 100644
--- a/src/bus-proxyd/proxy.c
+++ b/src/bus-proxyd/proxy.c
@@ -144,6 +144,10 @@ static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fd
return 0;
}
+/*
+ * dbus-1 clients receive NameOwnerChanged and directed signals without
+ * subscribing to them; install the matches to receive them on kdbus.
+ */
static int proxy_prepare_matches(Proxy *p) {
_cleanup_free_ char *match = NULL;
const char *unique;
@@ -189,6 +193,20 @@ static int proxy_prepare_matches(Proxy *p) {
if (r < 0)
return log_error_errno(r, "Failed to add match for NameAcquired: %m");
+ free(match);
+ match = strjoin("type='signal',"
+ "destination='",
+ unique,
+ "'",
+ NULL);
+ if (!match)
+ return log_oom();
+
+ r = sd_bus_add_match(p->destination_bus, NULL, match, NULL, NULL);
+ if (r < 0)
+ log_error_errno(r, "Failed to add match for directed signals: %m");
+ /* FIXME: temporarily ignore error to support older kdbus versions */
+
return 0;
}
diff --git a/src/core/job.c b/src/core/job.c
index 8a047df0c3..1448e5b69a 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -452,7 +452,7 @@ static bool job_is_runnable(Job *j) {
j->type == JOB_RELOAD) {
/* Immediate result is that the job is or might be
- * started. In this case lets wait for the
+ * started. In this case let's wait for the
* dependencies, regardless whether they are
* starting or stopping something. */
@@ -462,7 +462,7 @@ static bool job_is_runnable(Job *j) {
}
/* Also, if something else is being stopped and we should
- * change state after it, then lets wait. */
+ * change state after it, then let's wait. */
SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i)
if (other->job &&
diff --git a/src/core/service.c b/src/core/service.c
index fa1e80b710..d72ff54daa 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1235,7 +1235,7 @@ static int main_pid_good(Service *s) {
/* Returns 0 if the pid is dead, 1 if it is good, -1 if we
* don't know */
- /* If we know the pid file, then lets just check if it is
+ /* If we know the pid file, then let's just check if it is
* still valid */
if (s->main_pid_known) {
diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c
index fddda97f52..6a2c05185d 100644
--- a/src/libsystemd-network/sd-lldp.c
+++ b/src/libsystemd-network/sd-lldp.c
@@ -133,8 +133,6 @@ static int lldp_receive_frame(sd_lldp *lldp, tlv_packet *tlv) {
lldp->statistics.stats_frames_in_total ++;
- return 0;
-
out:
if (r < 0)
log_lldp("Receive frame failed: %s", strerror(-r));
diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c
index 30c1a726eb..10c13e348a 100644
--- a/src/libsystemd-terminal/grdev-drm.c
+++ b/src/libsystemd-terminal/grdev-drm.c
@@ -2584,7 +2584,7 @@ static int unmanaged_card_new(grdev_card **out, grdev_session *session, struct u
} else {
/* We might get DRM-Master implicitly on open(); drop it immediately
* so we acquire it only once we're actually enabled. We don't
- * really care whether this call fails or not, but lets log any
+ * really care whether this call fails or not, but let's log any
* weird errors, anyway. */
r = ioctl(fd, DRM_IOCTL_DROP_MASTER, 0);
if (r < 0 && errno != EACCES && errno != EINVAL)
@@ -2777,7 +2777,7 @@ static int managed_card_resume_device_fn(sd_bus_message *signal,
if (cm->card.fd < 0) {
/* This shouldn't happen. We should already own an FD from
- * TakeDevice(). However, lets be safe and use this FD in case
+ * TakeDevice(). However, let's be safe and use this FD in case
* we really don't have one. There is no harm in doing this
* and our code works fine this way. */
fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c
index 7a59702cb2..a38c5c50fc 100644
--- a/src/libsystemd/sd-bus/bus-control.c
+++ b/src/libsystemd/sd-bus/bus-control.c
@@ -1219,7 +1219,7 @@ int bus_add_match_internal_kernel(
size_t sz;
const char *sender = NULL;
size_t sender_length = 0;
- uint64_t src_id = KDBUS_MATCH_ID_ANY;
+ uint64_t src_id = KDBUS_MATCH_ID_ANY, dst_id = KDBUS_MATCH_ID_ANY;
bool using_bloom = false;
unsigned i;
bool matches_name_change = true;
@@ -1332,13 +1332,21 @@ int bus_add_match_internal_kernel(
break;
}
- case BUS_MATCH_DESTINATION:
- /* The bloom filter does not include
- the destination, since it is only
- available for broadcast messages
- which do not carry a destination
- since they are undirected. */
+ case BUS_MATCH_DESTINATION: {
+ /*
+ * Kernel only supports matching on destination IDs, but
+ * not on destination names. So just skip the
+ * destination name restriction and verify it in
+ * user-space on retrieval.
+ */
+ r = bus_kernel_parse_unique_name(c->value_str, &dst_id);
+ if (r < 0)
+ return r;
+ else if (r > 0)
+ sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
+
break;
+ }
case BUS_MATCH_ROOT:
case BUS_MATCH_VALUE:
@@ -1365,6 +1373,13 @@ int bus_add_match_internal_kernel(
item = KDBUS_ITEM_NEXT(item);
}
+ if (dst_id != KDBUS_MATCH_ID_ANY) {
+ item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
+ item->type = KDBUS_ITEM_DST_ID;
+ item->id = dst_id;
+ item = KDBUS_ITEM_NEXT(item);
+ }
+
if (using_bloom) {
item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
item->type = KDBUS_ITEM_BLOOM_MASK;
diff --git a/src/libsystemd/sd-bus/kdbus.h b/src/libsystemd/sd-bus/kdbus.h
index 00a6e142c9..ecffc6b13c 100644
--- a/src/libsystemd/sd-bus/kdbus.h
+++ b/src/libsystemd/sd-bus/kdbus.h
@@ -374,6 +374,7 @@ enum kdbus_item_type {
KDBUS_ITEM_ATTACH_FLAGS_RECV,
KDBUS_ITEM_ID,
KDBUS_ITEM_NAME,
+ KDBUS_ITEM_DST_ID,
/* keep these item types in sync with KDBUS_ATTACH_* flags */
_KDBUS_ITEM_ATTACH_BASE = 0x1000,
diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h
index b8a3668bfc..6f51ebe73d 100644
--- a/src/libsystemd/sd-netlink/netlink-internal.h
+++ b/src/libsystemd/sd-netlink/netlink-internal.h
@@ -93,7 +93,7 @@ struct sd_netlink {
};
struct netlink_attribute {
- size_t offset; /* offset from hdr to attirubte */
+ size_t offset; /* offset from hdr to attribute */
};
struct netlink_container {
diff --git a/src/login/71-seat.rules.in b/src/login/71-seat.rules.in
index 47d68b85fb..de55c9a4ec 100644
--- a/src/login/71-seat.rules.in
+++ b/src/login/71-seat.rules.in
@@ -18,7 +18,7 @@ SUBSYSTEM=="usb", ATTR{bDeviceClass}=="09", TAG+="seat"
SUBSYSTEM=="usb", ATTR{idVendor}=="2230", ATTR{idProduct}=="000[13]", ENV{ID_AUTOSEAT}="1"
# qemu (version 2.4+) has a PCI-PCI bridge (-device pci-bridge-seat) to group
-# evices belonging to one seat. See:
+# devices belonging to one seat. See:
# http://git.qemu.org/?p=qemu.git;a=blob;f=docs/multiseat.txt
SUBSYSTEM=="pci", ATTR{vendor}=="0x1b36", ATTR{device}=="0x000a", TAG+="seat", ENV{ID_AUTOSEAT}="1"
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index dff81a5cf0..5607cf470e 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -116,6 +116,16 @@ static bool link_ipv6_forward_enabled(Link *link) {
return link->network->ip_forward & ADDRESS_FAMILY_IPV6;
}
+static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) {
+ if (link->flags & IFF_LOOPBACK)
+ return _IPV6_PRIVACY_EXTENSIONS_INVALID;
+
+ if (!link->network)
+ return _IPV6_PRIVACY_EXTENSIONS_INVALID;
+
+ return link->network->ipv6_privacy_extensions;
+}
+
#define FLAG_STRING(string, flag, old, new) \
(((old ^ new) & flag) \
? ((old & flag) ? (" -" string) : (" +" string)) \
@@ -1473,35 +1483,84 @@ static int link_enter_join_netdev(Link *link) {
}
static int link_set_ipv4_forward(Link *link) {
- const char *p = NULL;
+ const char *p = NULL, *v;
int r;
+ if (link->flags & IFF_LOOPBACK)
+ return 0;
+
if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID)
return 0;
p = strjoina("/proc/sys/net/ipv4/conf/", link->ifname, "/forwarding");
- r = write_string_file_no_create(p, one_zero(link_ipv4_forward_enabled(link)));
- if (r < 0)
+ v = one_zero(link_ipv4_forward_enabled(link));
+
+ r = write_string_file_no_create(p, v);
+ if (r < 0) {
+ /* If the right value is set anyway, don't complain */
+ if (verify_one_line_file(p, v) > 0)
+ return 0;
+
log_link_warning_errno(link, r, "Cannot configure IPv4 forwarding for interface %s: %m", link->ifname);
+ }
return 0;
}
static int link_set_ipv6_forward(Link *link) {
- const char *p = NULL;
+ const char *p = NULL, *v = NULL;
int r;
/* Make this a NOP if IPv6 is not available */
if (!socket_ipv6_is_supported())
return 0;
+ if (link->flags & IFF_LOOPBACK)
+ return 0;
+
if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID)
return 0;
p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/forwarding");
- r = write_string_file_no_create(p, one_zero(link_ipv6_forward_enabled(link)));
- if (r < 0)
+ v = one_zero(link_ipv6_forward_enabled(link));
+
+ r = write_string_file_no_create(p, v);
+ if (r < 0) {
+ /* If the right value is set anyway, don't complain */
+ if (verify_one_line_file(p, v) > 0)
+ return 0;
+
log_link_warning_errno(link, r, "Cannot configure IPv6 forwarding for interface: %m");
+ }
+
+ return 0;
+}
+
+static int link_set_ipv6_privacy_extensions(Link *link) {
+ char buf[DECIMAL_STR_MAX(unsigned) + 1];
+ IPv6PrivacyExtensions s;
+ const char *p = NULL;
+ int r;
+
+ /* Make this a NOP if IPv6 is not available */
+ if (!socket_ipv6_is_supported())
+ return 0;
+
+ s = link_ipv6_privacy_extensions(link);
+ if (s == _IPV6_PRIVACY_EXTENSIONS_INVALID)
+ return 0;
+
+ p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/use_tempaddr");
+ xsprintf(buf, "%u", link->network->ipv6_privacy_extensions);
+
+ r = write_string_file_no_create(p, buf);
+ if (r < 0) {
+ /* If the right value is set anyway, don't complain */
+ if (verify_one_line_file(p, buf) > 0)
+ return 0;
+
+ log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extension for interface: %m");
+ }
return 0;
}
@@ -1525,6 +1584,10 @@ static int link_configure(Link *link) {
if (r < 0)
return r;
+ r = link_set_ipv6_privacy_extensions(link);
+ if (r < 0)
+ return r;
+
if (link_ipv4ll_enabled(link)) {
r = ipv4ll_configure(link);
if (r < 0)
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index b05bc949f2..787fc2ff5b 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -15,69 +15,70 @@ struct ConfigPerfItem;
%struct-type
%includes
%%
-Match.MACAddress, config_parse_hwaddr, 0, offsetof(Network, match_mac)
-Match.Path, config_parse_strv, 0, offsetof(Network, match_path)
-Match.Driver, config_parse_strv, 0, offsetof(Network, match_driver)
-Match.Type, config_parse_strv, 0, offsetof(Network, match_type)
-Match.Name, config_parse_ifnames, 0, offsetof(Network, match_name)
-Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, match_host)
-Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, match_virt)
-Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, match_kernel)
-Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch)
-Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac)
-Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu)
-Network.Description, config_parse_string, 0, offsetof(Network, description)
-Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge)
-Network.Bond, config_parse_netdev, 0, offsetof(Network, bond)
-Network.VLAN, config_parse_netdev, 0, 0
-Network.MACVLAN, config_parse_netdev, 0, 0
-Network.IPVLAN, config_parse_netdev, 0, 0
-Network.VXLAN, config_parse_netdev, 0, 0
-Network.Tunnel, config_parse_tunnel, 0, 0
-Network.DHCP, config_parse_dhcp, 0, offsetof(Network, dhcp)
-Network.DHCPServer, config_parse_bool, 0, offsetof(Network, dhcp_server)
-Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local)
-Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route)
-Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token)
-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.DNS, config_parse_strv, 0, offsetof(Network, dns)
-Network.LLMNR, config_parse_llmnr, 0, offsetof(Network, llmnr)
-Network.NTP, config_parse_strv, 0, offsetof(Network, ntp)
-Network.IPForward, config_parse_address_family_boolean_with_kernel,0, offsetof(Network, ip_forward)
-Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade)
-Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier)
-Address.Address, config_parse_address, 0, 0
-Address.Peer, config_parse_address, 0, 0
-Address.Broadcast, config_parse_broadcast, 0, 0
-Address.Label, config_parse_label, 0, 0
-Route.Gateway, config_parse_gateway, 0, 0
-Route.Destination, config_parse_destination, 0, 0
-Route.Source, config_parse_destination, 0, 0
-Route.Metric, config_parse_route_priority, 0, 0
-Route.Scope, config_parse_route_scope, 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.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)
-Bridge.Cost, config_parse_unsigned, 0, offsetof(Network, cost)
-BridgeFDB.MACAddress, config_parse_fdb_hwaddr, 0, 0
-BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0
+Match.MACAddress, config_parse_hwaddr, 0, offsetof(Network, match_mac)
+Match.Path, config_parse_strv, 0, offsetof(Network, match_path)
+Match.Driver, config_parse_strv, 0, offsetof(Network, match_driver)
+Match.Type, config_parse_strv, 0, offsetof(Network, match_type)
+Match.Name, config_parse_ifnames, 0, offsetof(Network, match_name)
+Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, match_host)
+Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, match_virt)
+Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, match_kernel)
+Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch)
+Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac)
+Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu)
+Network.Description, config_parse_string, 0, offsetof(Network, description)
+Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge)
+Network.Bond, config_parse_netdev, 0, offsetof(Network, bond)
+Network.VLAN, config_parse_netdev, 0, 0
+Network.MACVLAN, config_parse_netdev, 0, 0
+Network.IPVLAN, config_parse_netdev, 0, 0
+Network.VXLAN, config_parse_netdev, 0, 0
+Network.Tunnel, config_parse_tunnel, 0, 0
+Network.DHCP, config_parse_dhcp, 0, offsetof(Network, dhcp)
+Network.DHCPServer, config_parse_bool, 0, offsetof(Network, dhcp_server)
+Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local)
+Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route)
+Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token)
+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.DNS, config_parse_strv, 0, offsetof(Network, dns)
+Network.LLMNR, config_parse_llmnr, 0, offsetof(Network, llmnr)
+Network.NTP, config_parse_strv, 0, offsetof(Network, ntp)
+Network.IPForward, config_parse_address_family_boolean_with_kernel,0, offsetof(Network, ip_forward)
+Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade)
+Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Network, ipv6_privacy_extensions)
+Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier)
+Address.Address, config_parse_address, 0, 0
+Address.Peer, config_parse_address, 0, 0
+Address.Broadcast, config_parse_broadcast, 0, 0
+Address.Label, config_parse_label, 0, 0
+Route.Gateway, config_parse_gateway, 0, 0
+Route.Destination, config_parse_destination, 0, 0
+Route.Source, config_parse_destination, 0, 0
+Route.Metric, config_parse_route_priority, 0, 0
+Route.Scope, config_parse_route_scope, 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.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)
+Bridge.Cost, config_parse_unsigned, 0, offsetof(Network, cost)
+BridgeFDB.MACAddress, config_parse_fdb_hwaddr, 0, 0
+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.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical)
+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.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index ec95c8661e..a8e9ef909c 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -111,6 +111,8 @@ static int network_load_one(Manager *manager, const char *filename) {
network->link_local = ADDRESS_FAMILY_IPV6;
+ network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
+
r = config_parse(NULL, filename, file,
"Match\0"
"Link\0"
@@ -751,3 +753,59 @@ int config_parse_address_family_boolean_with_kernel(
return 0;
}
+
+static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
+ [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
+ [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
+ [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
+
+int config_parse_ipv6_privacy_extensions(
+ 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) {
+
+ IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
+ int k;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(ipv6_privacy_extensions);
+
+ /* Our enum shall be a superset of booleans, hence first try
+ * to parse as boolean, and then as enum */
+
+ k = parse_boolean(rvalue);
+ if (k > 0)
+ *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
+ else if (k == 0)
+ *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
+ else {
+ IPv6PrivacyExtensions s;
+
+ s = ipv6_privacy_extensions_from_string(rvalue);
+ if (s < 0) {
+
+ if (streq(rvalue, "kernel"))
+ s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
+ else {
+ log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
+ return 0;
+ }
+ }
+
+ *ipv6_privacy_extensions = s;
+ }
+
+ return 0;
+}
diff --git a/src/network/networkd.h b/src/network/networkd.h
index ac6e2c8a8e..f98c640822 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -90,6 +90,15 @@ typedef enum DCHPClientIdentifier {
_DHCP_CLIENT_ID_INVALID = -1,
} DCHPClientIdentifier;
+typedef enum IPv6PrivacyExtensions {
+ /* The values map to the kernel's /proc/sys/net/ipv6/conf/xxx/use_tempaddr values */
+ IPV6_PRIVACY_EXTENSIONS_NO,
+ IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC,
+ IPV6_PRIVACY_EXTENSIONS_YES, /* aka prefer-temporary */
+ _IPV6_PRIVACY_EXTENSIONS_MAX,
+ _IPV6_PRIVACY_EXTENSIONS_INVALID = -1,
+} IPv6PrivacyExtensions;
+
struct FdbEntry {
Network *network;
unsigned section;
@@ -145,6 +154,8 @@ struct Network {
AddressFamilyBoolean ip_forward;
bool ip_masquerade;
+ IPv6PrivacyExtensions ipv6_privacy_extensions;
+
struct ether_addr *mac;
unsigned mtu;
@@ -455,3 +466,10 @@ int config_parse_address_family_boolean_with_kernel(const char *unit, const char
const char* link_operstate_to_string(LinkOperationalState s) _const_;
LinkOperationalState link_operstate_from_string(const char *s) _pure_;
+
+/* IPv6 privacy extensions support */
+
+const char* ipv6_privacy_extensions_to_string(IPv6PrivacyExtensions i) _const_;
+IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_;
+
+int config_parse_ipv6_privacy_extensions(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);
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 1ba248f6d6..ab9fbaf138 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -341,6 +341,11 @@ static int custom_mounts_prepare(void) {
for (i = 0; i < arg_n_custom_mounts; i++) {
CustomMount *m = &arg_custom_mounts[i];
+ if (arg_userns && arg_uid_shift == UID_INVALID && path_equal(m->destination, "/")) {
+ log_error("--private-users with automatic UID shift may not be combined with custom root mounts.");
+ return -EINVAL;
+ }
+
if (m->type != CUSTOM_MOUNT_OVERLAY)
continue;
@@ -1028,6 +1033,7 @@ static int tmpfs_patch_options(const char *options, char **ret) {
char *buf = NULL;
if (arg_userns && arg_uid_shift != 0) {
+ assert(arg_uid_shift != UID_INVALID);
if (options)
(void) asprintf(&buf, "%s,uid=" UID_FMT ",gid=" UID_FMT, options, arg_uid_shift, arg_uid_shift);
@@ -4259,6 +4265,7 @@ static int outer_child(
int pid_socket,
int kmsg_socket,
int rtnl_socket,
+ int uid_shift_socket,
FDSet *fds,
int argc,
char *argv[]) {
@@ -4317,6 +4324,16 @@ static int outer_child(
if (r < 0)
return r;
+ if (arg_userns) {
+ l = send(uid_shift_socket, &arg_uid_shift, sizeof(arg_uid_shift), MSG_NOSIGNAL);
+ if (l < 0)
+ return log_error_errno(errno, "Failed to send UID shift: %m");
+ if (l != sizeof(arg_uid_shift)) {
+ log_error("Short write while sending UID shift.");
+ return -EIO;
+ }
+ }
+
/* Turn directory into bind mount */
if (mount(directory, directory, NULL, MS_BIND|MS_REC, NULL) < 0)
return log_error_errno(errno, "Failed to make bind mount: %m");
@@ -4397,6 +4414,7 @@ static int outer_child(
if (pid == 0) {
pid_socket = safe_close(pid_socket);
+ uid_shift_socket = safe_close(uid_shift_socket);
/* The inner child has all namespaces that are
* requested, so that we all are owned by the user if
@@ -4687,7 +4705,8 @@ int main(int argc, char *argv[]) {
}
for (;;) {
- _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 };
+ _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 },
+ uid_shift_socket_pair[2] = { -1, -1 };
ContainerStatus container_status;
_cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
static const struct sigaction sa = {
@@ -4696,10 +4715,10 @@ int main(int argc, char *argv[]) {
};
int ifi = 0;
ssize_t l;
- _cleanup_event_unref_ sd_event *event = NULL;
- _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
- _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
- char last_char = 0;
+ _cleanup_event_unref_ sd_event *event = NULL;
+ _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
+ _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+ char last_char = 0;
r = barrier_create(&barrier);
if (r < 0) {
@@ -4722,6 +4741,12 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ if (arg_userns)
+ if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, uid_shift_socket_pair) < 0) {
+ r = log_error_errno(errno, "Failed to create uid shift socket pair: %m");
+ goto finish;
+ }
+
/* Child can be killed before execv(), so handle SIGCHLD
* in order to interrupt parent's blocking calls and
* give it a chance to call wait() and terminate. */
@@ -4756,6 +4781,7 @@ int main(int argc, char *argv[]) {
kmsg_socket_pair[0] = safe_close(kmsg_socket_pair[0]);
rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]);
pid_socket_pair[0] = safe_close(pid_socket_pair[0]);
+ uid_shift_socket_pair[0] = safe_close(uid_shift_socket_pair[0]);
(void) reset_all_signal_handlers();
(void) reset_signal_mask();
@@ -4771,6 +4797,7 @@ int main(int argc, char *argv[]) {
pid_socket_pair[1],
kmsg_socket_pair[1],
rtnl_socket_pair[1],
+ uid_shift_socket_pair[1],
fds,
argc, argv);
if (r < 0)
@@ -4819,6 +4846,17 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ l = recv(uid_shift_socket_pair[0], &arg_uid_shift, sizeof(arg_uid_shift), 0);
+ if (l < 0) {
+ r = log_error_errno(errno, "Failed to read UID shift: %m");
+ goto finish;
+ }
+ if (l != sizeof(arg_uid_shift)) {
+ log_error("Short read while reading UID shift: %m");
+ r = EIO;
+ goto finish;
+ }
+
r = setup_uid_map(pid);
if (r < 0)
goto finish;
diff --git a/src/test/test-pty.c b/src/test/test-pty.c
index 3f97a64ccd..fbab3d4ebe 100644
--- a/src/test/test-pty.c
+++ b/src/test/test-pty.c
@@ -133,7 +133,7 @@ int main(int argc, char *argv[]) {
/* Oh, there're ugly races in the TTY layer regarding HUP vs IN. Turns
* out they appear only 10% of the time. I fixed all of them and
- * don't see them, anymore. But lets be safe and run this 1000 times
+ * don't see them, anymore. But let's be safe and run this 1000 times
* so we catch any new ones, in case they appear again. */
for (i = 0; i < 1000; ++i)
test_pty();