nic_router: fix exc. in Interface::handle_config_3

When Interface::handle_config_3 (third step of applying a new configuration to
interfaces) tried to detach the interface from the current IP config because
the old and new IP config differed, it did so using the new domain. The former
steps of the reconfiguration already installed the new domain reference at the
interface. Therefore, also the DHCP server of the new domain was used. This,
however caused uncaught exceptions because detaching from an IP config
includes dissolving all DHCP allocations. This dissolving of DHCP allocations
now operated on a DHCP server (the one of the new domain) that wasn't related
to the allocations and, in the worst case, caused an uncaught exception
because the IPs were out of its range.

That said, this commit ensures that detaching an interface from an IP config
is always done on the domain from which the IP config originated. Normally,
this is the domain the interface is attached to. But in the case of
Interface::handle_config_3, it is another - the former domain the interface
was attached to.

The commit also adapts the nic_router_dhcp_* tests in a way that they
reconfigure the router in a way that would trigger the uncaught exception
without the fix.

Fixes #4200
This commit is contained in:
Martin Stein 2021-06-24 14:34:13 +02:00 committed by Christian Helmuth
parent fd9bc43be1
commit be644098d7
4 changed files with 35 additions and 13 deletions

View File

@ -71,7 +71,7 @@ append config {
</config>
</inline>
<sleep milliseconds="3000"/>
<sleep milliseconds="2000"/>
<inline>
<config>
@ -93,17 +93,17 @@ append config {
</config>
</inline>
<sleep milliseconds="3000"/>
<sleep milliseconds="2000"/>
<inline>
<config>
<policy label="nic_router_2 -> " domain="downlink"/>
<domain name="downlink" interface="10.2.3.1/24">
<domain name="downlink" interface="10.2.4.1/24">
<dhcp-server ip_first="10.2.3.2"
ip_last="10.2.3.2">
<dhcp-server ip_first="10.2.4.2"
ip_last="10.2.4.2">
<dns-server ip="6.7.8.9"/>
@ -114,7 +114,26 @@ append config {
</config>
</inline>
<sleep milliseconds="3000"/>
<sleep milliseconds="2000"/>
<inline>
<config>
<policy label="nic_router_2 -> " domain="downlink"/>
<domain name="downlink" interface="10.2.4.1/24">
<dhcp-server ip_first="10.2.4.200"
ip_last="10.2.4.200">
</dhcp-server>
</domain>
</config>
</inline>
<sleep milliseconds="2000"/>
<inline>
<config>
@ -133,7 +152,7 @@ append config {
</config>
</inline>
<sleep milliseconds="3000"/>
<sleep milliseconds="2000"/>
</rom>
</config>
@ -281,6 +300,10 @@ append done_string ".*DHCP request completed:.*\n"
append done_string ".* IP lease time: 3600 seconds.*\n"
append done_string ".* Interface: 10.0.3.2/24.*\n"
append done_string ".* Router: 10.0.3.1.*\n"
append done_string ".*DHCP request completed:.*\n"
append done_string ".* IP lease time: 3600 seconds.*\n"
append done_string ".* Interface: 10.0.3.2/24.*\n"
append done_string ".* Router: 10.0.3.1.*\n"
append done_string ".* DNS server #1: 1.2.3.4.*\n"
append done_string ".* DNS server #2: 2.3.4.5.*\n"
append done_string ".* DNS server #3: 3.4.5.6.*\n"

View File

@ -73,7 +73,7 @@ void Domain::_prepare_reconstructing_ip_config()
/* detach all dependent interfaces from old IP config */
_interfaces.for_each([&] (Interface &interface) {
interface.detach_from_ip_config();
interface.detach_from_ip_config(*this);
});
_ip_config_dependents.for_each([&] (Domain &domain) {
domain._interfaces.for_each([&] (Interface &interface) {

View File

@ -412,10 +412,9 @@ void Interface::attach_to_ip_config(Domain &domain,
}
void Interface::detach_from_ip_config()
void Interface::detach_from_ip_config(Domain &domain)
{
/* destroy our own ARP waiters */
Domain &domain = _domain();
while (_own_arp_waiters.first()) {
cancel_arp_waiting(*_own_arp_waiters.first()->object());
}
@ -453,7 +452,7 @@ void Interface::attach_to_remote_ip_config()
void Interface::_detach_from_domain()
{
try {
detach_from_ip_config();
detach_from_ip_config(domain());
_detach_from_domain_raw();
}
catch (Pointer<Domain>::Invalid) { }
@ -2086,7 +2085,7 @@ void Interface::handle_config_3()
/* if the IP configs differ, detach completely from the IP config */
if (old_domain.ip_config() != new_domain.ip_config()) {
detach_from_ip_config();
detach_from_ip_config(old_domain);
attach_to_domain_finish();
return;
}

View File

@ -436,7 +436,7 @@ class Net::Interface : private Interface_list::Element
void attach_to_domain();
void detach_from_ip_config();
void detach_from_ip_config(Domain &domain);
void attach_to_ip_config(Domain &domain,
Ipv4_config const &ip_config);