Merge pull request #32299 from yuwata/network-radv-ignore-rs-from-the-same-interface

network/radv: ignore RS message from the same interface
This commit is contained in:
Luca Boccassi 2024-04-18 23:45:06 +02:00 committed by GitHub
commit e54bf3fe0b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 59 additions and 57 deletions

View file

@ -888,12 +888,13 @@ Table=1234</programlisting></para>
<varlistentry>
<term><varname>IPv6AcceptRA=</varname></term>
<listitem>
<para>Takes a boolean. Controls IPv6 Router Advertisement (RA) reception support for the
interface. If true, RAs are accepted; if false, RAs are ignored. When RAs are accepted, they
may trigger the start of the DHCPv6 client if the relevant flags are set in the RA data, or
if no routers are found on the link. The default is to disable RA reception for bridge
devices or when IP forwarding is enabled, and to enable it otherwise. Cannot be enabled on
devices aggregated in a bond device or when link-local addressing is disabled.</para>
<para>Takes a boolean. Controls IPv6 Router Advertisement (RA) reception support for the interface.
If true, RAs are accepted; if false, RAs are ignored. When RAs are accepted, they may trigger the
start of the DHCPv6 client if the relevant flags are set in the RA data, or if no routers are found
on the link. Defaults to false for bridge devices, when IP forwarding is enabled,
<varname>IPv6SendRA=</varname> or <varname>KeepMaster=</varname> is enabled. Otherwise, enabled by
default. Cannot be enabled on devices aggregated in a bond device or when link-local addressing is
disabled.</para>
<para>Further settings for the IPv6 RA support may be configured in the [IPv6AcceptRA]
section, see below.</para>

View file

@ -98,6 +98,7 @@ struct sd_radv {
int ifindex;
char *ifname;
struct in6_addr ipv6ll;
sd_event *event;
int event_priority;

View file

@ -283,6 +283,10 @@ static int radv_process_packet(sd_radv *ra, ICMP6Packet *packet) {
r = sd_ndisc_router_solicit_get_sender_address(rs, &src);
if (r < 0 && r != -ENODATA) /* null address is allowed */
return log_radv_errno(ra, r, "Failed to get sender address of RS, ignoring: %m");
if (r >= 0 && in6_addr_equal(&src, &ra->ipv6ll))
/* This should be definitely caused by a misconfiguration. If we send RA to ourself, the
* kernel complains about that. Let's ignore the packet. */
return log_radv_errno(ra, SYNTHETIC_ERRNO(EADDRINUSE), "Received RS from the same interface, ignoring.");
r = radv_send_router(ra, &src);
if (r < 0)
@ -495,6 +499,18 @@ int sd_radv_get_ifname(sd_radv *ra, const char **ret) {
return 0;
}
int sd_radv_set_link_local_address(sd_radv *ra, const struct in6_addr *addr) {
assert_return(ra, -EINVAL);
assert_return(!addr || in6_addr_is_link_local(addr), -EINVAL);
if (addr)
ra->ipv6ll = *addr;
else
zero(ra->ipv6ll);
return 0;
}
int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr) {
assert_return(ra, -EINVAL);

View file

@ -53,9 +53,14 @@ bool link_ndisc_enabled(Link *link) {
if (!link_may_have_ipv6ll(link, /* check_multicast = */ true))
return false;
/* Honor explicitly specified value. */
if (link->network->ndisc >= 0)
return link->network->ndisc;
/* Disable if RADV is enabled. */
if (link_radv_enabled(link))
return false;
/* Accept RAs if IPv6 forwarding is disabled, and ignore RAs if IPv6 forwarding is enabled. */
int t = link_get_ip_forwarding(link, AF_INET6);
if (t >= 0)

View file

@ -769,6 +769,10 @@ int radv_start(Link *link) {
return log_link_debug_errno(link, r, "Failed to request DHCP delegated subnet prefix: %m");
}
r = sd_radv_set_link_local_address(link->radv, &link->ipv6ll_address);
if (r < 0)
return r;
log_link_debug(link, "Starting IPv6 Router Advertisements");
return sd_radv_start(link->radv);
}

View file

@ -52,6 +52,7 @@ int sd_radv_is_running(sd_radv *ra);
int sd_radv_set_ifindex(sd_radv *ra, int interface_index);
int sd_radv_set_ifname(sd_radv *ra, const char *interface_name);
int sd_radv_get_ifname(sd_radv *ra, const char **ret);
int sd_radv_set_link_local_address(sd_radv *ra, const struct in6_addr *addr);
int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr);
int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu);
int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit);

View file

