Compare commits

...

5 Commits

Author SHA1 Message Date
Yu Watanabe 3c4ddf5db5
Merge pull request #14407 from ssahani/dhcp-decline
network: DHCP4 introduce send decline
2019-12-21 08:40:22 +09:00
Lennart Poettering b895fa08e6 Revert "Drop dbus activation stub service"
This reverts commit 07125d24ee.

In contrast to what is claimed in #13396 dbus-broker apparently does
care for the service file to be around, and otherwise will claim
"Service Not Activatable" in the time between systemd starting up the
broker and connecting to it, which the stub service file is supposed to
make go away.

Reverting this makes the integration test suite pass again on host with
dbus-broker (i.e. current Fedora desktop).

Tested with dbus-broker-21-6.fc31.x86_64.
2019-12-20 17:28:12 +01:00
Yu Watanabe 0fd8b71809 test-network: add a test case for DHCPv4.SendDecline= 2019-12-21 00:26:44 +09:00
Yu Watanabe c1d3fa29ca network: link should not become configured state during ACD probing 2019-12-21 00:26:44 +09:00
Susant Sahani 0f3ff4eae2 network: DHCP4 introduce send decline 2019-12-21 00:26:44 +09:00
15 changed files with 234 additions and 14 deletions

4
README
View File

@ -174,7 +174,9 @@ REQUIREMENTS:
dependencies: dependencies:
util-linux >= v2.27.1 required util-linux >= v2.27.1 required
dbus >= 1.11.0 (strictly speaking optional, but recommended) dbus >= 1.4.0 (strictly speaking optional, but recommended)
NOTE: If using dbus < 1.9.18, you should override the default
policy directory (--with-dbuspolicydir=/etc/dbus-1/system.d).
dracut (optional) dracut (optional)
polkit (optional) polkit (optional)

View File

@ -1633,6 +1633,17 @@
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>SendDecline=</varname></term>
<listitem>
<para>A boolen. When <literal>true</literal>, DHCPv4 clients receives IP address from DHCP server.
After new IP is received, DHCPv4 performs IPv4 Duplicate Address Detection. If duplicate use of IP is detected
the DHCPv4 client rejects the IP by sending a DHCPDECLINE packet DHCP clients try to obtain an IP address again.
See <ulink url="https://tools.ietf.org/html/rfc5227">RFC 5224</ulink>.
Defaults to <literal>unset</literal>.</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>BlackList=</varname></term> <term><varname>BlackList=</varname></term>
<listitem> <listitem>

View File

