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,