nic_router: act as ICMP Echo server

The ICMP-Echo-server functionality of the router has the following
configuration attributes (default values shown):

! <config icmp_echo_server="yes">
!    <domain icmp_echo_server="yes" ... />
! </config>

The icmp_echo_server attribute configures whether the router answers ICMP Echo
requests that address the router. The <config> value affects all domains
without a <domain> local value.

Issue #2874
This commit is contained in:
Martin Stein 2018-06-18 19:04:40 +02:00 committed by Norman Feske
parent a9183da87b
commit 0b8520a208
8 changed files with 116 additions and 44 deletions

View File

@ -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):
! <config icmp_echo_server="yes">
! <domain icmp_echo_server="yes" ... />
! </config>
The icmp_echo_server attribute configures whether the router answers ICMP Echo
requests that address the router. The <config> value affects all domains
without a <domain> local value.
Configuring DHCP server functionality
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -151,11 +151,12 @@
<xs:element name="udp-forward" type="L3_forward_rule" />
</xs:choice>
<xs:attribute name="name" type="Domain_name" />
<xs:attribute name="interface" type="Ipv4_address_prefix" />
<xs:attribute name="gateway" type="Ipv4_address" />
<xs:attribute name="verbose_packets" type="Boolean" />
<xs:attribute name="label" type="Session_label" />
<xs:attribute name="name" type="Domain_name" />
<xs:attribute name="interface" type="Ipv4_address_prefix" />
<xs:attribute name="gateway" type="Ipv4_address" />
<xs:attribute name="verbose_packets" type="Boolean" />
<xs:attribute name="label" type="Session_label" />
<xs:attribute name="icmp_echo_server" type="Boolean" />
</xs:complexType>
</xs:element><!-- domain -->
@ -170,6 +171,7 @@
<xs:attribute name="tcp_idle_timeout_sec" type="Seconds" />
<xs:attribute name="icmp_idle_timeout_sec" type="Seconds" />
<xs:attribute name="tcp_max_segm_lifetime_sec" type="Seconds" />
<xs:attribute name="icmp_echo_server" type="Boolean" />
</xs:complexType>
</xs:element><!-- config -->

View File

@ -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 )),

View File

@ -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; }

View File

@ -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();

View File

@ -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<Domain> &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<Domain> &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_ */

View File

@ -787,6 +787,33 @@ void Interface::handle_link_state()
}
void Interface::_send_icmp_echo_reply(Ethernet_frame &eth,
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 &eth,
Size_guard &size_guard,
Ipv4_packet &ip,
@ -908,26 +935,38 @@ void Interface::_handle_icmp_error(Ethernet_frame &eth,
}
void Interface::_handle_icmp(Ethernet_frame &eth,
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 &eth,
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<Icmp_packet *>(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 &eth,
}
}
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;
}

View File

@ -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 &eth,
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 &eth,
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 &eth,
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 &eth,
Ipv4_address const &dst_ip,