How to get network device stats? - c

I tried some examples. Part is for old linux-api, part does not compiles, part is depends on kernel version.
I need transmitted and recieved bytes on evice by its name.
Trying this, but dont know how to set default namespace or init_net:
#include <linux/netdevice.h>
struct net_device *dev;
dev = (struct net_device*) dev_get_by_name(&init_net,"eth0");
Is posible to get stats from posix sockets, not from netdevice?

There is simpler approach. copied from http://man7.org/linux/man-pages/man3/getifaddrs.3.html
VERSIONS top
The getifaddrs() function first appeared in glibc 2.3, but before
glibc 2.3.3, the implementation supported only IPv4 addresses; IPv6
support was added in glibc 2.3.3. Support of address families other
than IPv4 is available only on kernels that support netlink.
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/if_link.h>
int main(int argc, char *argv[])
{
struct ifaddrs *ifaddr, *ifa;
int family, s, n;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
/* Walk through linked list, maintaining head pointer so we
can free list later */
for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
if (ifa->ifa_addr == NULL)
continue;
family = ifa->ifa_addr->sa_family;
/* Display interface name and family (including symbolic
form of the latter for the common families) */
printf("%-8s %s (%d)\n",
ifa->ifa_name,
(family == AF_PACKET) ? "AF_PACKET" :
(family == AF_INET) ? "AF_INET" :
(family == AF_INET6) ? "AF_INET6" : "???",
family);
/* For an AF_INET* interface address, display the address */
if (family == AF_INET || family == AF_INET6) {
s = getnameinfo(ifa->ifa_addr,
(family == AF_INET) ? sizeof(struct sockaddr_in) :
sizeof(struct sockaddr_in6),
host, NI_MAXHOST,
NULL, 0, NI_NUMERICHOST);
if (s != 0) {
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf("\t\taddress: <%s>\n", host);
} else if (family == AF_PACKET && ifa->ifa_data != NULL) {
struct rtnl_link_stats *stats = (struct rtnl_link_stats *)ifa->ifa_data;
printf("\t\ttx_packets = %10u; rx_packets = %10u\n"
"\t\ttx_bytes = %10u; rx_bytes = %10u\n",
stats->tx_packets, stats->rx_packets,
stats->tx_bytes, stats->rx_bytes);
}
}
freeifaddrs(ifaddr);
exit(EXIT_SUCCESS);
}

you can use mii-tool or ethtool to get stats from network phy

Related

How to find the network interface used by a connected socket

