There are a lot of cool things you can do from a C program. One of them is setting an interface’s IP address using ioctl calls. You can of course, set it the old fashioned way using ifconfig, which I wrote about earlier. Rather than having to execute a system call to ifconfig from your C process, you can actually set the interface IP address using an input/output control call (ioctl) much the same way that ifconfig does itself. Holy crap Batman!
It goes to say also, if you can set the IP address then you may also read it via an ioctl call. The example I have crafted includes the function call which takes two parameters, the first is the interface name, the second is the IP address in normal form (192.168.1.1) which is then converted to binary. This function will also bring the interface up prior to setting the IP address. Lets take a look:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <sys/ioctl.h>
#include <linux/sockios.h>
#include <errno.h>
#include <netinet/in.h>
#if defined(__GLIBC__) && __GLIBC__ >=2 && __GLIBC_MINOR__ >= 1
#include <netpacket/packet.h>
#include <net/ethernet.h>
#else
#include <sys/types.h>
#include <netinet/if_ether.h>
#endif
int set_ip(char *iface_name, char *ip_addr)
{
if(!iface_name)
return -1;
int sockfd;
struct ifreq ifr;
struct sockaddr_in sin;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd == -1){
fprintf(stderr, "Could not get socket.\n");
return -1;
}
/* get interface name */
strncpy(ifr.ifr_name, iface_name, IFNAMSIZ);
/* Read interface flags */
if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
fprintf(stderr, "ifdown: shutdown ");
perror(ifr.ifr_name);
return -1;
}
/*
* Expected in <net/if.h> according to
* "UNIX Network Programming".
*/
#ifdef ifr_flags
# define IRFFLAGS ifr_flags
#else /* Present on kFreeBSD */
# define IRFFLAGS ifr_flagshigh
#endif
// If interface is down, bring it up
if (!(ifr.IRFFLAGS & IFF_UP)) {
fprintf(stdout, "Device is currently down..setting up.-- %u\n",ifr.IRFFLAGS);
ifr.IRFFLAGS |= IFF_UP;
if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
fprintf(stderr, "ifup: failed ");
perror(ifr.ifr_name);
return -1;
}
}
sin.sin_family = AF_INET;
// Convert IP from numbers and dots to binary notation
inet_aton(ip_addr,&sin.sin_addr.s_addr);
memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
// Set interface address
if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) {
fprintf(stderr, "Cannot set IP address. ");
perror(ifr.ifr_name);
return -1;
}
#undef IRFFLAGS
return 0;
}
void usage()
{
const char *usage = {
"./set_ip [interface] [ip address]\n"
};
fprintf(stderr,"%s",usage);
}
int main(int argc, char **argv)
{
if(argc < 3){
usage();
return -1;
}
set_ip(argv[1],argv[2]);
return 0;
}
Lets check if it works. I will do an ifconfig on eth1 to see its current IP address, then use the program above to set it to a new IP address, then use ifconfig again to view it.
$ ifconfig eth1
eth1 Link encap:Ethernet HWaddr 00:1b:21:0a:d2:cf
inet addr:192.168.5.12 Bcast:192.168.5.255 Mask:255.255.255.0
inet6 addr: fe80::21b:21ff:fe0a:d2cf/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:2690 errors:0 dropped:0 overruns:0 frame:0
TX packets:14732 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:516826 (516.8 KB) TX bytes:2242645 (2.2 MB)
$ sudo ./set_ip eth1 12.13.14.15
Device is currently down..setting up.-- 4163
$ ifconfig eth1
eth1 Link encap:Ethernet HWaddr 00:1b:21:0a:d2:cf
inet addr:12.13.14.15 Bcast:12.255.255.255 Mask:255.0.0.0
inet6 addr: fe80::21b:21ff:fe0a:d2cf/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:2690 errors:0 dropped:0 overruns:0 frame:0
TX packets:14742 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:516826 (516.8 KB) TX bytes:2247309 (2.2 MB)
Because we are modifying an interfaces IP address, we must run this process as root or with the use of sudo. Looks like it works! Of course you may want to set your IP address to something more useful than this. Also not that I do no error checking on user input, you may wish to take that into account if your input comes from an untrusted source.
One thought on “Set Interface IP Address From C In Linux”