Question

I am trying to set ip address of a network interface from a C program. I looked around and found out that I can do it using ioctl() and inet_pton(). My problem is, I am not able to figure out where in struct ifreq am I supposed to store the converted address. I keep on getting ioctl() - invalid argument error.

I have particularly looked at the example How to set the IP address from C in linux. This says that we can cast ifr.ifr_addr to struct sockaddr_in. However, after doing the address conversion, ioctl() fails with invalid argument error.

Following is the code:

280 void setip (int fd) {
281 
282     struct ifreq ifr;
283     struct sockaddr_in * addr;
284     int stat;
285 
286     strcpy(ifr.ifr_name, in.dev.device);          // in.dev.device = tun2
287     addr = (struct sockaddr_in *) &ifr.ifr_addr;
288 
289     addr->sin_family = AF_INET;
290 
291     stat = inet_pton(addr->sin_family, in.dev.ip_addr, &addr->sin_addr); // in.dev.ip_addr = "100.0.0.10"
292     if (stat == 0)
293         raise_error("inet_pton() - invalid ip");
294     if (stat == -1)
295         raise_error("inet_pton() - invalid family");
296 
297     if (stat == 1);
298     else
299         raise_error("inet_pton()");
300 
301     /* This is just to test if address conversion happened properly */
302     char buff[BUFF_SIZE];
303     char * foo;
304     foo = inet_ntop(AF_INET, &addr->sin_addr, buff, BUFF_SIZE);
305     if (foo == NULL)
306         raise_error("inet_ntop()");
307     else
308         printf("main = %s, addr = %s\n",in.dev.ip_addr, buff);
309     
310     if (ioctl(fd, SIOCSIFADDR, &ifr, sizeof(ifr)) == -1)
311         raise_error("ioctl() - SIOCSIFADDR");
312 }

Edit: raise_error function is:

void raise_error (const char * msg) {

    perror(msg);
    exit(1);
}

Output I get is:

main = 100.0.0.10, addr = 100.0.0.10
ioctl() - SIOCSIFADDR: Invalid argument

I am guessing the converted the address is getting placed at wrong location in struct ifreq, but I am not able to figure out exactly what location it should be placed. I also tried using ifr.ifr_addr for address conversion but that didn't work either.

Edit: I am running the program as root.

Any help will be much appreciated. Please let me know if I need to post more code or debugging output.

Thanks

Was it helpful?

Solution 2

As per mux's comment, I tried the same code on eth0 which worked. Hence I guess tun devices are different and we can't use same ioctl() call for them. So the way of using inet_pton and struct ifreq for ioctl() for setting ip address is right, but it doesn't work on tun devices.

OTHER TIPS

I think you're seeing the wrong error message because raise_error makes calls another function before perror and you're seeing the result of that call not ioctl.. you should always call perror right after the function you want to test. I tried your code and ioctl() fails with "ioctl(): Permission denied" you need to run that as root (also note that you don't need to pass the size of ifreq)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top