nic_router: send ICMP error on unroutable packet

Send an ICMP "Destination Network Unreachable" as response to packets that
are not routable by the NIC router.

Issue #2732
This commit is contained in:
Martin Stein 2018-03-23 17:34:01 +01:00 committed by Christian Helmuth
parent 4dc8f6dca4
commit 98617432c3
4 changed files with 74 additions and 6 deletions

View File

@ -173,7 +173,7 @@ void Dhcp_client::_send(Message_type msg_type,
Ipv4_address server_ip)
{
enum { PKT_SIZE = 1024 };
using Size_guard = Size_guard_tpl<PKT_SIZE, Interface::Dhcp_msg_buffer_too_small>;
using Size_guard = Size_guard_tpl<PKT_SIZE, Interface::Send_buffer_too_small>;
Mac_address client_mac = _interface.router_mac();
_interface.send(PKT_SIZE, [&] (void *pkt_base) {

View File

@ -433,7 +433,7 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
Ipv4_address_prefix const &local_intf)
{
enum { PKT_SIZE = 512 };
using Size_guard = Genode::Size_guard_tpl<PKT_SIZE, Dhcp_msg_buffer_too_small>;
using Size_guard = Genode::Size_guard_tpl<PKT_SIZE, Send_buffer_too_small>;
send(PKT_SIZE, [&] (void *pkt_base) {
/* create ETH header of the reply */
@ -445,7 +445,6 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
eth.type(Ethernet_frame::Type::IPV4);
/* create IP header of the reply */
enum { IPV4_TIME_TO_LIVE = 64 };
size_t const ip_off = size.curr();
Ipv4_packet &ip = *eth.data<Ipv4_packet>(size.left());
size.add(sizeof(Ipv4_packet));
@ -676,6 +675,64 @@ void Interface::_domain_broadcast(Ethernet_frame &eth,
}
void Interface::_send_icmp_dst_unreachable(Ipv4_address_prefix const &local_intf,
Ethernet_frame const &req_eth,
Ipv4_packet const &req_ip,
Icmp_packet::Code const code)
{
enum {
ICMP_MAX_DATA_SIZE = sizeof(Ipv4_packet) + 8,
PKT_SIZE = sizeof(Ethernet_frame) + sizeof(Ipv4_packet) +
sizeof(Icmp_packet) + ICMP_MAX_DATA_SIZE,
};
using Size_guard = Genode::Size_guard_tpl<PKT_SIZE, Send_buffer_too_small>;
send(PKT_SIZE, [&] (void *pkt_base) {
/* create ETH header */
Size_guard size;
size.add(sizeof(Ethernet_frame));
Ethernet_frame &eth = *reinterpret_cast<Ethernet_frame *>(pkt_base);
eth.dst(req_eth.src());
eth.src(_router_mac);
eth.type(Ethernet_frame::Type::IPV4);
/* create IP header */
size_t const ip_off = size.curr();
Ipv4_packet &ip = *eth.data<Ipv4_packet>(size.left());
size.add(sizeof(Ipv4_packet));
ip.header_length(sizeof(Ipv4_packet) / 4);
ip.version(4);
ip.diff_service(0);
ip.ecn(0);
ip.identification(0);
ip.flags(0);
ip.fragment_offset(0);
ip.time_to_live(IPV4_TIME_TO_LIVE);
ip.protocol(Ipv4_packet::Protocol::ICMP);
ip.src(local_intf.address);
ip.dst(req_ip.src());
/* create ICMP header */
Icmp_packet &icmp = *ip.data<Icmp_packet>(size.left());
size.add(sizeof(Icmp_packet));
icmp.type(Icmp_packet::Type::DST_UNREACHABLE);
icmp.code(code);
icmp.rest_of_header(0);
size_t icmp_data_size = req_ip.total_length();
if (icmp_data_size > ICMP_MAX_DATA_SIZE) {
icmp_data_size = ICMP_MAX_DATA_SIZE;
}
size.add(icmp_data_size);
Genode::memcpy(&icmp.data<char>(~0), &req_ip, icmp_data_size);
/* fill in header values that require the packet to be complete */
icmp.update_checksum(icmp_data_size);
ip.total_length(size.curr() - ip_off);
ip.checksum(Ipv4_packet::calculate_checksum(ip));
});
}
void Interface::_handle_ip(Ethernet_frame &eth,
Genode::size_t const eth_size,
Packet_descriptor const &pkt,
@ -812,6 +869,8 @@ void Interface::_handle_ip(Ethernet_frame &eth,
catch (Ip_rule_list::No_match) { }
/* give up and drop packet */
_send_icmp_dst_unreachable(local_intf, eth, ip,
Icmp_packet::Code::DST_NET_UNREACHABLE);
if (_config().verbose()) {
log("Unroutable packet"); }
}
@ -1076,8 +1135,8 @@ void Interface::_handle_eth(void *const eth_base,
catch (Alloc_dhcp_msg_buffer_failed) {
error("failed to allocate buffer for DHCP reply"); }
catch (Dhcp_msg_buffer_too_small) {
error("DHCP reply buffer too small"); }
catch (Send_buffer_too_small) {
error("Send buffer buffer too small"); }
catch (Dhcp_server::Alloc_ip_failed) {
error("failed to allocate IP for DHCP client"); }

View File

@ -25,6 +25,7 @@
/* Genode includes */
#include <nic_session/nic_session.h>
#include <net/dhcp.h>
#include <net/icmp.h>
namespace Net {
@ -75,6 +76,8 @@ class Net::Interface : private Interface_list::Element
private:
enum { IPV4_TIME_TO_LIVE = 64 };
struct Dismiss_link : Genode::Exception { };
struct Dismiss_arp_waiter : Genode::Exception { };
@ -239,6 +242,11 @@ class Net::Interface : private Interface_list::Element
void _apply_foreign_arp();
void _send_icmp_dst_unreachable(Ipv4_address_prefix const &local_intf,
Ethernet_frame const &req_eth,
Ipv4_packet const &req_ip,
Icmp_packet::Code const code);
/***********************************
@ -257,7 +265,7 @@ class Net::Interface : private Interface_list::Element
struct Bad_network_protocol : Genode::Exception { };
struct Packet_postponed : Genode::Exception { };
struct Alloc_dhcp_msg_buffer_failed : Genode::Exception { };
struct Dhcp_msg_buffer_too_small : Genode::Exception { };
struct Send_buffer_too_small : Genode::Exception { };
struct Drop_packet_inform : Genode::Exception
{

View File

@ -176,6 +176,7 @@ void Link::handle_config(Domain &cln_domain,
switch (_protocol) {
case L3_protocol::TCP: dissolve_timeout_us = config.tcp_idle_timeout(); break;
case L3_protocol::UDP: dissolve_timeout_us = config.tcp_idle_timeout(); break;
default: throw Interface::Bad_transport_protocol();
}
_dissolve_timeout_us = dissolve_timeout_us;
_dissolve_timeout.schedule(_dissolve_timeout_us);