@ -195,6 +195,8 @@ endforeach
install_data('org.freedesktop.systemd1.conf', install_data('org.freedesktop.systemd1.conf',
install_dir : dbuspolicydir) install_dir : dbuspolicydir)
install_data('org.freedesktop.systemd1.service',
install_dir : dbussystemservicedir)
policy = configure_file( policy = configure_file(
input : 'org.freedesktop.systemd1.policy.in', input : 'org.freedesktop.systemd1.policy.in',

View File

@ -0,0 +1,13 @@
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[D-BUS Service]
Name=org.freedesktop.systemd1
Exec=/bin/false
User=root

View File

@ -643,7 +643,7 @@ static int client_message_init(
assert(ret); assert(ret);
assert(_optlen); assert(_optlen);
assert(_optoffset); assert(_optoffset);
assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE)); assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE, DHCP_DECLINE));
optlen = DHCP_MIN_OPTIONS_SIZE; optlen = DHCP_MIN_OPTIONS_SIZE;
size = sizeof(DHCPPacket) + optlen; size = sizeof(DHCPPacket) + optlen;
@ -1966,6 +1966,48 @@ int sd_dhcp_client_send_release(sd_dhcp_client *client) {
return 0; return 0;
} }
int sd_dhcp_client_send_decline(sd_dhcp_client *client) {
assert_return(client, -EINVAL);
assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE);
assert_return(client->lease, -EUNATCH);
_cleanup_free_ DHCPPacket *release = NULL;
size_t optoffset, optlen;
int r;
r = client_message_init(client, &release, DHCP_DECLINE, &optlen, &optoffset);
if (r < 0)
return r;
release->dhcp.ciaddr = client->lease->address;
memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len);
r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
SD_DHCP_OPTION_END, 0, NULL);
if (r < 0)
return r;
r = dhcp_network_send_udp_socket(client->fd,
client->lease->server_address,
DHCP_PORT_SERVER,
&release->dhcp,
sizeof(DHCPMessage) + optoffset);
if (r < 0)
return r;
log_dhcp_client(client, "DECLINE");
client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
if (client->state != DHCP_STATE_STOPPED) {
r = sd_dhcp_client_start(client);
if (r < 0)
return r;
}
return 0;
}
int sd_dhcp_client_stop(sd_dhcp_client *client) { int sd_dhcp_client_stop(sd_dhcp_client *client) {
DHCP_CLIENT_DONT_DESTROY(client); DHCP_CLIENT_DONT_DESTROY(client);

View File

@ -48,6 +48,15 @@ void dhcp4_release_old_lease(Link *link) {
link_dirty(link); link_dirty(link);
} }
static void dhcp4_check_ready(Link *link) {
if (link->dhcp4_messages == 0) {
link->dhcp4_configured = true;
/* New address and routes are configured now. Let's release old lease. */
dhcp4_release_old_lease(link);
link_check_ready(link);
}
}
static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r; int r;
@ -89,10 +98,8 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
return 1; return 1;
} }
link->dhcp4_configured = true; if (!link->network->dhcp_send_decline)
/* New address and routes are configured now. Let's release old lease. */ dhcp4_check_ready(link);
dhcp4_release_old_lease(link);
link_check_ready(link);
} }
return 1; return 1;
@ -655,6 +662,78 @@ static int dhcp_lease_lost(Link *link) {
return 0; return 0;
} }
static void dhcp_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
_cleanup_free_ char *pretty = NULL;
union in_addr_union address = {};
Link *link;
int r;
assert(acd);
assert(userdata);
link = userdata;
switch (event) {
case SD_IPV4ACD_EVENT_STOP:
log_link_debug(link, "Stopping ACD client for DHCP4...");
return;
case SD_IPV4ACD_EVENT_BIND:
if (DEBUG_LOGGING) {
(void) sd_dhcp_lease_get_address(link->dhcp_lease, &address.in);
(void) in_addr_to_string(AF_INET, &address, &pretty);
log_link_debug(link, "Successfully claimed DHCP4 address %s", strna(pretty));
}
dhcp4_check_ready(link);
break;
case SD_IPV4ACD_EVENT_CONFLICT:
(void) sd_dhcp_lease_get_address(link->dhcp_lease, &address.in);
(void) in_addr_to_string(AF_INET, &address, &pretty);
log_link_warning(link, "DAD conflict. Dropping DHCP4 address %s", strna(pretty));
(void) sd_dhcp_client_send_decline(link->dhcp_client);
if (link->dhcp_lease) {
r = dhcp_lease_lost(link);
if (r < 0)
link_enter_failed(link);
}
break;
default:
assert_not_reached("Invalid IPv4ACD event.");
}
sd_ipv4acd_stop(acd);
return;
}
static int configure_dhcpv4_duplicate_address_detection(Link *link) {
int r;
assert(link);
r = sd_ipv4acd_new(&link->network->dhcp_acd);
if (r < 0)
return r;
r = sd_ipv4acd_attach_event(link->network->dhcp_acd, NULL, 0);
if (r < 0)
return r;
r = sd_ipv4acd_set_ifindex(link->network->dhcp_acd, link->ifindex);
if (r < 0)
return r;
r = sd_ipv4acd_set_mac(link->network->dhcp_acd, &link->mac);
if (r < 0)
return r;
return 0;
}
static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r; int r;
@ -684,14 +763,32 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
return 1; return 1;
} }
if (link->dhcp4_messages == 0) { if (link->network->dhcp_send_decline) {
link->dhcp4_configured = true; union in_addr_union addr;
/* The new address is configured, and no route is requested.
* Let's drop the old lease. */ (void) sd_dhcp_lease_get_address(link->dhcp_lease, &addr.in);
dhcp4_release_old_lease(link);
link_check_ready(link); r = sd_ipv4acd_set_address(link->network->dhcp_acd, &addr.in);
if (r < 0)
return r;
r = sd_ipv4acd_set_callback(link->network->dhcp_acd, dhcp_address_on_acd, link);
if (r < 0)
return r;
if (DEBUG_LOGGING) {
_cleanup_free_ char *pretty = NULL;
(void) in_addr_to_string(AF_INET, &addr, &pretty);
log_debug("Starting IPv4ACD client. Probing DHCPv4 address %s", strna(pretty));
} }
r = sd_ipv4acd_start(link->network->dhcp_acd, true);
if (r < 0)
log_link_warning_errno(link, r, "Failed to start IPv4ACD client, ignoring: %m");
} else
dhcp4_check_ready(link);
return 1; return 1;
} }
@ -1033,6 +1130,7 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
return r; return r;
if (r != 0) if (r != 0)
return -ENOMSG; return -ENOMSG;
break; break;
default: default:
if (event < 0) if (event < 0)
@ -1334,6 +1432,13 @@ int dhcp4_configure(Link *link) {
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set ip service type: %m"); return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set ip service type: %m");
} }
if (link->network->dhcp_send_decline) {
r = configure_dhcpv4_duplicate_address_detection(link);
if (r < 0)
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to configure service type: %m");
}
return dhcp4_set_client_identifier(link); return dhcp4_set_client_identifier(link);
} }

