How to differentiate ethernet from the others? - c

It was suggested in an answer here, Get the IP address of the machine, one could use getifaddrs() to obtain the IP address of the machine the program was running on, which worked great :D:D
However, running the same program on two different systems, one displayed
SERVER_ADDRESS lo 127.0.0.1
SERVER_ADDRESS eth0 129.xxx.xxx.xxx
SERVER_ADDRESS virbr0 192.zzz.zzz.1
while the other displayed
SERVER_ADDRESS lo0 127.0.0.1
SERVER_ADDRESS en0 192.yyy.yyy.yyy
I was going to use strcmp to differentiate ethernet, but now I realized it doesn't work across systems since different strings may be printed out.
Is there a function (or better way) to check whether or not an ifa_name is ethernet or not?

To (again) state this explicitly: All addresses of the 127.0.0.0/255.0.0.0 net (range) as there are the addresses from 127.0.0.0 to 127.255.255.255, are defined to be treated as local loopback addresses. Data addressed to such will not leave the local machine.
Anyhow as you are already using getifaddrs() live is easy .. - just test the member ifa_flags of the structure(s) struct ifaddrs returned for IFF_LOOPBACK like so:
#include <sys/types.h>
#include <ifaddrs.h>
#include <net/if.h> /* for IFF_LOOPBACK */
...
struct ifaddrs * pIfAddrs = NULL;
if (!getifaddrs(&pIfAddrs)) {
/* Test if the first interface is looping back to the local host. */
int iIsLoopBack = (0 != (pIfAddrs->ifa_flags & IFF_LOOPBACK));
...
}
...
/* clean up */
if (pIfAddrs) {
freeifaddrs(pIfAddrs);
pIfAddrs = NULL;
}
...

You're likely to run into more than just that issue.. say for example there are multiple NICs, vLANs, WANS that look like LANS, and vice-versa, etc.
What is known? 127.X.X.X Throw out that result and you've got your non-loopbacks.
If you want to know if the address is private or not.. you'll then have to go down this road.

/* Output:
Name: 'eth0' Addr: 'xxx.xxx.xxx.xxx'
Name: 'eth0:0' Addr: 'xxx.xxx.xxx.xxx'
*/
struct ifaddrs *ifaddr;
char ip[255];
if (getifaddrs(&ifaddr) == -1)
{
//sprintf(ip[0], "%s", strerror(errno));
}
else
{
struct ifaddrs *ifa;
int i = 0, family;
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL)
{
continue;
}
family = ifa->ifa_addr->sa_family;
if (family == AF_INET || family == AF_INET6)
{
if(!(ifa->ifa_flags & IFF_LOOPBACK) && (family == AF_INET) && getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), ip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == 0)
{
printf("Name: '%s' Addr: '%s'\n", ifa->ifa_name, ip);
}
}
}
}
freeifaddrs(ifaddr);

Related

Get all IP-Addresses in C

I have the following problem. I have to write a Plugin for Pidgin in the Language C. I am completely new to C.
I found the following Code.
WORD wVersionRequested;
WSADATA wsaData;
char name[255];
char* ip;
PHOSTENT hostinfo;
wVersionRequested = MAKEWORD( 2, 0 );
if ( WSAStartup( wVersionRequested, &wsaData ) == 0 ) {
if( gethostname ( name, sizeof(name)) == 0) {
if((hostinfo = gethostbyname(name)) != NULL) {
ip = inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list);
}
}
WSACleanup( );
}
I have the IP-Address
172.28.52.220
But because of my VMWare I also have the IP 10.0.1.3.
In my Plugin now the IP 10.0.1.3 is assigned to my variable.
i need the IP to find out in which location of my company I am. I need hte 172...
Now I could find in the winsock2.h that *hostinfo->h_addr_list contains the list of Ip addresses. How can I assign the 172. Address to my IP_Variable?
Thank you in advance for your help!
Edit:
Just to clarify: I donĀ“t want to have my external IP address. I need my internals.
Here is an example I tested on on linux. I dont have access to a Windows system until tomorrow, but can test and update the answer if required.
It is comparable to the Windows version only without the WSAStartup call at the beginning.
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <netdb.h>
int main()
{
char hostnamebuff[100];
if(gethostname(hostnamebuff, 100) == 0)
{
struct hostent* hostinfo = gethostbyname(hostnamebuff);
printf("host name is %s\n", hostnamebuff);
if(hostinfo != NULL)
{
char** paddrlist = hostinfo->h_addr_list;
printf("host list is\n");
while(*paddrlist != NULL)
{
char addrbuff[INET6_ADDRSTRLEN];
if(inet_ntop(hostinfo->h_addrtype, *paddrlist, addrbuff, hostinfo->h_addrtype == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN))
{
printf("%s\n", addrbuff);
if(strncmp(addrbuff, "172.", 4) == 0)
{
printf("its a match\n");
break;
}
} else
{
printf("failed to convert an address\n");
}
paddrlist++;
}
} else
{
printf("failed on gethostbyname\n");
}
} else
{
printf("failed on gethostname errno=%d\n", errno);
}
}
The h_addr_list member of hostent is a NULL terminated array of pointers to char* (so its double pointer). My example shows how to traverse this. Hope it helps.
As for this distinctly smelly bit of code
ip = inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list);
This is a highly unreadable way of getting the first entry in the address list.

