Bridging Network Connections with Proxy ARP
This document describes a means to bridge IP traffic between two interfaces using Proxy ARP, /32 host routes and standard Linux routing/forwarding. For a Layer 2 solution - an ethernet bridge - refer to BridgeNetworkConnections.
The benefit of using an IP / Layer 3 solution is that it will work when the outward-facing interface is a wireless ethernet client, without using WDS and without resorting to NAT. Simple Layer 2 bridging does not work in this case due to the vagaries of wireless AP client behaviour; WDS may help but AP support can be patchy.
Using Proxy ARP permits the bridged clients to be part of the existing network and supports bidirectional traffic, e.g. for a server or printer. DHCP and mDNS will also work using the appropriate helpers.
One scenario is connecting a wired network to a wireless LAN using a host that has both wifi (wlan0) and ethernet (eth0) interfaces. A specific example is using a Raspberry Pi with a USB wifi adapter to connect a wired-ethernet printer to the WLAN. No static configuration is required other than the wifi SSID and authentication for the Pi - the Pi and printer acquire DHCP addresses from the existing DHCP server, and the printer continues to be reachable via mDNS and otherwise operates as if it were patched to a wired port on the main network.
The term 'bridge' in this document refers to the host doing the proxy-arp and routing between the two networks, though keep in mind there is no layer 2 bridging involved. The 'outside' network is the existing network that hosts the DHCP server, gateway router, etc. The 'inside' network is the one with the hosts that need to be bridged and made to appear to be on the outside network.
Proxy ARP is a technique by which a device on a given network answers the ARP queries for a network address that is not on that network, that is to make the hosts on one network appear to be logically part of a different physical network.
The bridge host will proxy ARP requests from the inside network to the outside, and respond to ARPs from the outside network on behalf of inside hosts. Linux will only do this for hosts that are known via the routing table, so a /32 host route must be created pointing to the inside host (one for each inside host). The route is also required for IP forwarding to work, i.e. when IP traffic arrives after the ARP process has completed.
As an example, to manually configure and test this out where the primary LAN has a network address of 10.42.0.0/24:
- configure an inside client with a static IP of 10.42.0.11/24
- on the bridge:
bridge# echo 1 > /proc/sys/net/ipv4/conf/all/proxy_arp bridge# echo 1 > /proc/sys/net/ipv4/ip_forward bridge# ip ro add 10.42.0.11/32 dev eth0
- ping from the inside host to an outside host, and examine the ARP table:
insidehost$ ping -c 1 10.42.0.2 PING 10.42.0.2 (10.42.0.2) 56(84) bytes of data. 64 bytes from 10.42.0.2: icmp_req=1 ttl=64 time=14.7 ms insidehost$ arp -n 10.42.0.2 Address HWtype HWaddress Flags Mask Iface 10.42.0.2 ether b8:27:eb:6b:52:b9 C eth0 # b8:27:eb:6b:52:b9 is the MAC of eth0 - the inside interface - on the bridge
bridge$ arp -n 10.42.0.2 Address HWtype HWaddress Flags Mask Iface 10.42.0.2 ether 00:08:9b:be:f8:a2 C wlan0 # 00:08:9b:be:f8:a2 is the MAC of eth0 on the outside host bridge$ arp -n 10.42.0.11 Address HWtype HWaddress Flags Mask Iface 10.42.0.11 ether 00:1b:a9:be:16:73 C eth0 10.42.0.11 (incomplete) wlan0 # 00:1b:a9:be:16:73 is the MAC of the inside host; the outside wlan0 entry if present should always be incomplete
outsidehost$ # arp -n 10.84.42.11 Address HWtype HWaddress Flags Mask Iface 10.84.42.11 ether 00:e0:4c:10:3c:75 C eth0 # 00:e0:4c:10:3c:75 is the MAC of wlan0 on the bridge
Note that no IP address is required on the bridge's inside ethernet interface for proxy ARP to work (though see below re. DHCP relay).
If you run tcpdump on the bridge's ethernet and wlan interfaces, you'll see the ARP request from the inside host being proxied to the outside interface, with the ARP source being the bridge's outside-facing interface's MAC address. The ARP table on the inside hosts will show the bridge's inside interface MAC for all outside hosts, and similarly for outside hosts the MAC for all inside hosts will be the bridge's outside interface MAC.
DHCP is a Layer 2 protocol and can't traverse the Layer 3 'bridge' so we use the dhcp-helper utility to listen for DHCP requests from the inside network and relay them to the DHCP server on the outside network. The relayed DHCP request will contain the IP address of the bridge's inside interface in order for the DHCP server to know which network to allocate an IP address for the new client from. We want the DHCP allocation to be from the same network as the outside LAN, the simplest implementation is to reflect the outside interface's IP address on to the inside interface. i.e. the bridge's inside and outside interfaces will have the same IP address; though the inside interface's network will be a host /32 netmask so as not to upset routing.
Alternatively the bridge inside interface can be assigned a static IP from the outside network, in which case the post-up step in /etc/network/interfaces configuration below can be omitted.
Automating the Process
parprouted is designed to monitor the ARP table and both proxy ARP requests and install matching /32 host routes. Running parprouted with the inside and outside interfaces handles the ARP and routing completely automatically. Note that the kernel's proxy ARP mechanism (/proc/sys/net/ipv4/conf/all/proxy_arp) is not required.
parprouted does not handle packet forwarding nor DHCP or mDNS, so these features need to be enabled separately.
Installing the software
The following assumes wlan0 is the already-configured outside interface, eth0 the unconfigured inside interface. Tested on Debian Wheezy 7.8 on 2015-08-02, on armv6l (Raspberry Pi v1).
bridge$ sudo apt-get install parprouted dhcp-helper avahi-daemon
Edit /etc/network/interfaces to configure the interfaces:
auto lo iface lo inet loopback auto eth0 allow-hotplug eth0 iface eth0 inet manual auto wlan0 allow-hotplug wlan0 iface wlan0 inet dhcp wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf post-up /usr/sbin/parprouted eth0 wlan0 post-down /usr/bin/killall /usr/sbin/parprouted # clone the dhcp-allocated IP to eth0 so dhcp-helper will relay for the correct subnet post-up /sbin/ip addr add $(/sbin/ip addr show wlan0 | perl -wne 'm|^\s+inet (.*)/| && print $1')/32 dev eth0 post-down /sbin/ifdown eth0
Edit /etc/sysctl.d/local.conf to enable IP forwarding:
Enable DHCP relay: /etc/default/dhcp-helper
# relay dhcp requests as broadcast to wlan0 DHCPHELPER_OPTS="-b wlan0"
Edit /etc/avahi/avahi-daemon.conf to enable mDNS relaying:
Reboot, and hosts connected to the bridge's ethernet should acquire a DHCP address and have full IP connectivity!
Known Issue with RTL8188CUS USB Wifi Adapter
Description of issue: When using an RTL8188CUS based wifi device, bridge connectivity is very unreliable and most ARP requests to the bridge's wlan address fail. This issue has minimal impact on a host that is configured as a normal client and primarily sending traffic but has a significant impact when the host is acting as a bridge.
Resolution: Edit /etc/modprobe.d/8192cu.conf
# disable power management and USB suspend options 8192cu rtw_power_mgnt=0 rtw_enusbss=0