36

On Arch Linux, I would like to have eth0 (connected to bridged router) share the connection received from wlan0, I've read tutorials but I'm not command savvy as other users are and don't completely understand.

Dessa Simpson
  • 491
  • 7
  • 25
dbdii407
  • 463
  • 1
  • 5
  • 7
  • 9
    please do not put '[solved]' in the question or title, accepting an answer is the correct way to show that a problem was solved. It changes the way the question is displayed on the main listing as well as putting the green check mark on the answer you have marked as correct. – Zypher Sep 25 '10 at 00:14
  • 14
    http://serverfault.com/faq Specifically the heading "Other people can edit my stuff" – Zypher Sep 25 '10 at 00:45
  • @Zypher The URL you link to no longer exists. Has the relevant paragraph moved elsewhere? – kasperd Apr 15 '15 at 13:04
  • 4
    @kasperd http://serverfault.com/help/editing – Zypher Apr 15 '15 at 13:06

6 Answers6

39

To bridge wifi interface you may use iw tool to enable 4addr likewise:

# iw dev <wifiInterface> set 4addr on

ie:

# brctl addif <bridgename> <wifiInterface>
can't add <wifiInterface> to bridge <bridgename>: Operation not supported

# iw dev <wifiInterface> set 4addr on
# brctl addif <bridgename> <wifiInterface>

Now it should work. You can show bridges using:

# brctl show
amized
  • 501
  • 4
  • 3
  • 2
    What is this setting for and why do you specifically suggest to use it in this scenario? – hakre Jun 19 '16 at 17:07
  • This is a solution for "Operation not permited" error when trying to add wlan0 interface to the bridge interface. After that you have to specify the bridge interface in /etc/network/interfaces in order to be bringed up after startup. – Str82DHeaD Oct 19 '16 at 12:45
  • 1
    @hakre The `4addr` mode make WiFi behave enough like wired Ethernet that bridging will work. Without it, bridging will not work without NAT. – David Schwartz Apr 21 '17 at 08:42
  • 2
    `4addr` does require that both sides of a wireless link support it (presuming you are trying to implement a wifi extender) – nhed Apr 17 '18 at 16:15
31

UPDATE

It is not possible to bridge between wireless (client a.k.a. station mode) and wired interfaces according to this thread on linux-ath5k-devel.

Setup NAT

One should set up NAT instead:

echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE

Assigning an IP

Then you have to assign IP addresses to yourself:

ifconfig eth0 10.0.0.1 netmask 255.255.255.0 up

Install dhcp daemon

Install a dhcp server and add the following text to its config file (in /etc/dhcpd.conf or something similar)

subnet 10.0.0.0 netmask 255.255.255.0 {
    range 10.0.0.100 10.0.0.120;
    option routers 10.0.0.1;
    option domain-name-servers the-ip-address-you-have-in-etc-resolv.conf;
}

Start dhcpd

Then start it /etc/init.d/dhcpd start

And that's it!

Only read below if you are interested in the non-working bridging setup


brctl addbr mybridge
brctl addif mybridge eth0
brctl addif mybridge wlan0

First you create a bridge interface I choose an arbitrary name mybridge then add intefaces to it.

You should request a new ip address (This is needed only if you want to get a valid IP for the bridging device itself):

dhclient -d mybridge
cstamas
  • 6,607
  • 24
  • 42
16

Bridge wlan and 4addr:

Bridging wlan0 is a pain. You normally cannot add it to a bridge interface (brctl returns "Operation not permitted"), and using VirtualBox "bridged" filter results in a big mess of ARP and DHCP conflicts. The cause of this is that 802.11 frames contain only three addresses by default: the MAC addresses of both wireless devices (laptop and AP) and of the final recipient (as in Ethernet). It is always assumed that there is only one possible originator.

802.11 can carry the fourth, originator's MAC address, and this is used in WDS mode by repeaters. This feature can be enabled on Linux too, using iw, and enabling this mode will allow wlan0 to be used in bridge interfaces, as well as with VirtualBox bridged networking:

iw dev wlan0 set 4addr on

However, with 4addr enabled, you're likely to get completely ignored by the AP: association succeeds but all data frames disappear into the ether. This could be for security reasons (because it's damn hard to spoof the source MAC address. Yeah.) In my router (running OpenRG), it's necessary to enable "WDS" mode for the wireless AP interface, add a WDS device restricted to my laptop's MAC address, and add it to the LAN bridge. 4addr packets now work.

There's another problem with this, though – the router now rejects three-address packets from the laptop, which can be rather inconvenient (having to toggle 4addr every time the WLAN network is changed). The workaround is to add, on the laptop, a second wireless interface linked to the same device, but with a different MAC address. First undo the earlier configuration:

iw dev wlan0 set 4addr off

Then, add a second interface – the name was chosen arbitrarily – with a different MAC address:

iw dev wlan0 interface add wds.wlan0 type managed 4addr on
ip link set dev wds.wlan0 addr <addr>
ip link set dev wds.wlan0 up

Here must match the WDS device address configured in the router; other than that, it can be any valid MAC address. The original MAC of wlan0 then remains for "normal" usage.

It's possible to use both wlan0 and wds.wlan0 at the same time – although I've only tested associating to the same AP twice, not to different APs. I'm guessing they would need to at least be on the same channel.

Some people have asked why use this when VirtualBox can bridge WiFi "just fine". The answer is that VirtualBox does not send the virtual machines' MAC addresses; rather, it performs NAT at the MAC layer too. – 2014-08-22

Direct wlan bridge

Under certain circumstances, you could also use wlan_kabel. It uses packet sockets to directly bridge wlan*-devices with ethernet devices. However, you can only bridge one single MAC at a time with wlan_kabel. It doesn't have the drawback of being barred by access points, because only the original MAC of the wlan device is used. In your case this would mean, that wlan0 could only be used by one VM and not even by the host. You can get wlan_kabel here. This is similar to the macvlans solution.

Bridging with ipvlan

IP Vlan does not have the limitation of a bridge it could be used to bridge a network details on how to use it can be found here

Masquerade alternative

Linux routing can be used instead with iptables-masquerade and ip_forward to achieve a bridge but as mentioned this require to enable ip_forward and will make linux act like a router this need to be setup carefully because it could introduce some security concern.

# bridge setup
brctl addbr br0
ifconfig br0 10.10.20.1/24 up
 
# enable ipv4 forwarding
echo "1" > /proc/sys/net/ipv4/ip_forward
 
# netfilter cleanup
iptables --flush
iptables -t nat -F
iptables -X
iptables -Z
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
 
# netfilter network address translation
iptables -t nat -A POSTROUTING -o wlan0 -s 10.10.20.0/24  -j MASQUERADE

The interface br0 will then have access to the wlan0 network

Important and related

Also, and very important, you should not use obsolete, deprecated commands like ifconfig, brctl, and so on. The iproute2 suite contains commands for all of this, including setting up virtual interfaces (something for which we once had to use openvpn) and creating bridges. If you do not know how to set up a bridge with ip, here we go

  ip tuntap add tap0 mode tap user root 
  ip link set tap0 up
  ip link add br0 type bridge
  ip link set tap0 master br0
  ip link set eth0 master br0
  ip addr add 10.173.10.1/24  dev br0
  ip link set br0 up

With this set of commands, we create a virtual interface called tap0, then a bridge called br0, then enslave eth0 and tap0 to the bridge, to which we assign an IP address of 10.173.10.1, then bring it all up. The three separate instances of bringing the interfaces up (for tap0, eth0, and br0) are required.

The trick to make this work is to use proxy.arp, which allows your pc (not your VM/Linux container/network namespace) to answer ARP queries in their stead.

In other words, by using IPv4 forwarding between your hardware interface and your virtual interface, you think you can connect your VM/LXC/NNS to your LAN as if it were a physical interface, but this is not true: you are forgetting the absolutely fundamental ARP traffic, which is what truly allows LAN to operate. So, the problem is: if I correctly forward IPv4 traffic, how can I also forward ARP traffic, so that my VM/LXC/NNS work? The trick is to use proxy-arp.

The full answer to that is in Bohdi Zazen's Blog, with the revealing title: Bridge wireless cards. He uses an obsolete package, uml-utilities, to create a virtual interface by means of the command tunctl: this is the only command for which he uses uml-utilities, so that you can safely neglect downloading the package, and use the command I wrote above to create a tap or tun interface, whichever you like, just modify the command accordingly. then create a veth pair for your LXC, and now create a bridge between tap0 and veth0. This bridge, called br0, is what you must proxy-arp for, instead of the simple tap0 interface described by Bohdi Zazen.


Sources: askubuntu.com, nullroute.eu.org, firejail.wordpress.com, superuser.com

intika
  • 369
  • 2
  • 11
5

Depends on how mean the AP is to you:

1) It might only want to see packets coming from you, with your known link layer address (and hence not of bridged packets) 2) It might actually be even smarter, and know which IP address should belong to which link layer address (cause it knows DHCP and inspects it)

If 1+2 are both true, you need indeed something like IP NAT, DHCP, ..