C procedure entry point inet_ntop WS2_32.dll on XP?

I am getting an error on windows xp "The procedure entry point inet_ntop could not be located in the dynamic link library WS2_32.dll" and after some Googling I found that inet_ntop is not available in XP, so I made a Macro to use inet_ntoa instead. But it doesn't seem to be working, I still get the same error... Am I missing something?
char *get_ip(char *host)
{
struct hostent *hent;
int iplen = 39;
long errorcode;
char *ip = (char *)malloc(iplen + 1);
memset(ip, 0, iplen + 1);
if ((hent = gethostbyname(host)) == NULL)
{
perror("Could not get the IP address");
exit(1);
}
#if (_WIN32_WINNT >= 0x600)
if (inet_ntop(AF_INET, (void *)hent->h_addr_list[0], ip, iplen) == NULL)
{
perror("Could not resolve the host");
exit(1);
}
#else
ip = inet_ntoa(*((struct in_addr *)hent->h_addr_list[0]));
if (ip == NULL)
{
perror("Could not resolve the host");
exit(1);
}
#endif
return ip;
}
Your code needs to switch behaviour at runtime. Instead it uses conditional compilation which determines behaviour at compile time. Your #if code is evaluated at compile time. Not what you intended I expect. Only one of those branches is actually compiled. Again, not what you expected I am sure.
You need to use run time linking (LoadLibrary and GetProcAddress) and check the version of the OS at runtime to determine behaviour.

Get IP address of interface in Linux using pcap

Is there a way how to get an IP address of an interface in Linux using libpcap?
I have found this,
Get IP address of an interface on Linux, but that doesn't use pcap.
Also, in the pcap examples it is said that something like this should get your IP but it gives you your network address.
Using the pcap_findalldevs function:
#include <pcap/pcap.h>
#include <arpa/inet.h>
static char errbuf[PCAP_ERRBUF_SIZE];
int main() {
pcap_if_t *alldevs;
int status = pcap_findalldevs(&alldevs, errbuf);
if(status != 0) {
printf("%s\n", errbuf);
return 1;
}
for(pcap_if_t *d=alldevs; d!=NULL; d=d->next) {
printf("%s:", d->name);
for(pcap_addr_t *a=d->addresses; a!=NULL; a=a->next) {
if(a->addr->sa_family == AF_INET)
printf(" %s", inet_ntoa(((struct sockaddr_in*)a->addr)->sin_addr));
}
printf("\n");
}
pcap_freealldevs(alldevs);
return 0;
}
Output of sudo ./pcap:
eth0: 192.168.2.1
usbmon1:
usbmon2:
usbmon3:
usbmon4:
usbmon5:
any:
lo: 127.0.0.1

Getting gateway to use for a given ip in ANSI C

