nic_router: manipulate port-forwarding port

The new configuration attributes <tcp-forward to_port="123" /> and
<udp-forward to_port="123" /> enable manipulating the destination port of
port-forwarded packets.

Fixes #3237
This commit is contained in:
Martin Stein 2019-03-18 17:31:59 +01:00 committed by Norman Feske
parent 3a59f11708
commit bcc049ceeb
6 changed files with 63 additions and 31 deletions

View File

@ -34,8 +34,8 @@ create_boot_directory
proc test_1_config { } { proc test_1_config { } {
if {[enable_test_1]} { return " if {[enable_test_1]} { return "
[client_config t1_d1_c1_udp udp 10.0.98.55 10.0.98.33 255.255.255.0 nic_router 1337 10.0.98.33] [client_config t1_d1_c1_udp udp 10.0.98.55 10.0.98.33 255.255.255.0 nic_router 1337 10.0.98.33]
[client_config t1_d2_c1_udp udp 10.0.99.56 10.0.99.33 255.255.255.0 nic_router 1337 10.0.99.55] [client_config t1_d2_c1_udp udp 10.0.99.56 10.0.99.33 255.255.255.0 nic_router 999 10.0.99.55]
[server_config t1_d2_s1_udp udp 10.0.99.55 10.0.99.33 255.255.255.0 nic_router 1337 ]" } [server_config t1_d2_s1_udp udp 10.0.99.55 10.0.99.33 255.255.255.0 nic_router 999 ]" }
} }
proc test_1_router_config { } { proc test_1_router_config { } {
@ -44,7 +44,7 @@ proc test_1_router_config { } {
<policy label_prefix="t1_d2" domain="t1_d2" /> <policy label_prefix="t1_d2" domain="t1_d2" />
<domain name="t1_d1" interface="10.0.98.33/24"> <domain name="t1_d1" interface="10.0.98.33/24">
<udp-forward port="1337" domain="t1_d2" to="10.0.99.55" /> <udp-forward port="1337" domain="t1_d2" to="10.0.99.55" to_port="999" />
</domain> </domain>
<domain name="t1_d2" interface="10.0.99.33/24" />} } <domain name="t1_d2" interface="10.0.99.33/24" />} }
@ -107,7 +107,7 @@ proc test_3_router_uplink_config { } {
proc test_4_config { } { proc test_4_config { } {
if {[enable_test_4]} { return " if {[enable_test_4]} { return "
[client_config t4_d0_c1_tcp http 10.0.2.201 10.0.2.1 255.255.255.0 nic_bridge 80 10.0.2.55] [client_config t4_d0_c1_tcp http 10.0.2.201 10.0.2.1 255.255.255.0 nic_bridge 80 10.0.2.55]
[server_config t4_d1_s1_tcp http 192.168.1.18 192.168.1.1 255.255.255.0 nic_router 80 ]" } [server_config t4_d1_s1_tcp http 192.168.1.18 192.168.1.1 255.255.255.0 nic_router 2048 ]" }
} }
proc test_4_router_config { } { proc test_4_router_config { } {
@ -118,7 +118,7 @@ proc test_4_router_config { } {
proc test_4_router_uplink_config { } { proc test_4_router_uplink_config { } {
if {[enable_test_4]} { return { if {[enable_test_4]} { return {
<tcp-forward port="80" domain="t4_d1" to="192.168.1.18" />} } <tcp-forward port="80" domain="t4_d1" to="192.168.1.18" to_port="2048" />} }
} }
# #

View File

@ -239,18 +239,19 @@ Port-forwarding rules
These are examples for port-forwarding rules: These are examples for port-forwarding rules:
! <tcp-forward port="80" domain="http_servers" to="192.168.1.18" /> ! <tcp-forward port="80" domain="http_servers" to="192.168.1.18" to_port="1234" />
! <udp-forward port="69" domain="tftp_servers" to="192.168.2.23" /> ! <udp-forward port="69" domain="tftp_servers" to="192.168.2.23" />
Port-forwarding rules only apply to packets that come from the session of the Port-forwarding rules only apply to packets that come from the session of the
surrounding domain and are addressed to the router's IP identity at this surrounding domain and are addressed to the router's IP identity at this domain
domain (Section [Basics]). Amongst those, 'tcp-forward' rules only apply to (Section [Basics]). Amongst those, 'tcp-forward' rules only apply to the TCP
the TCP packets and 'udp-forward' rules only to the UDP packets. The 'port' packets and 'udp-forward' rules only to the UDP packets. The 'port' attribute
attribute is compared with the packet's destination port. If a matching rule is compared with the packet's destination port. If a matching rule is found,
is found, the IP destination of the packet is changed to the value of the 'to' the IP destination of the packet is changed to the value of the 'to' attribute.
attribute. Then, the packet is routed to the domain given in the rule. Note If the 'to_port' attribute is set and not zero, the packet's destination port
that the router accepts only system and registered ports (0 to 49151) for port is changed to the attribute value. Then, the packet is routed to the domain
forwarding. given in the rule. Note that the router accepts only system and registered
ports other than zero (1 to 49151) for port forwarding.
For bidirectional traffic, you'll need only one port-forwarding rule For bidirectional traffic, you'll need only one port-forwarding rule
describing the client-to-server direction. The server-sided domain doesn't describing the client-to-server direction. The server-sided domain doesn't
@ -628,7 +629,7 @@ following configuration:
! <domain name="uplink" interface="10.0.2.55/24" gateway="10.0.2.1"> ! <domain name="uplink" interface="10.0.2.55/24" gateway="10.0.2.1">
! <tcp-forward port="80" domain="virtnet_a" to="192.168.1.2" /> ! <tcp-forward port="80" domain="virtnet_a" to="192.168.1.2" />
! <tcp-forward port="70" domain="virtnet_a" to="192.168.1.3" /> ! <tcp-forward port="70" domain="virtnet_a" to="192.168.1.3" />
! <udp-forward port="69" domain="virtnet_a" to="192.168.1.4" /> ! <udp-forward port="69" domain="virtnet_a" to="192.168.1.4" to_port="2048"/>
! </domain> ! </domain>
! !
! <domain name="virtnet_a" interface="192.168.1.1/24" /> ! <domain name="virtnet_a" interface="192.168.1.1/24" />
@ -638,7 +639,8 @@ Amongst the packets that come from the uplink, only those that are addressed
to 10.0.2.55 and TCP port 80, TCP port 70, or UDP port 69 are forwarded. to 10.0.2.55 and TCP port 80, TCP port 70, or UDP port 69 are forwarded.
All these packets are forwarded to Virtnet A. But beforehand, their IP All these packets are forwarded to Virtnet A. But beforehand, their IP
destination is adapted. TCP-port-80 packets are redirected to 192.168.1.2, destination is adapted. TCP-port-80 packets are redirected to 192.168.1.2,
TCP-port-70 packets to 192.168.1.3, and UDP-port-69 packets to 192.168.1.4. TCP-port-70 packets to 192.168.1.3, and UDP-port-69 packets to
192.168.1.4:2048.
Amongst the packets that come from Virtnet A, only those that match a link Amongst the packets that come from Virtnet A, only those that match a link
state at the uplink are forwarded, because the Virtnet-A domain contains no state at the uplink are forwarded, because the Virtnet-A domain contains no

View File

@ -48,6 +48,7 @@
<xs:attribute name="port" type="Port" /> <xs:attribute name="port" type="Port" />
<xs:attribute name="domain" type="Domain_name" /> <xs:attribute name="domain" type="Domain_name" />
<xs:attribute name="to" type="Ipv4_address" /> <xs:attribute name="to" type="Ipv4_address" />
<xs:attribute name="to_port" type="Port" />
</xs:complexType><!-- L3_forward_rule --> </xs:complexType><!-- L3_forward_rule -->
<xs:element name="config"> <xs:element name="config">

View File

@ -40,17 +40,19 @@ Domain &Forward_rule::_find_domain(Domain_tree &domains,
void Forward_rule::print(Output &output) const void Forward_rule::print(Output &output) const
{ {
Genode::print(output, "port ", _port, " domain ", _domain, " to ", _to); Genode::print(output, "port ", _port, " domain ", _domain, " to ip ",
_to_ip, " to port ", _to_port);
} }
Forward_rule::Forward_rule(Domain_tree &domains, Xml_node const node) Forward_rule::Forward_rule(Domain_tree &domains, Xml_node const node)
: :
_port(node.attribute_value("port", Port(0))), _port { node.attribute_value("port", Port(0)) },
_to(node.attribute_value("to", Ipv4_address())), _to_ip { node.attribute_value("to", Ipv4_address()) },
_domain(_find_domain(domains, node)) _to_port { node.attribute_value("to_port", Port(0)) },
_domain { _find_domain(domains, node) }
{ {
if (_port == Port(0) || !_to.valid() || dynamic_port(_port)) { if (_port == Port(0) || !_to_ip.valid() || dynamic_port(_port)) {
throw Invalid(); } throw Invalid(); }
} }

View File

@ -41,7 +41,8 @@ class Net::Forward_rule : public Genode::Avl_node<Forward_rule>
private: private:
Port const _port; Port const _port;
Ipv4_address const _to; Ipv4_address const _to_ip;
Port const _to_port;
Domain &_domain; Domain &_domain;
static Domain &_find_domain(Domain_tree &domains, static Domain &_find_domain(Domain_tree &domains,
@ -75,7 +76,8 @@ class Net::Forward_rule : public Genode::Avl_node<Forward_rule>
** Accessors ** ** Accessors **
***************/ ***************/
Ipv4_address const &to() const { return _to; } Ipv4_address const &to_ip() const { return _to_ip; }
Port const &to_port() const { return _to_port; }
Domain &domain() const { return _domain; } Domain &domain() const { return _domain; }
}; };

View File

@ -1148,8 +1148,11 @@ void Interface::_handle_ip(Ethernet_frame &eth,
l3_protocol_name(prot), " ", rule); l3_protocol_name(prot), " ", rule);
} }
Domain &remote_domain = rule.domain(); Domain &remote_domain = rule.domain();
_adapt_eth(eth, rule.to(), pkt, remote_domain); _adapt_eth(eth, rule.to_ip(), pkt, remote_domain);
ip.dst(rule.to()); ip.dst(rule.to_ip());
if (!(rule.to_port() == Port(0))) {
_dst_port(prot, prot_base, rule.to_port());
}
_nat_link_and_pass(eth, size_guard, ip, prot, prot_base, _nat_link_and_pass(eth, size_guard, ip, prot, prot_base,
prot_size, local_id, local_domain, remote_domain); prot_size, local_id, local_domain, remote_domain);
return; return;
@ -1704,10 +1707,32 @@ void Interface::_update_udp_tcp_links(L3_protocol prot,
find_by_port(link.client().dst_port()); find_by_port(link.client().dst_port());
/* if destination IP of forwarding changed, dismiss link */ /* if destination IP of forwarding changed, dismiss link */
if (rule.to() != link.server().src_ip()) { if (rule.to_ip() != link.server().src_ip()) {
_dismiss_link_log(link, "other forward-rule to"); _dismiss_link_log(link, "other forward-rule to");
throw Dismiss_link(); throw Dismiss_link();
} }
/*
* If destination port of forwarding was set and then was
* modified or unset, dismiss link
*/
if (!(link.server().src_port() == link.client().dst_port())) {
if (!(rule.to_port() == link.server().src_port())) {
_dismiss_link_log(link, "other forward-rule to_port");
throw Dismiss_link();
}
}
/*
* If destination port of forwarding was not set and then was
* set, dismiss link
*/
else {
if (!(rule.to_port() == link.server().src_port()) &&
!(rule.to_port() == Port(0)))
{
_dismiss_link_log(link, "new forward-rule to_port");
throw Dismiss_link();
}
}
_update_link_check_nat(link, rule.domain(), prot, cln_dom); _update_link_check_nat(link, rule.domain(), prot, cln_dom);
return; return;
} }