How to find the interface used by a connected socket.So that i can set status codes for different interfaces.I used the below code.But I didnt get it.
I've tried two different approaches in the test code below, but both fail. The first one connects to a remote server, and uses ioctl with SIOCGIFNAME, but this fails with 'no such device'. The second one instead uses getsockopt with SO_BINDTODEVICE, but this again fails (it sets the name length to 0).
Any ideas on why these are failing, or how to get the I/F name? after compiling, run the test code as test "a.b.c.d", where a.b.c.d is any IPV4 address which is listening on port 80. Note that I've compiled this on Centos 7, which doesn't appear to have IFNAMSZ in <net/if.h>, so you may have to comment out the #define IFNAMSZ line to get this to compile on other systems.
Thanks.
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if.h>
int main(int argc, char **argv) {
int sock;
struct sockaddr_in dst_sin;
struct in_addr haddr;
if(argc != 2)
return 1;
if(inet_aton(argv[1], &haddr) == 0) {
printf("'%s' is not a valid IP address\n", argv[1]);
return 1;
}
dst_sin.sin_family = AF_INET;
dst_sin.sin_port = htons(80);
dst_sin.sin_addr = haddr;
if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
return 1;
}
if(connect(sock, (struct sockaddr*)&dst_sin, sizeof(dst_sin)) < 0) {
perror("connect");
return 1;
}
printf("connected to %s:%d\n",
inet_ntoa(dst_sin.sin_addr), ntohs(dst_sin.sin_port));
#if 0 // ioctl fails with 'no such device'
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
// get the socket's interface index into ifreq.ifr_ifindex
if(ioctl(sock, SIOCGIFINDEX, &ifr) < 0) {
perror("SIOCGIFINDEX");
return 1;
}
// get the I/F name for ifreq.ifr_ifindex
if(ioctl(sock, SIOCGIFNAME, &ifr) < 0) {
perror("SIOCGIFNAME");
return 1;
}
printf("I/F is on '%s'\n", ifr.ifr_name);
#else // only works on Linux 3.8+
#define IFNAMSZ IFNAMSIZ // Centos7 bug in if.h??
char optval[IFNAMSZ] = {0};
socklen_t optlen = IFNAMSZ;
if(getsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &optval, &optlen) < 0) {
perror("getsockopt");
return 1;
}
if(!optlen) {
printf("invalid optlen\n");
return 1;
}
printf("I/F is on '%s'\n", optval);
#endif
close(sock);
return 0;
Idea based on another post
Create socket
Connect
Get interface address
Get interface id and name from interface address
$ gcc -std=gnu11 -Wall so_q_63899229.c
$ ./a.out 93.184.216.34 # example.org
interface index : 2
interface name : wlp2s0
interface address : 192.168.1.223
remote address : 93.184.216.34
so_q_63899229.c
#include <arpa/inet.h>
#include <assert.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
int sockfd=-1;
void connect2(const char *const dst){
sockfd=socket(AF_INET,SOCK_STREAM,0);
assert(sockfd>=3);
struct sockaddr_in sin={
.sin_family=AF_INET,
.sin_port=htons(80),
.sin_addr={}
};
assert(1==inet_pton(AF_INET,dst,&(sin.sin_addr)));
assert(0==connect(sockfd,(struct sockaddr*)(&sin),sizeof(struct sockaddr_in)));
}
void getsockname2(struct sockaddr_in *const sin){
socklen_t addrlen=sizeof(struct sockaddr_in);
assert(0==getsockname(sockfd,(struct sockaddr*)sin,&addrlen));
assert(addrlen==sizeof(struct sockaddr_in));
}
void disconnect(){
close(sockfd);
sockfd=-1;
}
void addr2iface_ifconf(const struct in_addr *const sin_addr,int *const index,char *const name){
struct ifconf ifc={
.ifc_len=0,
.ifc_req=NULL
};
int ioctlfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
assert(ioctlfd>=3);
assert(0==ioctl(ioctlfd,SIOCGIFCONF,&ifc));
const int sz=ifc.ifc_len;
assert(sz%sizeof(struct ifreq)==0);
const int n=sz/sizeof(struct ifreq);
char buf[sz];
bzero(buf,sz);
ifc.ifc_buf=buf;
assert(0==ioctl(ioctlfd,SIOCGIFCONF,&ifc));
assert(
ifc.ifc_len==sz &&
(char*)ifc.ifc_req==buf
);
for(int i=0;i<n;++i)if(0==memcmp(
&(((struct sockaddr_in*)(&(ifc.ifc_req[i].ifr_addr)))->sin_addr),
sin_addr,
sizeof(struct in_addr)
)){
*index=ifc.ifc_req[i].ifr_ifindex;
assert(name==strncpy(name,ifc.ifc_req[i].ifr_name,IFNAMSIZ));
return;
}
assert(0);
}
int main(int argc,const char *argv[]){
assert(argc==2);
assert(argv[1]&&strlen(argv[1]));
const char *const remoteaddr_s=argv[1];
// const char *const remoteaddr_s="93.184.216.34";
connect2(remoteaddr_s);
struct sockaddr_in ifaddr={};
getsockname2(&ifaddr);
disconnect();
int index=0;
char ifname[IFNAMSIZ]={};
addr2iface_ifconf(&(ifaddr.sin_addr),&index,ifname);
char ifaddr_s[INET_ADDRSTRLEN]={};
assert(ifaddr_s==inet_ntop(AF_INET,&(ifaddr.sin_addr),ifaddr_s,INET_ADDRSTRLEN));
printf("interface index : %d\n",index);
printf("interface name : %s\n",ifname);
printf("interface address : %s\n",ifaddr_s);
printf("remote address : %s\n",remoteaddr_s);
// printf("#%d %s %s -> %s\n",
// index,
// ifname,
// ifaddr_s,
// remoteaddr_s
// );
return 0;
}
Also there doesn't seem to be an identifier named IFNAMSZ. IFNAMSIZ defined in <net/if.h> should be the maxinum legth (including '\0') allowed for the name of any interface IMHO.

