Reputation: 11
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.
Upvotes: 1
Views: 564
Reputation: 58848
The SIOCSIFADDR
and SIOCSIFFLAGS
(and other SIOwhatever
) ioctl
calls should be made towards any AF_INET
socket, not towards the tun
interface itself. The design is so that you can use them to configure any interface, not only the one you created. You have to create an AF_INET
socket and then call ioctl
on that socket.
If you think it's a bit weird that you have to make a socket, you're right. ioctl
is used to make "special requests" about files, other than read
or write
. 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 on tun
interfaces, 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.
Upvotes: 1