Bridge wireless cards

I spent a few days configuring my wireless network card to allow KMV guests to act as if they have a bridged network interface rather then NAT.

As it turns out you can not simply bridge your wireless card with brctl as you do a wired NIC and this type of network configuration is not supported in virt-manager. It also so happens you do not need parprouted either.

Use what is referred to as Proxy arp

Note: Although this how to was written for KVM, it should work with other protocols / guests as well. VirtualBox will configure all this automagically.

1. Install tunctl (Fedora / Centos) or uml-utilities (Debian / Ubuntu).

yum install tunctl

sudo apt-get install uml-utilities

2. Secure the tun. I prefer to configure the tun to be owned by root.kvm by adding the following to /etc/rc.local.

/bin/chown root.kvm /dev/kvm
/bin/chown -R root.kvm /dev/net
/bin/chmod -R 660 /dev/net

3. Bring up a tap device. This command must be run as root. Change “bodhi” to you user name.

tunctl -u bodhi

4. Enable arp proxy. Again these commands are run as root.

echo 1 > /proc/sys/net/ipv4/ip_forward
echo 1 > /proc/sys/net/ipv4/conf/wlan0/proxy_arp
echo 1 > /proc/sys/net/ipv4/conf/tap0/proxy_arp

5. Configuration. This step is a bit complex.

A : Network. Assume a network of 192.168.0.0/24 with a router (used for DNS) at 192.168.0.1

B : Host. Assume the wireless card is wlan0.
The IP of the host does not matter, although we need to know it to configure the guest.
IP Host = 192.168.0.10
The IP address of the host will become the default gateway for the guest.

C : Tap. We do not assign a ip address to the tap, rather we assign a route on the host. This route will become the ip address of the guest.
route = 192.168.0.20

D: Guest. DHCP does not work so you will need to manually configure a static IP address of the guest.
IP address = route we assign to the tap, in this example 192.168.0.20
Netmask = 255.255.255.0
Default gateway = 192.168.0.10
DNS (nameserver) = 192.168.0.1

With that background …

On the host, set a route to be used by the tap / guest. Again, these commands need to be run as root.

ip link set tap0 up
route add -host 192.168.0.20 dev tap0

6. Now start the guest using the tap for networking, For KVM (note, unlike the previous examples, kvm is run as a user, not root !).

kvm -hda ~/fedora.qcow2 -net nic -net tap,ifname=tap0,script=no -usb -usbdevice tables

The guest will boot, but will not obtain an IP address via DHCP. Log into the guest and configure manually configure a static IP for the guest. This varies by guest, for linux guests (running gnome) you may use network manager if you wish :

Right click the NetworkManager icon -> Edit Connections …
Select “Auto eth0” -> Click the Edit button on the Left.
In the IPv4 tab :
Change Method to “Manual”
In the “Address” section click the “Add button”
Address = 192.168.0.20 <- From the route command. Netmask = 255.255.255.0 Gateway = 192.168.0.10 <- IP address of the host. In the DNS Servers box use 192.168.0.1 Click the "Apply" box. That's it , it should be working.

Extra Credit

For extra credit we can firewall the guest. This is may not be necessary if you are behind a LAN, but it is fun anyways.

Run these commands on the HOST.

# Allow all outgoing traffic from the guest to the LAN or internet.
iptables -A FORWARD -i tap0 -o wlan0 -j ACCEPT

# Allow only related / established connections fron the LAN/internet to the guest
iptables -A FORWARD -i wlan0 -o tap0 -m –state RELATED,ESTABLISHED -j ACCEPT

# As an example, allow connections to port 80 (Apache) to the guest.
iptables -A FORWARD -i wlan0 -o tap0 -p tcp –dport 80 -j ACCEPT

# Drop all other traffic
iptables -A FORWARD -i wlan0 -o tap0 -j DROP

This entry was posted in Linux. Bookmark the permalink.

