mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-23 12:58:02 +00:00
209 lines
9.6 KiB
Plaintext
209 lines
9.6 KiB
Plaintext
|
|
||
|
=================================
|
||
|
Component for routing NIC packets
|
||
|
=================================
|
||
|
|
||
|
|
||
|
Brief
|
||
|
#####
|
||
|
|
||
|
The nic_router component can be used to individually route IPv4 packets between
|
||
|
multiple NIC sessions. Thereby, it can translate between different IP subnets.
|
||
|
The component supports port forwarding, as well as the partitioning of the TCP
|
||
|
and UDP port spaces.
|
||
|
|
||
|
|
||
|
Basic routing
|
||
|
#############
|
||
|
|
||
|
The nic_router component provides multiple sessions of the 'NIC' service
|
||
|
(downlinks) while requesting one 'NIC' session (the uplink) itself. Through
|
||
|
common Genode session routing, the uplink can be connected to any other NIC
|
||
|
server. Inside the component, uplink and downlinks are treated the same. Its
|
||
|
routing algorithm is ultimately controlled through the configuration. For each
|
||
|
NIC session there must be a policy:
|
||
|
|
||
|
! <policy label="uplink" src="192.168.1.3" />
|
||
|
! <policy label="http_servers" src="10.0.2.1" />
|
||
|
|
||
|
The 'label' attribute must match the session label respectively 'uplink' for the
|
||
|
uplink session. The 'src' attribute contains a static IPv4 identity that
|
||
|
represents the nic_router with respect to that session. This identity is used
|
||
|
when doing Network-Address-Translation to the session. Moreover, a policy tag
|
||
|
may contain multiple 'ip' sub-tags:
|
||
|
|
||
|
! <ip dst="192.168.1.0/24" label="uplink" />
|
||
|
! <ip dst="10.0.0.0/16" label="http_servers" />
|
||
|
|
||
|
Each 'ip' tag defines a routing rule for IPv4 packets that are sent by the
|
||
|
session of the surrounding policy. Such a rule needs at least a 'dst' attribute
|
||
|
that contains an IPv4 address prefix. When the nic_router receives an IPv4
|
||
|
packet, it goes top-down through all the rules of the session, checking whether
|
||
|
the packet destination matches the 'dst' attribute. The first rule that matches
|
||
|
is inspected deeper. The next thing to be read is the 'label' attribute that
|
||
|
names the target session of the rule. If the label points to a valid session,
|
||
|
the packet could now be routed via this rule. But the IP rule is only remembered
|
||
|
as fallback yet because it may contain sub-tags for preferred UDP and TCP
|
||
|
routing:
|
||
|
|
||
|
! <udp dst="443" label="udp_servers" />
|
||
|
! <tcp dst="80" label="http_servers" />
|
||
|
|
||
|
Those tags work pretty similar to the IP rules. The 'dst' attribute defines
|
||
|
the port that a packet must be addressed to for a match. The 'label' attribute
|
||
|
again points to the target session. If no matching UDP or TCP rule with a
|
||
|
valid target session is found inside the matching IP rule, the nic_router
|
||
|
falls back to the IP rule. If the target session of the matching IP rule isn't
|
||
|
valid, it continues with the next matching IP rule, and so on.
|
||
|
|
||
|
|
||
|
Modify destination and gateway
|
||
|
##############################
|
||
|
|
||
|
All three, the 'ip', 'udp', and 'tcp' tag may have further attributes 'to'
|
||
|
and/or 'via'. Both attributes define an IPv4 address. The address in the 'to'
|
||
|
attribute replaces the IPv4 destination of an affected packet. The address in
|
||
|
the 'via' attribute is the gateway for that rule. This means, when searching
|
||
|
for the next Ethernet destination of an affected packet, the nic_router uses the
|
||
|
'via' address as criterion. If not set, the 'via' address is always the IPv4
|
||
|
destination of the packet. Hence, if only the 'to' attribute is set for a
|
||
|
rule, the value is also used as 'via' address.
|
||
|
|
||
|
! <udp ... via="192.168.2.1" />
|
||
|
! <ip ... to="10.0.2.234" via="192.168.2.1" />
|
||
|
! <tcp ... to="10.0.2.234" />
|
||
|
|
||
|
|
||
|
Network address translation
|
||
|
###########################
|
||
|
|
||
|
The nic_router component can translate between different IPv4 subnets of clients,
|
||
|
and "uplink". When enabled within the policy of a client:
|
||
|
|
||
|
! <policy ... nat="yes" />
|
||
|
|
||
|
the source address of all IPv4 packets of that client is replaced by the 'src'
|
||
|
value of the applied target session. And the TCP/UDP source port is replaced
|
||
|
by a dynamically allocated source port of the applied target session. There is
|
||
|
an exception from the latter. If the source port of the packet matches a
|
||
|
TCP/UDP rule of the applied target session, the packet is assumed to be a
|
||
|
reply to a port-forwarded request from the counterside. In this case, the
|
||
|
source port remains unchanged to enable the receiver to correlate the packet
|
||
|
correctly.
|
||
|
|
||
|
For partitioning the TCP/UDP port space, e.g., the source ports regarding the
|
||
|
'uplink' session between different client sessions, one can configure how many
|
||
|
ports may be used concurrently per client session:
|
||
|
|
||
|
! <policy ... nat="yes" nat-udp-ports="1001" />
|
||
|
! <policy ... nat="yes" nat-tcp-ports="43" nat-udp-ports="21" />
|
||
|
! <policy ... nat="yes" nat-tcp-ports="3" />
|
||
|
|
||
|
The ports attribute contains the maximum number of ports that the nic_router
|
||
|
assigns to the given session. This is necessary to avoid that a NIC session
|
||
|
can run Denial-of-Service attacks against the nic_router by occupying all of
|
||
|
its ports.
|
||
|
|
||
|
For both, UDP and TCP activities, the nic_router holds link states. The link
|
||
|
states enable the nic_router to re-direct related packets from the counterside
|
||
|
correctly without the need for additional routing rules. Such link state rules
|
||
|
are the most preferred way of routing. Before the nic_router starts looking
|
||
|
for IP, UDP, or TCP rules for a packet, it tries to find a matching rule
|
||
|
amongst the link states.
|
||
|
|
||
|
As link state rules are created on demand and are bound to an active
|
||
|
connection between two peers, it is desirable to clear them away as soon as
|
||
|
they are not needed anymore. A precise algorithm for that enables the NIC
|
||
|
sessions to get the maximum out of their resources (ports, RAM). A TCP state
|
||
|
rule corresponding is held until the nic_router observes the four-way
|
||
|
termination handshake of TCP and two times the estimated round-trip time has
|
||
|
passed. The nic_router currently doesn't estimate any round-trip times by
|
||
|
itself. Instead it expects an attribute 'rtt_sec' in its 'config' tag:
|
||
|
|
||
|
! <config rtt_sec="3"> ... </config>
|
||
|
|
||
|
This would set the round-trip time to three seconds which means that link
|
||
|
state rules wait six seconds after a termination handshake before they close
|
||
|
themselves. As UDP has no notion of connections, UDP state rules are simply
|
||
|
held for a duration of two times the round-trip time after the last packet.
|
||
|
This way, the peers can keep alive a UDP pseudo-connection by frequently
|
||
|
sending empty packets.
|
||
|
|
||
|
|
||
|
Examples
|
||
|
########
|
||
|
|
||
|
This paragraph will list and explain some interesting configuration snippets.
|
||
|
A comprehensive example of how to use the nic_router can be found in the test
|
||
|
script 'libports/run/nic_router.run' .
|
||
|
|
||
|
|
||
|
Accessing a private server network
|
||
|
==================================
|
||
|
|
||
|
In this example, we assume that there is a HTTP server "behind" the nic_router
|
||
|
(downlink) listening at port 80. Through the uplink session, several clients
|
||
|
may ask the nic_router for HTTP. The nic_router has the following
|
||
|
configuration:
|
||
|
|
||
|
! <policy label="uplink" src="10.0.2.55">
|
||
|
! <ip dst="10.0.2.55/32">
|
||
|
! <tcp dst="80" label="http_servers" to="192.168.1.2" />
|
||
|
! </ip>
|
||
|
! </policy>
|
||
|
!
|
||
|
! <policy label="http_servers" src="192.168.1.1" nat="yes" nat-tcp-ports="30">
|
||
|
! <ip dst="10.0.2.0/24" label="uplink" />
|
||
|
! </policy>
|
||
|
|
||
|
The uplink IP rule matches only packets that directly address the nic_router's
|
||
|
uplink identity. Amongst those packets, the ones to TCP port 80 also match the
|
||
|
TCP sub-rule. The TCP sub-rule is rated higher than the surrounding IP rule
|
||
|
and thus gets applied. Consequently, the nic_router replaces the IPv4
|
||
|
destination of the packets with the 'to' value (which is the local server
|
||
|
address), then looks up and installs the next Ethernet destination for the
|
||
|
given server address, and finally sends the packet on the servers NIC session.
|
||
|
All other packets from the uplink are dropped. Even those that address the
|
||
|
nic_router directly but with another port. This is because, although the IP
|
||
|
rule still matches, it specifies no target session.
|
||
|
|
||
|
If the server sends back reply packets to the client, they address the clients
|
||
|
public IP because the IPv4 source of the previous request wasn't modified.
|
||
|
Thus, these packets match the IP rule in the server policy and get forwarded
|
||
|
to the uplink. But furthermore, the nic_router is configured do NAT for the
|
||
|
server (with 30 simultaneous TCP connections allowed). Hence, the nic_router
|
||
|
replaces the IPv4 source in the server replies by its uplink identity
|
||
|
'10.0.2.55'. The source port, at the other hand, is not replaced because it
|
||
|
matches a TCP rule in the uplink policy. This way, the client is able to
|
||
|
associate the replies to its TCP connection with the server.
|
||
|
|
||
|
|
||
|
Using public servers from a private network
|
||
|
===========================================
|
||
|
|
||
|
Let's assume we have a UDP client "behind" the nic_router and like to talk to an
|
||
|
"outside" server. An example configuration for that would be:
|
||
|
|
||
|
! <policy label="uplink" src="10.0.2.55" />
|
||
|
!
|
||
|
! <policy label="udp_clients" src="100.200.0.1" nat="yes" nat-udp-ports="2">
|
||
|
! <ip dst="10.0.2.0/24" label="uplink" />
|
||
|
! </policy>
|
||
|
|
||
|
UDP packets from the client to the public network match the clients IP rule
|
||
|
and therefore are forwarded to the uplink. Because of the NAT attributes, the
|
||
|
packets are modified to have '10.0.2.55' as IPv4 source and a free UDP port of
|
||
|
the uplink session as source port. The client is allowed to open a maximum of
|
||
|
two such connections at a time. The uplink doesn't need any rules to forward
|
||
|
the replies for the UDP client correctly as long as the server replies in
|
||
|
time. This is because the nic_router still holds the link state of the initial
|
||
|
UDP packet from the client and can use it to map back IP address and port.
|
||
|
|
||
|
|
||
|
Limitations
|
||
|
###########
|
||
|
|
||
|
Currently, different client sessions should not share the same subnet to be able
|
||
|
to communicate with each other, because forwarding broadcast packets (e.g., ARP
|
||
|
packets) between different clients of the same subnet is not supported yet.
|