1
0
mirror of https://github.com/systemd/systemd synced 2025-10-08 21:24:45 +02:00

Compare commits

...

5 Commits

Author SHA1 Message Date
Lennart Poettering
ee7561d014 update TODO 2021-04-20 16:32:24 +02:00
Yegor Alexeyev
c95df5879e relay role implementation 2021-04-20 15:11:53 +02:00
Yu Watanabe
d5bfddf037 man: fix typo
Follow-up for e73309c532999cb15490a78575dd882b24bbe96f.
2021-04-20 11:41:05 +01:00
Miroslav Suchý
0084d4f6b5 document DefaultOOMPolicy
the `man systemd.service` say:
   Defaults to the setting DefaultOOMPolicy= in systemd-system.conf(5) is set to
but there is no such line in this config.
This is the default value I extracted from
   systemctl show --property=DefaultOOMPolicy
2021-04-20 10:40:42 +02:00
Yu Watanabe
66205cb3f5 wifi-util: do not set zero errno to log_debug_errno() 2021-04-20 10:39:50 +02:00
21 changed files with 237 additions and 24 deletions

11
TODO
View File

@ -22,6 +22,17 @@ Janitorial Clean-ups:
Features:
* ability to insert trusted configuration and secrets into the boot paramaters
of a kernel booting in a VM or on baremetal some way, via TPM
protection. idea:
1. pass via /proc/bootconfig
2. for secrets: put secrets in node of /proc/bootconfig, decrypt them via
TPM early on in PID 1, put them in $CREDENTIAL_PATH logic
3. for config: put signed data in node /proc/booconfig, validate via TPM
early on in PID 1, put data into /run/bootconfig/ as individual files
4. boot loader/stub should pick these up automatically from the boot loader
file systems
* journald: support RFC3164 fully for the incoming syslog transport, see
https://github.com/systemd/systemd/issues/19251#issuecomment-816601955

View File

@ -572,7 +572,7 @@
<listitem><para>Configures the 64bit GPT partition flags to set for the partition when creating
it. This option has no effect if the partition already exists. If not specified the flags values is
set to all zeroes, except if the partition type (as configured with <varname>Type=</varname> above)
refers to a Verity partition, in wich case bit 60 is set (i.e. the read-only bit). This bit may also
refers to a Verity partition, in which case bit 60 is set (i.e. the read-only bit). This bit may also
be configured separately via <varname>ReadOnly=</varname>, see below. Specify the flags value in
hexadecimal (by prefixing it with <literal>0x</literal>), binary (prefix <literal>0b</literal>) or
decimal (no prefix).</para></listitem>

View File

@ -2294,6 +2294,17 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
<variablelist class='network-directives'>
<varlistentry>
<term><varname>RelayTarget=</varname></term>
<listitem>
<para>Takes an IPv4 address, which must be in the format
described in
<citerefentry project='man-pages'><refentrytitle>inet_pton</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
Turns this DHCP server into a DHCP relay agent. See <ulink url="https://tools.ietf.org/html/rfc1542">RFC 1542</ulink>.
The address is the address of DHCP server or another relay agent to forward DHCP messages to and from.</para>
Check also BindToInterface= option. Turning it off is required for relaying messages outside.
</listitem>
</varlistentry>
<varlistentry>
<term><varname>PoolOffset=</varname></term>
<term><varname>PoolSize=</varname></term>

View File

@ -72,3 +72,4 @@
#DefaultLimitNICE=
#DefaultLimitRTPRIO=
#DefaultLimitRTTIME=
#DefaultOOMPolicy=stop

View File

