Let's say I'm running a program called IpAddresses.c. I want that program to get all IP addresses this device has according to each interface. Just like ifconfig. How can I do that?
I don't know much about ioctl, but I read it might help me.
Just use getifaddrs(). Here's an example:
#include <arpa/inet.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <stdio.h>
int main ()
{
struct ifaddrs *ifap, *ifa;
struct sockaddr_in *sa;
char *addr;
getifaddrs (&ifap);
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (ifa->ifa_addr && ifa->ifa_addr->sa_family==AF_INET) {
sa = (struct sockaddr_in *) ifa->ifa_addr;
addr = inet_ntoa(sa->sin_addr);
printf("Interface: %s\tAddress: %s\n", ifa->ifa_name, addr);
}
}
freeifaddrs(ifap);
return 0;
}
And here's the output I get on my machine:
Interface: lo Address: 127.0.0.1
Interface: eth0 Address: 69.72.234.7
Interface: eth0:1 Address: 10.207.9.3
#include <stdlib.h>
" below the stdio.h
line, and added this line "if (getifaddrs(&ifap) == -1) { perror("getifaddrs"); exit(1); }
" by replacing this line "getifaddrs (&ifap);
" . Without previous (2-lines) changes, if the "ifa_addr" has a NULL pointer then it creates segmentation fault . Mentioned changes are inspired by Michael-Hampton's code shown here: https://mcmap.net/q/742779/-how-to-know-the-ip-address-for-interfaces-in-c-using-ipv6 . This code worked fine on macOS (10.15.x/Catalina). –
Sukkoth Here's some Linux sample code that might help you out.
#include <stdio.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#define INT_TO_ADDR(_addr) \
(_addr & 0xFF), \
(_addr >> 8 & 0xFF), \
(_addr >> 16 & 0xFF), \
(_addr >> 24 & 0xFF)
int main()
{
struct ifconf ifc;
struct ifreq ifr[10];
int sd, ifc_num, addr, bcast, mask, network, i;
/* Create a socket so we can use ioctl on the file
* descriptor to retrieve the interface info.
*/
sd = socket(PF_INET, SOCK_DGRAM, 0);
if (sd > 0)
{
ifc.ifc_len = sizeof(ifr);
ifc.ifc_ifcu.ifcu_buf = (caddr_t)ifr;
if (ioctl(sd, SIOCGIFCONF, &ifc) == 0)
{
ifc_num = ifc.ifc_len / sizeof(struct ifreq);
printf("%d interfaces found\n", ifc_num);
for (i = 0; i < ifc_num; ++i)
{
if (ifr[i].ifr_addr.sa_family != AF_INET)
{
continue;
}
/* display the interface name */
printf("%d) interface: %s\n", i+1, ifr[i].ifr_name);
/* Retrieve the IP address, broadcast address, and subnet mask. */
if (ioctl(sd, SIOCGIFADDR, &ifr[i]) == 0)
{
addr = ((struct sockaddr_in *)(&ifr[i].ifr_addr))->sin_addr.s_addr;
printf("%d) address: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(addr));
}
if (ioctl(sd, SIOCGIFBRDADDR, &ifr[i]) == 0)
{
bcast = ((struct sockaddr_in *)(&ifr[i].ifr_broadaddr))->sin_addr.s_addr;
printf("%d) broadcast: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(bcast));
}
if (ioctl(sd, SIOCGIFNETMASK, &ifr[i]) == 0)
{
mask = ((struct sockaddr_in *)(&ifr[i].ifr_netmask))->sin_addr.s_addr;
printf("%d) netmask: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(mask));
}
/* Compute the current network value from the address and netmask. */
network = addr & mask;
printf("%d) network: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(network));
}
}
close(sd);
}
return 0;
}
ioctl
and when getifaddrs
. –
Cleodal ioctl
may be somewhat more portable even if it does not conform to any single standard. It is supported on most Unix and Unix-like systems and the ioctl
function call first appeared in Version 7 AT&T UNIX. I believe getifaddrs
is supported in BSD and Linux and first appeared in glibc 2.3. –
Elk ifaddrs
thing for some reason but doesn't on OS X. Here's an example that works on both. –
Pulmonary htonl()
/ntohl()
instead of custom INT_TO_ADDR
macro. –
Veliavelick The solution using getifaddrs() is great. I would suggest only one improve:
--- chrisaycock
+++ normando
@@ -11,7 +11,7 @@
getifaddrs (&ifap);
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
- if (ifa->ifa_addr->sa_family==AF_INET) {
+ if (ifa->ifa_addr && ifa->ifa_addr->sa_family==AF_INET) {
sa = (struct sockaddr_in *) ifa->ifa_addr;
addr = inet_ntoa(sa->sin_addr);
printf("Interface: %s\tAddress: %s\n", ifa->ifa_name, addr);
Just because I myself got a Segmentation Fault.
See this other Stack Overflow question, Enumerating each IP address assigned to network interfaces.
In summary, you can use:
ioctl(SIOCGIFCONF)
-> the traditional ioctlgetifaddrs()
-> from BSDi, now also on Linux and the BSD's.You could try something like that:
struct ifreq ifr[MAX_INTERFACES];
struct ifconf ifc;
memset(ifr, 0, sizeof(ifr));
ifc.ifc_len = sizeof(ifr);
ifc.ifc_req = ifr;
// Get the list of interfaces
if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) {
fprintf(stderr, "ioctl SIOCGIFCONF failed: %d", errno);
}
struct ifreq *ifr_iterator = ifc.ireq;
int i = 0;
size_t len;
while (i < ifc.ifc_len) {
/* DO STUFF */
// Maybe some more filtering based on SIOCGIFFLAGS
// Your code
// Use ifr_iterator-> ...
len = IFNAMSIZ + ifr_iterator->ifr_addr.sa_len;
ifr_iterator = (struct ifreq *)((char *)ifr_iterator + len);
i += len;
}
ifc.ifc_len/sizeof(struct ifreq)
will give you the interface count. Instead you need to iterate through the elements in the list like this: struct ifreq *ifr_iterator = ifc.ireq; size_t len; while (i < ifc.ifc_len) { /* DO STUFF */ len = IFNAMSIZ + ifr_iterator->ifr_addr.sa_len; ifr_iterator = (struct ifreq *)((char *)ifr_iterator + len); i += len; }
–
Stratocracy #define ifc_req ifc_ifcu.ifcu_req /* array of structures ret'd */
technically isnt an array because size varies? It seems 5.9 had added more stuff. Also ifconfig.c code didnt seem to have SIOCGIFCONF –
Tritanopia Check out the (Windows specific) IP Helper API - fortunately you don't need ioctl
for this on Windows.
In case you also need IP6 addresses, you can extend the accepted answer like this:
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <netdb.h>
int main() {
struct ifaddrs *ifap;
getifaddrs(&ifap);
for (struct ifaddrs *ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (ifa->ifa_addr && (ifa->ifa_addr->sa_family == AF_INET6)) {
char addr[INET6_ADDRSTRLEN];
getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), addr, sizeof(addr), NULL, 0, NI_NUMERICHOST);
printf("Interface: %s\tAddress: %s\n", ifa->ifa_name, addr);
} else if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) {
struct sockaddr_in *sa = (struct sockaddr_in *)ifa->ifa_addr;
char *addr = inet_ntoa(sa->sin_addr);
printf("Interface: %s\tAddress: %s\n", ifa->ifa_name, addr);
}
}
freeifaddrs(ifap);
return 0;
}
© 2022 - 2024 — McMap. All rights reserved.