In UNIX systems TUN/TAP devices are a mechanism that allows to create a virtual, software based networking devices.

TAP devices are layer 2 devices which means that they act as Ethernet devices. TAP devices are often used for virtualize network connection to VMs physical network.

TUN devices (Tunnel) are layer 3 devices which means they live at the IP level. TUN devices are often used for routing IP packets and creating virtual point-to-point network connections, i.e like in VPN.

How TUN/TAP devices work

OK, so now that we understand what is TUN/TAP devices let’s talk about how it supported by the kernel.

TUN/TAP devices in Linux are supported by the TUN and TAP kernel modules. These modules provide the infrastructure for creating and managing virtual network interfaces used for various networking tasks, including VPNs, network tunneling, and bridging.

When working with TUN/TAP devices, interaction occurs through the /dev/net/tun device file, which acts as a bridge between user space and the kernel’s TUN/TAP modules.

tun source code
tap source code

/dev/net/tun file

The /dev/net/tun is usually created automatically by some script or tool in the system, like udev rules, Init scripts, etc.. But if missing this is how you can manually create one.

create the file

mkdir /dev/net (if it doesn't exist already) sudo mknod /dev/net/tun c 10 200

  • /dev/net/tun is the path to the device file you want to create.
  • c specifies that you are creating a character device.
  • 10 is the major device number associated with TUN/TAP devices.
  • 200 is a minor device number; you can use any number you like.

set appropriate permissions chmod 0666 /dev/net/tun

in case that the TUN and TAP modules aren’t loaded you should also run:

sudo modprobe tun
sudo modprobe tap

Creating TUN/TAP device

First of all creating TUN/TAP device requires root privileges or to be more precisely cap_net_admin capability.

To create TUN/TAP device from commandline we can use the ip command from the iproute2 toolkit which comes with most Linux distros.

TAP Examples

  • creating TAP device and connect to a bridge device
# Create a TAP device (e.g., tap0)
sudo ip tuntap add name tap0 mode tap

# Connect the TAP device to a bridge (e.g., br0)
sudo brctl addif br0 tap0

# Enable the TAP device
sudo ifconfig tap0 up
  • creating TAP device for packet capture
# Create a TAP device for packet capture (e.g., tap_capture)
sudo ip tuntap add name tap_capture mode tap

# Enable the TAP device
sudo ifconfig tap_capture up

# Use packet capture software (e.g., Wireshark) to capture network traffic on tap_capture

To create TUN/TAP device with code we can use the ioctl syscall.

Example

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/if_tun.h>

int main() {
    int tun_fd;
    struct ifreq ifr;

    // Open the TUN device
    if ((tun_fd = open("/dev/net/tun", O_RDWR)) < 0) {
        perror("Failed to open TUN device");
        exit(1);
    }

    // Configure the TUN device
    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_flags = IFF_TUN | IFF_NO_PI; // TUN device without packet information

    if (ioctl(tun_fd, TUNSETIFF, (void *)&ifr) < 0) {
        perror("Failed to configure TUN device");
        close(tun_fd);
        exit(1);
    }

    printf("TUN device name: %s\n", ifr.ifr_name);

    // You can now use the TUN device (tun_fd) to read and write network packets.

    // Remember to close the TUN device when done
    close(tun_fd);

    return 0;
}