tutorials/tcpip/tap-driver/README.md
This example allows the use of Mongoose's built-in TCP/IP stack in systems that support a TUN/TAP device. The application opens a TAP device and uses the standard socket interface to read and write on it.
The interface can be created by the example itself, but it will also disappear when the example exits. Since we usually need to do something before, like setting up a DHCP server or establishing some connections to the rest of the world, we'll manually create a specific TAP interface and the example will open it; this way, we can have everything setup in advance.
Create a TAP interface; you can use it as is, attach it to a virtual bridge, or forward/masquerade its traffic.
$ sudo ip tuntap add dev tap0 mode tap
$ sudo ip link set tap0 up
In some systems, you might need superuser privileges to open the device with the example. In others, you can add user yourusername or group yourgroup at creation time, to grant access to it.
In this scenario, Mongoose is only reachable from the hosting machine, but you can add forwarding and masquerading later. Once you have your TAP interface up and running with an IP address, you can configure any services on it.
$ sudo ip addr add 192.168.0.1/24 dev tap0
$ make -C tutorials/tcpip/tap-driver/ clean all
tap0, add ARGS="-i ifcname", and use the proper interface name [DHCP server for 192.168.0.x]
192.168.0.1 192.168.0.x
┌─────────┐
│ tap0 ├──────────────────── tap-driver
└─────────┘
As you can't access any other host than your workstation, you need to add any required services (as DNS) there, and configure Mongoose appropriately. This is a foundation, you can expand it by choosing one of the solutions that follow.
If you happen to have a virtual bridge interface (for linking several virtual machines together, for example) (probably br0 or virbr0), we can take advantage of it.
We will attach one end of the virtual interface to a bridge, which will also be attached to your network interface. In this case, Mongoose will have access to your network (and through it, to the Internet) and will also be reachable from your own workstation and other hosts in your network. You don't need to add IP addresses as in the example above, unless you don't have a DHCP server in your network, in which case you will configure Mongoose for a fixed address in your subnet.
$ sudo ip link add virbr0 type bridge
$ sudo ip link set virbr0 up
$ sudo ip addr del 10.1.0.10/24 dev enp9s0
$ sudo ip link set enp9s0 master virbr0
$ sudo ip addr add 10.1.0.10/24 dev virbr0
ifconfig, and try to ping some host in your network$ sudo ip link set tap0 master virbr0
$ ip link show master virbr0
2: enp9s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master virbr0 state UP mode DEFAULT group default qlen 1000
link/ether 30:5a:3a:08:db:90 brd ff:ff:ff:ff:ff:ff
6: tap0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast master virbr0 state DOWN mode DEFAULT group default qlen 1000
link/ether 66:91:e2:5f:d7:ed brd ff:ff:ff:ff:ff:ff
$ make -C tutorials/tcpip/tap-driver/ clean all
tap0, add ARGS="-i ifcname", and use the proper interface name$ ip link show master virbr0
2: enp9s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master virbr0 state UP mode DEFAULT group default qlen 1000
link/ether 30:5a:3a:08:db:90 brd ff:ff:ff:ff:ff:ff
6: tap0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master virbr0 state UP mode DEFAULT group default qlen 1000
link/ether 66:91:e2:5f:d7:ed brd ff:ff:ff:ff:ff:ff
10.1.0.10
virbr0
│
┌──────────────────┴──────────────────┐
│ │ 10.1.0.x
│ ┌────────┐ │
│ │ tap0 ├─────────────┼─────── tap-driver
│ └────────┘ │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ vnet1 │ │ enp9s0 │ │ vnet2 │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │
└──────┼───────────┼───────────┼──────┘
│ │ │
│
Ethernet
│ Local LAN 10.1.0.x
│ DHCP server, router
▼
Internet
If you have Docker running, it may introduce firewall rules that will disrupt your bridging.
Bridging usually does not work for Wi-Fi, see Appendix below
Once you have your virtual interface up and running with an IP address, you can use your Linux to NAT and forward Mongoose traffic to another interface, for example the one that connects you to the Internet. In this case, Mongoose will have access to the Internet and will also be reachable from your own workstation; but not from any other hosts in your local network (if there is one). You can use this setup with a direct connection to the Internet or being part of a network, when you want to isolate Mongoose from the rest of your network.
$ sudo iptables -t nat -A POSTROUTING -o enp9s0 -j MASQUERADE
$ echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
$ make -C tutorials/tcpip/tap-driver/ clean all
tap0, add ARGS="-i ifcname", and use the proper interface name [DHCP server for 192.168.0.x]
┌────────────► 192.168.0.1 192.168.0.x
│ forwarding ┌─────────┐
│ masquerading │ tap0 ├──────────────────── tap-driver
│ └─────────┘
▼
Your IP (LAN / Public)
┌─────────┐
│ enp9s0 │
└────┬────┘
│
│
Ethernet [WiFi]
│
▼
Internet
You can also use this setup if your NIC is part of a bridge (for example: you have virtual machines); in that case:
$ sudo iptables -t nat -A POSTROUTING -o virbr0 -j MASQUERADE
$ echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
[DHCP server for 192.168.0.x]
10.1.0.10 ◀──────────────► 192.168.0.1 192.168.0.x
virbr0 forwarding ┌─────────┐
│ masquerading │ tap0 ├──────────────────── tap-driver
│ └─────────┘
┌──────────────────┴──────────────────┐
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ vnet1 │ │ enp9s0 │ │ vnet2 │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │
└──────┼───────────┼───────────┼──────┘
│ │ │
│
Ethernet
│ Local LAN 10.1.0.x
│ DHCP server, router
▼
Internet
Bridging usually does not work for Wi-Fi, see Appendix below
Due to the way the wireless standard works, bridging might require having knowledgeable access to the Access Point / Wireless Router (AP). In addition to the Sender Address (SA) and Destination Address (DA) found in Ethernet frames, Wi-Fi requires the Transmitter Address (TA) and Receiver Address (RA) fields to work; a total of 4 MAC addresses. Usually, the common case, is: TA = SA for station (STA) to AP frames and DA = RA for AP to STA; that means usually only 3 addresses are in use.
Bridging at an AP just changes SA for AP to STA frames and DA for STA to AP frames, so there's still 3 addresses in use and this will usually work with no issues.
Bridging at a STA means: for STA to AP frames, SA and TA are no longer equal; for AP to STA frames, DA and RA are also different. We need to use all 4 addresses and usually both STA and AP are not configured for this mode. At the station, a configuration tool may allow to enable `4addr' mode, while at the AP, the scenario is similar to that of bridging two LANs, a Wireless Distribution System (WDS), so we need to enable this. Unfortunately, there can be incompatibilities in the way this is implemented by vendors, so even in those cases when we actually can access and reconfigure the AP, there's no guarantee it will work.