Wandering Thoughts archives


Modern proxy (IPv4) ARP and proxy IPv6 NDP on Linux

Suppose, not hypothetically, that you have a remote system (on the other side of some tunnel or other connection) that wants to pretend to be on the local network, for either or both of IPv4 and IPv6. To make this work smoothly, this remote system's gateway (on the local network) needs to answer ARP requests for this remote system's IPv4 address and/or NDP requests for the remote system's IPv6 address. This is called 'proxy ARP' or 'proxy NDP', because the gateway is acting as an ARP or NDP proxy for the remote system.

At this point my memories are vague, but I think that in the old days, configuring proxy ARP on Linux was somewhat challenging and obscure, requiring you to add various magic settings in various places. These days it has gotten much easier and more uniform, and there are at least two approaches, the by hand one and the systemd one, although it turns out I don't know how to make systemd work for the IPv4 proxy ARP case.

The by hand approach is with the ip neighbour (sub)command. This can be used to add IPv4 or IPv6 proxy announcements to some network, which is normally the network the remote machine is pretending to be on:

ip neigh add proxy 128.X.Y.Z dev em0
ip neigh add proxy 2606:fa00:.... dev em0

# apparently necessary
echo 1 >/proc/sys/net/ipv6/conf/em0/proxy_arp

Here em0 is the interface that the 128.X.Y.0/24 and 2606:fa00:.../64 networks are on, where we want other machines to see 128.X.Y.Z (and its IPv6 version) as being on the network.

You can see these proxies (if any) with 'ip neigh show proxy'. To actually be useful, the system doing proxy ARP also generally needs to have IP forwarding turned on and to have appropriate routes or other ways to get packets to the IP it's proxying for.

Although there is a /proc/sys/net/ipv4/conf/*/proxy_arp setting (cf), it appears to be unimportant in today's modern 'ip neighbour' based setup. One of my machines is happily doing proxy ARP with this at the default of '0' on all interfaces. IPv6 has a similar ipv6/conf/*/proxy_ndp, but unlike with IPv4, the setting here appears to matter and you have to turn it on on the relevant interface; it's on for the relevant interface on my IPv6 gateway and turning it off makes external pings stop working.

(It's possible that other settings are affecting my lack of need for proxy_arp in my IPv4 case.)

The systemd way is to set up a systemd-networkd .network file that has the relevant settings. You set this on the interface where you want the proxy ARP or NDP to be on, not on the tunnel interface to the remote machine (as I found out). For IPv6, you want to set IPv6ProxyNDP= and at least one IPv6ProxyNDPAddress=, although it's not strictly necessary to explicitly set IPv6ProxyNDP (I'd do it for clarity). I was going to write something about how to do this for IPv4, but I can't actually work out how to do the equivalent of 'ip neigh add proxy ...' in systemd .network files; all they appear to do is support turning on proxy ARP in general, and I'm not sure what this does these days.

(If it's like eg this old discussion, then it may cause Linux to do proxy ARP for anything that it has routes for. There's also this Debian Wiki page suggesting the same thing.)

I don't know if NetworkManager has much support for proxy ARP or proxy NDP, since both seem somewhat out of scope for it.

PS: The systemd-networkd approach for IPv6 proxy NDP definitely results in an appropriate entry in 'ip -6 neigh show proxy', so it's not just turning on some form of general proxy NDP and calling it a day. That's certainly what I'd expect given that you list one or more proxy NDP addresses, but I like to verify these things.

linux/ModernProxyIPv6AndARP written at 23:32:40; Add Comment

Page tools: See As Normal.
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.