C - How to convert the char to string to pass strcpy?

I need to fetch the active network interface of a device in c language using the system command and the system response has to be passed to get the mac address of the device and for the same, below is the sample which I have been using,
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <netdb.h>
char interface[100];
char reader_mac[13] = {00};
int main()
{
FILE *f = popen("ip addr show | awk '/inet.*brd/{print $NF}'", "r");
while (fgets(interface, 100, f) != NULL) {
}
printf( "interface :: %s\n", interface );
pclose(f);
struct ifreq s;
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
// strcpy(s.ifr_name, "eth0");
strcpy(s.ifr_name, interface);
if (0 == ioctl(fd, SIOCGIFHWADDR, &s)) {
int i;
for (i = 0; i < 6; ++i){
unsigned char data = s.ifr_addr.sa_data[i];
// printf("ddd:::%02x\n", data );
sprintf(reader_mac+(i*2), "%02x", data);
}
reader_mac[12] = '\0';
printf("reader_mac ::: %s\n",reader_mac);
}
}
How to address this?
I can able to get the active interface as,
interface :: wlp1s0
Whereas, the same interface is passed to strcpy(s.ifr_name, interface) and for the same unable to get the address. Instead of strcpy(s.ifr_name, interface), if i use it as strcpy(s.ifr_name, "wlp1s0), the same returns the mac address without any issue.
Yes, you can parse the output of ip addr show, but wait, what if the implementer changes the way ip addr show produces the output! It's output has not been standardized. Did you consider using getifaddrs()? The below code is from their man page:
#define _GNU_SOURCE /* To get defns of NI_MAXSERV and NI_MAXHOST */
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/if_link.h>
int main(int argc, char *argv[])
{
struct ifaddrs *ifaddr, *ifa;
int family, s;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
/* Walk through linked list, maintaining head pointer so we
can free list later */
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;
family = ifa->ifa_addr->sa_family;
/* Display interface name and family (including symbolic
form of the latter for the common families) */
printf("%-8s %s (%d)\n",
ifa->ifa_name,
(family == AF_PACKET) ? "AF_PACKET" :
(family == AF_INET) ? "AF_INET" :
(family == AF_INET6) ? "AF_INET6" : "???",
family);
/* For an AF_INET* interface address, display the address */
if (family == AF_INET || family == AF_INET6) {
s = getnameinfo(ifa->ifa_addr,
(family == AF_INET) ? sizeof(struct sockaddr_in) :
sizeof(struct sockaddr_in6),
host, NI_MAXHOST,
NULL, 0, NI_NUMERICHOST);
if (s != 0) {
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf("\t\taddress: <%s>\n", host);
} else if (family == AF_PACKET && ifa->ifa_data != NULL) {
struct rtnl_link_stats *stats = ifa->ifa_data;
printf("\t\ttx_packets = %10u; rx_packets = %10u\n"
"\t\ttx_bytes = %10u; rx_bytes = %10u\n",
stats->tx_packets, stats->rx_packets,
stats->tx_bytes, stats->rx_bytes);
}
}
freeifaddrs(ifaddr);
exit(EXIT_SUCCESS);
}

Check port reachable in C

I have a C function to check a host and its port, when I use FQDN host name, the function return error like: connect() failed: connect time out, but if I use IP address instead, it seems ok, how to fix this?
Thanks.
#include <unistd.h>
#include <string.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
int is_network_up(char *chkhost, unsigned short chkport) {
int sock;
struct sockaddr_in chksock;
struct hostent *host = NULL;
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
syslog(LOG_ERR, "socket() creation error: %s", strerror(errno));
return 0;
}
memset(&chksock, 0, sizeof(chksock));
chksock.sin_family = AF_INET;
chksock.sin_port = htons(chkport);
/* get the server address */
if (inet_pton(AF_INET, chkhost, &(chksock.sin_addr.s_addr)) <= 0) {
if ((host = gethostbyname(chkhost)) == NULL) {
syslog(LOG_ERR, "%s", hstrerror(h_errno));
return 0;
}
memcpy(&(chksock.sin_addr.s_addr), &(host->h_addr_list[0]),
sizeof(struct in_addr));
}
/* try to connect */
if (connect(sock, (struct sockaddr *) &chksock, sizeof(chksock)) < 0) {
syslog(LOG_ERR, "connect() failed: %s", strerror(errno));
return 0;
}
close(sock);
return 1;
}
inet_pton() is the wrong task for that. It only accepts numerical addresses.
In former times, people used to use gethostbyname() for name resolution.
But as we have 2012 meanwhile, this method is outdated for several years now, as it is still restricted to AF_INET.
With the program below, you should achieve about the same and stay future compatible.
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <stdio.h>
int is_network_up(char *chkhost, unsigned short chkport) {
int sock = -1;
struct addrinfo * res, *rp;
int ret = 0;
char sport[10];
snprintf(sport, sizeof sport, "%d", chkport);
struct addrinfo hints = { .ai_socktype=SOCK_STREAM };
if (getaddrinfo(chkhost, sport, &hints, &res)) {
perror("gai");
return 0;
}
for (rp = res; rp && !ret; rp = rp->ai_next) {
sock = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (sock == -1) continue;
if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) {
char node[200], service[100];
getnameinfo(res->ai_addr, res->ai_addrlen, node, sizeof node, service, sizeof
service, NI_NUMERICHOST);
printf("Success on %s, %s\n", node, service);
ret = 1; /* Success */
}
close(sock);
}
freeaddrinfo(res);
return ret;
}
int main(int argc, char** argv) {
if (argc > 1) {
printf("%s: %d\n", argv[1], is_network_up(argv[1], 22));
}
}
Make sure name resolution is working. See if you can ping the machine by name from the exact same environment in which your code runs.
If ping works, try telnet <machinename> <portnumber> -- If both of those work it is likely a problem with your code (which I did not look at in depth, too sleepy:).
Make sure you're converting anything returned by the OS as an ip address from network order to host order. IIRC, gethostbyname returns binary ip addresses in network order.
ntohl can be used on chksock.sin_addr.s_addr after the memcpy to achieve this.