View File

@ -174,6 +174,7 @@ DHCPv4.UseTimezone, config_parse_bool,
DHCPv4.IAID, config_parse_iaid, 0, 0 DHCPv4.IAID, config_parse_iaid, 0, 0
DHCPv4.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port) DHCPv4.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port)
DHCPv4.SendRelease, config_parse_bool, 0, offsetof(Network, dhcp_send_release) DHCPv4.SendRelease, config_parse_bool, 0, offsetof(Network, dhcp_send_release)
DHCPv4.SendDecline, config_parse_bool, 0, offsetof(Network, dhcp_send_decline)
DHCPv4.BlackList, config_parse_dhcp_black_listed_ip_address, 0, 0 DHCPv4.BlackList, config_parse_dhcp_black_listed_ip_address, 0, 0
DHCPv4.IPServiceType, config_parse_ip_service_type, 0, offsetof(Network, ip_service_type) DHCPv4.IPServiceType, config_parse_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, 0, offsetof(Network, dhcp_client_send_options)

View File

@ -619,6 +619,9 @@ static Network *network_free(Network *network) {
set_free(network->dhcp_request_options); set_free(network->dhcp_request_options);
free(network->mac); free(network->mac);
if (network->dhcp_acd)
sd_ipv4acd_unref(network->dhcp_acd);
strv_free(network->ntp); strv_free(network->ntp);
free(network->dns); free(network->dns);
strv_free(network->sip); strv_free(network->sip);

View File

@ -5,6 +5,7 @@
#include "sd-bus.h" #include "sd-bus.h"
#include "sd-device.h" #include "sd-device.h"
#include "sd-ipv4acd.h"
#include "bridge.h" #include "bridge.h"
#include "condition.h" #include "condition.h"
@ -111,7 +112,9 @@ struct Network {
bool dhcp_use_hostname; bool dhcp_use_hostname;
bool dhcp_route_table_set; bool dhcp_route_table_set;
bool dhcp_send_release; bool dhcp_send_release;
bool dhcp_send_decline;
DHCPUseDomains dhcp_use_domains; DHCPUseDomains dhcp_use_domains;
sd_ipv4acd *dhcp_acd;
Set *dhcp_black_listed_ip; Set *dhcp_black_listed_ip;
Set *dhcp_request_options; Set *dhcp_request_options;
OrderedHashmap *dhcp_client_send_options; OrderedHashmap *dhcp_client_send_options;

View File

@ -184,6 +184,7 @@ int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v);
int sd_dhcp_client_stop(sd_dhcp_client *client); int sd_dhcp_client_stop(sd_dhcp_client *client);
int sd_dhcp_client_start(sd_dhcp_client *client); int sd_dhcp_client_start(sd_dhcp_client *client);
int sd_dhcp_client_send_release(sd_dhcp_client *client); int sd_dhcp_client_send_release(sd_dhcp_client *client);
int sd_dhcp_client_send_decline(sd_dhcp_client *client);
int sd_dhcp_client_send_renew(sd_dhcp_client *client); int sd_dhcp_client_send_renew(sd_dhcp_client *client);
sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client); sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client);

