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
Related
I have a NXP FRDM-K64F board and I want to set the ethernet example but I cannot get it working. This is how my code looks like after setting the static IP address.
#include "mbed.h"
#include "main-hw.h"
#include "EthernetInterface.h"
// Network interface
EthernetInterface net;
int main(void)
{
// Bring up the ethernet interface
printf("Ethernet socket example\r\n");
int ret;
ret = net.set_network("192.168.15.177","255.255.255.0","192.168.15.1");
printf("Set Net: %d\r\n",ret);
char macadd[6];
mbed_mac_address(macadd);
printf("%02x:%02x:%02x:%02x:%02x:%02x \r\n", macadd[0], macadd[1], macadd[2], macadd[3], macadd[4], macadd[5]);
const char *mac = net.get_mac_address();
printf("MAC address is: %s\r\n", mac ? mac : "No MAC");
const char *ip = net.get_ip_address();
printf("IP address is: %s\r\n", ip ? ip : "No IP");
ret = net.connect();
printf("Connect: %d\n",ret);
// Show the network address
// const char *ip = net.get_ip_address();
// printf("IP address is: %s\n", ip ? ip : "No IP");
// Open a socket on the network interface, and create a TCP connection to mbed.org
TCPSocket socket;
socket.open(&net);
socket.connect("developer.mbed.org", 80);
// Send a simple http request
char sbuffer[] = "GET / HTTP/1.1\r\nHost: developer.mbed.org\r\n\r\n";
int scount = socket.send(sbuffer, sizeof sbuffer);
printf("sent %d [%.*s]\n", scount, strstr(sbuffer, "\r\n")-sbuffer, sbuffer);
// Recieve a simple http response and print out the response line
char rbuffer[64];
int rcount = socket.recv(rbuffer, sizeof rbuffer);
printf("recv %d [%.*s]\n", rcount, strstr(rbuffer, "\r\n")-rbuffer, rbuffer);
// Close the socket to return its memory and bring down the network interface
socket.close();
// Bring down the ethernet interface
net.disconnect();
printf("Done\n");
return 0;
}
What I see is that I only get the macAddress with the mbed_mac_address command. With net.get_mac_address and net.get_ip_address I only get NULL values.
The process get to the net.connect and I see no more results.
What am I doing wrong?
With mbed OS 5.3.4 this works fine for me on a K64F:
#include "mbed.h"
#include "EthernetInterface.h"
// Network interface
EthernetInterface net;
// Socket demo
int main() {
// Set static IP
net.set_network("192.168.1.99", "255.255.255.0", "192.168.1.1");
// Bring up the ethernet interface
printf("Ethernet socket example\n");
net.connect();
// Show the network address
const char *ip = net.get_ip_address();
printf("IP address is: %s\n", ip ? ip : "No IP");
printf("MAC address is: %s\n", net.get_mac_address());
// Open a socket on the network interface, and create a TCP connection to mbed.org
TCPSocket socket;
socket.open(&net);
socket.connect("developer.mbed.org", 80);
// Send a simple http request
char sbuffer[] = "GET / HTTP/1.1\r\nHost: developer.mbed.org\r\n\r\n";
int scount = socket.send(sbuffer, sizeof sbuffer);
printf("sent %d [%.*s]\n", scount, strstr(sbuffer, "\r\n")-sbuffer, sbuffer);
// Recieve a simple http response and print out the response line
char rbuffer[64];
int rcount = socket.recv(rbuffer, sizeof rbuffer);
printf("recv %d [%.*s]\n", rcount, strstr(rbuffer, "\r\n")-rbuffer, rbuffer);
// Close the socket to return its memory and bring down the network interface
socket.close();
// Bring down the ethernet interface
net.disconnect();
printf("Done\n");
}
Updating mbed OS
If you still have the mbed library (not mbed-os) in the online compiler, right click on 'mbed', and click 'Remove'. Then click on 'Add library' > 'From URL' and enter https://github.com/armmbed/mbed-os.
If you have mbed-os, right click on the library and select 'Upgrade'.
From mbed CLI:
$ mbed remove mbed
$ mbed add mbed-os
Or when you already have mbed-os:
$ cd mbed-os
$ git pull
$ git checkout latest
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.
Hi I am new to Linux and have a project related to sockets. The problem I'm facing is that when I run the code with inputs eth0 for interface and ip address of my router i.e
./mycode eth0 192.168.1.1 it gives an error
You don't have permission to capture on that device (socket: Operation not permitted)
The code I took from a link is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pcap.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <net/ethernet.h>
#include <netinet/if_ether.h>
#include <sys/ioctl.h>
int main(int argc,const char* argv[]) {
// Get interface name and target IP address from command line.
if (argc<2) {
fprintf(stderr,"usage: send_arp <interface> <ipv4-address>\n");
exit(1);
}
const char* if_name=argv[1];
const char* target_ip_string=argv[2];
// Construct Ethernet header (except for source MAC address).
// (Destination set to broadcast address, FF:FF:FF:FF:FF:FF.)
struct ether_header header;
header.ether_type=htons(ETH_P_ARP);
memset(header.ether_dhost,0xff,sizeof(header.ether_dhost));
// Construct ARP request (except for MAC and IP addresses).
struct ether_arp req;
req.arp_hrd=htons(ARPHRD_ETHER);
req.arp_pro=htons(ETH_P_IP);
req.arp_hln=ETHER_ADDR_LEN;
req.arp_pln=sizeof(in_addr_t);
req.arp_op=htons(ARPOP_REQUEST);
memset(&req.arp_tha,0,sizeof(req.arp_tha));
// Convert target IP address from string, copy into ARP request.
struct in_addr target_ip_addr={0};
if (!inet_aton(target_ip_string,&target_ip_addr)) {
fprintf(stderr,"%s is not a valid IP address",target_ip_string);
exit(1);
}
memcpy(&req.arp_tpa,&target_ip_addr.s_addr,sizeof(req.arp_tpa));
// Write the interface name to an ifreq structure,
// for obtaining the source MAC and IP addresses.
struct ifreq ifr;
size_t if_name_len=strlen(if_name);
if (if_name_len<sizeof(ifr.ifr_name)) {
memcpy(ifr.ifr_name,if_name,if_name_len);
ifr.ifr_name[if_name_len]=0;
} else {
fprintf(stderr,"interface name is too long");
exit(1);
}
// Open an IPv4-family socket for use when calling ioctl.
int fd=socket(AF_INET,SOCK_DGRAM,0);
if (fd==-1) {
perror(0);
exit(1);
}
// Obtain the source IP address, copy into ARP request
if (ioctl(fd,SIOCGIFADDR,&ifr)==-1) {
perror(0);
close(fd);
exit(1);
}
struct sockaddr_in* source_ip_addr = (struct sockaddr_in*)&ifr.ifr_addr;
memcpy(&req.arp_spa,&source_ip_addr->sin_addr.s_addr,sizeof(req.arp_spa));
// Obtain the source MAC address, copy into Ethernet header and ARP request.
if (ioctl(fd,SIOCGIFHWADDR,&ifr)==-1) {
perror(0);
close(fd);
exit(1);
}
if (ifr.ifr_hwaddr.sa_family!=ARPHRD_ETHER) {
fprintf(stderr,"not an Ethernet interface");
close(fd);
exit(1);
}
const unsigned char* source_mac_addr=(unsigned char*)ifr.ifr_hwaddr.sa_data;
memcpy(header.ether_shost,source_mac_addr,sizeof(header.ether_shost));
memcpy(&req.arp_sha,source_mac_addr,sizeof(req.arp_sha));
close(fd);
// Combine the Ethernet header and ARP request into a contiguous block.
unsigned char frame[sizeof(struct ether_header)+sizeof(struct ether_arp)];
memcpy(frame,&header,sizeof(struct ether_header));
memcpy(frame+sizeof(struct ether_header),&req,sizeof(struct ether_arp));
// Open a PCAP packet capture descriptor for the specified interface.
char pcap_errbuf[PCAP_ERRBUF_SIZE];
pcap_errbuf[0]='\0';
pcap_t* pcap=pcap_open_live(if_name,96,0,0,pcap_errbuf);
if (pcap_errbuf[0]!='\0') {
fprintf(stderr,"%s\n",pcap_errbuf);
}
if (!pcap) {
exit(1);
}
// Write the Ethernet frame to the interface.
if (pcap_inject(pcap,frame,sizeof(frame))==-1) {
pcap_perror(pcap,0);
pcap_close(pcap);
exit(1);
}
// Close the PCAP descriptor.
pcap_close(pcap);
return 0;
}
You need root permissions to do that. Trying running your program as root.
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);
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