But if only 1) is the case, you can fake the link-layer address, and reverse map it onto the right one in the other direction as described here:

https://wiki.debian.org/BridgeNetworkConnections#Bridging_with_a_wireless_NIC

Arnout
  • 321
  • 4
  • 4
5

4addr as described in other answers is certainly the best way when supported by the adapter/driver, but not all of them does. NAT might work for some things, but getting proper communication both ways on the lan will become problematic (ex. connecting a printer or accessing other IoT devices on the other side of the NAT). Anything relying on broadcast/multicast (ex. auto-discovery, bonjour) will fail through the NAT.

The alternative is using an ARP Proxy (parprouted) as described in https://wiki.debian.org/BridgeNetworkConnectionsProxyArp. I've set this up on a Raspberry Pi for a printer and it works like a charm (I have added a 10 second sleep in the post-up commands to let it get an IP address first, it might have to do with the slowness of my old RPi...)

  • this link to the proxy-arp plus dhcp-helper solution is the most compatible and cleanest solution so far I've seen. – minghua May 18 '19 at 22:34
2

I liked the Proxy Arp approach, but the original question specified Arch Linux. Here's an Arch Linux version of a Raspbian implementation. I tried very hard to adapt the original approach from the Debian Wiki mentioned here to netctl using ExecUpPost and ExecDownPre without success. Everything worked at the command line, but not within the profile.

The steps:

  1. Implement wireless networking with systemd-networkd. Within the .network file, set IPForward=yes. I used WPA Supplicant to manage the wireless network interface.
  2. Enable mDNS relaying by setting enable-reflector=yes within /etc/avahi/avahi-daemon.conf; start and enable avahi-daemon.service if it's not already.
  3. Install parprouted from the AUR, and create a service file for it by adapting the one from the Raspbian answer. I did not find it was necessary to set the interface to be promiscuous. Naturally, this service will need to be started and enabled.
[Unit]
Description=proxy arp routing service
Documentation=https://raspberrypi.stackexchange.com/q/88954/79866

[Service]
Type=forking
# Restart until wlan0 gained carrier
Restart=on-failure
RestartSec=5
TimeoutStartSec=30
ExecStartPre=/lib/systemd/systemd-networkd-wait-online --interface=wlan0 --timeout=6 --quiet
ExecStartPre=/usr/bin/echo 'systemd-networkd-wait-online: wlan0 is online'
# clone the dhcp-allocated IP to eth0 so dhcrelay will relay for the correct subnet
ExecStartPre=/usr/bin/bash -c '/usr/bin/ip addr add $(/usr/bin/ip -4 -br addr show wlan0 | /usr/bin/grep -Po "\\d+\\.\\d+\\.\\d+\\.\\d+")/32 dev eth0'
ExecStartPre=/usr/bin/ip link set dev eth0 up

#         v minus sign
ExecStart=-/usr/bin/parprouted eth0 wlan0

ExecStopPost=/usr/bin/ip link set dev eth0 down
ExecStopPost=/usr/bin/bash -c '/usr/bin/ip addr del $(/usr/bin/ip -4 -br addr show eth0 | /usr/bin/grep -Po "\\d+\\.\\d+\\.\\d+\\.\\d+")/32 dev eth0'

[Install]
WantedBy=wpa_supplicant@wlan0.service
  1. To support DHCP for the device connected to the ethernet port, create a dhcrelay (from the DHCP package) service. Finding the address of the DHCP server by grep'ing through logs seems inelegant, but it works. Start and enable.
[Unit]
Description=DHCRelay Service
After=network-online.target parprouted_bridge.service
Type=simple

[Service]
ExecStart=/usr/bin/bash -c '/usr/bin/dhcrelay -d -4 -iu wlan0 -id eth0 $(/usr/bin/journalctl -b -u systemd-networkd.service | /usr/bin/grep -Po "via\s+\K\\d+\\.\\d+\\.\\d+\\.\\d+")'

[Install]
WantedBy=multi-user.target

This approach worked for me on a Raspberry Pi Model B+ w/ ArchLinuxArm sporting a USB WiFi adapter with the RT5370 chipset. As the Pi will be providing WiFi to a printer with only ethernet, I'd like it to be robust to rough handling, so my next step will be to configure the SD card as read only.

eponymous
  • 21
  • 1
  • I was able to use this with raspbian lite on a pi zero w, bridging the usb0 gadget-mode ethernet to wlan0. There are some details missing in this answer (like enabling the services, and especially enabing systemd-networkd, which isn't enabled by default), but those are the easy things to figure out. Overall, this is a solid approach. – Chris Cleeland Jan 03 '21 at 03:46