iwlib.h Print BSSID of nearby Access Points - c

So recently I've been looking into Beacon Frames and 802.11 packets in C and came across iwlib.h in Linux. I made a tiny snippet of code to show all nearby networks and their SSID. Here is the code:
#include <stdio.h>
#include <iwlib.h>
int main() {
wireless_scan_head head;
wireless_scan *result;
int sockfd = iw_sockets_open();
iw_get_range_info(sockfd "wlan0", &range);
result = head.result
do {
printf ("%s\n", result->b.essid);
result = result->next;
} while(result != NULL);
return 0;
}
Is there any way of extracting the BSSID/AP MAC address using this code in such a way I can print it like FF:12:34:56:AB:CD or FF123456ABCD? Any help will be much appreciated! Many thanks.

Unfortunately, the support to read the Mac Address is disabled in iwlib, there is an API iw_get_mac_addr() but it's been disabled.
However the MAC address of a specific interface can be easily pulled using its socket descriptor.
The below C example code assumes the interface for WiFi has name "wlp3s0".
#include <stdio.h>
#include <time.h>
#include <iwlib.h>
int main(void) {
wireless_scan_head head;
wireless_scan *result;
iwrange range;
int sock;
struct ifreq s;
sock = iw_sockets_open();
if (iw_get_range_info(sock, "wlp3s0", &range) < 0) {
printf("Error during iw_get_range_info.\n");
exit(2);
}
if (iw_scan(sock, "wlp3s0", range.we_version_compiled, &head) < 0) {
printf("Error during iw_scan.\n");
exit(2);
}
strcpy(s.ifr_name, "wlp3s0");
if (0 == ioctl(sock, SIOCGIFHWADDR, &s)) {
int i;
for (i = 0; i < 6; ++i)
printf("%02x", (unsigned char) s.ifr_addr.sa_data[i]);
puts("\n");
}
result = head.result;
while (NULL != result) {
printf("%s\n", result->b.essid);
result = result->next;
}
exit(0);
}

Related

Issues printing a MAC address

A MAC address is parsed into an array of bytes (macaddr). The bytes are
printed with printf() one after another. The bytes are supposed to look as
pairs of hexadecimal characters. But some of them are padded with f
characters.
For example, for macaddr[3] it prints 'ffffffcc' rather than 'cc', i.e.
4 bytes instead of single byte. The rest of the array items are printed
correctly (macaddr[0] = 00, macaddr[1] = AA, macaddr[2] = BB,
etc.)
What's the problem?
Please help me to figure out what's wrong with the program.
#include <stdio.h>
#include <net/if.h> // struct ifconf
#include <errno.h>
#include <libnet.h>
#include <pcap.h>
#include <stdlib.h>
#include <unistd.h>
int getmacaddr() ;
int main(int argc, char *argv[])
{
getmacaddr();
}
int getmacaddr()
{
struct ifconf ifc;
struct ifreq *ifr;
int sfd;
int i;
int devnums;
char macaddr[ETHER_ADDR_LEN];
ifc.ifc_req = NULL;
sfd = socket(AF_INET,SOCK_DGRAM,0);
if(sfd == -1)
{
perror("socket : ");
return -1;
}
// get ifc.ifc_len
if(ioctl(sfd,SIOCGIFCONF,&ifc) == -1)
{
perror("ioctl - SIOCGIFCONF : ");
return -1;
}
devnums = ifc.ifc_len / sizeof(struct ifreq);
// malloc ifc.ifc_buf and get IFCONF list
ifc.ifc_buf = malloc(ifc.ifc_len);
memset(ifc.ifc_buf,0x0,ifc.ifc_len);
if(ioctl(sfd,SIOCGIFCONF,&ifc) == -1)
{
perror("ioctl - SIOCGIFCONF : ");
return -1;
}
for(i = 0; i < devnums; i++,ifc.ifc_req++)
{
// idfy dev
if( strcmp(ifc.ifc_req->ifr_ifrn.ifrn_name,"lo") && ifc.ifc_req->ifr_ifrn.ifrn_name != 0)
{
ifr = ifc.ifc_req;
// IP address
struct sockaddr_in *a = (struct sockaddr_in *) &ifr->ifr_addr;
printf("%s",inet_ntoa(a->sin_addr));
printf("\n");
//get IFHWADDR
if(ioctl(sfd,SIOCGIFHWADDR,ifr) == -1)
{
perror("ioctl - SIOCGIFHWADDR : ");
return -1;
}
}
}
memcpy(macaddr,ifr->ifr_hwaddr.sa_data,sizeof(macaddr));
for(i = 0; i < ETHER_ADDR_LEN; i++)
{
printf("%02x ",macaddr[i]);
}
printf("\n");
close(sfd);
// free(ifc.ifc_buf); <- ?? error
return 0;
}
EDIT
I've replaced the following line:
printf("%02x ",macaddr[i]);
with
printf("%02x ", (macaddr[i] & 0xff));
Try this:
printf("%02x ", (unsigned char)macaddr[i] & 0xff);
We specify the minimum field width in the format string. So to make sure that the value will look exactly as a single byte, you can leave only the first 16 bits by applying a bit mask.

