How to receive UDP packet with 127.0.0.0/8 dst address in userspace

I would like to know if it is possible in linux to receive an UDP packet in userspace that has a 127.0.0.0/8 dst address but coming from an external interface.

I tested it with nc and I can see although nc binds to all addresses it doesn’t receive the packet.

On Device 1 I manipulated the local routing table to route this packet to desired interface then I send a test packet.
Device 1:

frr:~# ip route show table local 
...  
127.1.1.1 nhid 17  encap mpls  16 via 10.10.10.5 dev eth5
...
frr:~# echo "foo" | nc -w1 -u -v -s 3.3.3.3 127.1.1.1 3503

Device 2:

frr:~# nc -l -u -p 3503

The following packet is generated and captured in wireshark on Device 2 interface:
enter image description here

I know that according to RFC 1812 this should never happen. On the other hand this is a valid use case according RFC4379. The trick here that the packet I’m sending is actually not IP routed but MPLS switched and on the last hop the MPLS label is missing due to PHP (Penultimate Hop Popping) and the goal of using 127.0.0.0/8 address as dst is to make sure that when label stack runs out or no valid nexthop then the router will not forward based on IP address but process the packet. This is called MPLS OAM or LSP Ping.

Asked By: zskr

||

When lo0 is created, it is assigned 127.0.0.1 with a netmask of /8. This is done by the kernel (see net/ipv4/devinet.c). So, is you want to try to reuse some of the 127.0.0.0/8 space, you must re-assign the IP mask after the initialisation. So, you should probably set the network on lo0 as 127.0.0.0/24, before setting your ethernet to 127.1.1.0/24.

Note that there are many processes that expect 127.0.0.0/8 to be on lo0. So, setting the network on lo0 to a /24 will probably work, but may break other processes. You might want to use a systemd-free distribution.

There are discussions about reclaiming, at least part of, 127.0.0.0/8. See for example an IETF draft.

You will not be able to go through standard routers. You will need to customize them as well.

Answered By: Ljm Dullaart

By default the Linux kernel enforces RFC 1812 when performing route validation on packets with such source or destination. Here are a few samples: IPv4: 1 2 3 4 5, ARP: 6. They all look about the same:

  if (ipv4_is_loopback(saddr) && !IN_DEV_ROUTE_LOCALNET(in_dev))
      return -EINVAL;

If the source or destination of address is within 127.0.0.0/8 and this doesn’t happen within the host, ie through the loopback interface, the packet will be dropped… unless the dedicated sysctl toggle route_localnet (checked by the macro above) is enabled, in which case the address is considered a normal routable address:

route_localnet – BOOLEAN

Do not consider loopback addresses as martian source or destination
while routing. This enables the use of 127/8 for local routing
purposes.

default FALSE

So to have an interface accept to receive or emit such traffic without it being dropped by the routing stack, the toggle has to be enabled on it. For an interface eth5 this would be done with:

sysctl -w net.ipv4.conf.eth5.route_localnet=1

Depending on how the encapsulation is done and on the overall setup, possibly other interfaces could be involved, use all instead of eth5 first, in case of doubt.


Here’s a question I answered on SU about such packet on the wire:

Sending packets meant for an address on 127.0.0.1/8 to the network on Ubuntu

Hint: also disable rp_filter everywhere (including all and default) when debugging until it starts working. That’s what causes some of the RTNETLINK answers: Invalid argument until all routes for both directions are properly configured.


Beside this RFC 4379 use case, one possibly more common case is when a Destination NAT is done to change a normal address into a loopback address to cheaply overcome an application that binds its service only on a loopback address. Simplified example:

iptables -t nat -I PREROUTING -p tcp --dport 80 -j DNAT --to-destination 127.0.0.1:8080

It can work only with the toggle enabled, because the routing stack itself sees packets not on the loopback with a loopback address inside (destination for incoming, source for reply). No such packet actually appears on the wire (NAT happens) but the routing stack doesn’t know this, so the check has to be ignored.

Answered By: A.B
Categories: Answers Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.