From 6b4b6623570094a5298db617380472c3cde9b909 Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Thu, 21 Sep 2017 20:00:37 +0200 Subject: [PATCH] nic_router: fix for unknown transport protocols Do not stop routing if the transport layer protocol is unknown but continue with trying IP routing instead. The latter was already done when no transport routing could be applied but for unknown transport protocols we caught the exception at the wrong place. Ref #2490 --- repos/os/src/server/nic_router/interface.cc | 147 +++++++++++--------- repos/os/src/server/nic_router/interface.h | 16 ++- 2 files changed, 88 insertions(+), 75 deletions(-) diff --git a/repos/os/src/server/nic_router/interface.cc b/repos/os/src/server/nic_router/interface.cc index e45a81264..dd52a49fa 100644 --- a/repos/os/src/server/nic_router/interface.cc +++ b/repos/os/src/server/nic_router/interface.cc @@ -147,14 +147,22 @@ static void *_prot_base(uint8_t const prot, ** Interface ** ***************/ -void Interface::_pass_ip(Ethernet_frame ð, - size_t const eth_size, - Ipv4_packet &ip, - uint8_t const prot, - void *const prot_base, - size_t const prot_size) +void Interface::_pass_prot(Ethernet_frame ð, + size_t const eth_size, + Ipv4_packet &ip, + uint8_t const prot, + void *const prot_base, + size_t const prot_size) { _update_checksum(prot, prot_base, prot_size, ip.src(), ip.dst()); + _pass_ip(eth, eth_size, ip); +} + + +void Interface::_pass_ip(Ethernet_frame ð, + size_t const eth_size, + Ipv4_packet &ip) +{ ip.checksum(Ipv4_packet::calculate_checksum(ip)); _send(eth, eth_size); } @@ -288,7 +296,7 @@ void Interface::_nat_link_and_pass(Ethernet_frame ð, Link_side_id const remote = { ip.dst(), _dst_port(prot, prot_base), ip.src(), _src_port(prot, prot_base) }; _new_link(prot, local, remote_port_alloc, interface, remote); - interface._pass_ip(eth, eth_size, ip, prot, prot_base, prot_size); + interface._pass_prot(eth, eth_size, ip, prot, prot_base, prot_size); } @@ -303,84 +311,88 @@ void Interface::_handle_ip(Ethernet_frame ð, Ipv4_packet &ip = *new (eth.data()) Ipv4_packet(eth_size - sizeof(Ethernet_frame)); - uint8_t const prot = ip.protocol(); - size_t const prot_size = ip.total_length() - ip.header_length() * 4; - void *const prot_base = _prot_base(prot, prot_size, ip); - Link_side_id const local = { ip.src(), _src_port(prot, prot_base), - ip.dst(), _dst_port(prot, prot_base) }; - - /* try to route via existing UDP/TCP links */ + /* try to route via transport layer rules */ try { - Link_side const &local_side = _links(prot).find_by_id(local); - Link &link = local_side.link(); - bool const client = local_side.is_client(); - Link_side &remote_side = client ? link.server() : link.client(); - Interface &interface = remote_side.interface(); - if(_config().verbose()) { - log("Using ", protocol_name(prot), " link: ", link); } + uint8_t const prot = ip.protocol(); + size_t const prot_size = ip.total_length() - ip.header_length() * 4; + void *const prot_base = _prot_base(prot, prot_size, ip); + Link_side_id const local = { ip.src(), _src_port(prot, prot_base), + ip.dst(), _dst_port(prot, prot_base) }; - _adapt_eth(eth, eth_size, remote_side.src_ip(), pkt, interface); - ip.src(remote_side.dst_ip()); - ip.dst(remote_side.src_ip()); - _src_port(prot, prot_base, remote_side.dst_port()); - _dst_port(prot, prot_base, remote_side.src_port()); - - interface._pass_ip(eth, eth_size, ip, prot, prot_base, prot_size); - _link_packet(prot, prot_base, link, client); - return; - } - catch (Link_side_tree::No_match) { } - - /* try to route via forward rules */ - if (local.dst_ip == _router_ip()) { + /* try to route via existing UDP/TCP links */ try { - Forward_rule const &rule = - _forward_rules(prot).find_by_port(local.dst_port); - - Interface &interface = rule.domain().interface().deref(); + Link_side const &local_side = _links(prot).find_by_id(local); + Link &link = local_side.link(); + bool const client = local_side.is_client(); + Link_side &remote_side = client ? link.server() : link.client(); + Interface &interface = remote_side.interface(); if(_config().verbose()) { - log("Using forward rule: ", protocol_name(prot), " ", rule); } + log("Using ", protocol_name(prot), " link: ", link); } - _adapt_eth(eth, eth_size, rule.to(), pkt, interface); - ip.dst(rule.to()); + _adapt_eth(eth, eth_size, remote_side.src_ip(), pkt, interface); + ip.src(remote_side.dst_ip()); + ip.dst(remote_side.src_ip()); + _src_port(prot, prot_base, remote_side.dst_port()); + _dst_port(prot, prot_base, remote_side.src_port()); + + interface._pass_prot(eth, eth_size, ip, prot, prot_base, prot_size); + _link_packet(prot, prot_base, link, client); + return; + } + catch (Link_side_tree::No_match) { } + + /* try to route via forward rules */ + if (local.dst_ip == _router_ip()) { + try { + Forward_rule const &rule = + _forward_rules(prot).find_by_port(local.dst_port); + + Interface &interface = rule.domain().interface().deref(); + if(_config().verbose()) { + log("Using forward rule: ", protocol_name(prot), " ", rule); } + + _adapt_eth(eth, eth_size, rule.to(), pkt, interface); + ip.dst(rule.to()); + _nat_link_and_pass(eth, eth_size, ip, prot, prot_base, prot_size, + local, interface); + return; + } + catch (Forward_rule_tree::No_match) { } + } + /* try to route via transport and permit rules */ + try { + Transport_rule const &transport_rule = + _transport_rules(prot).longest_prefix_match(local.dst_ip); + + Permit_rule const &permit_rule = + transport_rule.permit_rule(local.dst_port); + + Interface &interface = permit_rule.domain().interface().deref(); + if(_config().verbose()) { + log("Using ", protocol_name(prot), " rule: ", transport_rule, + " ", permit_rule); } + + _adapt_eth(eth, eth_size, local.dst_ip, pkt, interface); _nat_link_and_pass(eth, eth_size, ip, prot, prot_base, prot_size, local, interface); return; } - catch (Forward_rule_tree::No_match) { } + catch (Transport_rule_list::No_match) { } + catch (Permit_single_rule_tree::No_match) { } } - /* try to route via transport and permit rules */ - try { - Transport_rule const &transport_rule = - _transport_rules(prot).longest_prefix_match(local.dst_ip); - - Permit_rule const &permit_rule = - transport_rule.permit_rule(local.dst_port); - - Interface &interface = permit_rule.domain().interface().deref(); - if(_config().verbose()) { - log("Using ", protocol_name(prot), " rule: ", transport_rule, - " ", permit_rule); } - - _adapt_eth(eth, eth_size, local.dst_ip, pkt, interface); - _nat_link_and_pass(eth, eth_size, ip, prot, prot_base, prot_size, - local, interface); - return; - } - catch (Transport_rule_list::No_match) { } - catch (Permit_single_rule_tree::No_match) { } + catch (Interface::Bad_transport_protocol) { } /* try to route via IP rules */ try { Ip_rule const &rule = - _domain.ip_rules().longest_prefix_match(local.dst_ip); + _domain.ip_rules().longest_prefix_match(ip.dst()); Interface &interface = rule.domain().interface().deref(); if(_config().verbose()) { log("Using IP rule: ", rule); } - _adapt_eth(eth, eth_size, local.dst_ip, pkt, interface); - interface._pass_ip(eth, eth_size, ip, prot, prot_base, prot_size); + _adapt_eth(eth, eth_size, ip.dst(), pkt, interface); + interface._pass_ip(eth, eth_size, ip); return; } catch (Ip_rule_list::No_match) { } @@ -531,9 +543,6 @@ void Interface::_handle_eth(void *const eth_base, catch (Ethernet_frame::No_ethernet_frame) { error("invalid ethernet frame"); } - catch (Interface::Bad_transport_protocol) { - error("unknown transport layer protocol"); } - catch (Interface::Bad_network_protocol) { error("unknown network layer protocol"); } diff --git a/repos/os/src/server/nic_router/interface.h b/repos/os/src/server/nic_router/interface.h index 683416304..fedada3a0 100644 --- a/repos/os/src/server/nic_router/interface.h +++ b/repos/os/src/server/nic_router/interface.h @@ -104,12 +104,16 @@ class Net::Interface void _send(Ethernet_frame ð, Genode::size_t const eth_size); - void _pass_ip(Ethernet_frame ð, - Genode::size_t const eth_size, - Ipv4_packet &ip, - Genode::uint8_t const prot, - void *const prot_base, - Genode::size_t const prot_size); + void _pass_prot(Ethernet_frame ð, + Genode::size_t const eth_size, + Ipv4_packet &ip, + Genode::uint8_t const prot, + void *const prot_base, + Genode::size_t const prot_size); + + void _pass_ip(Ethernet_frame ð, + Genode::size_t const eth_size, + Ipv4_packet &ip); void _continue_handle_eth(Packet_descriptor const &pkt);