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 { } {
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_d2_c1_udp udp 10.0.99.56 10.0.99.33 255.255.255.0 nic_router 1337 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 ]" }
[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 999 ]" }
}
proc test_1_router_config { } {
@ -44,7 +44,7 @@ proc test_1_router_config { } {
<policy label_prefix="t1_d2" domain="t1_d2" />
<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 name="t1_d2" interface="10.0.99.33/24" />} }
@ -107,7 +107,7 @@ proc test_3_router_uplink_config { } {
proc test_4_config { } {
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]
[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 { } {
@ -118,7 +118,7 @@ proc test_4_router_config { } {
proc test_4_router_uplink_config { } {
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:
! <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" />
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
domain (Section [Basics]). Amongst those, 'tcp-forward' rules only apply to
the TCP packets and 'udp-forward' rules only to the UDP packets. The 'port'
attribute is compared with the packet's destination port. If a matching rule
is found, the IP destination of the packet is changed to the value of the 'to'
attribute. Then, the packet is routed to the domain given in the rule. Note
that the router accepts only system and registered ports (0 to 49151) for port
forwarding.
surrounding domain and are addressed to the router's IP identity at this domain
(Section [Basics]). Amongst those, 'tcp-forward' rules only apply to the TCP
packets and 'udp-forward' rules only to the UDP packets. The 'port' attribute
is compared with the packet's destination port. If a matching rule is found,
the IP destination of the packet is changed to the value of the 'to' attribute.
If the 'to_port' attribute is set and not zero, the packet's destination port
is changed to the attribute value. Then, the packet is routed to the domain
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
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">
! <tcp-forward port="80" domain="virtnet_a" to="192.168.1.2" />
! <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 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.
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,
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
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="domain" type="Domain_name" />
<xs:attribute name="to" type="Ipv4_address" />
<xs:attribute name="to_port" type="Port" />
</xs:complexType><!-- L3_forward_rule -->
<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
{
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)
:
_port(node.attribute_value("port", Port(0))),
_to(node.attribute_value("to", Ipv4_address())),
_domain(_find_domain(domains, node))
_port { node.attribute_value("port", Port(0)) },
_to_ip { node.attribute_value("to", Ipv4_address()) },
_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(); }
}

View File

@ -41,7 +41,8 @@ class Net::Forward_rule : public Genode::Avl_node<Forward_rule>
private:
Port const _port;
Ipv4_address const _to;
Ipv4_address const _to_ip;
Port const _to_port;
Domain &_domain;
static Domain &_find_domain(Domain_tree &domains,
@ -75,7 +76,8 @@ class Net::Forward_rule : public Genode::Avl_node<Forward_rule>
** 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; }
};

View File

@ -1148,8 +1148,11 @@ void Interface::_handle_ip(Ethernet_frame &eth,
l3_protocol_name(prot), " ", rule);
}
Domain &remote_domain = rule.domain();
_adapt_eth(eth, rule.to(), pkt, remote_domain);
ip.dst(rule.to());
_adapt_eth(eth, rule.to_ip(), pkt, remote_domain);
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,
prot_size, local_id, local_domain, remote_domain);
return;
@ -1704,10 +1707,32 @@ void Interface::_update_udp_tcp_links(L3_protocol prot,
find_by_port(link.client().dst_port());
/* 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");
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);
return;
}