pf_ring and libpcap if_index not returning

I have recently been getting involved with having to utilize pf_ring / libpcap. I have never developed with libpcap or pf_ring so please forgive what might appear to be a silly question, as network programming is semi new to me... In broad terms what I am trying to do is access the if_index for packets received. I currently have a simple raw packet sniffer created with "C" utilizing pf_ring as shown below:
#include <pcap.h>
#include <pfring.h>
#include <string.h>
#include <stdlib.h>
#define MAXBYTES2CAPTURE 2048
void processRingPacket(const struct pfring_pkthdr* pkthdr, const u_char* packet, const u_char *arg)
{
int i=0, *counter = (int*)arg;
printf("Packet Count: %d ", ++(*counter));
printf("Received Packet Size: %d ", pkthdr->len);
printf("ifIndex: %d ", pkthdr->extended_hdr.if_index);
printf("Payload:\n");
for(i=0; i < pkthdr->len; i++)
{
if(isprint(packet[i]))
{
printf("%c ", packet[i]);
}
else
{
printf(". ");
}
if((i % 16 == 0) && (i != 0) || (i == pkthdr->len-1))
{
printf("\n");
}
}
return;
}
int main()
{
int count = 0;
char *device = "eth0";
printf("Opening Device: %s\n", device);
pfring* ring = pfring_open(device, MAXBYTES2CAPTURE, 0);
pfring_enable_ring(ring);
pfring_loop(ring, processRingPacket, (u_char*)&count, 1);
return 0;
}
Looking at the pfring_pkthdr struct within the pf_ring API, I should be able to do the following:
pkthdr->extended_hdr.if_index
However, when I try to print out the index it just prints 0. I am guessing the if_index is not actually being set, as when I actually call the pf_ring function to get the device if index, I actually receive a value for the specified device:
pfring_get_device_ifindex (pfring *ring, char *device_name, int *if_index)
The problem is I am trying to view the if_index for each packet, hence within the call back function "processRingPacket" there is no way to generically specify the device. I say generically here because there will be two interfaces capturing packets. Any ideas on what my rookie mistake might be?
I think you need to pass in PF_RING_LONG_HEADER as a flag to pfring_open(). So it becomes, pfring_open(device, MAXBYTES2CAPTURE, PF_RING_LONG_HEADER);
If pkthdr->extended_hdr.if_index isn't set in the callback function, you can always pass it in to your callback function in the arg argument.
struct Dev {
int count;
int if_index;
};
...
char *device = "eth0";
struct Dev dev;
dev.count = 0;
dev.if_index = if_nametoindex(device); //from #include <net/in.h>
printf("Opening Device: %s\n", device);
pfring* ring = pfring_open(device, MAXBYTES2CAPTURE, 0);
pfring_enable_ring(ring);
pfring_loop(ring, processRingPacket, (u_char*)&dev, 1);
And recover that in the callback function:
void processRingPacket(const struct pfring_pkthdr* pkthdr, const u_char* packet, const u_char *arg)
{
struct Dev *dev = (struct Dev*)arg;
int i=0, *counter = (int*)&dev->count;
//and use dev->if_index; whenever you need to.

Why is my printf printing the wrong values?

I can't figure out why my code is not working. I am trying to create something similar to P2P file transfer where multiple threads simultaneously grab different parts of a file from a pre-existing server program. The actual problem I am having right now, is much simpler, however.
Since you cannot pass multiple arguments into pthread_create, I created a structure that had the two pieces of information I want to pass. I also created an array of pointers to these structures and initialize each one individually before passing it's pointer in.
printf("In thread: port=%d & ipAddr=%s\n",conn->port,conn->ipAddr);
When that line runs, everything prints out correctly with the correct port number and IP address.
printf("Size of chunk %d received by %lu on port %d: %d bytes\n",chunkNum,pthread_self(),conn->port,sizeRec);
However, when that line runs shortly after, the port number does not print out correctly. Instead of 9210 and 9211, I get 0 and 134520848. Otherwise, everything seems to be working so I'm thinking it may just be a printf problem of some sort, but I want to be sure before I move on to implementing the next part of my project.
If anyone has any idea why the same variable would print with one value and a completely different a few lines later when no changes were made, it would be very helpful for me. I have included all of my code below for reference. Thanks for your help!
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
char * file_name = "output.txt";
int nextChunk = 0;
pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
struct connection{
int port;
char* ipAddr;
};
void* getFile(void* args) {
int con_fd = 0;
int ret = 0;
struct sockaddr_in serv_addr;
struct connection* conn = (struct connection*)args;
printf("In thread: port=%d & ipAddr=%s\n",conn->port,conn->ipAddr);
memset(&serv_addr, 0, sizeof(struct sockaddr));
serv_addr.sin_family = AF_INET;
//printf("port number: %d\n",conn->port);
serv_addr.sin_port = htons(conn->port);
serv_addr.sin_addr.s_addr = inet_addr(conn->ipAddr);
int sizeRec;
char buf[1024];
while(1) {
con_fd = socket(PF_INET, SOCK_STREAM, 0);
if (con_fd == -1) {
printf("Socket Error\n");
fflush(stdout);
return 0;
}
ret = connect(con_fd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr));
if (ret < 0) {
printf("Connect error\n");
fflush(stdout);
return 0;
}
char chunkStr[128];
pthread_mutex_lock(&lock1);
int chunkNum = nextChunk++;
pthread_mutex_unlock(&lock1);
sprintf(chunkStr,"%d",chunkNum);
send(con_fd,chunkStr,128,0);
sizeRec = recv(con_fd,buf,1024,0);
printf("Size of chunk %d received by %lu on port %d: %d bytes\n",chunkNum,pthread_self(),conn->port,sizeRec);
if (sizeRec <= 0) {
return 0;
}
}
/*FILE *f = fopen(filename, "w");
if (!f) {
printf("Can't open %s for input. Program halting\n",filename);
exit(0);
}*/
/*while ((sizeReceived = recv(sock,buf,1024,0)) > 0) {
if (fwrite(buf,sizeof(char),sizeReceived,f) == -1) {
printf("Error writing file");
exit(0);
}
}
fclose(f);*/
close(con_fd);
return 0;
}
int main(int argc, char ** argv) {
if (argc < 3 || argc % 2 == 0) {
printf("Usage: ./client <ipaddr1> <port1> <ipaddr2> <port2> . . .\n");
return -1;
}
int numThreads = argc / 2;
pthread_t threads[numThreads];
struct connection** connections = malloc(sizeof(struct connection*)*numThreads);
//char* args[numThreads][2];
printf("numThreads: %d\n",numThreads);
for (int i=0; i<numThreads; i++) {
connections[i] = malloc(sizeof(struct connection));
connections[i]->ipAddr = argv[2*i+1];
connections[i]->port = atoi(argv[2*i+2]);
printf("port number: %d\n",connections[i]->port);
pthread_create(&threads[i], NULL, getFile, (void*)(connections[i]));
}
for (int i=0; i<numThreads; i++) {
free(connections[i]);
pthread_join(threads[i], NULL);
}
pthread_mutex_destroy(&lock1);
return 0;
}
Your main problem is the second for loop in main().
You first free the data structure and then call pthread_join(). Reverse these two statements and it should work reliable.
If you use Linux, I suggest to use valgrind tool, which easily helps to spot such issues. For windows I only know expensive commercial tools doing the same (like Purify).
Change this :
for (int i=0; i<numThreads; i++) {
free(connections[i]);
pthread_join(threads[i], NULL);
To :
for (int i=0; i<numThreads; i++) {
pthread_join(threads[i], NULL);
free(connections[i]);

libpcap get MAC from AF_LINK sockaddr_dl (OSX)

I am trying to obtain the MAC addresses of all of my interface on OSX using C. The common ways to obtain it Linux dont work on BSD - from everything I have seen, you must obtain the interfaces and look for the ones that are of type AF_LINK. My problem is that the LLADDR(sockaddr_dl) gives me a whole bunch of data (which includes my MAC) and I dont know what format the data is in. For example; the following code will output:
Device: en1
link sdl_alen: 101 mac:
31:f8:1e:df:d6:22:1d:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:b0:06:10:00:01:00:00:00:c0:02:10:00:01:00:00:00:00:00:00:00:00:00:00:00:40
:03:10:00:01:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:03:00:6c:6f:30:00:00:00:00:00:00:00:00:00:00:00:00:00:70:03:10:00:01:00:00:00:e0:
02:10:00:01:00:00:
My MAC is bolded. It seems that this is the format all of the time, but I would be a lot more comfortable if I could cast LLADDR(sockaddr_dl) to something. In the net/if_dl.h, LLADDR is defied as:
#define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen))
which, as far as I can tell, is saying that the results are of type (void *) - no help.
Other posts like:
Having a problem figuring out how to get Ethernet interface info on Mac OS X using ioctl/SIOCGIFADDR/SIOCGIFCONF?
seem to think they have it figured out, but if you look through the code, you can see it will not work due to sdl_alen not being 6.
int main() {
pcap_if_t *alldevs;
pcap_if_t *d;
pcap_addr_t *alladdrs;
pcap_addr_t *a;
struct sockaddr_dl* link;
char eb[PCAP_ERRBUF_SIZE];
char *addr_buf[40];
if (pcap_findalldevs(&alldevs, eb) == -1) {
printf("no devs found\n");
return(-1);
}
for (d = alldevs; d != NULL; d = d->next) {
printf("Device: %s\n", d->name);
alladdrs = d->addresses;
for (a = alladdrs; a != NULL; a = a->next) {
if(a->addr->sa_family == AF_LINK && a->addr->sa_data != NULL){
// MAC ADDRESS
//struct sockaddr_dl *sdl = (struct sockaddr_dl *) a->addr->sa_data;
link = (struct sockaddr_dl*)a->addr->sa_data;
char mac[link->sdl_alen];
caddr_t macaddr = LLADDR(link);
memcpy(mac, LLADDR(link), link->sdl_alen);
printf("link sdl_alen: %i\n", link->sdl_alen);
int i;
printf("mac: ");
for(i = 0; i<link->sdl_alen; i++){
printf("%02x:", (unsigned char)mac[i]);
}
printf("\n");
}
}
}
}
The problem is that you are casting the sockaddr->sa_data to sockaddr_dl instead of casting the sockaddr itself to sockaddr_dl. Keep in mind that sockaddr_dl is an OS X/BSD thing, so #ifdef that part for portability.
Don't do:
link = (struct sockaddr_dl*)a->addr->sa_data;
Do:
link = (struct sockaddr_dl*)a->addr;
Then you will get the correct sdl_alen and things will work with out any hacks. And if you want to really easily get the name of addresses that may be either AF_INET, AF_INET6, or AF_LINK use getnameinfo():
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <net/if_dl.h>
int get_sock_len(struct sockaddr *sa)
{
switch (sa->sa_family) {
case AF_INET:
return sizeof(struct sockaddr_in);
case AF_INET6:
return sizeof(struct sockaddr_in6);
case AF_LINK:
return sizeof(struct sockaddr_dl);
default:
return -1;
}
}
int get_numeric_address(struct sockaddr *sa, char *outbuf, size_t buflen) {
socklen_t len;
if ((len = get_sock_len(sa)) < 0) {
return -1;
}
if (getnameinfo(sa, len, outbuf, buflen, NULL, 0, NI_NUMERICHOST)) {
return -1;
}
return 0;
}
...
char buf[NI_MAXHOST];
if (!get_numeric_address(sa, buf, sizeof(buf))) { /* For some struct sockaddr *sa */
printf("address: %s\n", buf);
} else {
printf("doh!\n");
}
Here is what I ended up doing:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <errno.h>
#include <net/if_dl.h>
#include <pcap.h>
#include "mac.h"
int main() {
printf("en1: %s\n", lookupDeviceMac("vnic0"));
}
unsigned char *lookupDeviceMac(char *dev){
pcap_if_t *alldevs;
pcap_if_t *d;
pcap_addr_t *alladdrs;
pcap_addr_t *a;
struct sockaddr_dl* link;
char eb[PCAP_ERRBUF_SIZE];
char *ret = malloc(6);
if (pcap_findalldevs(&alldevs, eb) == -1) {
printf("%s\n", eb);
return(ret);
}
for (d = alldevs; d != NULL; d = d->next) {
if(strcmp(d->name, dev) == 0){
printf("Device: %s\n", d->name);
alladdrs = d->addresses;
for (a = alladdrs; a != NULL; a = a->next) {
if(a->addr->sa_family == AF_LINK && a->addr->sa_data != NULL){
// MAC ADDRESS
//struct sockaddr_dl *sdl = (struct sockaddr_dl *) a->addr->sa_data;
link = (struct sockaddr_dl*)a->addr->sa_data;
char mac[link->sdl_alen];
caddr_t macaddr = LLADDR(link);
memcpy(mac, LLADDR(link), link->sdl_alen);
if(link->sdl_alen == 6){
// Seen in some sample code
sprintf(ret, "%02x:%02x:%02x:%02x:%02x:%02x",(unsigned char)mac[0],
(unsigned char)mac[1],
(unsigned char)mac[2],
(unsigned char)mac[3],
(unsigned char)mac[4],
(unsigned char)mac[5]);
} else if(link->sdl_alen > 6) {
// This is what happens in OSX 10.6.5
sprintf(ret, "%02x:%02x:%02x:%02x:%02x:%02x",(unsigned char)mac[1],
(unsigned char)mac[2],
(unsigned char)mac[3],
(unsigned char)mac[4],
(unsigned char)mac[5],
(unsigned char)mac[6]);
}
return(ret);
}
}
}
}
}
I was trying to see all devices reported by pcap_findalldevs and ended up here looking for information on interpreting AF_LINK addresses on MAC OS.
I'm used to seeing the struct sockaddr standing in for a interface family and being immediately cast to the appropriate type and not writing code to access *sa_data*.
For what I wanted it was sufficient to use link_ntoa to convert the address to a human readable form.
#import <Foundation/Foundation.h>
#include <pcap.h>
#include <netinet/in.h>
#include <net/if_dl.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
pcap_if_t* allDevs = NULL;
char errbuff[PCAP_ERRBUF_SIZE];
if (pcap_findalldevs(&allDevs, errbuff) <0) {
NSLog(#"Failed with error '%s'", errbuff);
}
else {
for (pcap_if_t* device = allDevs; device != NULL; device = device->next) {
for (pcap_addr_t* address = device->addresses; address != NULL; address = address->next) {
struct sockaddr* sa_addr = address->addr;
if (sa_addr->sa_family == AF_LINK) {
struct sockaddr_dl* link_addr = (struct sockaddr_dl*) sa_addr;
char* linkAddress = link_ntoa(link_addr);
NSLog(#"ntoa %s", linkAddress);
}
}
}
}
pcap_freealldevs(allDevs);
[pool drain];
return 0;
}
Running on my machine I get the following devices with AF_LINK entries.
2011-08-14 02:22:43.024 HomePlugToolHelper[12473:903] ntoa en0:0.16.cb.xx.x.xx
2011-08-14 02:22:43.027 HomePlugToolHelper[12473:903] ntoa fw0:0.16.cb.xx.xx.xx.xx.xx
2011-08-14 02:22:43.028 HomePlugToolHelper[12473:903] ntoa en1:0.16.cb.x.xx.xx
2011-08-14 02:22:43.028 HomePlugToolHelper[12473:903] ntoa lo0

How to get MAC address of your machine using a C program?

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.

Resources