I'm trying to create a tunnel in C and im struggling to set its IP address up. I have an "invalid argument" error in ioctl with SIOCSIFADDR argument. Can someone explain me how to set up the IP address if this function doesn't work with tun ?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/if_tun.h>
#include <linux/if.h>
#include <fcntl.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#define IP_DEST "127.0.0.1"
#define IP_SOURCE "127.0.0.1"
int tun_alloc(char* dev) {
//dev will store the name of the tun created
struct ifreq ifr;
int fd, err;
char *clonedev = "/dev/net/tun";
//open the clone device
if( (fd = open(clonedev, O_RDWR)) < 0 ) {
printf("Error opening directory");
return fd;
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN;
if (*dev) {
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
}
//Create the TUN
if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) {
close(fd);
printf("Error creating the tun");
return err;
}
strcpy(dev, ifr.ifr_name);
return fd;
}
int main(int argc, char* argv[]) {
//Creating the TUN interface
char tun_name[IFNAMSIZ];
strncpy(tun_name, "tun3", IFNAMSIZ);
int tunfd = tun_alloc(tun_name);
if (tunfd < 0) {
perror("tun_create");
return 1;
}
printf("TUN interface %s created\n", tun_name);
//Setting its IP Adress
struct ifreq ifr;
struct sockaddr_in addr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, tun_name, IFNAMSIZ);
addr.sin_family = AF_INET;
if(inet_pton(AF_INET,IP_DEST,&(addr.sin_addr))<0){
fprintf(stderr,"ERROR with the IP address");
return 1;
};
memcpy(&(ifr.ifr_addr), &addr, sizeof (struct sockaddr));
if (ioctl(tunfd, SIOCSIFADDR, &ifr) < 0) {
perror("ioctl");
exit(1);
}
printf("TUN interface %s set IP address to %s\n", tun_name, IP_DEST);
ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
if(ioctl(tunfd, SIOCSIFFLAGS, &ifr)<0){
perror("ioctl");
exit(1);
};
printf("TUN running");
return 0;
}
I don't really understand how iotcl works and the documentation hasn't helped me for tun interfaces.
The
SIOCSIFADDRandSIOCSIFFLAGS(and otherSIOwhatever)ioctlcalls should be made towards anyAF_INETsocket, not towards thetuninterface itself. The design is so that you can use them to configure any interface, not only the one you created. You have to create anAF_INETsocket and then callioctlon that socket.If you think it's a bit weird that you have to make a socket, you're right.
ioctlis used to make "special requests" about files, other thanreadorwrite. The request is interpreted depending on the type of file. Using a socket makes sure it is interpreted by the IP networking system as a request relating to IP sockets. It would make logical sense that you could also make IP-related special requests ontuninterfaces, but apparently the kernel developers didn't think of that, and there is no need for them to work since you can just create a socket.There is another way to set IP addresses using a system called "rtnetlink", but it is more complicated and unnecessary for a simple scenario like this.