How to interface with the Linux tun driver

Go To StackoverFlow.com

14

I'm having a hard time figuring this problem out - I am trying to write a program that will interact with the Linux tunnel driver. At a very basic level, I simply want to create an application that is able to transfer data over a network tunnel. However, I am completely at a loss as to how to properly set up the tunnel driver in order to accomplish this.

I am developing on Ubuntu 9.04, and I have the tunnel driver kernel module loaded.

There exists the device /dev/net/tun, however there are no /dev/tunX devices. I am unable to create these devices using ifconfig - whenever I run /sbin/ifconfig tun0 up, for example, I get the following error:

tun0: ERROR while getting interface flags: No such device.

If I attempt to look at the /dev/net/tun device, the following error is presented:

cat: /dev/net/tun: File descriptor in bad state.

Attempting to open /dev/tunX via a small program, basically, a simple

tun_fd = open( "/dev/tun0", O_RDWR )

returns -1: the application is running as root and still cannot open this tunnel device. It is possible to open /dev/net/tun, however this does not appear to generate a new /dev/tunX device to use instead.

So, in summary - how does one go about writing an application that wishes to use the Linux tunnel driver? Any insights would be greatly appreciated.

Thanks; ~Robert

2009-06-16 20:07
by rmrobins


14

Read /usr/src/linux/Documentation/networking/tuntap.txt.

You are supposed to open the /dev/net/tun device. A subsequent ioctl on the open fd will create the tun0 (or whatever you wish to name it) network interface. Linux's network interfaces do not correspond to any /dev/* device.

2009-06-16 20:30
by ephemient
@rmrobins; what did you do to actually get this working? I believe I have a very similar problem to your original question. I have the /dev/net/tun device visible, but opening this does not produce a network interface. I have been trying to use the brselect.c and brsigio.c examples - simon 2009-11-16 15:40
As mentioned above, open /dev/net/tun. Then, an ioctl will be used to create the actual interface itself. The ioctl is called TUNSETIFF, and the argument is of type struct ifreq. The flags of the ifreq struct should be set to IFFTUN. Once the ioctl has returned, the ifrname field of the ifreq struct will be set with the name of the opened interface. Hope this helps - rmrobins 2009-11-24 06:45


10

There are no /dev/tunX device files. Instead, you open the /dev/net/tun and configure it via ioctl() to "point" to tun0. To show the basic procedure, I will create the TUN interface using the command line tool ip tun tap and then show the C code to read from that TUN device. So to create the tun interface via commands line:

sudo ip tuntap add mode tun dev tun0
ip addr add 10.0.0.0/24 dev tun0  # give it an ip
ip link set dev tun0 up  # bring the if up
ip route get 10.0.0.2  # check that packets to 10.0.0.x are going through tun0
ping 10.0.0.2  # leave this running in another shell to be able to see the effect of the next example

Now we have tun0 created. To read / write packets to this interface from an user space program you need to interact with the /dev/net/tun device file using ioctl(). Here is an example that will read the packets arriving at the tun0 interface and print the size:

#include <fcntl.h>  /* O_RDWR */
#include <string.h> /* memset(), memcpy() */
#include <stdio.h> /* perror(), printf(), fprintf() */
#include <stdlib.h> /* exit(), malloc(), free() */
#include <sys/ioctl.h> /* ioctl() */

/* includes for struct ifreq, etc */
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_tun.h>

int tun_open(char *devname)
{
  struct ifreq ifr;
  int fd, err;

  if ( (fd = open("/dev/net/tun", O_RDWR)) == -1 ) {
       perror("open /dev/net/tun");exit(1);
  }
  memset(&ifr, 0, sizeof(ifr));
  ifr.ifr_flags = IFF_TUN;
  strncpy(ifr.ifr_name, devname, IFNAMSIZ); // devname = "tun0" or "tun1", etc 

  /* ioctl will use ifr.if_name as the name of TUN 
   * interface to open: "tun0", etc. */
  if ( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) == -1 ) {
    perror("ioctl TUNSETIFF");close(fd);exit(1);
  }

  /* After the ioctl call the fd is "connected" to tun device specified
   * by devname ("tun0", "tun1", etc)*/

  return fd;
}


int main(int argc, char *argv[])
{
  int fd, nbytes;
  char buf[1600];

  fd = tun_open("tun0"); /* devname = ifr.if_name = "tun0" */
  printf("Device tun0 opened\n");
  while(1) {
    nbytes = read(fd, buf, sizeof(buf));
    printf("Read %d bytes from tun0\n", nbytes);
  }
  return 0;
}
2016-03-01 23:42
by ecerulm


2

I came across a nice intro tutorial about this

http://backreference.org/2010/03/26/tuntap-interface-tutorial/

It comes with a source tarball.

It was in the same set of Google results as this question. :-)

2012-05-30 04:42
by Duke Robillard
Ads