@ -39,6 +39,7 @@ typedef struct DHCPLease {
} DHCPLease;
struct sd_dhcp_server {
struct in_addr relay_target;
unsigned n_ref;
sd_event *event;

View File

@ -114,6 +114,12 @@ int sd_dhcp_server_is_running(sd_dhcp_server *server) {
return !!server->receive_message;
}
int sd_dhcp_server_is_in_relay_mode(sd_dhcp_server *server) {
assert_return(server, -EINVAL);
return in4_addr_is_set(&server->relay_target);
}
void client_id_hash_func(const DHCPClientId *id, struct siphash *state) {
assert(id);
assert(id->length);
@ -343,10 +349,27 @@ static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination,
return 0;
}
static bool requested_broadcast(DHCPRequest *req) {
assert(req);
static bool requested_broadcast(DHCPMessage *message) {
assert(message);
return message->flags & htobe16(0x8000);
}
return req->message->flags & htobe16(0x8000);
static int dhcp_server_send(sd_dhcp_server *server, be32_t destination, uint16_t destination_port,
DHCPPacket *packet, size_t optoffset, bool l2_broadcast) {
if (destination != INADDR_ANY)
return dhcp_server_send_udp(server, destination,
destination_port, &packet->dhcp,
sizeof(DHCPMessage) + optoffset);
else if (l2_broadcast)
return dhcp_server_send_udp(server, INADDR_BROADCAST,
destination_port, &packet->dhcp,
sizeof(DHCPMessage) + optoffset);
else
/* we cannot send UDP packet to specific MAC address when the
address is not yet configured, so must fall back to raw
packets */
return dhcp_server_send_unicast_raw(server, packet,
sizeof(DHCPPacket) + optoffset);
}
int dhcp_server_send_packet(sd_dhcp_server *server,
@ -404,20 +427,8 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
} else if (req->message->ciaddr && type != DHCP_NAK)
destination = req->message->ciaddr;
if (destination != INADDR_ANY)
return dhcp_server_send_udp(server, destination,
destination_port, &packet->dhcp,
sizeof(DHCPMessage) + optoffset);
else if (requested_broadcast(req) || type == DHCP_NAK)
return dhcp_server_send_udp(server, INADDR_BROADCAST,
destination_port, &packet->dhcp,
sizeof(DHCPMessage) + optoffset);
else
/* we cannot send UDP packet to specific MAC address when the
address is not yet configured, so must fall back to raw
packets */
return dhcp_server_send_unicast_raw(server, packet,
sizeof(DHCPPacket) + optoffset);
bool l2_broadcast = requested_broadcast(req->message) || type == DHCP_NAK;
return dhcp_server_send(server, destination, destination_port, packet, optoffset, l2_broadcast);
}
static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
@ -701,6 +712,47 @@ static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
return be32toh(requested_ip & ~server->netmask) - server->pool_offset;
}
static int dhcp_server_relay_message(sd_dhcp_server *server, DHCPMessage *message, size_t opt_length) {
_cleanup_free_ DHCPPacket *packet = NULL;
assert(server);
assert(message);
assert(sd_dhcp_server_is_in_relay_mode(server));
if (message->op == BOOTREQUEST) {
log_dhcp_server(server, "(relay agent) BOOTREQUEST (0x%x)", be32toh(message->xid));
if (message->hops >= 16)
return -ETIME;
message->hops++;
/* https://tools.ietf.org/html/rfc1542#section-4.1.1 */
if (message->giaddr == 0)
message->giaddr = server->address;
return dhcp_server_send_udp(server, server->relay_target.s_addr, DHCP_PORT_SERVER, message, sizeof(DHCPMessage) + opt_length);
} else if (message->op == BOOTREPLY) {
log_dhcp_server(server, "(relay agent) BOOTREPLY (0x%x)", be32toh(message->xid));
if (message->giaddr != server->address) {
return log_dhcp_server_errno(server, SYNTHETIC_ERRNO(EBADMSG),
"(relay agent) BOOTREPLY giaddr mismatch, discarding");
}
int message_type = dhcp_option_parse(message, sizeof(DHCPMessage) + opt_length, NULL, NULL, NULL);
if (message_type < 0)
return message_type;
packet = malloc0(sizeof(DHCPPacket) + opt_length);
if (!packet)
return -ENOMEM;
memcpy(&packet->dhcp, message, sizeof(DHCPMessage) + opt_length);
bool l2_broadcast = requested_broadcast(message) || message_type == DHCP_NAK;
const be32_t destination = message_type == DHCP_NAK ? INADDR_ANY : message->ciaddr;
return dhcp_server_send(server, destination, DHCP_PORT_CLIENT, packet, opt_length, l2_broadcast);
}
return -EBADMSG;
}
#define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
@ -999,10 +1051,15 @@ static int server_receive_message(sd_event_source *s, int fd,
}
}
r = dhcp_server_handle_message(server, message, (size_t) len);
if (r < 0)
log_dhcp_server_errno(server, r, "Couldn't process incoming message: %m");
if (sd_dhcp_server_is_in_relay_mode(server)) {
r = dhcp_server_relay_message(server, message, len - sizeof(DHCPMessage));
if (r < 0)
log_dhcp_server_errno(server, r, "Couldn't relay message: %m");
} else {
r = dhcp_server_handle_message(server, message, (size_t) len);
if (r < 0)
log_dhcp_server_errno(server, r, "Couldn't process incoming message: %m");
}
return 0;
}
@ -1238,3 +1295,14 @@ int sd_dhcp_server_set_callback(sd_dhcp_server *server, sd_dhcp_server_callback_
return 0;
}
int sd_dhcp_server_set_relay_target(sd_dhcp_server *server, const struct in_addr* address) {
assert_return(server, -EINVAL);
assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
if (memcmp(address, &server->relay_target, sizeof(struct in_addr)) == 0)
return 0;
server->relay_target = *address;
return 1;
}

