diff --git a/repos/os/src/server/nic_router/README b/repos/os/src/server/nic_router/README index 2c95a5c190..ee5658ab18 100644 --- a/repos/os/src/server/nic_router/README +++ b/repos/os/src/server/nic_router/README @@ -10,6 +10,7 @@ these domains. This is a brief overview of the features thereby provided: * NAPT for UDP, TCP and ICMP "Echo", * forwarding of ICMP "Destination Unreachable" according to the UDP, TCP or ICMP "Echo" connection it refers to, +* acting as ICMP echo server per domain * acting as DHCP server or client per domain, * provide per-domain network statistics via a report session, * print out header information for each packet received or sent, @@ -361,6 +362,21 @@ Denial-of-Service attacks against the destination domain by occupying all of its ports or IDs. +Configuring ICMP-Echo-server functionality +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ICMP-Echo-server functionality of the router has the following +configuration attributes (default values shown): + +! +! +! + +The icmp_echo_server attribute configures whether the router answers ICMP Echo +requests that address the router. The value affects all domains +without a local value. + + Configuring DHCP server functionality ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/repos/os/src/server/nic_router/config.xsd b/repos/os/src/server/nic_router/config.xsd index 573fdb7469..73cd4f1d42 100644 --- a/repos/os/src/server/nic_router/config.xsd +++ b/repos/os/src/server/nic_router/config.xsd @@ -151,11 +151,12 @@ - - - - - + + + + + + @@ -170,6 +171,7 @@ + diff --git a/repos/os/src/server/nic_router/configuration.cc b/repos/os/src/server/nic_router/configuration.cc index a4818f7d24..be4e7a279c 100644 --- a/repos/os/src/server/nic_router/configuration.cc +++ b/repos/os/src/server/nic_router/configuration.cc @@ -68,6 +68,7 @@ Configuration::Configuration(Env &env, _verbose (node.attribute_value("verbose", false)), _verbose_packets (node.attribute_value("verbose_packets", 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 )), diff --git a/repos/os/src/server/nic_router/configuration.h b/repos/os/src/server/nic_router/configuration.h index 3c030a007d..1bcefc7a46 100644 --- a/repos/os/src/server/nic_router/configuration.h +++ b/repos/os/src/server/nic_router/configuration.h @@ -37,6 +37,7 @@ class Net::Configuration bool const _verbose { false }; bool const _verbose_packets { false }; bool const _verbose_domain_state { false }; + bool const _icmp_echo_server { true }; Genode::Microseconds const _dhcp_discover_timeout { DEFAULT_DHCP_DISCOVER_TIMEOUT_SEC }; Genode::Microseconds const _dhcp_request_timeout { DEFAULT_DHCP_REQUEST_TIMEOUT_SEC }; Genode::Microseconds const _dhcp_offer_timeout { DEFAULT_DHCP_OFFER_TIMEOUT_SEC }; @@ -87,6 +88,7 @@ class Net::Configuration bool verbose() const { return _verbose; } bool verbose_packets() const { return _verbose_packets; } 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; } diff --git a/repos/os/src/server/nic_router/domain.cc b/repos/os/src/server/nic_router/domain.cc index 685da77aa0..7a175d41ed 100644 --- a/repos/os/src/server/nic_router/domain.cc +++ b/repos/os/src/server/nic_router/domain.cc @@ -205,6 +205,8 @@ Domain::Domain(Configuration &config, Xml_node const node, Allocator &alloc) Ipv4_address()), _verbose_packets(_node.attribute_value("verbose_packets", false) || _config.verbose_packets()), + _icmp_echo_server(_node.attribute_value("icmp_echo_server", + _config.icmp_echo_server())), _label(_node.attribute_value("label", String<160>()).string()) { _log_ip_config(); diff --git a/repos/os/src/server/nic_router/domain.h b/repos/os/src/server/nic_router/domain.h index 242c70b883..2af1b5aa28 100644 --- a/repos/os/src/server/nic_router/domain.h +++ b/repos/os/src/server/nic_router/domain.h @@ -93,6 +93,7 @@ class Net::Domain : public Domain_base, Genode::size_t _tx_bytes { 0 }; Genode::size_t _rx_bytes { 0 }; bool const _verbose_packets { false }; + bool const _icmp_echo_server; Genode::Session_label const _label; void _read_forward_rules(Genode::Cstring const &protocol, @@ -166,26 +167,27 @@ class Net::Domain : public Domain_base, ** Accessors ** ***************/ - bool verbose_packets() const { return _verbose_packets; } - Genode::Session_label const &label() const { return _label; } - Ipv4_config const &ip_config() const { return *_ip_config; } - List &ip_config_dependents() { return _ip_config_dependents; } - Domain_name const &name() const { return _name; } - Ip_rule_list &ip_rules() { return _ip_rules; } - Forward_rule_tree &tcp_forward_rules() { return _tcp_forward_rules; } - Forward_rule_tree &udp_forward_rules() { return _udp_forward_rules; } - Transport_rule_list &tcp_rules() { return _tcp_rules; } - Transport_rule_list &udp_rules() { return _udp_rules; } - Ip_rule_list &icmp_rules() { return _icmp_rules; } - Nat_rule_tree &nat_rules() { return _nat_rules; } - Interface_list &interfaces() { return _interfaces; } - Configuration &config() const { return _config; } + bool verbose_packets() const { return _verbose_packets; } + bool icmp_echo_server() const { return _icmp_echo_server; } + Genode::Session_label const &label() const { return _label; } + Ipv4_config const &ip_config() const { return *_ip_config; } + List &ip_config_dependents() { return _ip_config_dependents; } + Domain_name const &name() const { return _name; } + Ip_rule_list &ip_rules() { return _ip_rules; } + Forward_rule_tree &tcp_forward_rules() { return _tcp_forward_rules; } + Forward_rule_tree &udp_forward_rules() { return _udp_forward_rules; } + Transport_rule_list &tcp_rules() { return _tcp_rules; } + Transport_rule_list &udp_rules() { return _udp_rules; } + Ip_rule_list &icmp_rules() { return _icmp_rules; } + Nat_rule_tree &nat_rules() { return _nat_rules; } + Interface_list &interfaces() { return _interfaces; } + Configuration &config() const { return _config; } Dhcp_server &dhcp_server(); - Arp_cache &arp_cache() { return _arp_cache; } - Arp_waiter_list &foreign_arp_waiters() { return _foreign_arp_waiters; } - Link_side_tree &tcp_links() { return _tcp_links; } - Link_side_tree &udp_links() { return _udp_links; } - Link_side_tree &icmp_links() { return _icmp_links; } + Arp_cache &arp_cache() { return _arp_cache; } + Arp_waiter_list &foreign_arp_waiters() { return _foreign_arp_waiters; } + Link_side_tree &tcp_links() { return _tcp_links; } + Link_side_tree &udp_links() { return _udp_links; } + Link_side_tree &icmp_links() { return _icmp_links; } }; #endif /* _DOMAIN_H_ */ diff --git a/repos/os/src/server/nic_router/interface.cc b/repos/os/src/server/nic_router/interface.cc index 366c68b89a..cc7583c3c6 100644 --- a/repos/os/src/server/nic_router/interface.cc +++ b/repos/os/src/server/nic_router/interface.cc @@ -787,6 +787,33 @@ void Interface::handle_link_state() } +void Interface::_send_icmp_echo_reply(Ethernet_frame ð, + Ipv4_packet &ip, + Icmp_packet &icmp, + size_t icmp_sz, + Size_guard &size_guard) +{ + /* adapt Ethernet header */ + Mac_address const eth_src = eth.src(); + eth.src(eth.dst()); + eth.dst(eth_src); + + /* adapt IPv4 header */ + Ipv4_address const ip_src = ip.src(); + ip.src(ip.dst()); + ip.dst(ip_src); + + /* adapt ICMP header */ + icmp.type(Icmp_packet::Type::ECHO_REPLY); + icmp.code(Icmp_packet::Code::ECHO_REPLY); + + /* update checksums and send */ + icmp.update_checksum(icmp_sz - sizeof(Icmp_packet)); + ip.update_checksum(); + send(eth, size_guard); +} + + void Interface::_handle_icmp_query(Ethernet_frame ð, Size_guard &size_guard, Ipv4_packet &ip, @@ -908,26 +935,38 @@ void Interface::_handle_icmp_error(Ethernet_frame ð, } -void Interface::_handle_icmp(Ethernet_frame ð, - Size_guard &size_guard, - Ipv4_packet &ip, - Packet_descriptor const &pkt, - L3_protocol prot, - void *prot_base, - size_t prot_size, - Domain &local_domain) +void Interface::_handle_icmp(Ethernet_frame ð, + Size_guard &size_guard, + Ipv4_packet &ip, + Packet_descriptor const &pkt, + L3_protocol prot, + void *prot_base, + size_t prot_size, + Domain &local_domain, + Ipv4_address_prefix const &local_intf) { /* drop packet if ICMP checksum is invalid */ Icmp_packet &icmp = *reinterpret_cast(prot_base); if (icmp.checksum_error(size_guard.unconsumed())) { - throw Drop_packet("bad ICMP checksum"); + throw Drop_packet("bad ICMP checksum"); } + + /* try to act as ICMP Echo server */ + if (icmp.type() == Icmp_packet::Type::ECHO_REQUEST && + ip.dst() == local_intf.address && + local_domain.icmp_echo_server()) + { + if(_config().verbose()) { + log("[", local_domain, "] act as ICMP Echo server"); } + + _send_icmp_echo_reply(eth, ip, icmp, prot_size, size_guard); + return; } - /* select ICMP message type */ + /* try to act as ICMP router */ switch (icmp.type()) { case Icmp_packet::Type::ECHO_REPLY: case Icmp_packet::Type::ECHO_REQUEST: _handle_icmp_query(eth, size_guard, ip, pkt, prot, prot_base, prot_size, local_domain); break; case Icmp_packet::Type::DST_UNREACHABLE: _handle_icmp_error(eth, size_guard, ip, pkt, local_domain, icmp, prot_size); break; - default: Drop_packet("unknown ICMP message type"); } + default: Drop_packet("unhandled type in ICMP"); } } @@ -979,7 +1018,8 @@ void Interface::_handle_ip(Ethernet_frame ð, } } else if (prot == L3_protocol::ICMP) { - _handle_icmp(eth, size_guard, ip, pkt, prot, prot_base, prot_size, local_domain); + _handle_icmp(eth, size_guard, ip, pkt, prot, prot_base, prot_size, + local_domain, local_intf); return; } diff --git a/repos/os/src/server/nic_router/interface.h b/repos/os/src/server/nic_router/interface.h index a6ac2e16ee..1a45f1b1c9 100644 --- a/repos/os/src/server/nic_router/interface.h +++ b/repos/os/src/server/nic_router/interface.h @@ -140,6 +140,12 @@ class Net::Interface : private Interface_list::Element Genode::uint32_t xid, Ipv4_address_prefix const &local_intf); + void _send_icmp_echo_reply(Ethernet_frame ð, + Ipv4_packet &ip, + Icmp_packet &icmp, + Genode::size_t icmp_sz, + Size_guard &size_guard); + Forward_rule_tree &_forward_rules(Domain &local_domain, L3_protocol const prot) const; @@ -190,14 +196,15 @@ class Net::Interface : private Interface_list::Element Icmp_packet &icmp, Genode::size_t icmp_sz); - void _handle_icmp(Ethernet_frame ð, - Size_guard &size_guard, - Ipv4_packet &ip, - Packet_descriptor const &pkt, - L3_protocol prot, - void *prot_base, - Genode::size_t prot_size, - Domain &local_domain); + void _handle_icmp(Ethernet_frame ð, + Size_guard &size_guard, + Ipv4_packet &ip, + Packet_descriptor const &pkt, + L3_protocol prot, + void *prot_base, + Genode::size_t prot_size, + Domain &local_domain, + Ipv4_address_prefix const &local_intf); void _adapt_eth(Ethernet_frame ð, Ipv4_address const &dst_ip,