From 3db718110494621607e535d6b87942fcefa9f5d0 Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Sun, 30 Sep 2018 17:27:44 +0200 Subject: [PATCH] nic_router: limit packets handled per signal Make it configurable how many packets get handled at a max per signal to prevent DoS attacks by clients. Issue #2953 --- repos/os/src/server/nic_router/README | 15 +++++++++ repos/os/src/server/nic_router/config.xsd | 1 + .../os/src/server/nic_router/configuration.cc | 25 +++++++------- .../os/src/server/nic_router/configuration.h | 33 ++++++++++--------- repos/os/src/server/nic_router/interface.cc | 31 +++++++++++++---- repos/os/src/server/nic_router/interface.h | 2 ++ 6 files changed, 73 insertions(+), 34 deletions(-) diff --git a/repos/os/src/server/nic_router/README b/repos/os/src/server/nic_router/README index 5799055f4..f4bf5ae83 100644 --- a/repos/os/src/server/nic_router/README +++ b/repos/os/src/server/nic_router/README @@ -494,6 +494,21 @@ Whether to log most important changes in the state of a domain (number of NIC sessions connected, current IPv4 config). +Other configuration attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If possible, the NIC router normally handles multiple packets from a NIC +session per signal. However, if one NIC session has a high packet rate and a +big buffer, this can lead to starvation of the other NIC sessions. Thus, the +maximum number of packets handled per signal is limited by default. This limit +can be configured as follows (default value shown): + +! + +When set to zero, the limit is deactivated, meaning that the router always +handles all available packets of a NIC session. + + Examples ~~~~~~~~ diff --git a/repos/os/src/server/nic_router/config.xsd b/repos/os/src/server/nic_router/config.xsd index 199b01849..b322953a1 100644 --- a/repos/os/src/server/nic_router/config.xsd +++ b/repos/os/src/server/nic_router/config.xsd @@ -129,6 +129,7 @@ + diff --git a/repos/os/src/server/nic_router/configuration.cc b/repos/os/src/server/nic_router/configuration.cc index e420db964..b7a920c34 100644 --- a/repos/os/src/server/nic_router/configuration.cc +++ b/repos/os/src/server/nic_router/configuration.cc @@ -65,18 +65,19 @@ Configuration::Configuration(Env &env, Interface_list &interfaces) : _alloc(alloc), - _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", DEFAULT_DHCP_DISCOVER_TIMEOUT_SEC)), - _dhcp_request_timeout (read_sec_attr(node, "dhcp_request_timeout_sec", DEFAULT_DHCP_REQUEST_TIMEOUT_SEC )), - _dhcp_offer_timeout (read_sec_attr(node, "dhcp_offer_timeout_sec", DEFAULT_DHCP_OFFER_TIMEOUT_SEC )), - _icmp_idle_timeout (read_sec_attr(node, "icmp_idle_timeout_sec", DEFAULT_ICMP_IDLE_TIMEOUT_SEC )), - _udp_idle_timeout (read_sec_attr(node, "udp_idle_timeout_sec", DEFAULT_UDP_IDLE_TIMEOUT_SEC )), - _tcp_idle_timeout (read_sec_attr(node, "tcp_idle_timeout_sec", DEFAULT_TCP_IDLE_TIMEOUT_SEC )), - _tcp_max_segm_lifetime(read_sec_attr(node, "tcp_max_segm_lifetime_sec", DEFAULT_TCP_MAX_SEGM_LIFETIME_SEC)), + _max_packets_per_signal(node.attribute_value("max_packets_per_signal", (unsigned long)DEFAULT_MAX_PACKETS_PER_SIGNAL)), + _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", DEFAULT_DHCP_DISCOVER_TIMEOUT_SEC)), + _dhcp_request_timeout (read_sec_attr(node, "dhcp_request_timeout_sec", DEFAULT_DHCP_REQUEST_TIMEOUT_SEC )), + _dhcp_offer_timeout (read_sec_attr(node, "dhcp_offer_timeout_sec", DEFAULT_DHCP_OFFER_TIMEOUT_SEC )), + _icmp_idle_timeout (read_sec_attr(node, "icmp_idle_timeout_sec", DEFAULT_ICMP_IDLE_TIMEOUT_SEC )), + _udp_idle_timeout (read_sec_attr(node, "udp_idle_timeout_sec", DEFAULT_UDP_IDLE_TIMEOUT_SEC )), + _tcp_idle_timeout (read_sec_attr(node, "tcp_idle_timeout_sec", DEFAULT_TCP_IDLE_TIMEOUT_SEC )), + _tcp_max_segm_lifetime (read_sec_attr(node, "tcp_max_segm_lifetime_sec", DEFAULT_TCP_MAX_SEGM_LIFETIME_SEC)), _node(node) { /* do parts of domain initialization that do not lookup other domains */ diff --git a/repos/os/src/server/nic_router/configuration.h b/repos/os/src/server/nic_router/configuration.h index 9c74a9b48..747d41098 100644 --- a/repos/os/src/server/nic_router/configuration.h +++ b/repos/os/src/server/nic_router/configuration.h @@ -34,6 +34,7 @@ class Net::Configuration using Mac_string = Genode::String<17>; Genode::Allocator &_alloc; + unsigned long const _max_packets_per_signal { 0 }; bool const _verbose { false }; bool const _verbose_packets { false }; bool const _verbose_packet_drop { false }; @@ -68,6 +69,7 @@ class Net::Configuration enum { DEFAULT_UDP_IDLE_TIMEOUT_SEC = 30 }; enum { DEFAULT_TCP_IDLE_TIMEOUT_SEC = 600 }; enum { DEFAULT_TCP_MAX_SEGM_LIFETIME_SEC = 30 }; + enum { DEFAULT_MAX_PACKETS_PER_SIGNAL = 32 }; Configuration(Genode::Xml_node const node, Genode::Allocator &alloc); @@ -86,21 +88,22 @@ class Net::Configuration ** Accessors ** ***************/ - 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; } + 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 173c84b79..042351d67 100644 --- a/repos/os/src/server/nic_router/interface.cc +++ b/repos/os/src/server/nic_router/interface.cc @@ -1278,16 +1278,33 @@ void Interface::_handle_arp(Ethernet_frame ð, } +void Interface::_handle_pkt() +{ + Packet_descriptor const pkt = _sink.get_packet(); + Size_guard size_guard(pkt.size()); + try { + _handle_eth(_sink.packet_content(pkt), size_guard, pkt); + _ack_packet(pkt); + } + catch (Packet_postponed) { } +} + + void Interface::_ready_to_submit() { - while (_sink.packet_avail()) { - Packet_descriptor const pkt = _sink.get_packet(); - Size_guard size_guard(pkt.size()); - try { - _handle_eth(_sink.packet_content(pkt), size_guard, pkt); - _ack_packet(pkt); + unsigned long const max_pkts = _config().max_packets_per_signal(); + if (max_pkts) { + for (unsigned long i = 0; _sink.packet_avail(); i++) { + + if (i >= max_pkts) { + Signal_transmitter(_sink_submit).submit(); + break; + } + _handle_pkt(); } - catch (Packet_postponed) { } + } else { + while (_sink.packet_avail()) { + _handle_pkt(); } } } diff --git a/repos/os/src/server/nic_router/interface.h b/repos/os/src/server/nic_router/interface.h index d2fb13615..742717468 100644 --- a/repos/os/src/server/nic_router/interface.h +++ b/repos/os/src/server/nic_router/interface.h @@ -239,6 +239,8 @@ class Net::Interface : private Interface_list::Element Size_guard &size_guard, Ipv4_packet &ip); + void _handle_pkt(); + void _continue_handle_eth(Domain const &domain, Packet_descriptor const &pkt);