By using strace and ifconfig, I found that I can set the IP address this way:
#include <sys/ioctl.h> #include <arpa/inet.h> #include <net/if.h> #include <string.h> int main(int argc, const char *argv[]) { struct ifreq ifr; const char * name = "eth1"; int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); strncpy(ifr.ifr_name, name, IFNAMSIZ); ifr.ifr_addr.sa_family = AF_INET; inet_pton(AF_INET, "10.12.0.1", ifr.ifr_addr.sa_data + 2); ioctl(fd, SIOCSIFADDR, &ifr); inet_pton(AF_INET, "255.255.0.0", ifr.ifr_addr.sa_data + 2); ioctl(fd, SIOCSIFNETMASK, &ifr); ioctl(fd, SIOCGIFFLAGS, &ifr); strncpy(ifr.ifr_name, name, IFNAMSIZ); ifr.ifr_flags |= (IFF_UP | IFF_RUNNING); ioctl(fd, SIOCSIFFLAGS, &ifr); return 0; }
But I am not very happy with this solution:
inet_pton(AF_INET, "10.12.0.1", ifr.ifr_addr.sa_data + 2);
What is the "right" way of doing this?
To change your IP address on Linux, use the “ifconfig” command followed by the name of your network interface and the new IP address to be changed on your computer. To assign the subnet mask, you can either add a “netmask” clause followed by the subnet mask or use the CIDR notation directly.
To configure an IP address for a network interface, enter the following command: ifconfig interface_name IP_address interface_name is the name of the network interface. IP_address is the IP address that you want to assign to the network interface.
To assign an IP address to a specific interface, use the following command with an interface name (eth0) and ip address that you want to set. For example, “ifconfig eth0 172.16. 25.125” will set the IP address to interface eth0.
The "correct" way for IPv4 without magic +2:
struct sockaddr_in* addr = (struct sockaddr_in*)&ifr.ifr_addr; inet_pton(AF_INET, "10.12.0.1", &addr->sin_addr);
To use IPv6, cast it to sockaddr_in6
#include <stdio.h> #include <stdlib.h> #include <unistd.h> // close() #include <string.h> // strcpy, memset(), and memcpy() #include <netdb.h> // struct addrinfo #include <sys/types.h> // needed for socket(), uint8_t, uint16_t #include <sys/socket.h> // needed for socket() #include <netinet/in.h> // IPPROTO_RAW, INET_ADDRSTRLEN #include <netinet/ip.h> // IP_MAXPACKET (which is 65535) #include <arpa/inet.h> // inet_pton() and inet_ntop() #include <sys/ioctl.h> // macro ioctl is defined #include <bits/ioctls.h> // defines values for argument "request" of ioctl. #include <net/if.h> // struct ifreq #include <linux/if_ether.h> // ETH_P_ARP = 0x0806 #include <linux/if_packet.h> // struct sockaddr_ll (see man 7 packet) #include <net/ethernet.h> #include <errno.h> // errno, perror() #include <netinet/in.h> #include <net/route.h> /** * Create socket function */ int create_socket() { int sockfd = 0; sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd == -1){ fprintf(stderr, "Could not get socket.\n"); return -1; } return sockfd; } /** * Generic ioctrlcall to reduce code size */ int generic_ioctrlcall(int sockfd, u_long *flags, struct ifreq *ifr) { if (ioctl(sockfd, (long unsigned int)flags, &ifr) < 0) { fprintf(stderr, "ioctl: %s\n", (char *)flags); return -1; } return 1; } /** * Set route with metric 100 */ int set_route(int sockfd, char *gateway_addr, struct sockaddr_in *addr) { struct rtentry route; int err = 0; memset(&route, 0, sizeof(route)); addr = (struct sockaddr_in*) &route.rt_gateway; addr->sin_family = AF_INET; addr->sin_addr.s_addr = inet_addr(gateway_addr); addr = (struct sockaddr_in*) &route.rt_dst; addr->sin_family = AF_INET; addr->sin_addr.s_addr = inet_addr("0.0.0.0"); addr = (struct sockaddr_in*) &route.rt_genmask; addr->sin_family = AF_INET; addr->sin_addr.s_addr = inet_addr("0.0.0.0"); route.rt_flags = RTF_UP | RTF_GATEWAY; route.rt_metric = 100; err = ioctl(sockfd, SIOCADDRT, &route); if ((err) < 0) { fprintf(stderr, "ioctl: %s\n", "mahdi MOAHMMADI Error"); return -1; } return 1; } /** * Set ip function */ int set_ip(char *iface_name, char *ip_addr, char *gateway_addr) { if(!iface_name) return -1; struct ifreq ifr; struct sockaddr_in sin; int sockfd = create_socket(); sin.sin_family = AF_INET; // Convert IP from numbers and dots to binary notation inet_aton(ip_addr,&sin.sin_addr.s_addr); /* get interface name */ strncpy(ifr.ifr_name, iface_name, IFNAMSIZ); /* Read interface flags */ generic_ioctrlcall(sockfd, (u_long *)"SIOCGIFFLAGS", &ifr); /* * 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)) { ifr.IRFFLAGS |= IFF_UP; generic_ioctrlcall(sockfd, (u_long *)"SIOCSIFFLAGS", &ifr); } // Set route set_route(sockfd, gateway_addr , &sin); 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; }
usage:
set_ip("eth0", "192.168.181.128", "192.168.181.1");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With