View File

@ -98,6 +98,7 @@ SendRelease=
MaxAttempts= MaxAttempts=
IPServiceType= IPServiceType=
SendOption= SendOption=
SendDecline=
[DHCPv6] [DHCPv6]
UseNTP= UseNTP=
UseDNS= UseDNS=

View File

@ -0,0 +1,9 @@
[Match]
Name=veth99
[Network]
DHCP=ipv4
IPv6AcceptRA=false
[DHCPv4]
SendDecline=yes

View File

@ -0,0 +1,14 @@
[Match]
Name=veth-peer
[Network]
Address=192.168.5.1/24
Address=192.168.5.10/24
IPv6AcceptRA=false
DHCPServer=yes
[DHCPServer]
PoolOffset=10
PoolSize=1
DNS=192.168.5.1
NTP=192.168.5.1

View File

@ -2632,6 +2632,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
'25-vrf.netdev', '25-vrf.netdev',
'25-vrf.network', '25-vrf.network',
'dhcp-client-anonymize.network', 'dhcp-client-anonymize.network',
'dhcp-client-decline.network',
'dhcp-client-gateway-onlink-implicit.network', 'dhcp-client-gateway-onlink-implicit.network',
'dhcp-client-ipv4-dhcp-settings.network', 'dhcp-client-ipv4-dhcp-settings.network',
'dhcp-client-ipv4-only-ipv6-disabled.network', 'dhcp-client-ipv4-only-ipv6-disabled.network',
@ -2656,6 +2657,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network', 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
'dhcp-client-with-static-address.network', 'dhcp-client-with-static-address.network',
'dhcp-client.network', 'dhcp-client.network',
'dhcp-server-decline.network',
'dhcp-server-veth-peer.network', 'dhcp-server-veth-peer.network',
'dhcp-v4-server-veth-peer.network', 'dhcp-v4-server-veth-peer.network',
'dhcp-client-use-domains.network', 'dhcp-client-use-domains.network',
@ -3328,6 +3330,14 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
print(output) print(output)
self.assertRegex(output, 'example.com') self.assertRegex(output, 'example.com')
def test_dhcp_client_decline(self):
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
start_networkd()
self.wait_online(['veth-peer:carrier'])
rc = call(*wait_online_cmd, '--timeout=10s', '--interface=veth99:routable', env=env)
self.assertTrue(rc == 1)
class NetworkdIPv6PrefixTests(unittest.TestCase, Utilities): class NetworkdIPv6PrefixTests(unittest.TestCase, Utilities):
links = ['veth99'] links = ['veth99']

View File

@ -310,6 +310,9 @@ install_data('user-.slice.d/10-defaults.conf',
meson.add_install_script(meson_make_symlink, meson.add_install_script(meson_make_symlink,
join_paths(pkgsysconfdir, 'user'), join_paths(pkgsysconfdir, 'user'),
join_paths(sysconfdir, 'xdg/systemd/user')) join_paths(sysconfdir, 'xdg/systemd/user'))
meson.add_install_script(meson_make_symlink,
join_paths(dbussystemservicedir, 'org.freedesktop.systemd1.service'),
join_paths(dbussessionservicedir, 'org.freedesktop.systemd1.service'))
if conf.get('HAVE_SYSV_COMPAT') == 1 if conf.get('HAVE_SYSV_COMPAT') == 1
foreach i : [1, 2, 3, 4, 5] foreach i : [1, 2, 3, 4, 5]
meson.add_install_script( meson.add_install_script(