30 Responses to Bridge wireless cards

  1. jaymzter says:

    this worked for my VMware installation as well. Super job!

  2. Kr0m says:

    I think that you forgotten a “0”:
    iptables -A FORWARD -i tap0 -o wlan -j ACCEPT –> Wrong
    iptables -A FORWARD -i tap0 -o wlan0 -j ACCEPT –> Correct

  3. bodhi.zazen says:

    You are correct, updated.

    Hope it is otherwise working for you.

  4. LINUX bridge is a way to connect two Ethernet segments together in a protocol independent way.Packets are forwarded based on Ethernet address, rather than IP address (like a router). Since forwarding is done at Layer 2, all protocols can go transparently through a bridge.

  5. dlh says:

    FWIW, with Ubuntu 10.10, and qemu (think its 12.5)…

    Could not get the following from your example above to be accepted:
    # Allow only related / established connections fron the LAN/internet to the guest
    iptables -A FORWARD -i wlan0 -o tap0 -m –state RELATED,ESTABLISHED -j ACCEPT

    Did get the two following possibilities accepted:
    sudo iptables -A FORWARD -i eth0 -o tap0 -m conntrack –ctstate ESTABLISHED,RELATED -j ACCEPT

    (replaced “-state” with “conntrack –ctstate)

    and

    sudo iptables -A FORWARD -i eth0 -o tap0 -m state –state ESTABLISHED,RELATED -j ACCEPT

    (replaced “-state” with “state –state”)

    I haven’t yet obtained access to the outside world from guest, nor access to guest from outside world, only between guest and host. But I expect I’ll eventually figure it out, or figure out what else I may have done incorrectly. Also not yet sure what difference, if any, there is between –state and –ctstate…

  6. Pingback: Research group digest – ulno.net

  7. majikins says:

    Hi

    I’m stuck at step number 6. I use virt-manager to start my kvm’s and not cli. I can’t seem to figure out how to get the vm to use tap as you have stated. Please could you provide some guidance? Also tap does not come up automatically on restart – how do I keep settings?

  8. bodhi.zazen says:

    @majikins with virt-manager you do not use a tap at all, you configure your network interface via virt-manager and use the bridged option.

    Looks something like this : http://www.linux-kvm.com/sites/default/files/virt-manager-bridged.png

  9. Nathan says:

    This worked perfectly on Debian (squeeze)! The only step I did differently was that I used openvpn to create the tap device:

    openvpn –mktun –dev tap0 –user

    Thanks for the info!

  10. bodhi.zazen says:

    @Nathan: Glad it worked for you, thank you for the tip.

  11. qorrow says:

    This still works perfect today but with the openvpn instead of tunctl. However it only works if I run the VM as root. Do not know why. Is there any workaround to make it works with invoking the VM as a normal user?

    Anyway, Thanks for the great procedure.

  12. Pingback: KVM bridge to wlan0

  13. David says:

    Hey there! Big noob here.

    Can you use this to bridge two regular Ubuntus? No virtual machines involved?
    Many thanks in advance.

  14. bodhi.zazen says:

    You can connect 2 machines directly, but not using this tutorial. Start a thread on the forums.

  15. hs says:

    Thanks a bunch! This works painlessly.

  16. Chris says:

    Hmm.. doesn’t work for me. I have a Mint Host, and a windows 7 guest… I have tried this several times, and re-read it every time… has something changed, or does this not work with a windows guest os? The windows guest can ping itself, it can ping the host, but it cannot ping the host’s gateway, or anything beyond it.

    Thanks.

  17. bodhi.zazen says:

    @Chris – I can see no reason it would not work on Mint. Did you disable Network Manager ? If you are having a problem, post on the Mint forums and be sure to include your configuration files.

  18. chris says:

    Yes, I am sure network manager is stopped… I have started over about 6 times now, and it just won’t work :(. I may post on mint, or I may just switch distros… I just wanted to give mint a shot…

    Thanks.

  19. bodhi.zazen says:

    @chris – post your configuration on the Mint forums.

  20. Franesco says:

    HI there,

    my guest machine is sending ARP requests, but doesnt get replies.
    USing TCPDUMP on the host machine I see arp requests coming in on the TAP interface, but they are left there.
    I have enabled proxy_arp on both wlan0 and tap0 interfaces are shown and I’ve also tried using parprouted, but no success.
    The only passage I’ve skipped is numer 2 as I am running everything as root and for the moment I dont mind.Also I dont have root.kvm user

    Any advice?
    Thanks

  21. Pingback: Wireless bridging for Virtual Machines (e.g. KVM) | Specman, VLSI, Linux and friends...

  22. K says:

    Hi,
    very useful article -thanks.
    Tried this on Fedora 20 and it works fine – except for one issue. The guest runs only as root (and is accessible from the LAN). However, i don’t wish to run VMs as root.

    Tried by disabling SELINUX (setenforce 0) – but still get the same error:

    qemu-system-x86_64: -net tap,ifname=tap3,script=no: could not open /dev/net/tun: Permission denied
    qemu-system-x86_64: -net tap,ifname=tap3,script=no: Device 'tap' could not be initialized">

    The permissions on the /dev/net* are correct (as suggested by the article):
    [root ~]$ ll /dev/net* -d
    drw-rw----. 2 root kvm 60 Apr 20 10:31 /dev/net/
    [root ~]$ ll /dev/net/
    total 0
    drw-rw----. 2 root kvm 60 Apr 20 10:31 ./
    drwxr-xr-x. 21 root root 3660 Apr 22 18:51 ../
    crw-rw-rw-. 1 root kvm 10, 200 Apr 22 19:07 tun">

    My local user account is member of the kvm group.
    kvm:x:36:qemu,

    tun3 interface was created with ownership to this local user account (tunctl -u ).
    Highly appreciate if you can help.
    TIA.
    k
    PS: the qemu cmd I’m using as myusername:
    /usr/bin/qemu-kvm -m 1586 -localtime -vga std -cpu host -net nic -net tap,ifname=tap3,script=no -usb -device usb-tablet -cdrom ~/ISO/systemrescuecd-x86-3.8.1.iso -boot d

  23. ziomario says:

    Hello.

    I’m trying to configure and run debian squeeze for armel emulated with qemu-kvm on top of ubuntu 15.04 64 bit. I’ve followed your instructions carefully and then I did :

    qemu-system-arm -M versatilepb -kernel vmlinuz-3.2.0-4-versatile -initrd initrd_squeeze.gz -hda hda.img -append “root=/dev/ram” -net nic -net tap,ifname=tap0,script=no

    but it does not work because it says :

    root@mariuccio-Z87-HD3:/home/mariuccio/Scrivania/Arm# ./first.sh
    : could not launch network script
    : Device ‘tap’ could not be initializedcript=no

    this is what says ifconfig :

    root@mariuccio-Z87-HD3:/home/mariuccio/Scrivania/Arm# ifconfig

    eth0 Link encap:Ethernet IndirizzoHW
    UP BROADCAST MULTICAST MTU:1500 Metric:1
    RX packets:0 errors:0 dropped:0 overruns:0 frame:0
    TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
    collisioni:0 txqueuelen:1000
    Byte RX:0 (0.0 B) Byte TX:0 (0.0 B)

    lo Link encap:Loopback locale
    indirizzo inet:127.0.0.1 Maschera:255.0.0.0
    indirizzo inet6: ::1/128 Scope:Host
    UP LOOPBACK RUNNING MTU:65536 Metric:1
    RX packets:47065 errors:0 dropped:0 overruns:0 frame:0
    TX packets:47065 errors:0 dropped:0 overruns:0 carrier:0
    collisioni:0 txqueuelen:0
    Byte RX:9511313 (9.5 MB) Byte TX:9511313 (9.5 MB)

    lxcbr0 Link encap:Ethernet IndirizzoHW
    indirizzo inet:10.0.3.1 Bcast:0.0.0.0 Maschera:255.255.255.0
    indirizzo inet6: fe80::a007:a2ff:feea:b1c2/64 Scope:Link
    UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
    RX packets:0 errors:0 dropped:0 overruns:0 frame:0
    TX packets:66 errors:0 dropped:0 overruns:0 carrier:0
    collisioni:0 txqueuelen:0
    Byte RX:0 (0.0 B) Byte TX:10889 (10.8 KB)

    tap0 Link encap:Ethernet IndirizzoHW
    indirizzo inet6: fe80::a0c3:c5ff:fe73:7499/64 Scope:Link
    UP BROADCAST MULTICAST MTU:1500 Metric:1
    RX packets:0 errors:0 dropped:0 overruns:0 frame:0
    TX packets:0 errors:0 dropped:3 overruns:0 carrier:0
    collisioni:0 txqueuelen:500
    Byte RX:0 (0.0 B) Byte TX:0 (0.0 B)

    virbr0 Link encap:Ethernet IndirizzoHW
    indirizzo inet:192.168.122.1 Bcast:192.168.122.255 Maschera:255.255.255.0
    UP BROADCAST MULTICAST MTU:1500 Metric:1
    RX packets:0 errors:0 dropped:0 overruns:0 frame:0
    TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
    collisioni:0 txqueuelen:0
    Byte RX:0 (0.0 B) Byte TX:0 (0.0 B)

    wlan0 Link encap:Ethernet IndirizzoHW
    indirizzo inet:172.30.141.54 Bcast:172.30.143.255 Maschera:255.255.248.0
    indirizzo inet6: fe80::20e:8eff:fe19:8c4b/64 Scope:Link
    UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
    RX packets:505304 errors:0 dropped:4 overruns:0 frame:0
    TX packets:207332 errors:0 dropped:0 overruns:0 carrier:0
    collisioni:0 txqueuelen:1000
    Byte RX:295629714 (295.6 MB) Byte TX:33532780 (33.5 MB)

    what can I do ? I’m connected to the network using wlan0….

  24. ziomario says:

    this is what route says :

    root@mariuccio-Z87-HD3:/home/mariuccio/Scrivania/Arm# route

    Tabella di routing IP del kernel
    Destination Gateway Genmask Flags Metric Ref Use Iface
    default 172.30.136.1 0.0.0.0 UG 1024 0 0 wlan0
    10.0.3.0 * 255.255.255.0 U 0 0 0 lxcbr0
    link-local * 255.255.0.0 U 1000 0 0 wlan0
    172.30.136.0 * 255.255.248.0 U 0 0 0 wlan0
    192.168.0.20 * 255.255.255.255 UH 0 0 0 tap0
    192.168.122.0 * 255.255.255.0 U 0 0 0 virbr0

  25. Pingback: » Linux: setup kvm on a wireless interface on a laptop machine

  26. terry says:

    How to convert the command line options ‘-net nic -net tap,ifname=tap0,script=no’ to libvirt xml?

  27. terry says:

    https://libvirt.org/drvqemu.html#xmlimport
    I have found the answer, thanks for inspire me.

  28. Pingback: Ubuntu:How do I deploy a virtualized server on a headless machine running 12.04 Server? – Ubuntu Linux Questions

  29. Pingback: Unix:QEMU how to ping host network? – Unix Questions

  30. Niladri Halder says:

    Hi, I am new to networking. I am confused with step 5:
    A: How do I find the IP for my router?
    B: The name of my wireless card is wlp3s0

    What IP address should I assign to the tap, and guest? My wlp3s0 details are as follows:
    IP address: 192.168.1.105
    Netmask: 255.255.255.0
    Broadcast:192.168.1.255
    I pulled these off ifconfig.
    I am running Fedora 24, kernel 4.5.7-301
    I have 2 rhel7.2 virtual machines on libvirt.

Leave a Reply

Your email address will not be published. Required fields are marked *