I'm attempting to poll networking device names. I've pieced this together from various snippets,
http://unixhelp.ed.ac.uk/CGI/man-cgi?netdevice+7
http://lists.apple.com/archives/Unix-porting/2002/Apr/msg00134.html
http://ubuntuforums.org/showthread.php?t=1421487
But my output is just gibberish.
#include <stdio.h>
#include <stdlib.h>
#include <net/route.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#define BUFLEN 1024
#define SEQ 9999
int main (int argc, const char* argv[])
{
// File descriptor for socket
int socketfd;
struct ifconf conf;
struct ifreq req[10];
struct ifreq *ifr;
printf("Opening socket...");
socketfd = socket(AF_ROUTE, SOCK_RAW, 0);
if (socketfd >= 0) {
printf(" OK\n");
conf.ifc_len = sizeof(req);
conf.ifc_buf = (__caddr_t) req;
ioctl(socketfd,SIOCGIFCONF,&conf);
printf("Discovering interfaces...\n");
int i;
for (i=0; i<conf.ifc_len/sizeof(req[0]); i++) {
ifr = &conf.ifc_req[i];
printf("%d. %s\n", i+1, req[i].ifr_name);
}
}
else {
printf("Failed!\n");
}
return 0;
}
Output:
Opening socket... OK
Discovering interfaces...
?u???}??Gh???
2. p?9}?
3.
4. v?=?n??u?`?y??]g?<?~?v??
5.
6.
7.
8. ?v?T?
9. ?|?mw??j??v??h??|??v?T00~??v?$?|??|?#
10. T00~??v?$?|??|?#
I tried outputting each char of the ifr_name array one-by-one to see if they were null terminated but that didn't change much. Each iteration of my program outputs something different so this leads me to think I'm referencing something wrong. Can someone provide me some insight as to what I may be doing wrong?
Here's some code I put together for Mac OS X:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <netinet/in.h>
/* This is defined on Mac OS X */
#ifndef _SIZEOF_ADDR_IFREQ
#define _SIZEOF_ADDR_IFREQ sizeof
#endif
int main (int argc, const char* argv[])
{
// File descriptor for socket
int socketfd;
struct ifconf conf;
char data[4096];
struct ifreq *ifr;
char addrbuf[1024];
int i;
printf("Opening socket...");
socketfd = socket(AF_INET, SOCK_DGRAM, 0);
if (socketfd >= 0) {
printf(" OK\n");
conf.ifc_len = sizeof(data);
conf.ifc_buf = (caddr_t) data;
if (ioctl(socketfd,SIOCGIFCONF,&conf) < 0) {
perror("ioctl");
}
printf("Discovering interfaces...\n");
i = 0;
ifr = (struct ifreq*)data;
while ((char*)ifr < data+conf.ifc_len) {
switch (ifr->ifr_addr.sa_family) {
case AF_INET:
++i;
printf("%d. %s : %s\n", i, ifr->ifr_name, inet_ntop(ifr->ifr_addr.sa_family, &((struct sockaddr_in*)&ifr->ifr_addr)->sin_addr, addrbuf, sizeof(addrbuf)));
break;
#if 0
case AF_INET6:
++i;
printf("%d. %s : %s\n", i, ifr->ifr_name, inet_ntop(ifr->ifr_addr.sa_family, &((struct sockaddr_in6*)&ifr->ifr_addr)->sin6_addr, addrbuf, sizeof(addrbuf)));
break;
#endif
}
ifr = (struct ifreq*)((char*)ifr +_SIZEOF_ADDR_IFREQ(*ifr));
}
close(socketfd);
}
else {
printf(" Failed!\n");
}
return 0;
}
Poll as in you want to be notified if an interface is added or removed? Or polled as in you just want to find out the interface names once from the system? If the latter, take a look at getifaddrs().
Please see http://git.netfilter.org/cgi-bin/gitweb.cgi?p=libmnl.git;a=blob;f=examples/rtnl/rtnl-link-dump.c;hb=HEAD on how to get the list of interfaces on Linux. AF_ROUTE is some BSD thing and the use of ioctl is discouraged on Linux for its apparent limitations (such as to convey multiple addresses on a single interface).
Related
I have a basic server-client program that I'm writing in C and I am stuck with an issue regarding strings and concatenation.
Basically I have some strings (in the example below just 2) that I have to put into a buffer which size is determined by:
total # of registered people * 33
Both the strings in the example have a length which is much less than the length of the buffer. I want to obtain something like this after the concatenation:
[0] [32]
people_list=Mark Amy\0;
where Mark(which is inserted secondly) is right at the start of the buffer (people_list) and Amy is 32 characters away from the start of Mark (I hope I've made myself clear).
This is because the client code was given to me and I cannot modify it. The client code takes the buffer and reads the first element, then jumps of 32 chars and reads again.
The output I get from the printf of the client is this:
connected to server
Registered people:
Mark
while I'd like this:
connected to server
Registered people:
Mark
Amy
The communication is implemented through sockets, which I have already checked, but if you wish to suggest some changes I would appreciate that.
Server code:
#include <stdio.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#define LENGTH 32
struct person {
char name[LENGTH+1];
struct person *next;
struct person *prev;
};
struct person *p_head = NULL;
void addPerson(char* name_p){
struct person *new = (struct person*) malloc(sizeof(struct person));
strcpy(new->name, name_p);
new->name[LENGTH]='\0';
new->next=p_head;
new->prev=NULL;
p_head=new;
}
int main(){
int fd_ser;
int fd_c;
int N=100;
char buf[N];
int times=0;
char* path="tmp/sock";
struct sockaddr_un sa;
unlink(path);
sa.sun_family=AF_UNIX;
strncpy(sa.sun_path,(char*) path, sizeof(sa.sun_path));
if((fd_ser=socket(AF_UNIX,SOCK_STREAM,0))<0){ //socket
perror((const char*) (size_t) errno);
exit(EXIT_FAILURE);
}
if ( bind(fd_ser,(struct sockaddr *)&sa, sizeof(sa))<0){
perror("bind\n");
}
listen(fd_ser,10); //listen
struct sockaddr_un addr;
int addr_size= sizeof(struct sockaddr_un);
fd_c=0;
while( (fd_c=accept(fd_ser,(struct sockaddr*) &addr, (socklen_t*)&addr_size))<0){
printf("waiting for connections...\n");
sleep(2);
}
//initialize list of people
char* Amy="Amy";
char* Mark="Mark";
addPerson(Amy);
addPerson(Mark);
//now concat the name strings in a buffer to be sent to the client
char* people_list;
unsigned int list_len;
int value;
struct person* ptr=(struct person*) malloc(sizeof(struct person));
ptr=p_head;
int offset=0;
int i=0;
while(ptr!=NULL){
i++;
people_list=realloc(people_list,i*LENGTH); //every single name has to be LENGTH characters
strcpy(&people_list[offset],ptr->name);
ptr=ptr->next;
offset=offset+LENGTH;
}
people_list[i*LENGTH]='\0';
list_len=(i*LENGTH)+1;
value=write(fd_c, &(list_len), sizeof(unsigned int));
if(value==-1){
perror("write length");
return -1;
}
int toWrite=list_len;
char *toRead=people_list;
while(toWrite>0){
value=write(fd_c, toRead, toWrite);
if(value==-1){
perror("write data");
return -1;
}
toWrite=toWrite-value;
toRead=toRead+value;
if(toRead<=people_list + list_len) break;
}
close(fd_c);
close(fd_ser);
return 0;
}
Client code:
#include <stdio.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <assert.h>
#include <errno.h>
#define MAX_LENGTH 2048
#define LENGTH 32
int main(){
int fd_cli;
char* path="tmp/sock";
struct sockaddr_un sa;
sa.sun_family=AF_UNIX;
strncpy(sa.sun_path,(char*) path, sizeof(sa.sun_path));
if( (fd_cli = socket(AF_UNIX, SOCK_STREAM, 0))==-1){
perror((const char*) (size_t) errno);
return -1;
}
while( (connect(fd_cli,(struct sockaddr*)&sa, sizeof(struct sockaddr_un))) == -1 ) {
if ( errno == ENOENT ) { sleep(1); }
else perror("connect:");
errno=0;
sleep(1);
}
printf("connected to server\n");
int value;
unsigned int len_data;
value=read(fd_cli,&(len_data),sizeof(unsigned int));
if(value==-1){
perror("read length");
return -1;
}
char* buffer=malloc(len_data*sizeof(char));
int toRead=len_data;
char *toWrite=buffer;
while(toRead>0){
value=read(fd_cli, toWrite, toRead);
if(value==-1){
perror("read buffer");
return -1;
}
toRead=toRead-value;
toWrite=toWrite+value;
if(toWrite<=buffer + len_data) break;
}
int people_n = len_data / (LENGTH+1);
assert(people_n > 0); //proceeds only if there is at least one person registered
printf("Registered people:\n");
for(int i=0,p=0;i<people_n; ++i, p+=(LENGTH+1)) {
printf(" %s\n", &buffer[p]);
}
close(fd_cli);
return 0;
}
I really hope I've explained the problem clearly! Thank you for your help!
It's printing only the first user (Mark) because of this line:
int people_n = len_data / (LENGTH+1);
In this example, len_data = 65, LENGTH = 32. So when you are adding 1 to LENGTH, it will return 1 (65/33 = 1.96 => you get 1). Then it only prints the first user.
Consider using Valgrind. It will help you checking the use of the memory.
i'm writing a server/client c program based on AX.25 protocol.
The server creating the socket, binding Successfully and listening for coming connections.
the client running in a different thread but fails on connect with " No route to host"
Server code
#include <sys/socket.h>
#include <netax25/ax25.h>
#include <netax25/axlib.h>
#include <netax25/axconfig.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <syslog.h>
#include <sys/types.h>
#include <linux/socket.h>
#include <stdlib.h>
#include <sys/un.h>
#include <string.h>
#include <errno.h>
int main(int argc,char **argv,char **envp) {
int ax25_socket = -1;
unsigned char buffer[512];
struct full_sockaddr_ax25 addr, axconnect ;
char *port ="3";// sm0 port number:3
char *call = "OH2BNS-8";// sm0 callsign
bzero((char *) &addr, sizeof(struct full_sockaddr_ax25));
addr.fsa_ax25.sax25_family = AF_AX25;
addr.fsa_ax25.sax25_ndigis = 1;
if (ax25_config_load_ports() == 0) {
printf( "Problem with axports file");
//return -1;
}
char* ax25port = (char*) ax25_config_get_addr(port);
ax25_aton_entry( call, addr.fsa_ax25.sax25_call.ax25_call);
ax25_aton_entry( ax25port, addr.fsa_digipeater[0].ax25_call);
ax25_socket = socket(AF_AX25, SOCK_SEQPACKET, 0);
if (ax25_socket < -1)
printf( "error in create socket");
if (bind(ax25_socket, (struct sockaddr *)&addr, sizeof(struct full_sockaddr_ax25)) < 0) {
perror("bind--");
return -1;
}
if(listen(ax25_socket,2) != 0)
{
printf("cannot listen on socket!\n");
close(ax25_socket);
return 0;
}
puts("listening");
//bzero((char *) &axconnect, sizeof(struct full_sockaddr_ax25));
int len =sizeof(struct full_sockaddr_ax25);
int temp_sock_desc = accept(ax25_socket, (struct sockaddr*)&axconnect, &len);
if (temp_sock_desc == -1)
{
printf("cannot accept client!\n");
close(ax25_socket);
return 0;
}
return 0;
}
Client code
#include <sys/socket.h>
#include <netax25/ax25.h>
#include <netax25/axlib.h>
#include <netax25/axconfig.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <syslog.h>
#include <sys/types.h>
#include <linux/socket.h>
#include <stdlib.h>
#include <sys/un.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int ax25_socket = -1;
unsigned char buffer[512];
struct full_sockaddr_ax25 axconnect ;
char *port ="3";// sm0 port number:3
char *call ="OH2BNS-8";// sm0 callsign
bzero((char *) &axconnect, sizeof(struct full_sockaddr_ax25));
axconnect.fsa_ax25.sax25_family = AF_AX25;
axconnect.fsa_ax25.sax25_ndigis = 1;
if (ax25_config_load_ports() == 0) {
printf( "Problem with axports file");
//return -1;
}
char* ax25port = (char*) ax25_config_get_addr(port);
ax25_aton_entry( call, axconnect.fsa_ax25.sax25_call.ax25_call);
ax25_aton_entry( ax25port, axconnect.fsa_digipeater[0].ax25_call);
ax25_socket = socket(AF_AX25, SOCK_SEQPACKET, 0);
if (ax25_socket < -1)
printf( "error in create socket");
if (connect(ax25_socket, (struct sockaddr *)&axconnect, sizeof(struct full_sockaddr_ax25)) != 0) {
perror("--");
switch (errno) {
case ECONNREFUSED:
printf("*** Connection refused\r");
break;
case ENETUNREACH:
printf("*** No known route\r");
break;
case EINTR:
printf("*** Connection timed out\r");
break;
default:
printf("ERROR: cannot connect to AX.25 callsign\r");
break;
}
close(ax25_socket);
}
printf("Connected!!\r");
int n = write(ax25_socket,"Message!!!!",18);
if(n = -1)
{
perror("write--");
}
return 0;
}
Simply put, a " No route to host"" would mean that there is no route for the server IP address in the client's routing table. Are you able to ping the server's IP address? Most likely you should not be able to and ping should say that the server is not reachable. If so, then this error has nothing to do with your program, you are probably running into a connectivity issue.
Can you find the entry for your server in the output of "route -n". If there is none, then you should check for a bigger prefix for the subnet of the server. If that also is not present, then you should confirm that you have a default route setup.
To further confirm, I would do the following two tests. First, what happens if you try to run the client/server on the same box? Second, what happens if you try to run the client/server on two boxes (present in the same subnet) and on the same LAN? If you do not see this issue and your application works just fine, then this should confirm that you are running into a connectivity issue.
I know this is an old question, but I would suspect a problem with ax25port - should be something like YOURCALL-0 where YOURCALL matches the HWaddr of an existing ax25 port ( try /sbin/ifconfig | fgrep AX.25
How can I get the IPv4 address of an interface on Linux from C code?
For example, I'd like to get the IP address (if any) assigned to eth0.
Try this:
#include <stdio.h>
#include <unistd.h>
#include <string.h> /* for strncpy */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
int
main()
{
int fd;
struct ifreq ifr;
fd = socket(AF_INET, SOCK_DGRAM, 0);
/* I want to get an IPv4 IP address */
ifr.ifr_addr.sa_family = AF_INET;
/* I want IP address attached to "eth0" */
strncpy(ifr.ifr_name, "eth0", IFNAMSIZ-1);
ioctl(fd, SIOCGIFADDR, &ifr);
close(fd);
/* display result */
printf("%s\n", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
return 0;
}
The code sample is taken from here.
In addition to the ioctl() method Filip demonstrated you can use getifaddrs(). There is an example program at the bottom of the man page.
If you're looking for an address (IPv4) of the specific interface say wlan0 then
try this code which uses getifaddrs():
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.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)
{
if (ifa->ifa_addr == NULL)
continue;
s=getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if((strcmp(ifa->ifa_name,"wlan0")==0)&&(ifa->ifa_addr->sa_family==AF_INET))
{
if (s != 0)
{
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf("\tInterface : <%s>\n",ifa->ifa_name );
printf("\t Address : <%s>\n", host);
}
}
freeifaddrs(ifaddr);
exit(EXIT_SUCCESS);
}
You can replace wlan0 with eth0 for ethernet and lo for local loopback.
The structure and detailed explanations of the data structures
used could be found here.
To know more about linked list in C this page will be a good starting point.
My 2 cents: the same code works even if iOS:
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
showIP();
}
void showIP()
{
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)
{
if (ifa->ifa_addr == NULL)
continue;
s=getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if( /*(strcmp(ifa->ifa_name,"wlan0")==0)&&( */ ifa->ifa_addr->sa_family==AF_INET) // )
{
if (s != 0)
{
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf("\tInterface : <%s>\n",ifa->ifa_name );
printf("\t Address : <%s>\n", host);
}
}
freeifaddrs(ifaddr);
}
#end
I simply removed the test against wlan0 to see data.
ps You can remove "family"
I have been in the same issue recently, and this is the code I made up and it works. Make sure to use the name of the network interface, exactly as you have it (could be "eth0" or else).
gotta check if ifconfigcommand beforehand to get the interface name and use it in C.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h>
#include <linux/if.h>
#include <errno.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void extract_ipaddress()
{
//create an ifreq struct for passing data in and out of ioctl
struct ifreq my_struct;
//declare and define the variable containing the name of the interface
char *interface_name="enp0s3"; //a very frequent interface name is "eth0";
//the ifreq structure should initially contains the name of the interface to be queried. Which should be copied into the ifr_name field.
//Since this is a fixed length buffer, one should ensure that the name does not cause an overrun
size_t interface_name_len=strlen(interface_name);
if(interface_name_len<sizeof(my_struct.ifr_name))
{
memcpy(my_struct.ifr_name,interface_name,interface_name_len);
my_struct.ifr_name[interface_name_len]=0;
}
else
{
perror("Copy name of interface to ifreq struct");
printf("The name you provided for the interface is too long...\n");
}
//provide an open socket descriptor with the address family AF_INET
/* ***************************************************************
* All ioctl call needs a file descriptor to act on. In the case of SIOCGIFADDR this must refer to a socket file descriptor. This socket must be in the address family that you wish to obtain (AF_INET for IPv4)
* ***************************************************************
*/
int file_descriptor=socket(AF_INET, SOCK_DGRAM,0);
if(file_descriptor==-1)
{
perror("Socket file descriptor");
printf("The construction of the socket file descriptor was unsuccessful.\n");
return -1;
}
//invoke ioctl() because the socket file descriptor exists and also the struct 'ifreq' exists
int myioctl_call=ioctl(file_descriptor,SIOCGIFADDR,&my_struct);
if (myioctl_call==-1)
{
perror("ioctl");
printf("Ooops, error when invoking ioctl() system call.\n");
close(file_descriptor);
return -1;
}
close(file_descriptor);
/* **********************************************************************
* If this completes without error , then the hardware address of the interface should have been returned in the 'my_struct.ifr_addr' which is types as struct sockaddr_in.
* ***********************************************************************/
//extract the IP Address (IPv4) from the my_struct.ifr_addr which has the type 'ifreq'
/* *** Cast the returned address to a struct 'sockaddr_in' *** */
struct sockaddr_in * ipaddress= (struct sockaddr_in *)&my_struct.ifr_addr;
/* *** Extract the 'sin_addr' field from the data type (struct) to obtain a struct 'in_addr' *** */
printf("IP Address is %s.\n", inet_ntoa(ipaddress->sin_addr));
}
If you don't mind the binary size, you can use iproute2 as library.
iproute2-as-lib
Pros:
No need to write the socket layer code.
More or even more information about network interfaces can be got. Same functionality with the iproute2 tools.
Simple API interface.
Cons:
iproute2-as-lib library size is big. ~500kb.
I found a quite easy way to get ip, by take advantage of using bash command:
hostname -I
but use "hostname -I" natively will print the result on screen, we need to use "popen()" to read result out and save it into a string, here is c code:
#include <stdio.h> // popen
#include "ip_common_def.h"
const char * get_ip()
{
// Read out "hostname -I" command output
FILE *fd = popen("hostname -I", "r");
if(fd == NULL) {
fprintf(stderr, "Could not open pipe.\n");
return NULL;
}
// Put output into a string (static memory)
static char buffer[IP_BUFFER_LEN];
fgets(buffer, IP_BUFFER_LEN, fd);
// Only keep the first ip.
for (int i = 0; i < IP_BUFFER_LEN; ++i)
{
if (buffer[i] == ' ')
{
buffer[i] = '\0';
break;
}
}
char *ret = malloc(strlen(buffer) + 1);
memcpy(ret, buffer, strlen(buffer));
ret[strlen(buffer)] = '\0';
printf("%s\n", ret);
return ret;
}
I am working on Ubuntu. How can I get MAC address of my machine or an interface say eth0 using C program.
Much nicer than all this socket or shell madness is simply using sysfs for this:
the file /sys/class/net/eth0/address carries your mac adress as simple string you can read with fopen()/fscanf()/fclose(). Nothing easier than that.
And if you want to support other network interfaces than eth0 (and you probably want), then simply use opendir()/readdir()/closedir() on /sys/class/net/.
You need to iterate over all the available interfaces on your machine, and use ioctl with SIOCGIFHWADDR flag to get the mac address. The mac address will be obtained as a 6-octet binary array. You also want to skip the loopback interface.
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
int main()
{
struct ifreq ifr;
struct ifconf ifc;
char buf[1024];
int success = 0;
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock == -1) { /* handle error*/ };
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) { /* handle error */ }
struct ifreq* it = ifc.ifc_req;
const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));
for (; it != end; ++it) {
strcpy(ifr.ifr_name, it->ifr_name);
if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) {
if (! (ifr.ifr_flags & IFF_LOOPBACK)) { // don't count loopback
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) {
success = 1;
break;
}
}
}
else { /* handle error */ }
}
unsigned char mac_address[6];
if (success) memcpy(mac_address, ifr.ifr_hwaddr.sa_data, 6);
}
You want to take a look at the getifaddrs(3) manual page. There is an example in C in the manpage itself that you can use. You want to get the address with the type AF_LINK.
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
int main()
{
struct ifreq s;
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
strcpy(s.ifr_name, "eth0");
if (0 == ioctl(fd, SIOCGIFHWADDR, &s)) {
int i;
for (i = 0; i < 6; ++i)
printf(" %02x", (unsigned char) s.ifr_addr.sa_data[i]);
puts("\n");
return 0;
}
return 1;
}
Using getifaddrs you can get MAC address from the family AF_PACKET.
In order to display the MAC address to each interface, you can proceed like this:
#include <stdio.h>
#include <ifaddrs.h>
#include <netpacket/packet.h>
int main (int argc, const char * argv[])
{
struct ifaddrs *ifaddr=NULL;
struct ifaddrs *ifa = NULL;
int i = 0;
if (getifaddrs(&ifaddr) == -1)
{
perror("getifaddrs");
}
else
{
for ( ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if ( (ifa->ifa_addr) && (ifa->ifa_addr->sa_family == AF_PACKET) )
{
struct sockaddr_ll *s = (struct sockaddr_ll*)ifa->ifa_addr;
printf("%-8s ", ifa->ifa_name);
for (i=0; i <s->sll_halen; i++)
{
printf("%02x%c", (s->sll_addr[i]), (i+1!=s->sll_halen)?':':'\n');
}
}
}
freeifaddrs(ifaddr);
}
return 0;
}
Ideone
I have just write one and test it on gentoo in virtualbox.
// get_mac.c
#include <stdio.h> //printf
#include <string.h> //strncpy
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h> //ifreq
#include <unistd.h> //close
int main()
{
int fd;
struct ifreq ifr;
char *iface = "enp0s3";
unsigned char *mac = NULL;
memset(&ifr, 0, sizeof(ifr));
fd = socket(AF_INET, SOCK_DGRAM, 0);
ifr.ifr_addr.sa_family = AF_INET;
strncpy(ifr.ifr_name , iface , IFNAMSIZ-1);
if (0 == ioctl(fd, SIOCGIFHWADDR, &ifr)) {
mac = (unsigned char *)ifr.ifr_hwaddr.sa_data;
//display mac address
printf("Mac : %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n" , mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
close(fd);
return 0;
}
Assuming that c++ code (c++11) is okay as well and the interface is known.
#include <cstdint>
#include <fstream>
#include <streambuf>
#include <regex>
using namespace std;
uint64_t getIFMAC(const string &ifname) {
ifstream iface("/sys/class/net/" + ifname + "/address");
string str((istreambuf_iterator<char>(iface)), istreambuf_iterator<char>());
if (str.length() > 0) {
string hex = regex_replace(str, std::regex(":"), "");
return stoull(hex, 0, 16);
} else {
return 0;
}
}
int main()
{
string iface = "eth0";
printf("%s: mac=%016llX\n", iface.c_str(), getIFMAC(iface));
}
On Linux, use the service of "Network Manager" over the DBus.
There is also good'ol shell program which can be invoke and the result grabbed (use an exec function under C):
$ /sbin/ifconfig | grep HWaddr
A very portable way is to parse the output of this command.
ifconfig | awk '$0 ~ /HWaddr/ { print $5 }'
Provided ifconfig can be run as the current user (usually can) and awk is installed (it often is). This will give you the mac address of the machine.
Expanding on the answer given by #user175104 ...
std::vector<std::string> GetAllFiles(const std::string& folder, bool recursive = false)
{
// uses opendir, readdir, and struct dirent.
// left as an exercise to the reader, as it isn't the point of this OP and answer.
}
bool ReadFileContents(const std::string& folder, const std::string& fname, std::string& contents)
{
// uses ifstream to read entire contents
// left as an exercise to the reader, as it isn't the point of this OP and answer.
}
std::vector<std::string> GetAllMacAddresses()
{
std::vector<std::string> macs;
std::string address;
// from: https://stackoverflow.com/questions/9034575/c-c-linux-mac-address-of-all-interfaces
// ... just read /sys/class/net/eth0/address
// NOTE: there may be more than one: /sys/class/net/*/address
// (1) so walk /sys/class/net/* to find the names to read the address of.
std::vector<std::string> nets = GetAllFiles("/sys/class/net/", false);
for (auto it = nets.begin(); it != nets.end(); ++it)
{
// we don't care about the local loopback interface
if (0 == strcmp((*it).substr(-3).c_str(), "/lo"))
continue;
address.clear();
if (ReadFileContents(*it, "address", address))
{
if (!address.empty())
{
macs.push_back(address);
}
}
}
return macs;
}
netlink socket is possible
man netlink(7) netlink(3) rtnetlink(7) rtnetlink(3)
#include <assert.h>
#include <stdio.h>
#include <linux/if.h>
#include <linux/rtnetlink.h>
#include <unistd.h>
#define SZ 8192
int main(){
// Send
typedef struct {
struct nlmsghdr nh;
struct ifinfomsg ifi;
} Req_getlink;
assert(NLMSG_LENGTH(sizeof(struct ifinfomsg))==sizeof(Req_getlink));
int fd=-1;
fd=socket(AF_NETLINK,SOCK_RAW,NETLINK_ROUTE);
assert(0==bind(fd,(struct sockaddr*)(&(struct sockaddr_nl){
.nl_family=AF_NETLINK,
.nl_pad=0,
.nl_pid=getpid(),
.nl_groups=0
}),sizeof(struct sockaddr_nl)));
assert(sizeof(Req_getlink)==send(fd,&(Req_getlink){
.nh={
.nlmsg_len=NLMSG_LENGTH(sizeof(struct ifinfomsg)),
.nlmsg_type=RTM_GETLINK,
.nlmsg_flags=NLM_F_REQUEST|NLM_F_ROOT,
.nlmsg_seq=0,
.nlmsg_pid=0
},
.ifi={
.ifi_family=AF_UNSPEC,
// .ifi_family=AF_INET,
.ifi_type=0,
.ifi_index=0,
.ifi_flags=0,
.ifi_change=0,
}
},sizeof(Req_getlink),0));
// Receive
char recvbuf[SZ]={};
int len=0;
for(char *p=recvbuf;;){
const int seglen=recv(fd,p,sizeof(recvbuf)-len,0);
assert(seglen>=1);
len += seglen;
if(((struct nlmsghdr*)p)->nlmsg_type==NLMSG_DONE||((struct nlmsghdr*)p)->nlmsg_type==NLMSG_ERROR)
break;
p += seglen;
}
struct nlmsghdr *nh=(struct nlmsghdr*)recvbuf;
for(;NLMSG_OK(nh,len);nh=NLMSG_NEXT(nh,len)){
if(nh->nlmsg_type==NLMSG_DONE)
break;
struct ifinfomsg *ifm=(struct ifinfomsg*)NLMSG_DATA(nh);
printf("#%d ",ifm->ifi_index);
#ifdef _NET_IF_H
#pragma GCC error "include <linux/if.h> instead of <net/if.h>"
#endif
// Part 3 rtattr
struct rtattr *rta=IFLA_RTA(ifm); // /usr/include/linux/if_link.h
int rtl=RTM_PAYLOAD(nh);
for(;RTA_OK(rta,rtl);rta=RTA_NEXT(rta,rtl))switch(rta->rta_type){
case IFLA_IFNAME:printf("%s ",(const char*)RTA_DATA(rta));break;
case IFLA_ADDRESS:
printf("hwaddr ");
for(int i=0;i<5;++i)
printf("%02X:",*((unsigned char*)RTA_DATA(rta)+i));
printf("%02X ",*((unsigned char*)RTA_DATA(rta)+5));
break;
case IFLA_BROADCAST:
printf("bcast ");
for(int i=0;i<5;++i)
printf("%02X:",*((unsigned char*)RTA_DATA(rta)+i));
printf("%02X ",*((unsigned char*)RTA_DATA(rta)+5));
break;
case IFLA_PERM_ADDRESS:
printf("perm ");
for(int i=0;i<5;++i)
printf("%02X:",*((unsigned char*)RTA_DATA(rta)+i));
printf("%02X ",*((unsigned char*)RTA_DATA(rta)+5));
break;
}
printf("\n");
}
close(fd);
fd=-1;
return 0;
}
Example
#1 lo hwaddr 00:00:00:00:00:00 bcast 00:00:00:00:00:00
#2 eth0 hwaddr 57:da:52:45:5b:1a bcast ff:ff:ff:ff:ff:ff perm 57:da:52:45:5b:1a
#3 wlan0 hwaddr 3c:7f:46:47:58:c2 bcast ff:ff:ff:ff:ff:ff perm 3c:7f:46:47:58:c2
This is a Bash line that prints all available mac addresses, except the loopback:
for x in `ls /sys/class/net |grep -v lo`; do cat /sys/class/net/$x/address; done
Can be executed from a C program.
I need to display all the IP addresses from my local computer, using the C language. How can this be done?
#include <stdio.h>
#include <stropts.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/netdevice.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
int print_addresses(const int domain)
{
int s;
struct ifconf ifconf;
struct ifreq ifr[50];
int ifs;
int i;
s = socket(domain, SOCK_STREAM, 0);
if (s < 0) {
perror("socket");
return 0;
}
ifconf.ifc_buf = (char *) ifr;
ifconf.ifc_len = sizeof ifr;
if (ioctl(s, SIOCGIFCONF, &ifconf) == -1) {
perror("ioctl");
return 0;
}
ifs = ifconf.ifc_len / sizeof(ifr[0]);
printf("interfaces = %d:\n", ifs);
for (i = 0; i < ifs; i++) {
char ip[INET_ADDRSTRLEN];
struct sockaddr_in *s_in = (struct sockaddr_in *) &ifr[i].ifr_addr;
if (!inet_ntop(domain, &s_in->sin_addr, ip, sizeof(ip))) {
perror("inet_ntop");
return 0;
}
printf("%s - %s\n", ifr[i].ifr_name, ip);
}
close(s);
return 1;
}
int main(int argc, char *argv[])
{
int domains[] = { AF_INET, AF_INET6 };
int i;
for (i = 0; i < sizeof(domains) / sizeof(domains[0]); i++)
if (!print_addresses(domains[i]))
return 1;
return 0;
}
Your question might be imprecise but I am not sure why everyone is breaking your chops.
I think you are asking the basics in which case you probably want is getifaddrs. The man page has a little example program.
You can also get similar info using the SIOCGIFCONF option with ioctl(). There is some sample code on here and the web.
If you search around for these and similar terms you will find this question has been asked in various forms before. You have to dig around a bit.
Also note, these will not give you the public facing IP of your network if you are behind NAT.
Another way to do it in C. I do have to say though.... there are so many ways to do it from the shell, what's the point?
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <errno.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
void show_address_info( struct ifaddrs *ifa ){
struct sockaddr_in *s4;
struct sockaddr_in6 *s6;
/* ipv6 addresses have to fit in this buffer */
char buf[64];
if (AF_INET == ifa->ifa_addr->sa_family){
s4 = (struct sockaddr_in *)(ifa->ifa_addr);
if (NULL == inet_ntop(ifa->ifa_addr->sa_family, (void *)&(s4->sin_addr), buf, sizeof(buf))){
printf("%s: inet_ntop failed!\n", ifa->ifa_name);
} else {
printf("IPv4 addr %s: %s\n", ifa->ifa_name, buf);
}
}
else if (AF_INET6 == ifa->ifa_addr->sa_family) {
s6 = (struct sockaddr_in6 *)(ifa->ifa_addr);
if (NULL == inet_ntop(ifa->ifa_addr->sa_family, (void *)&(s6->sin6_addr), buf, sizeof(buf))) {
printf("%s: inet_ntop failed!\n", ifa->ifa_name);
} else {
printf("IPv6 addr %s: %s\n", ifa->ifa_name, buf);
}
}
}
int main(int argc, char **argv){
struct ifaddrs *myaddrs, *ifa;
int status;
status = getifaddrs(&myaddrs);
if (status != 0){
perror("getifaddrs failed!");
exit(1);
}
for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next){
if (NULL == ifa->ifa_addr){
continue;
}
if ((ifa->ifa_flags & IFF_UP) == 0) {
continue;
}
show_address_info(ifa);
}
freeifaddrs(myaddrs);
return 0;
}
How about you simply cheat and look at the source of /sbin/ifconfig/ ? Nothing wrong with standing on the shoulders of other giants...
Not a complete solution yet, but take a look in /proc/net!
dev lists the available interface devices by name,
route lists some routes, as does ipv6_route,
arp lists devices in the actual routing table (does not include localhost).
Not as high-tech as the other solution, but it can be done with simple file reading. Linux specific, though.
You need POSIX function getaddrinfo() - it returns linked list of all IP addresses.
See man getaddrinfo for details and examples.
$ sudo ifconfig | grep 'inet addr' | cut -d':' -f2 | cut -d' ' -f1
213.xx.xxx.xx
192.168.xx.x
127.0.0.1
And you can put that into popen():
/* not tested */
ph = popen("sudo ifconfig | grep 'inet addr' | cut -d':' -f2 | cut -d' ' -f1", "r");
while (fgets(buf, sizeof buf, ph)) {
/* ip address, in nul-terminated string format, is in `buf` */
}
pclose(ph);
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
/*
* Who sez?
* http://blog.stackoverflow.com/2010/01/stack-overflow-where-we-hate-fun/
*/
int main(int argc, char *argv[])
{
int status;
const char * const cmd = /* die from END is too chatty */
"/sbin/ifconfig -a | \
perl -lne \
'print $1 if /inet6? addr:\\s*(\\S+)/; \
END { $. > 0 or \
warn(\"no output from ifconfig\\n\"), \
exit 1; }'";
status = system(cmd);
if (status < 0) {
perror("system");
return 1;
}
else if (status != 0) {
const char *extra;
status = WEXITSTATUS(status);
extra = status == 127 ? " (is /bin/sh ok?)" : "";
fprintf(stderr, "%s: command failed with status %d%s\n",
argv[0], status, extra);
}
return 0;
}