I have looked around like crazy but don't get a real answer. I got one example, but that depended on the individuals own library so not much good.
At first I wanted to get the default gateway of an interface, but since different IP's could be routed differently I quickly understood that what I want it get the gateway to use for a given destination IP by using an AF_ROUTE socket and the rtm_type RTM_GET.
Does anyone have an example where I actually end up with a string containing the gateways IP (or mac address)? The gateway entry seem to be in hex but also encoded in /proc/net/route, where I guess the AF_ROUTE socket get's it info from (but via the kernel I guess).
Thanx in advance
and p.s.
I just started using stack overflow and I must say, all of you guys are great! Fast replies and good ones! You are my new best friends ;)
This is OS specific, there's no unified(or ANSI C) API for this.
Assuming Linux, the best way is to just parse /proc/net/route , look for the entry where Destination is 00000000 , the default gateway is in the Gateway column , where you can read the hex representation of the gateway IP address (in big endian , I believe)
If you want to do this via more specific API calls, you'll have to go through quite some hoops, here's an example program:
#include <netinet/in.h>
#include <net/if.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define BUFSIZE 8192
char gateway[255];
struct route_info {
struct in_addr dstAddr;
struct in_addr srcAddr;
struct in_addr gateWay;
char ifName[IF_NAMESIZE];
};
int readNlSock(int sockFd, char *bufPtr, int seqNum, int pId)
{
struct nlmsghdr *nlHdr;
int readLen = 0, msgLen = 0;
do {
/* Recieve response from the kernel */
if ((readLen = recv(sockFd, bufPtr, BUFSIZE - msgLen, 0)) < 0) {
perror("SOCK READ: ");
return -1;
}
nlHdr = (struct nlmsghdr *) bufPtr;
/* Check if the header is valid */
if ((NLMSG_OK(nlHdr, readLen) == 0)
|| (nlHdr->nlmsg_type == NLMSG_ERROR)) {
perror("Error in recieved packet");
return -1;
}
/* Check if the its the last message */
if (nlHdr->nlmsg_type == NLMSG_DONE) {
break;
} else {
/* Else move the pointer to buffer appropriately */
bufPtr += readLen;
msgLen += readLen;
}
/* Check if its a multi part message */
if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0) {
/* return if its not */
break;
}
} while ((nlHdr->nlmsg_seq != seqNum) || (nlHdr->nlmsg_pid != pId));
return msgLen;
}
/* For printing the routes. */
void printRoute(struct route_info *rtInfo)
{
char tempBuf[512];
/* Print Destination address */
if (rtInfo->dstAddr.s_addr != 0)
strcpy(tempBuf, inet_ntoa(rtInfo->dstAddr));
else
sprintf(tempBuf, "*.*.*.*\t");
fprintf(stdout, "%s\t", tempBuf);
/* Print Gateway address */
if (rtInfo->gateWay.s_addr != 0)
strcpy(tempBuf, (char *) inet_ntoa(rtInfo->gateWay));
else
sprintf(tempBuf, "*.*.*.*\t");
fprintf(stdout, "%s\t", tempBuf);
/* Print Interface Name*/
fprintf(stdout, "%s\t", rtInfo->ifName);
/* Print Source address */
if (rtInfo->srcAddr.s_addr != 0)
strcpy(tempBuf, inet_ntoa(rtInfo->srcAddr));
else
sprintf(tempBuf, "*.*.*.*\t");
fprintf(stdout, "%s\n", tempBuf);
}
void printGateway()
{
printf("%s\n", gateway);
}
/* For parsing the route info returned */
void parseRoutes(struct nlmsghdr *nlHdr, struct route_info *rtInfo)
{
struct rtmsg *rtMsg;
struct rtattr *rtAttr;
int rtLen;
rtMsg = (struct rtmsg *) NLMSG_DATA(nlHdr);
/* If the route is not for AF_INET or does not belong to main routing table
then return. */
if ((rtMsg->rtm_family != AF_INET) || (rtMsg->rtm_table != RT_TABLE_MAIN))
return;
/* get the rtattr field */
rtAttr = (struct rtattr *) RTM_RTA(rtMsg);
rtLen = RTM_PAYLOAD(nlHdr);
for (; RTA_OK(rtAttr, rtLen); rtAttr = RTA_NEXT(rtAttr, rtLen)) {
switch (rtAttr->rta_type) {
case RTA_OIF:
if_indextoname(*(int *) RTA_DATA(rtAttr), rtInfo->ifName);
break;
case RTA_GATEWAY:
rtInfo->gateWay.s_addr= *(u_int *) RTA_DATA(rtAttr);
break;
case RTA_PREFSRC:
rtInfo->srcAddr.s_addr= *(u_int *) RTA_DATA(rtAttr);
break;
case RTA_DST:
rtInfo->dstAddr .s_addr= *(u_int *) RTA_DATA(rtAttr);
break;
}
}
//printf("%s\n", inet_ntoa(rtInfo->dstAddr));
if (rtInfo->dstAddr.s_addr == 0)
sprintf(gateway, (char *) inet_ntoa(rtInfo->gateWay));
//printRoute(rtInfo);
return;
}
int main()
{
struct nlmsghdr *nlMsg;
struct rtmsg *rtMsg;
struct route_info *rtInfo;
char msgBuf[BUFSIZE];
int sock, len, msgSeq = 0;
/* Create Socket */
if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
perror("Socket Creation: ");
memset(msgBuf, 0, BUFSIZE);
/* point the header and the msg structure pointers into the buffer */
nlMsg = (struct nlmsghdr *) msgBuf;
rtMsg = (struct rtmsg *) NLMSG_DATA(nlMsg);
/* Fill in the nlmsg header*/
nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); // Length of message.
nlMsg->nlmsg_type = RTM_GETROUTE; // Get the routes from kernel routing table .
nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; // The message is a request for dump.
nlMsg->nlmsg_seq = msgSeq++; // Sequence of the message packet.
nlMsg->nlmsg_pid = getpid(); // PID of process sending the request.
/* Send the request */
if (send(sock, nlMsg, nlMsg->nlmsg_len, 0) < 0) {
printf("Write To Socket Failed...\n");
return -1;
}
/* Read the response */
if ((len = readNlSock(sock, msgBuf, msgSeq, getpid())) < 0) {
printf("Read From Socket Failed...\n");
return -1;
}
/* Parse and print the response */
rtInfo = (struct route_info *) malloc(sizeof(struct route_info));
//fprintf(stdout, "Destination\tGateway\tInterface\tSource\n");
for (; NLMSG_OK(nlMsg, len); nlMsg = NLMSG_NEXT(nlMsg, len)) {
memset(rtInfo, 0, sizeof(struct route_info));
parseRoutes(nlMsg, rtInfo);
}
free(rtInfo);
close(sock);
printGateway();
return 0;
}
Maybe this is very old question but I had same problem and I can't find better result. Finally I solved my problem with these code that it has a few changes. So I decide to share it.
char* GetGatewayForInterface(const char* interface)
{
char* gateway = NULL;
char cmd [1000] = {0x0};
sprintf(cmd,"route -n | grep %s | grep 'UG[ \t]' | awk '{print $2}'", interface);
FILE* fp = popen(cmd, "r");
char line[256]={0x0};
if(fgets(line, sizeof(line), fp) != NULL)
gateway = string(line);
pclose(fp);
}
I decided to go the "quick-and-dirty" way to start with and read out the ip from /proc/net/route using netstat -rm.
I thought I'd share my function... Note however that there is some error in it and prehaps you could help me find it and I'll edit this to be without faults. The function take a iface name like eth0 and returns the ip of the gateway used by that iface.
char* GetGatewayForInterface(const char* interface) {
char* gateway = NULL;
FILE* fp = popen("netstat -rn", "r");
char line[256]={0x0};
while(fgets(line, sizeof(line), fp) != NULL)
{
/*
* Get destination.
*/
char* destination;
destination = strndup(line, 15);
/*
* Extract iface to compare with the requested one
* todo: fix for iface names longer than eth0, eth1 etc
*/
char* iface;
iface = strndup(line + 73, 4);
// Find line with the gateway
if(strcmp("0.0.0.0 ", destination) == 0 && strcmp(iface, interface) == 0) {
// Extract gateway
gateway = strndup(line + 16, 15);
}
free(destination);
free(iface);
}
pclose(fp);
return gateway;
}
The problem with this function is that when I leave pclose in there it causes a memory corruption chrash. But it works if I remove the pclose call (but that would not be a good solution beacuse the stream would remain open.. hehe). So if anyone can spot the error I'll edit the function with the correct version. I'm no C guru and gets a bit confused about all the memory fiddling ;)

