clinuxtun-tap

Convert `ip tuntap add` system() call to C code


I'm trying to convert a system() call I have in C that calls ip tuntap add ... to C code that doesn't rely on the system() call.

Basically, it's a problem that the tunnel adapter that I use the system("ip tuntap add ...") call to bring up is left there when my application is forcibly terminated.

I've been told I can use rtnetlink to achieve my goal. I'd like to convert the following line into C code that doesn't rely on the system() call. I believe if I use rtnetlink that the tunnel adapter I bring up will be destroyed by the kernel when my application is terminated, which is the main reason I want to do this.

This is my current line in C:

system("ip tuntap add dev tun1 mode tun");

If rtnetlink isn't how I would go about doing this, is there another method that would destroy the tunnel when my application is forcibly terminated?


Solution

  • @Jonathon Reinhart answered this in the comments:

    What you're looking for is a non-persistent TUN adapter. Instead of using

    system("ip tuntap add dev tun1 mode tun");
    

    The Function

    Originally taken from simpletun.c, code added to answer to avoid potential issues with dead links in the future.

    # Not certain that these are all of the imports you'll need,
    # but i'm pretty sure it covers everything.
    
    #include <net/if.h>
    #include <linux/if_tun.h>
    #include <sys/stat.h>
    #include <sys/ioctl.h>
    #include <string.h>
    #include <stdio.h>
    
    int tun_alloc(char *dev, int flags) {
      struct ifreq ifr;
      int fd, err;
      char *clonedev = "/dev/net/tun";
    
      if( (fd = open(clonedev , O_RDWR)) < 0 ) {
        perror("Opening /dev/net/tun");
        return fd;
      }
    
      memset(&ifr, 0, sizeof(ifr));
    
      ifr.ifr_flags = flags;
    
      if (*dev) {
        strncpy(ifr.ifr_name, dev, IFNAMSIZ);
      }
    
      if( (err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0 ) {
        perror("ioctl(TUNSETIFF)");
        close(fd);
        return err;
      }
    
      strcpy(dev, ifr.ifr_name);
    
      return fd;
    }
    

    Calling It

    int tun_fd = tun_alloc("tun1", IFF_TUN | IFF_NO_PI);
    

    What's happening?

    When it is called, this function will create the new tunnel if it doesn't exist and return the file descriptor for the tunnel. If it already exists, it will simply return the file descriptor for the tunnel.

    When it creates the tunnel, if your process dies it will actively destroy the tunnel and any associated routes.