using C code to get same info as ifconfig

Is there a way in Linux, using C code, to get the same information that "ifconfig eth0" would return? I'm interested in things like IP address, link status, and MAC address.
Here's sample output from ifconfig:
eth0 Link encap:Ethernet HWaddr 00:0F:20:CF:8B:42
inet addr:217.149.127.10 Bcast:217.149.127.63 Mask:255.255.255.192
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:2472694671 errors:1 dropped:0 overruns:0 frame:0
TX packets:44641779 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1761467179 (1679.8 Mb) TX bytes:2870928587 (2737.9 Mb)
Interrupt:28
One way to get to the bottom of problems like this, particularly in cases when you don't have source, is strace.
It gives you a list of all the system calls made by any program you pass it, along with their arguments and return values. If your program just dumps some info and quits rather than running for an extended time it can be pretty straightforward to just do a man on all the system calls you see that look like they might provide the info you're looking for.
When I run
strace ifconfig
Some of the interesting calls are:
open("/proc/net/dev", O_RDONLY) = 6
followed by a bunch of ioctls, corroborating #payne's answer:
ioctl(5, SIOCGIFFLAGS, {ifr_name="eth0", ifr_flags=IFF_UP|IFF_BROADCAST|IFF_RUNNING|IFF_MULTICAST}) = 0
ioctl(5, SIOCGIFHWADDR, {ifr_name="eth0", ifr_hwaddr=84:2b:2b:b7:9e:6d}) = 0
ioctl(5, SIOCGIFMETRIC, {ifr_name="eth0", ifr_metric=0}) = 0
ioctl(5, SIOCGIFMTU, {ifr_name="eth0", ifr_mtu=1500}) = 0
Yes, ifconfig itself is written in C. :) See: http://cvsweb.netbsd.org/bsdweb.cgi/src/sbin/ifconfig/ifconfig.c?rev=1.169&content-type=text/x-cvsweb-markup
Do man netdevice to see the details (on Linux). You use the ioctl() system call.
There is simpler approach. copied from http://man7.org/linux/man-pages/man3/getifaddrs.3.html
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/if_link.h>
int main(int argc, char *argv[])
{
struct ifaddrs *ifaddr, *ifa;
int family, s, n;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
/* Walk through linked list, maintaining head pointer so we
can free list later */
for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
if (ifa->ifa_addr == NULL)
continue;
family = ifa->ifa_addr->sa_family;
/* Display interface name and family (including symbolic
form of the latter for the common families) */
printf("%-8s %s (%d)\n",
ifa->ifa_name,
(family == AF_PACKET) ? "AF_PACKET" :
(family == AF_INET) ? "AF_INET" :
(family == AF_INET6) ? "AF_INET6" : "???",
family);
/* For an AF_INET* interface address, display the address */
if (family == AF_INET || family == AF_INET6) {
s = getnameinfo(ifa->ifa_addr,
(family == AF_INET) ? sizeof(struct sockaddr_in) :
sizeof(struct sockaddr_in6),
host, NI_MAXHOST,
NULL, 0, NI_NUMERICHOST);
if (s != 0) {
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf("\t\taddress: <%s>\n", host);
} else if (family == AF_PACKET && ifa->ifa_data != NULL) {
struct rtnl_link_stats *stats = (struct rtnl_link_stats *)ifa->ifa_data;
printf("\t\ttx_packets = %10u; rx_packets = %10u\n"
"\t\ttx_bytes = %10u; rx_bytes = %10u\n",
stats->tx_packets, stats->rx_packets,
stats->tx_bytes, stats->rx_bytes);
}
}
freeifaddrs(ifaddr);
exit(EXIT_SUCCESS);
}
One simple way is to use the popen function see:
http://pubs.opengroup.org/onlinepubs/009696899/functions/popen.html
Use something like:
FILE *fp;
char returnData[64];
fp = popen("/sbin/ifconfig eth0", "r");
while (fgets(returnData, 64, fp) != NULL)
{
printf("%s", returnData);
}
pclose(fp);
Here is how I get MAC and MTU in my code:
void getMACAddress(std::string _iface,unsigned char MAC[6]) {
int fd = socket(AF_INET, SOCK_DGRAM, 0);
struct ifreq ifr;
ifr.ifr_addr.sa_family = AF_INET;
strncpy(ifr.ifr_name , _iface.c_str() , IFNAMSIZ-1);
ioctl(fd, SIOCGIFHWADDR, &ifr);
for(unsigned int i=0;i<6;i++)
MAC[i] = ifr.ifr_hwaddr.sa_data[i];
ioctl(fd, SIOCGIFMTU, &ifr);
close(fd);
printf("MTU: %d\n",ifr.ifr_mtu);
printf("MAC:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",MAC[0],MAC[1],MAC[2],MAC[3],MAC[4],MAC[5]);
}
void parse_ioctl(const char *ifname)
{
printf("%s\n", "scarf rosari...");
int sock;
struct ifreq ifr;
struct sockaddr_in *ipaddr;
char address[INET_ADDRSTRLEN];
size_t ifnamelen;
/* copy ifname to ifr object */
ifnamelen = strlen(ifname);
if (ifnamelen >= sizeof(ifr.ifr_name)) {
printf("error :%s\n", ifr.ifr_name);
return ;
}
memcpy(ifr.ifr_name, ifname, ifnamelen);
ifr.ifr_name[ifnamelen] = '\0';
/* open socket */
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock < 0) {
printf("error :%s\n", "unable to open socket..");
return;
}
/* process mac */
if (ioctl(sock, SIOCGIFHWADDR, &ifr) != -1) {
printf("Mac address: %02x:%02x:%02x:%02x:%02x:%02x\n",
(unsigned char)ifr.ifr_hwaddr.sa_data[0],
(unsigned char)ifr.ifr_hwaddr.sa_data[1],
(unsigned char)ifr.ifr_hwaddr.sa_data[2],
(unsigned char)ifr.ifr_hwaddr.sa_data[3],
(unsigned char)ifr.ifr_hwaddr.sa_data[4],
(unsigned char)ifr.ifr_hwaddr.sa_data[5]);
}
/* process mtu */
if (ioctl(sock, SIOCGIFMTU, &ifr) != -1) {
printf("MTU: %d\n", ifr.ifr_mtu);
}
/* die if cannot get address */
if (ioctl(sock, SIOCGIFADDR, &ifr) == -1) {
close(sock);
return;
}
/* process ip */
ipaddr = (struct sockaddr_in *)&ifr.ifr_addr;
if (inet_ntop(AF_INET, &ipaddr->sin_addr, address, sizeof(address)) != NULL) {
printf("Ip address: %s\n", address);
}
/* try to get broadcast */
if (ioctl(sock, SIOCGIFBRDADDR, &ifr) != -1) {
ipaddr = (struct sockaddr_in *)&ifr.ifr_broadaddr;
if (inet_ntop(AF_INET, &ipaddr->sin_addr, address, sizeof(address)) != NULL) {
printf("Broadcast: %s\n", address);
}
}
/* try to get mask */
if (ioctl(sock, SIOCGIFNETMASK, &ifr) != -1) {
ipaddr = (struct sockaddr_in *)&ifr.ifr_netmask;
if (inet_ntop(AF_INET, &ipaddr->sin_addr, address, sizeof(address)) != NULL) {
printf("Netmask: %s\n", address);
}
}
close(sock);
}
usage :
parse_ioctl("eth0");

