2

I've been following the official documentation on creating a TUN device. There's very little documentation, but what even is there does not seem to work. Here's what I have so far:

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

int tun_alloc(char *dev)
{
    struct ifreq ifr;
    int fd, err;
    
    if( (fd = open("/dev/net/tun", O_RDWR)) < 0 )
       return 7; // tun_alloc_old(dev); // this does not happen, linux docs don't say what tun_alloc_old is anyway
     
    memset(&ifr, 0, sizeof(ifr));
    /* Flags: IFF_TUN   - TUN device (no Ethernet headers)
     *        IFF_TAP   - TAP device
     *
     *        IFF_NO_PI - Do not provide packet information
     */
    ifr.ifr_flags = IFF_TUN;
    if( *dev ) {
        printf("setting ifr.ifr_name to \"%s\"\n", dev);
       strncpy(ifr.ifr_name, dev, IFNAMSIZ);
    }
    printf("ifr.ifr_name is \"%s\"\n", ifr.ifr_name);
    
    if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){
        perror("ERR");
        close(fd);
        printf("GOT ERROR: %d\n", err);
        return err;
    }
    printf("past TUNSETIFF error checking\n");
    strcpy(dev, ifr.ifr_name);
    return fd;
}
int main() {
    char name[128];
    strcpy(&name, "tun23");
    int tun = tun_alloc(name);
    printf("tun_alloc: %s  id: %d\n", name, tun);
    if(tun == -1) return -1;
    while(1) {
        printf("in loop\n");
        char buf[128];
        ssize_t readAmount = read(tun, buf, 128);
        printf("finished read\n");
        if(readAmount == -1) {
            printf("read 0 bytes\n");
            continue;
        }
        printf("Read %d: ", readAmount);
        for(int i = 0; i < 128; i++) {
            printf("%hhx", buf[i]);
        }
        printf("\n");
    }
    return tun;
}


Compiler step is gcc -g3 test.c && a.out.

When ran as non-root, I get this output

setting ifr.ifr_name to "tun23"
ifr.ifr_name is "tun23"
ERR: Operation not permitted
GOT ERROR: -1
tun_alloc: tun23  id: -1

And as root, it successfully gets into the loop, but then the call to read seems to block.

setting ifr.ifr_name to "tun23"
ifr.ifr_name is "tun23"
past TUNSETIFF error checking
tun_alloc: tun23  id: 3
in loop

(In the event of an XY problem, the reason I'm doing this is to try and make a very simple vpn-like application)

The issue is that while it's blocking in this loop, no TUN devices are created. I am looking in /dev/. I'm not sure how I would give it any bytes to read.

Edit: added a proper perror call and the respective output Operation not permitted, valgrind output, and a couple print statements. Going to try and debug the strcpy error.

Edit: fixed the strcpy error, was pretty simple. Seems to fail in non-root due to a lack of permission to create TUN devices.

Carson Graham
  • 519
  • 4
  • 15
  • To aid debugging, call `perror` when `ioctl` fails to get a more specific error reason. – kaylum Nov 11 '20 at 00:27
  • Great suggestion, thanks! Using that it's much more clear that the error is a permissions issue - though I'm fine with working in root to figure out how to make it and then figure out permissions later. I've updated the question with all the newer stuff. – Carson Graham Nov 11 '20 at 01:00
  • I also found [this post](https://stackoverflow.com/questions/1003684/how-to-interface-with-the-linux-tun-driver) which has very similar code, but I don't see any differences that would make an impact – Carson Graham Nov 11 '20 at 01:01

0 Answers0