C Programming: Check if the IP address is added on any given NIC

Problem description:
I have a IP address (can be either IPv4/IPv6) and NIC address, how can I check if the IP address is added to the given NIC(or any NIC) using C.
I know it is simple to do the same on command line/using scripts, however I need to check the same in C Program.
Example:
IP - 192.168.0.1
NIC - eth0
Using command line(linux platform) the below command would tell me if the IP is added or not:
ip addr show | grep "192.168.0.1"
p.s.: Is there any library function which can be used to get similar outputs?
You want to use getifaddrs, which returns a list of network interfaces and the addresses associated with them.
From the man page:
int getifaddrs(struct ifaddrs **ifap);
The getifaddrs() function creates a linked list of structures
describing the network interfaces of the local system, and stores
the address of the first item of the list in *ifap. The list
consists of ifaddrs structures, defined as follows:
struct ifaddrs {
struct ifaddrs *ifa_next; /* Next item in list */
char *ifa_name; /* Name of interface */
unsigned int ifa_flags; /* Flags from SIOCGIFFLAGS */
struct sockaddr *ifa_addr; /* Address of interface */
struct sockaddr *ifa_netmask; /* Netmask of interface */
union {
struct sockaddr *ifu_broadaddr;
/* Broadcast address of interface */
struct sockaddr *ifu_dstaddr;
/* Point-to-point destination address */
} ifa_ifu;
#define ifa_broadaddr ifa_ifu.ifu_broadaddr
#define ifa_dstaddr ifa_ifu.ifu_dstaddr
void *ifa_data; /* Address-specific data */
};
Here's an example of how I've used it in one of my programs:
union sockaddr_u {
struct sockaddr_storage ss;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
};
struct iflist {
char name[IFNAME_LEN];
union sockaddr_u su;
int isloopback;
int ismulti;
int ifidx;
};
void getiflist(struct iflist *list, int *len)
{
struct ifaddrs *ifa, *ifa_tmp;
int count;
unsigned ifidx;
if (getifaddrs(&ifa) == -1) {
perror("getifaddrs failed");
*len = 0;
return;
}
ifa_tmp = ifa;
count = *len;
*len = 0;
while (ifa_tmp && (*len < count)) {
if ((ifidx = if_nametoindex(ifa_tmp->ifa_name)) == 0) {
perror("Error getting interface index for interface %s",
ifa_tmp->ifa_name);
continue;
}
if (ifa_tmp->ifa_addr && ((ifa_tmp->ifa_addr->sa_family == AF_INET) ||
(ifa_tmp->ifa_addr->sa_family == AF_INET6)) &&
((ifa_tmp->ifa_flags & IFF_UP) != 0)) {
memset(&list[*len], 0, sizeof(struct iflist));
strncpy(list[*len].name, ifa_tmp->ifa_name,
sizeof(list[*len].name) - 1);
memcpy(&list[*len].su, ifa_tmp->ifa_addr,
sizeof(struct sockaddr_storage));
list[*len].isloopback = (ifa_tmp->ifa_flags & IFF_LOOPBACK) != 0;
list[*len].ismulti = (ifa_tmp->ifa_flags & IFF_MULTICAST) != 0;
list[*len].ifidx = ifidx;
(*len)++;
}
ifa_tmp = ifa_tmp->ifa_next;
}
freeifaddrs(ifa);
}
You may want to use GETIFADDRS http://man7.org/linux/man-pages/man3/getifaddrs.3.html
This should Work:
#define _BSD_SOURCE
#include <ifaddrs.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<netdb.h>
int main(void){
struct ifaddrs *ip, *hosst;
int s;
char host[NI_MAXHOST];
if (getifaddrs(&ip) == -1){
perror("getifaddrs");
return 1;
}
for (hosst = ip; hosst != NULL; hosst = hosst->ifa_next){
if (hosst->ifa_addr == NULL){
continue;
}
s=getnameinfo(hosst->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if((strcmp(hosst->ifa_name,"wlan0")==0)&&(hosst->ifa_addr->sa_family==AF_INET)){
if (s != 0){
printf("getnameinfo() failed: %s\n", gai_strerror(s));
return 1;
}
printf("IP - %s\n", host);
printf("NIC - %s\n",hosst->ifa_name );
}
}
free(ip);
return 0;
}
Output:
IP - 192.168.0.110
NIC - wlan0
The method(GETIFADDRS) suggested above is correct solution for the stated problem description. The getifaddrs browses through all the IP's on the NIC.
However in my case there are many IP's addresses added on the NIC/system and I am OK with knowing if the IP is present in any of the NIC. I found a easier/faster solution.
To check if the IP is added on any of the NIC card of the machine, just open a TCP socket and bind with port=zero(0) and the IP address to be checked. The successful bind will suggest that the IP is available/present.
Note: This works if IP is added on any of the NIC card in the system. The port zero should be used instead of hard-coding as it selects any available port on in the system
(ref. http://compnetworking.about.com/od/tcpip/p/port-numbers-0.htm)
This method is tested for both IPv4/IPv6 in UNIX environment(rhel)
PS:Do not forget to close the socket after verifying the presence of IP

Resources