View File

@ -31,6 +31,9 @@ static int property_get_leases(
if (!s)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Link %s has no DHCP server.", l->ifname);
if (sd_dhcp_server_is_in_relay_mode(s))
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Link %s has DHCP relay agent active.", l->ifname);
r = sd_bus_message_open_container(reply, 'a', "(uayayayayt)");
if (r < 0)
return r;

View File

@ -352,6 +352,10 @@ int dhcp4_server_configure(Link *link) {
if (r < 0)
return log_link_error_errno(link, r, "Failed to set router emission for DHCP server: %m");
r = sd_dhcp_server_set_relay_target(link->dhcp_server, &link->network->dhcp_server_relay_target);
if (r < 0)
return log_link_error_errno(link, r, "Failed to set relay target for DHCP server: %m");
if (link->network->dhcp_server_emit_timezone) {
_cleanup_free_ char *buffer = NULL;
const char *tz;
@ -398,6 +402,32 @@ int dhcp4_server_configure(Link *link) {
return 0;
}
int config_parse_dhcp_server_relay_target(
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;
union in_addr_union a;
int r;
r = in_addr_from_string(AF_INET, rvalue, &a);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse %s= address '%s', ignoring: %m", lvalue, rvalue);
return 0;
}
network->dhcp_server_relay_target = a.in;
return r;
}
int config_parse_dhcp_server_emit(
const char *unit,
const char *filename,

View File

@ -9,4 +9,5 @@ typedef struct Link Link;
int dhcp4_server_configure(Link *link);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_relay_target);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_emit);

View File

@ -256,6 +256,7 @@ IPv6AcceptRA.PrefixAllowList, config_parse_ndisc_address_filter,
IPv6AcceptRA.PrefixDenyList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_prefix)
IPv6AcceptRA.RouteAllowList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_allow_listed_route_prefix)
IPv6AcceptRA.RouteDenyList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_route_prefix)
DHCPServer.RelayTarget, config_parse_dhcp_server_relay_target, 0, 0
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[SD_DHCP_LEASE_DNS].emit)

View File

