clinuxtun

Can't bring Linux TAP device up programically


I'm trying to implement a simple VPN as a learning experience, and I came across a problem. After I create a TAP device, I cannot bring it up. Here is a shorter version of my code:

typedef struct {
    int device;
    struct ifreq& ifr;
} AllocatedTap;

static AllocatedTap tap;
static struct ifreq ifr;
int fd, err;
char dev[16] = "\0"; // Let the kernel pick a name

if ((fd = open(TUN_CLONE_DEVICE, O_RDWR)) < 0) {
    return NULL;
}

memset(&ifr, 0, sizeof(ifr));

ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 
if (*dev) {
    strncpy(ifr.ifr_name, dev, IFNAMSIZ);
}

if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) {
    close(fd);
    eturn NULL;
}

strcpy(dev, ifr.ifr_name);

tap.device = fd;
tap.ifr = &ifr;

return &tap;

After that, I bring it up with:

int fd, err;

fd = socket(AF_INET, SOCK_DGRAM, 0); // 0: automically chose protocol
if (fd < 0) {
    return -1;
}

tap->ifr->ifr_flags |= IFF_UP;

if ((err = ioctl(fd, SIOCSIFFLAGS, &tap->ifr)) == -1) {
    return err;
}

This will always result in a No Such Device error when bringing the interface up. I can get it to work about half the time if I recreate the ifr struct while only carrying over the ip_name and ip_addr fields.

I expect for the code to bring the interface up to not err, and to actually bring said interface up.

I have tried, as stated above, recrating the ifr struct, which makes the code not error. However, using ip a, I've found out that the interface isn't up.

Can anyone help me figure out what going on?


Solution

  • First, i write same code as yours, and i met the same problem. You shoule add ioctl(fd, TUNSETPERSIST, 0x1), then reopen the tun dev fd like this, and use TUNSETIFF again.