diff --git a/repos/libports/run/nic_router_ipv4_fragm.run b/repos/libports/run/nic_router_ipv4_fragm.run index d0ffb69a52..8b4205fd6e 100644 --- a/repos/libports/run/nic_router_ipv4_fragm.run +++ b/repos/libports/run/nic_router_ipv4_fragm.run @@ -99,7 +99,8 @@ append config { + verbose_packet_drop="yes" + icmp_type_3_code_on_fragm_ipv4="4"> @@ -162,12 +163,18 @@ run_genode_until $pattern_string 30 $spawn_id # ping server with ipv4 fragmentation (should fail) spawn nping -c 1 --privileged --udp --data-length 1600 --mtu 800 -p 8000 10.0.2.55 set pattern_string "" -expect eof +append pattern_string {.*RCVD .* ICMP .*10\.0\.2\.55 > 10\.0\.2\.1 Fragmentation required.*\n} +append pattern_string {.*RCVD .* ICMP .*10\.0\.2\.55 > 10\.0\.2\.1 Fragmentation required.*\n} +append pattern_string {.*RCVD .* ICMP .*10\.0\.2\.55 > 10\.0\.2\.1 Fragmentation required.*\n} +run_genode_until $pattern_string 30 $spawn_id # check that the nic router dropped the ipv4 fragments of the second ping set pattern_string "" +append pattern_string {.*snd .*IPV4.* 10\.0\.2\.55 > 10\.0\.2\.1 .*ICMP.* 3 4.*\n} append pattern_string {.*drop packet .fragmented IPv4 not supported.*\n} +append pattern_string {.*snd .*IPV4.* 10\.0\.2\.55 > 10\.0\.2\.1 .*ICMP.* 3 4.*\n} append pattern_string {.*drop packet .fragmented IPv4 not supported.*\n} +append pattern_string {.*snd .*IPV4.* 10\.0\.2\.55 > 10\.0\.2\.1 .*ICMP.* 3 4.*\n} append pattern_string {.*drop packet .fragmented IPv4 not supported.*\n} append pattern_string {.*.*\n} run_genode_until $pattern_string 30 $genode_id diff --git a/repos/os/src/server/nic_router/README b/repos/os/src/server/nic_router/README index d61cba0a6e..b2e3e87355 100644 --- a/repos/os/src/server/nic_router/README +++ b/repos/os/src/server/nic_router/README @@ -758,6 +758,24 @@ interfaces assigned, current IPv4 config). Other configuration attributes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +ICMP response to dropped fragmented IPv4 +---------------------------------------- + +The NIC router can notify the sender of a fragmented IPv4 that was dropped by +the router (because fragmented IPv4 isn't supported) via an ICMP type-3 +(destination unreachable) packet. This is the attribute that controls this +functionality: + +! + +If not set, the value of the attribute defaults to "no" which results in not +sending the above mentioned packets on dropped fragmented IPv4 (i.e., +fragmented IPv4 gets dropped silently). If the value is set to a number in the +range from 0 to 15, the above mentioned ICMP responses are sent and the value +indicates which value the ICMP code field should have in the responses. If the +value is set to something else than "no" or a number in the range from 0 to 15, +the router prints a warning to the log and assumes value "no". + Maximum number of packets handled per signal -------------------------------------------- diff --git a/repos/os/src/server/nic_router/config.xsd b/repos/os/src/server/nic_router/config.xsd index 388b614c1e..b025055853 100644 --- a/repos/os/src/server/nic_router/config.xsd +++ b/repos/os/src/server/nic_router/config.xsd @@ -12,6 +12,28 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -144,20 +166,21 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/repos/os/src/server/nic_router/configuration.cc b/repos/os/src/server/nic_router/configuration.cc index 4d49b57d55..09efbbf57d 100644 --- a/repos/os/src/server/nic_router/configuration.cc +++ b/repos/os/src/server/nic_router/configuration.cc @@ -30,21 +30,22 @@ using namespace Genode; Configuration::Configuration(Xml_node const node, Allocator &alloc) : - _alloc { alloc }, - _max_packets_per_signal { 0 }, - _verbose { false }, - _verbose_packets { false }, - _verbose_packet_drop { false }, - _verbose_domain_state { false }, - _icmp_echo_server { false }, - _dhcp_discover_timeout { 0 }, - _dhcp_request_timeout { 0 }, - _dhcp_offer_timeout { 0 }, - _icmp_idle_timeout { 0 }, - _udp_idle_timeout { 0 }, - _tcp_idle_timeout { 0 }, - _tcp_max_segm_lifetime { 0 }, - _node { node } + _alloc { alloc }, + _max_packets_per_signal { 0 }, + _verbose { false }, + _verbose_packets { false }, + _verbose_packet_drop { false }, + _verbose_domain_state { false }, + _icmp_echo_server { false }, + _icmp_type_3_code_on_fragm_ipv4 { 0 }, + _dhcp_discover_timeout { 0 }, + _dhcp_request_timeout { 0 }, + _dhcp_offer_timeout { 0 }, + _icmp_idle_timeout { 0 }, + _udp_idle_timeout { 0 }, + _tcp_idle_timeout { 0 }, + _tcp_max_segm_lifetime { 0 }, + _node { node } { } @@ -70,6 +71,37 @@ void Configuration::_invalid_domain(Domain &domain, } +Icmp_packet::Code +Configuration::_init_icmp_type_3_code_on_fragm_ipv4(Xml_node const &node) const +{ + char const *const attr_name { "icmp_type_3_code_on_fragm_ipv4" }; + try { + Xml_attribute const &attr { node.attribute(attr_name) }; + if (attr.has_value("no")) { + return Icmp_packet::Code::INVALID; + } + uint8_t attr_val { }; + bool const attr_transl_succeeded { attr.value(attr_val) }; + Icmp_packet::Code const result { + Icmp_packet::code_from_uint8( + Icmp_packet::Type::DST_UNREACHABLE, attr_val) }; + + if (!attr_transl_succeeded || + result == Icmp_packet::Code::INVALID) { + + warning("attribute 'icmp_type_3_code_on_fragm_ipv4' has invalid " + "value, assuming value \"no\""); + + return Icmp_packet::Code::INVALID; + } + return result; + } + catch (Xml_node::Nonexistent_attribute) { + return Icmp_packet::Code::INVALID; + } +} + + Configuration::Configuration(Env &env, Xml_node const node, Allocator &alloc, @@ -78,21 +110,22 @@ Configuration::Configuration(Env &env, Quota const &shared_quota, Interface_list &interfaces) : - _alloc { alloc }, - _max_packets_per_signal { node.attribute_value("max_packets_per_signal", (unsigned long)32) }, - _verbose { node.attribute_value("verbose", false) }, - _verbose_packets { node.attribute_value("verbose_packets", false) }, - _verbose_packet_drop { node.attribute_value("verbose_packet_drop", false) }, - _verbose_domain_state { node.attribute_value("verbose_domain_state", false) }, - _icmp_echo_server { node.attribute_value("icmp_echo_server", true) }, - _dhcp_discover_timeout { read_sec_attr(node, "dhcp_discover_timeout_sec", 10) }, - _dhcp_request_timeout { read_sec_attr(node, "dhcp_request_timeout_sec", 10) }, - _dhcp_offer_timeout { read_sec_attr(node, "dhcp_offer_timeout_sec", 10) }, - _icmp_idle_timeout { read_sec_attr(node, "icmp_idle_timeout_sec", 10) }, - _udp_idle_timeout { read_sec_attr(node, "udp_idle_timeout_sec", 30) }, - _tcp_idle_timeout { read_sec_attr(node, "tcp_idle_timeout_sec", 600) }, - _tcp_max_segm_lifetime { read_sec_attr(node, "tcp_max_segm_lifetime_sec", 30) }, - _node { node } + _alloc { alloc }, + _max_packets_per_signal { node.attribute_value("max_packets_per_signal", (unsigned long)32) }, + _verbose { node.attribute_value("verbose", false) }, + _verbose_packets { node.attribute_value("verbose_packets", false) }, + _verbose_packet_drop { node.attribute_value("verbose_packet_drop", false) }, + _verbose_domain_state { node.attribute_value("verbose_domain_state", false) }, + _icmp_echo_server { node.attribute_value("icmp_echo_server", true) }, + _icmp_type_3_code_on_fragm_ipv4 { _init_icmp_type_3_code_on_fragm_ipv4(node) }, + _dhcp_discover_timeout { read_sec_attr(node, "dhcp_discover_timeout_sec", 10) }, + _dhcp_request_timeout { read_sec_attr(node, "dhcp_request_timeout_sec", 10) }, + _dhcp_offer_timeout { read_sec_attr(node, "dhcp_offer_timeout_sec", 10) }, + _icmp_idle_timeout { read_sec_attr(node, "icmp_idle_timeout_sec", 10) }, + _udp_idle_timeout { read_sec_attr(node, "udp_idle_timeout_sec", 30) }, + _tcp_idle_timeout { read_sec_attr(node, "tcp_idle_timeout_sec", 600) }, + _tcp_max_segm_lifetime { read_sec_attr(node, "tcp_max_segm_lifetime_sec", 30) }, + _node { node } { /* do parts of domain initialization that do not lookup other domains */ node.for_each_sub_node("domain", [&] (Xml_node const node) { diff --git a/repos/os/src/server/nic_router/configuration.h b/repos/os/src/server/nic_router/configuration.h index e5ffff8b8a..8eb0c1eb09 100644 --- a/repos/os/src/server/nic_router/configuration.h +++ b/repos/os/src/server/nic_router/configuration.h @@ -40,6 +40,7 @@ class Net::Configuration bool const _verbose_packet_drop; bool const _verbose_domain_state; bool const _icmp_echo_server; + Icmp_packet::Code const _icmp_type_3_code_on_fragm_ipv4; Genode::Microseconds const _dhcp_discover_timeout; Genode::Microseconds const _dhcp_request_timeout; Genode::Microseconds const _dhcp_offer_timeout; @@ -53,6 +54,9 @@ class Net::Configuration Nic_client_tree _nic_clients { }; Genode::Xml_node const _node; + Icmp_packet::Code + _init_icmp_type_3_code_on_fragm_ipv4(Genode::Xml_node const &node) const; + void _invalid_nic_client(Nic_client &nic_client, char const *reason); @@ -83,22 +87,23 @@ class Net::Configuration ** Accessors ** ***************/ - unsigned long max_packets_per_signal() const { return _max_packets_per_signal; } - bool verbose() const { return _verbose; } - bool verbose_packets() const { return _verbose_packets; } - bool verbose_packet_drop() const { return _verbose_packet_drop; } - bool verbose_domain_state() const { return _verbose_domain_state; } - bool icmp_echo_server() const { return _icmp_echo_server; } - Genode::Microseconds dhcp_discover_timeout() const { return _dhcp_discover_timeout; } - Genode::Microseconds dhcp_request_timeout() const { return _dhcp_request_timeout; } - Genode::Microseconds dhcp_offer_timeout() const { return _dhcp_offer_timeout; } - Genode::Microseconds icmp_idle_timeout() const { return _icmp_idle_timeout; } - Genode::Microseconds udp_idle_timeout() const { return _udp_idle_timeout; } - Genode::Microseconds tcp_idle_timeout() const { return _tcp_idle_timeout; } - Genode::Microseconds tcp_max_segm_lifetime() const { return _tcp_max_segm_lifetime; } - Domain_tree &domains() { return _domains; } - Report &report() { return _report(); } - Genode::Xml_node node() const { return _node; } + unsigned long max_packets_per_signal() const { return _max_packets_per_signal; } + bool verbose() const { return _verbose; } + bool verbose_packets() const { return _verbose_packets; } + bool verbose_packet_drop() const { return _verbose_packet_drop; } + bool verbose_domain_state() const { return _verbose_domain_state; } + bool icmp_echo_server() const { return _icmp_echo_server; } + Icmp_packet::Code icmp_type_3_code_on_fragm_ipv4() const { return _icmp_type_3_code_on_fragm_ipv4; } + Genode::Microseconds dhcp_discover_timeout() const { return _dhcp_discover_timeout; } + Genode::Microseconds dhcp_request_timeout() const { return _dhcp_request_timeout; } + Genode::Microseconds dhcp_offer_timeout() const { return _dhcp_offer_timeout; } + Genode::Microseconds icmp_idle_timeout() const { return _icmp_idle_timeout; } + Genode::Microseconds udp_idle_timeout() const { return _udp_idle_timeout; } + Genode::Microseconds tcp_idle_timeout() const { return _tcp_idle_timeout; } + Genode::Microseconds tcp_max_segm_lifetime() const { return _tcp_max_segm_lifetime; } + Domain_tree &domains() { return _domains; } + Report &report() { return _report(); } + Genode::Xml_node node() const { return _node; } }; #endif /* _CONFIGURATION_H_ */ diff --git a/repos/os/src/server/nic_router/interface.cc b/repos/os/src/server/nic_router/interface.cc index ec1cb27a4f..218a720240 100644 --- a/repos/os/src/server/nic_router/interface.cc +++ b/repos/os/src/server/nic_router/interface.cc @@ -1119,14 +1119,18 @@ void Interface::_handle_ip(Ethernet_frame ð, { /* drop fragmented IPv4 as it isn't supported */ Ipv4_packet &ip = eth.data(size_guard); + Ipv4_address_prefix const &local_intf = local_domain.ip_config().interface; if (ip.more_fragments() || ip.fragment_offset() != 0) { _dropped_fragm_ipv4++; + if (_config().icmp_type_3_code_on_fragm_ipv4() != Icmp_packet::Code::INVALID) { + _send_icmp_dst_unreachable( + local_intf, eth, ip, _config().icmp_type_3_code_on_fragm_ipv4()); + } throw Drop_packet("fragmented IPv4 not supported"); } /* try handling subnet-local IP packets */ - Ipv4_address_prefix const &local_intf = local_domain.ip_config().interface; if (local_intf.prefix_matches(ip.dst()) && ip.dst() != local_intf.address) {