I have a problem displaying my CAN ID . I'm sending out a message via the CAN bus , which has the ID 0x18FF11F3 . My program receives this message and also all data fields , only the ID does not match exactly
void set_can_listener(uint16 *s16_Socket, struct can_frame *Frame) {
/* Create the socket */
*s16_Socket = socket(PF_CAN, SOCK_RAW, CAN_RAW);
/* Locate the interface you wish to use */
struct ifreq t_Ifr;
strcpy(t_Ifr.ifr_name, "can0");
ioctl(*s16_Socket, SIOCGIFINDEX, &t_Ifr); /* Ifr.ifr_ifindex gets filled with that device's index*/
/* Select that CAN interface, and bind the socket to it.*/
struct sockaddr_can t_Addr;
t_Addr.can_family = AF_CAN;
t_Addr.can_ifindex = t_Ifr.ifr_ifindex;
bind(*s16_Socket, (struct sockaddr*) &t_Addr, sizeof(t_Addr));
}
void can_listener(uint16 *s16_Socket, struct can_frame *Frame) {
/* Read message from CAN */
unsigned int i;
uint16 s16_BytesRead = read(*s16_Socket, Frame, sizeof(*Frame));
if (s16_BytesRead >= 0) {
printf("\nMessage received!\nID: 0x%X\nDLC: %X\n", Frame->can_id,
Frame->can_dlc);
}
}
My Output looks like:
Message received!
ID: 0x98FF11F3
DLC: 8
You are reading ID with CAN_EFF_FLAG filter set, define as
#define CAN_EFF_FLAG 0x80000000U
HERE
The code is ok and received messages are ok. Sender has EFF filter enabled on the socket.
THIS link can explain you all about SocketCAN
Related
For a school project i made this program where clients (a tcpsock_t) can make a TCP connection with a server and pass data through it. I poll the different connections to see if there is data to read.
I got a tcpsock.c with functions for the TCP sockets which is used as library, a connmgr.c as server and a client code (which is not relevant).
In the tcpsock.h i typedef the struct of the tcpsock_t
(other functions below)
typedef struct tcpsock tcpsock_t;
and in the tcpsock.c i declare the struct (and it should stay here, i can not put it in de .h file)
struct tcpsock{
long cookie;
int sd;
char * ip_addr;
int port;
};
In the connmgr.c i want to make an array of this tcpsock_t to store all my connected clients, but when i compile it gives always the same sort of errors:
error: invalid use of undefined type ‘struct tcpsock’
client[conn_counter] = *requestclient;
Can someone tell me what i'm doing wrong?
Thanks a lot!
Here is my server code :
#include "tcpsock.h"
#include "connmgr.h"
int conn_counter = 0;
void add_client(tcpsock_t *newclient, tcpsock_t * array){
conn_counter++;
array= realloc(test,sizeof(get_size_tcpsock())*conn_counter);
array[conn_counter-1]=*newclient; //here i have the error
}
void add_poll(struct pollfd * polllist, tcpsock_t *client, tcpsock_t *server){
polllist = realloc(polllist,sizeof(struct pollfd)*conn_counter+1);
int clientsd;
tcp_get_sd(server, &clientsd);
polllist[conn_counter].fd= clientsd;
polllist[conn_counter].events = POLLIN;
}
int main(void){
tcpsock_t *server;
tcpsock_t *client;
client = malloc(sizeof(get_size_tcpsock()));
struct pollfd *poll_list;
poll_list = malloc(sizeof(struct pollfd));
sensor_data_t data;
int bytes,result;
if(tcp_passive_open(&server,PORT)!=TCP_NO_ERROR)exit(EXIT_FAILURE);
int serversd;
tcp_get_sd(server, &serversd);
poll_list[0].fd = serversd;
poll_list[0].events = POLLIN;
printf("start polling \n");
while(1){
int retval,i;
retval = poll(poll_list,conn_counter+1,5000);
if (retval>0){
if(poll_list[0].revents && POLLIN>0){
tcpsock_t *requestclient;
tcp_wait_for_connection(server,&requestclient);
client[conn_counter] = *requestclient; //here i have the error
add_client(requestclient,client);
add_poll(poll_list, requestclient, server);
}
for (i=0; i<conn_counter+1;i++){
if(poll_list[i+1].revents & POLLIN){
bytes = sizeof(data.id);
result = tcp_receive(client[i],(void *)&data.id,&bytes); //here i have the error
bytes = sizeof(data.value);
result = tcp_receive(client[i],(void *)&data.value,&bytes); //here i have the error
bytes = sizeof(data.ts);
result =tcp_receive(client[i],(void *)&data.ts,&bytes); //here i have the error
if ((result==TCP_NO_ERROR) && bytes){
printf("sensor id = %" PRIu16 " - temperature = %g - timestamp = %ld\n", data.id, data.value, (long int)data.ts);
}
fflush(stdout);
}
if (poll_list[i+1].revents & POLLHUP){
printf("client disconnected \n");
poll_list[conn_counter+1].fd=-1;
poll_list[conn_counter+1].events=0;
fflush(stdout);
}
}
}
}
tcp_close(&server);
return 1;
}
Here is the tcpsock.h, but the functions work fine.
typedef struct tcpsock tcpsock_t;
int get_size_tcpsock();
int tcp_passive_open(tcpsock_t ** socket, int port);
/* Creates a new socket and opens this socket in 'passive listening mode' (waiting for an active connection setup request)
* The socket is bound to port number 'port' and to any active IP interface of the system
*/
int tcp_active_open(tcpsock_t ** socket, int remote_port, char * remote_ip);
/* Creates a new TCP socket and opens a TCP connection to the system with IP address 'remote_ip' on port 'remote_port'
* The newly created socket is return as '*socket'
*/
int tcp_close(tcpsock_t ** socket);
int tcp_wait_for_connection(tcpsock_t * socket, tcpsock_t ** new_socket);
/* Puts the socket 'socket' in a blocking wait mode
* Returns when an incoming TCP connection setup request is received
* A newly created socket identifying the remote system that initiated the connection request is returned as '*new_socket'
*/
int tcp_send(tcpsock_t * socket, void * buffer, int * buf_size );
/* Initiates a send command on the socket 'socket' and tries to send the total '*buf_size' bytes of data in 'buffer' (recall that the function might block for a while)
* The function sets '*buf_size' to the number of bytes that were really sent, which might be less than the initial '*buf_size'
*/
int tcp_get_ip_addr( tcpsock_t * socket, char ** ip_addr);
/* Set '*ip_addr' to the IP address of 'socket' (could be NULL if the IP address is not set)
*/
int tcp_get_port(tcpsock_t * socket, int * port);
int tcp_get_sd(tcpsock_t * socket, int * sd);
How can I get the interface name for the IP address in linux from C code ?
e.g. I'd like to get the interface name ( like etho , eth1 , l0 ) assigned for the IP address 192.168.0.1
Using /proc/net/arp you can match it. Here is a command line tool example.
usage: getdevicebyip 192.168.0.1
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char **argv){
if (argc < 2) return 1;
FILE *fp = fopen("/proc/net/arp", "r");
char ip[99], hw[99], flags[99], mac[99], mask[99], dev[99], dummy[99];
fgets(dummy, 99, fp); //header line
while (fscanf(fp, "%s %s %s %s %s %s\n", ip, hw, flags, mac, mask, dev) != EOF)
if (!strcmp(argv[1],ip))
printf("%s\n",dev);
return 0;
}
You can use getifaddrs. See man 3 getifaddrs for usage information. This will only work on a Unix-like systems.
netlink is a way to do this on Linux. I think it might even be a proper way to do it on Linux (even though it isn't portable).
The strategy is:
Get a list of addresses on interfaces from the kernel by sending a netlink message.
Find the address you want (I have hard coded the one I want as address_dq) and record its interface (a number at this stage)
Get a list of interfaces by sending another netlink message,
Find the number of the interface matching the number you recorded in step (2).
Get the name of the interface.
The code below is not pretty, but I'm sure you could do a better job of it. I have been a especially sloppy by not checking for a multipart message (checking for the NLM_F_MULTI flag and for a message type of NLMSG_DONE is the way to do it). Instead I have just assumed the response to the first message is multipart -- it is on my machine -- and chewed up the NLMSG_DONE message which follows.
Code...
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, void ** argv) {
// This is the address we want the interface name for,
// expressed in dotted-quad format
char * address_dq = "127.0.0.1";
// Convert it to decimal format
unsigned int address;
inet_pton(AF_INET, address_dq, &address);
char buf[16384];
// Our first message will be a header followed by an address payload
struct {
struct nlmsghdr nlhdr;
struct ifaddrmsg addrmsg;
} msg;
// Our second message will be a header followed by a link payload
struct {
struct nlmsghdr nlhdr;
struct ifinfomsg infomsg;
} msg2;
struct nlmsghdr *retmsg;
// Set up the netlink socket
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
// Fill in the message
// NLM_F_REQUEST means we are asking the kernel for data
// NLM_F_ROOT means provide all the addresses
// RTM_GETADDR means we want address information
// AF_INET means limit the response to ipv4 addresses
memset(&msg, 0, sizeof(msg));
msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
msg.nlhdr.nlmsg_type = RTM_GETADDR;
msg.addrmsg.ifa_family = AF_INET;
// As above, but RTM_GETLINK means we want link information
memset(&msg2, 0, sizeof(msg2));
msg2.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
msg2.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
msg2.nlhdr.nlmsg_type = RTM_GETLINK;
msg2.infomsg.ifi_family = AF_UNSPEC;
// Send the first netlink message
send(sock, &msg, msg.nlhdr.nlmsg_len, 0);
int len;
// Get the netlink reply
len = recv(sock, buf, sizeof(buf), 0);
retmsg = (struct nlmsghdr *)buf;
// Loop through the reply messages (one for each address)
// Each message has a ifaddrmsg structure in it, which
// contains the prefix length as a member. The ifaddrmsg
// structure is followed by one or more rtattr structures,
// some of which (should) contain raw addresses.
while NLMSG_OK(retmsg, len) {
struct ifaddrmsg *retaddr;
retaddr = (struct ifaddrmsg *)NLMSG_DATA(retmsg);
int iface_idx = retaddr->ifa_index;
struct rtattr *retrta;
retrta = (struct rtattr *)IFA_RTA(retaddr);
int attlen;
attlen = IFA_PAYLOAD(retmsg);
char pradd[128];
// Loop through the routing information to look for the
// raw address.
while RTA_OK(retrta, attlen) {
if (retrta->rta_type == IFA_ADDRESS) {
// Found one -- is it the one we want?
unsigned int * tmp = RTA_DATA(retrta);
if (address == *tmp) {
// Yes!
inet_ntop(AF_INET, RTA_DATA(retrta), pradd, sizeof(pradd));
printf("Address %s ", pradd);
// Now we need to get the interface information
// First eat up the "DONE" message waiting for us
len = recv(sock, buf, sizeof(buf), 0);
// Send the second netlink message and get the reply
send(sock, &msg2, msg2.nlhdr.nlmsg_len, 0);
len = recv(sock, buf, sizeof(buf), 0);
retmsg = (struct nlmsghdr *)buf;
while NLMSG_OK(retmsg, len) {
struct ifinfomsg *retinfo;
retinfo = NLMSG_DATA(retmsg);
if (retinfo->ifi_index == iface_idx) {
retrta = IFLA_RTA(retinfo);
attlen = IFLA_PAYLOAD(retmsg);
char prname[128];
// Loop through the routing information
// to look for the interface name.
while RTA_OK(retrta, attlen) {
if (retrta->rta_type == IFLA_IFNAME) {
strcpy(prname, RTA_DATA(retrta));
printf("on %s\n", prname);
exit(EXIT_SUCCESS);
}
retrta = RTA_NEXT(retrta, attlen);
}
}
retmsg = NLMSG_NEXT(retmsg, len);
}
}
}
retrta = RTA_NEXT(retrta, attlen);
}
retmsg = NLMSG_NEXT(retmsg, len);
}
}
When run as above, returns Address 127.0.0.1 on lo.
Using "192.168.1.x" instead of "127.0.0.1" it instead returns Address 192.168.1.x on eth0.
Read the question carefully in order to propose a solution, please
I need to add permanent arp entry in Linux somehow.
The problem is: if I add an entry via shell, or via sockets, it always gets flag 0x6. Even if I use the code posted downhere, where I specify the flag, it remains the same, 0x6.
I found this information about 0x6 flag:
Notice the ARP flag of "0x6". The ASIC ARP entry with flag 0x6 is
MAC-cache related entry. It is caused by arp lookup failure when
installing the session. The session will try to use the source MAC
address of incoming packet, but it is not necessary for using this mac
address. We can get the MAC address when the reply packet arrives by
sending an ARP packet to the source host.
So anytime I add any arp entry, then I ping the same ip address, it always results in ARP request broadcast.
The question is, is there a way how to add a permanent ARP entry with proper flag? So I add an entry, and in case of any comunication afterwards, there wont be any ARP broadcast?
Btw, to get into what I am up to: I am sending a broadcast(L3) from PC1 containing PC1's IP and MAC, PC2 gets the packet and add addresses them into ARP table and establish TCP session, but always first run ARP broadcast.
via shell:
#!/bin/sh
arp -s $1 $2 2>/dev/null
via sockets:
char *mac_ntoa(unsigned char *ptr){
static char address[30];
sprintf(address, "%02X:%02X:%02X:%02X:%02X:%02X",
ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
return(address);
} /* End of mac_ntoa */
int mac_aton(char *addr, unsigned char *ptr){
int i, v[6];
if((i = sscanf(addr, "%x:%x:%x:%x:%x:%x", &v[0], &v[1], &v[2], &v[3],
&v[4], &v[5])) !=6){
fprintf(stderr, "arp: invalid Ethernet address '%s'\n", addr);
return(1);
} /* End of If*/
for(i = 0; i < 6; i++){
ptr[i] = v[i];
} /* End of For */
return(0);
}
int main(int argc, char* argv[]){
if(argc < 3 || argc > 4){
fprintf(stderr,"usage: %s <ip_addr> <hw_addr> [temp|pub|perm|trail]\n",
argv[0]);
fprintf(stderr, "default: temp.\n");
exit(-1);
} /* End of If */
int s, flags;
char *host = argv[1];
struct arpreq req;
struct hostent *hp;
struct sockaddr_in *sin;
bzero((caddr_t)&req, sizeof(req)); /* caddr_t is not really needed. */
sin = (struct sockaddr_in *)&req.arp_pa;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = inet_addr(host);
if(sin->sin_addr.s_addr ==-1){
if(!(hp = gethostbyname(host))){
fprintf(stderr, "arp: %s ", host);
herror((char *)NULL);
return(-1);
} /* End of If */
bcopy((char *)hp->h_addr,
(char *)&sin->sin_addr, sizeof(sin->sin_addr));
} /* End of If */
if(mac_aton(argv[2], req.arp_ha.sa_data)){ /* If address is valid... */
return(-1);
}
argc -=2;
argv +=2;
flags = ATF_PERM | ATF_COM;
while(argc-- > 0){
if(!(strncmp(argv[0], "temp", 4))){
flags &= ~ATF_PERM;
} else if(!(strncmp(argv[0], "pub", 3))){
flags |= ATF_PUBL;
} else if(!(strncmp(argv[0], "trail", 5))){
flags |= ATF_USETRAILERS;
} else if(!(strncmp(argv[0], "dontpub", 7))){ /* Not working yet */
flags |= ATF_DONTPUB;
} else if(!(strncmp(argv[0], "perm", 4))){
flags = ATF_PERM;
} else {
flags &= ~ATF_PERM;
} /* End of Else*/
argv++;
}/* End of While */
req.arp_flags = flags; /* Finally, asign the flags to the structure */
strcpy(req.arp_dev, "eth0"); /* Asign the device. */
if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
perror("socket() failed.");
exit(-1);
} /* End of If */
if(ioctl(s, SIOCSARP, (caddr_t)&req) <0){ /* caddr_t not really needed. */
perror(host);
exit(-1);
} /* End of If */
printf("ARP cache entry successfully added.\n");
close(s);
return(0);
}
0x06 flag value means the entry is complete and permanent. So I guess your shell script is good enough to add a static arp entry. Here is the relevant flag values -
#define ATF_COM 0x02 /* completed entry (ha valid) */
#define ATF_PERM 0x04 /* permanent entry */
The definition of flag 0x06 that you posted is not related to the linux kernel.
The reason you're seeing an arp request may be due to problems in your topology or IP addressing. Can you post those details? Or you could post the packet trace where PC2 does an arp request even when it has a static arp entry.
I'm trying to forge an IGMPv2 Membership Request packet and send it on a RAW socket.
The RFC 3376 states:
IGMP messages are encapsulated in IPv4 datagrams, with an IP protocol number of 2. Every IGMP message described in this document is sent with an IP Time-to-Live of 1, IP Precedence of Internetwork Control (e.g., Type of Service 0xc0), and carries an IP Router Alert option [RFC-2113] in its IP header
So the IP_ROUTER_ALERT flag must be set.
I'm trying to forge the strict necessary of the packet (e.g. only the IGMP header & payload), so i'm using the setsockopt to edit the IP options.
some useful variables:
#define C_IP_MULTICAST_TTL 1
#define C_IP_ROUTER_ALERT 1
int sockfd = 0;
int ecsockopt = 0;
int bytes_num = 0;
int ip_multicast_ttl = C_IP_MULTICAST_TTL;
int ip_router_alert = C_IP_ROUTER_ALERT;
Here's how I open the RAW socket:
sock_domain = AF_INET;
sock_type = SOCK_RAW;
sock_proto = IPPROTO_IGMP;
if ((ecsockopt = socket(sock_domain,sock_type,sock_proto)) < 0) {
printf("Error %d: Can't open socket.\n", errno);
return 1;
} else {
printf("** Socket opened.\n");
}
sockfd = ecsockopt;
Then I set the TTL and Router Alert option:
// Set the sent packets TTL
if((ecsockopt = setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ip_multicast_ttl, sizeof(ip_multicast_ttl))) < 0) {
printf("Error %d: Can't set TTL.\n", ecsockopt);
return 1;
} else {
printf("** TTL set.\n");
}
// Set the Router Alert
if((ecsockopt = setsockopt(sockfd, IPPROTO_IP, IP_ROUTER_ALERT, &ip_router_alert, sizeof(ip_router_alert))) < 0) {
printf("Error %d: Can't set Router Alert.\n", ecsockopt);
return 1;
} else {
printf("** Router Alert set.\n");
}
The setsockopt of IP_ROUTER_ALERT returns 0. After forging the packet, i send it with sendto in this way:
// Send the packet
if((bytes_num = sendto(sockfd, packet, packet_size, 0, (struct sockaddr*) &mgroup1_addr, sizeof(mgroup1_addr))) < 0) {
printf("Error %d: Can't send Membership report message.\n", bytes_num);
return 1;
} else {
printf("** Membership report message sent. (bytes=%d)\n",bytes_num);
}
The packet is sent, but the IP_ROUTER_ALERT option (checked with wireshark) is missing.
Am i doing something wrong? is there some other methods to set the IP_ROUTER_ALERT option?
Thanks in advance.
Finally i've found out that the IP_ROUTER_ALERT has to be set by the Linux Kernel. IGMP membership requests are sent after a IP_ADD_MEMBERSHIP is done and the Kernel takes charge of setting the IP_ROUTER_ALERT flag.
I do not know why your code is not working (it looks fine to me), but I can suggest a workaround: Drop one more layer down on your raw socket and build Ethernet frames. You may also want to take a look at Libnet, which handles building packets like this for you.
The documentation states:
Pass all to-be forwarded packets with
the IP Router Alert option set to this
socket. Only valid for raw sockets.
This is useful, for instance, for user
space RSVP daemons. The tapped packets
are not forwarded by the kernel, it is
the users responsibility to send them
out again. Socket binding is ignored,
such packets are only filtered by
protocol. Expects an integer flag.
This sounds as if the option only matters when receiving packets on the socket, not when sending them. If you're sending raw packets, can't you just set the required option in the IP header yourself?
As a reference I would recommend one of the many IGMP aware programs out there.
One example is igmpproxy:
https://github.com/ViToni/igmpproxy/blob/logging/src/igmp.c#L54
/*
* Open and initialize the igmp socket, and fill in the non-changing
* IP header fields in the output packet buffer.
*/
void initIgmp(void) {
struct ip *ip;
recv_buf = malloc(RECV_BUF_SIZE);
send_buf = malloc(RECV_BUF_SIZE);
k_hdr_include(true); /* include IP header when sending */
k_set_rcvbuf(256*1024,48*1024); /* lots of input buffering */
k_set_ttl(1); /* restrict multicasts to one hop */
k_set_loop(false); /* disable multicast loopback */
ip = (struct ip *)send_buf;
memset(ip, 0, sizeof(struct ip));
/*
* Fields zeroed that aren't filled in later:
* - IP ID (let the kernel fill it in)
* - Offset (we don't send fragments)
* - Checksum (let the kernel fill it in)
*/
ip->ip_v = IPVERSION;
ip->ip_hl = (sizeof(struct ip) + 4) >> 2; /* +4 for Router Alert option */
ip->ip_tos = 0xc0; /* Internet Control */
ip->ip_ttl = MAXTTL; /* applies to unicasts only */
ip->ip_p = IPPROTO_IGMP;
allhosts_group = htonl(INADDR_ALLHOSTS_GROUP);
allrouters_group = htonl(INADDR_ALLRTRS_GROUP);
alligmp3_group = htonl(INADDR_ALLIGMPV3_GROUP);
}
and https://github.com/ViToni/igmpproxy/blob/logging/src/igmp.c#L271
/*
* Construct an IGMP message in the output packet buffer. The caller may
* have already placed data in that buffer, of length 'datalen'.
*/
static void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, int datalen) {
struct ip *ip;
struct igmp *igmp;
extern int curttl;
ip = (struct ip *)send_buf;
ip->ip_src.s_addr = src;
ip->ip_dst.s_addr = dst;
ip_set_len(ip, IP_HEADER_RAOPT_LEN + IGMP_MINLEN + datalen);
if (IN_MULTICAST(ntohl(dst))) {
ip->ip_ttl = curttl;
} else {
ip->ip_ttl = MAXTTL;
}
/* Add Router Alert option */
((unsigned char*)send_buf+MIN_IP_HEADER_LEN)[0] = IPOPT_RA;
((unsigned char*)send_buf+MIN_IP_HEADER_LEN)[1] = 0x04;
((unsigned char*)send_buf+MIN_IP_HEADER_LEN)[2] = 0x00;
((unsigned char*)send_buf+MIN_IP_HEADER_LEN)[3] = 0x00;
igmp = (struct igmp *)(send_buf + IP_HEADER_RAOPT_LEN);
igmp->igmp_type = type;
igmp->igmp_code = code;
igmp->igmp_group.s_addr = group;
igmp->igmp_cksum = 0;
igmp->igmp_cksum = inetChksum((unsigned short *)igmp,
IP_HEADER_RAOPT_LEN + datalen);
}
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