C code to get the IP address

How do I get the IP address of the local machine using C code?
If there are multiple Interfaces then I should be able to display the IP address of each interface.
NOTE: Do not use any commands like ifconfig within C code to retrieve the IP address.
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
int main()
{
int fd;
struct ifreq ifr;
fd = socket(AF_INET, SOCK_DGRAM, 0);
ifr.ifr_addr.sa_family = AF_INET;
snprintf(ifr.ifr_name, IFNAMSIZ, "eth0");
ioctl(fd, SIOCGIFADDR, &ifr);
/* and more importantly */
printf("%s\n", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
close(fd);
}
If you want to enumerate all the interfaces, have a look at the getifaddrs() function - if you're on Linux.
With the inputs from Michael Foukarakis I am able to show the IP address for various interfaces on the same machine:
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
struct ifaddrs *ifaddr, *ifa;
int family, s;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
family = ifa->ifa_addr->sa_family;
if (family == AF_INET) {
s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in),
host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if (s != 0) {
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf("<Interface>: %s \t <Address> %s\n", ifa->ifa_name, host);
}
}
return 0;
}
Get known all interfaces from "/proc/net/dev". Note: it cannot get all interfaces using ioctl only.
#define PROC_NETDEV "/proc/net/dev"
fp = fopen(PROC_NETDEV, "r");
while (NULL != fgets(buf, sizeof buf, fp)) {
s = strchr(buf, ':');
*s = '\0';
s = buf;
// Filter all space ' ' here
got one interface name here, continue for others
}
fclose(fp);
Then get the address using ioctl():
struct ifreq ifr;
struct ifreq ifr_copy;
struct sockaddr_in *sin;
for each interface name {
strncpy(ifr.ifr_name, ifi->name, sizeof(ifr.ifr_name) - 1);
ifr_copy = ifr;
ioctl(fd, SIOCGIFFLAGS, &ifr_copy);
ifi->flags = ifr_copy.ifr_flags;
ioctl(fd, SIOCGIFADDR, &ifr_copy);
sin = (struct sockaddr_in*)&ifr_copy.ifr_addr;
ifi->addr = allocating address memory here
bzero(ifi->addr, sizeof *ifi->addr);
*(struct sockaddr_in*)ifi->addr = *sin;
/* Here also you could get netmask and hwaddr. */
}

Resources