@ -186,6 +186,7 @@ struct Network {
/* DHCP Server Support */
bool dhcp_server;
bool dhcp_server_bind_to_interface;
struct in_addr dhcp_server_relay_target;
NetworkDHCPServerEmitAddress dhcp_server_emit[_SD_DHCP_LEASE_SERVER_TYPE_MAX];
bool dhcp_server_emit_router;
bool dhcp_server_emit_timezone;

View File

@ -30,7 +30,7 @@ int wifi_get_interface(sd_netlink *genl, int ifindex, enum nl80211_iftype *iftyp
if (r < 0)
return log_debug_errno(r, "Failed to request information about wifi interface %d: %m", ifindex);
if (!reply) {
log_debug_errno(r, "No reply received to request for information about wifi interface %d, ignoring.", ifindex);
log_debug("No reply received to request for information about wifi interface %d, ignoring.", ifindex);
goto nodata;
}
@ -98,7 +98,7 @@ int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *bssid) {
if (r < 0)
return log_debug_errno(r, "Failed to request information about wifi station: %m");
if (!reply) {
log_debug_errno(r, "No reply received to request for information about wifi station, ignoring.");
log_debug("No reply received to request for information about wifi station, ignoring.");
goto nodata;
}

View File

@ -83,6 +83,8 @@ int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t);
int sd_dhcp_server_forcerenew(sd_dhcp_server *server);
int sd_dhcp_server_is_in_relay_mode(sd_dhcp_server *server);
int sd_dhcp_server_set_relay_target(sd_dhcp_server *server, const struct in_addr* address);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_server, sd_dhcp_server_unref);
_SD_END_DECLARATIONS;

View File

@ -352,6 +352,7 @@ DNS=
SendOption=
SendVendorOption=
BindToInterface=
RelayTarget=
[NextHop]
Id=
Gateway=

View File

@ -0,0 +1,9 @@
[Match]
Name=client-peer
[Network]
Address=192.168.6.2/24
DHCPServer=yes
IPForward=ipv4
[DHCPServer]
RelayTarget=192.168.5.1
BindToInterface=no

View File

@ -0,0 +1,5 @@
[Match]
Name=client
[Network]
DHCP=yes
IPForward=ipv4

View File

@ -0,0 +1,5 @@
[Match]
Name=server-peer
[Network]
Address=192.168.5.2/24
IPForward=ipv4

View File

@ -0,0 +1,10 @@
[Match]
Name=server
[Network]
Address=192.168.5.1/24
IPForward=ipv4
DHCPServer=yes
[DHCPServer]
BindToInterface=no
PoolOffset=150
PoolSize=1

View File

@ -0,0 +1,8 @@
[NetDev]
Name=client
Kind=veth
MACAddress=12:34:56:78:9a:bc
[Peer]
Name=client-peer
MACAddress=12:34:56:78:9a:bd

View File

@ -0,0 +1,8 @@
[NetDev]
Name=server
Kind=veth
MACAddress=12:34:56:78:9b:bc
[Peer]
Name=server-peer
MACAddress=12:34:56:78:9b:bd

View File

@ -3689,6 +3689,43 @@ class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
self.assertRegex(output, '192.168.5.*')
self.assertRegex(output, 'Europe/Berlin')
class NetworkdDHCPServerRelayAgentTests(unittest.TestCase, Utilities):
links = [
'client',
'server',
'client-peer',
'server-peer',
]
units = [
'agent-veth-client.netdev',
'agent-veth-server.netdev',
'agent-client.network',
'agent-server.network',
'agent-client-peer.network',
'agent-server-peer.network',
]
def setUp(self):
remove_links(self.links)
stop_networkd(show_logs=False)
def tearDown(self):
remove_links(self.links)
remove_unit_from_networkd_path(self.units)
stop_networkd(show_logs=True)
def test_relay_agent(self):
copy_unit_to_networkd_unit_path(*self.units)
start_networkd()
#Test is disabled until BindToInterface DHCP server configuration option is supported
self.wait_online(['client:routable'])
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'client', env=env)
print(output)
self.assertRegex(output, 'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)')
class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
links = [
'veth99',