@ -1182,6 +1182,14 @@ class Utilities():
print(output)
self.assertRegex(output, r'.*elements = { [^}]*' + contents + r'[^}]* }.*')
def check_networkd_log(self, contents, since=None, trial=20):
for _ in range(trial):
if contents in read_networkd_log(since=since):
break
time.sleep(0.5)
else:
self.fail(f'"{contents}" not found in journal.')
class NetworkctlTests(unittest.TestCase, Utilities):
def setUp(self):
@ -1373,8 +1381,7 @@ class NetworkctlTests(unittest.TestCase, Utilities):
self.assertIn('Network File: /run/systemd/network/11-test-unit-file.network', output)
self.assertIn('/run/systemd/network/11-test-unit-file.network.d/dropin.conf', output)
output = read_networkd_log()
self.assertIn('test1: Configuring with /run/systemd/network/11-test-unit-file.network (dropins: /run/systemd/network/11-test-unit-file.network.d/dropin.conf).', output)
self.check_networkd_log('test1: Configuring with /run/systemd/network/11-test-unit-file.network (dropins: /run/systemd/network/11-test-unit-file.network.d/dropin.conf).')
# This test may be run on the system that has older udevd than 70f32a260b5ebb68c19ecadf5d69b3844896ba55 (v249).
# In that case, the udev DB for the loopback network interface may already have ID_NET_LINK_FILE property.
@ -1624,16 +1631,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
self.wait_online('bond99:off')
self.wait_operstate('vlan99', operstate='off', setup_state='configuring', setup_timeout=10)
# The commit b05e52000b4eee764b383cc3031da0a3739e996e adds ", ignoring". To make it easily confirmed
# that the issue is fixed by the commit, let's allow to match both string.
log_re = re.compile('vlan99: Could not bring up interface(, ignoring|): Network is down$', re.MULTILINE)
for i in range(20):
if i > 0:
time.sleep(0.5)
if log_re.search(read_networkd_log()):
break
else:
self.fail()
self.check_networkd_log('vlan99: Could not bring up interface, ignoring: Network is down')
copy_network_unit('11-dummy.netdev', '12-dummy.netdev', '21-dummy-bond-slave.network')
networkctl_reload()
@ -5593,6 +5591,12 @@ class NetworkdRATests(unittest.TestCase, Utilities):
self.assertIn('2002:da8:1:1:1a:2b:3c:4d via fe80::1 proto redirect', output)
self.assertIn('2002:da8:1:2:1a:2b:3c:4d via fe80::2 proto redirect', output)
# Check if sd-radv refuses RS from the same interface.
# See https://github.com/systemd/systemd/pull/32267#discussion_r1566721306
since = datetime.datetime.now()
check_output(f'{test_ndisc_send} --interface veth-peer --type rs --dest {veth_peer_ipv6ll}')
self.check_networkd_log('veth-peer: RADV: Received RS from the same interface, ignoring.', since=since)
def check_ndisc_mtu(self, mtu):
for _ in range(20):
output = read_ipv6_sysctl_attr('veth99', 'mtu')
@ -5612,13 +5616,7 @@ class NetworkdRATests(unittest.TestCase, Utilities):
start_networkd()
self.wait_online('veth-peer:degraded')
for _ in range(20):
output = read_networkd_log()
if 'veth99: NDISC: Started IPv6 Router Solicitation client' in output:
break
time.sleep(0.5)
else:
self.fail('sd-ndisc does not started on veth99.')
self.check_networkd_log('veth99: NDISC: Started IPv6 Router Solicitation client')
check_output(f'{test_ndisc_send} --interface veth-peer --type ra --lifetime 1hour --mtu 1400')
self.check_ndisc_mtu(1400)
@ -6032,13 +6030,7 @@ class NetworkdDHCPServerRelayAgentTests(unittest.TestCase, Utilities):
self.wait_online('bridge-relay:routable', 'client-peer:enslaved')
# For issue #30763.
expect = 'bridge-relay: DHCPv4 server: STARTED'
for _ in range(20):
if expect in read_networkd_log():
break
time.sleep(0.5)
else:
self.fail()
self.check_networkd_log('bridge-relay: DHCPv4 server: STARTED')
class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
@ -6510,37 +6502,19 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
since = datetime.datetime.now()
start_dnsmasq()
expect = 'veth99: DHCPv4 server IP address 192.168.5.1 not found in allow-list, ignoring offer.'
for _ in range(20):
if expect in read_networkd_log(since=since):
break
time.sleep(0.5)
else:
self.fail()
self.check_networkd_log('veth99: DHCPv4 server IP address 192.168.5.1 not found in allow-list, ignoring offer.', since=since)
copy_network_unit('25-dhcp-client-allow-list.network.d/00-allow-list.conf')
since = datetime.datetime.now()
networkctl_reload()
expect = 'veth99: DHCPv4 server IP address 192.168.5.1 not found in allow-list, ignoring offer.'
for _ in range(20):
if expect in read_networkd_log(since=since):
break
time.sleep(0.5)
else:
self.fail()
self.check_networkd_log('veth99: DHCPv4 server IP address 192.168.5.1 not found in allow-list, ignoring offer.', since=since)
copy_network_unit('25-dhcp-client-allow-list.network.d/10-deny-list.conf')
since = datetime.datetime.now()
networkctl_reload()
expect = 'veth99: DHCPv4 server IP address 192.168.5.1 found in deny-list, ignoring offer.'
for _ in range(20):
if expect in read_networkd_log(since=since):
break
time.sleep(0.5)
else:
self.fail()
self.check_networkd_log('veth99: DHCPv4 server IP address 192.168.5.1 found in deny-list, ignoring offer.', since=since)
@unittest.skipUnless("--dhcp-rapid-commit" in run("dnsmasq --help").stdout, reason="dnsmasq is missing dhcp-rapid-commit support")
def test_dhcp_client_rapid_commit(self):
@ -6933,8 +6907,8 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
check(self, True, False)
check(self, False, True)
check(self, False, False)
def test_dhcp_client_default_use_domains(self):
def test_dhcp_client_default_use_domains(self):
def check(self, ipv4, ipv6):
mkdir_p(networkd_conf_dropin_dir)
with open(os.path.join(networkd_conf_dropin_dir, 'default_use_domains.conf'), mode='w', encoding='utf-8') as f:
@ -6942,7 +6916,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
f.write('yes\n' if ipv4 else 'no\n')
f.write('[DHCPv6]\nUseDomains=')
f.write('yes\n' if ipv6 else 'no\n')
restart_networkd()
self.wait_online('veth-peer:carrier')
start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1',
@ -6968,7 +6942,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
else:
print(output)
self.fail('unexpected domain setting in resolved...')
stop_dnsmasq()
remove_networkd_conf_dropin('default_use_domains.conf')