红联Linux门户
Linux帮助

Linux下获取eth网卡MAC地址的代码

发布时间:2015-02-28 22:16:19来源:carltao 的BLOG作者:linux人

因开发需要获取有线网卡的MAC地址,发现网上获取的方法多数只能获取联网网卡的MAC地址,因此重写了下Ubuntu 10下测试通过。

下面代码无论网卡是否连线,都可以获取MAC地址,稍作修改,可以输出系统所有的网卡硬件MAC地址,无论是否已经联网。


/*
* getmac.c
*
*  Created on: 2015

*  Author: carl
*/
 
#include <stdio.h>
#include <fcntl.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 <linux/if.h>
 
#define IFNAMSIZ 16
 
// data structs to store interface name list
char ifname_buf[2048];
char *ifnames = ifname_buf;
int count = 0;
 
void add_interface_name(const char * name)
{
int i;
for (i=0;i<count;i++)
{
if (!strcmp(ifnames+i*IFNAMSIZ, name))
return;
}
strncpy(ifnames+(count++)*IFNAMSIZ, name, IFNAMSIZ-1);
}
 
char * get_name(char *name, char *p)
{
while (isspace(*p))
p++;
while (*p) {
if (isspace(*p))
break;
if (*p == ':') {/* could be an alias */
char *dot = p, *dotname = name;
*name++ = *p++;
while (isdigit(*p))
*name++ = *p++;
if (*p != ':') {/* it wasn't, backup */
p = dot;
name = dotname;
}
if (*p == '\0')
return NULL;
p++;
break;
}
*name++ = *p++;
}
*name++ = '\0';
return p;
}
 
// get /proc/net/dev interface name list into buffer
// return 0 if success
int get_procnet_list()
{
FILE *fh;
char buf[512];
fh = fopen("/proc/net/dev", "r");
if (!fh)
return -1;
 
fgets(buf, sizeof buf, fh); /* eat title lines */
fgets(buf, sizeof buf, fh);
while (fgets(buf, sizeof buf, fh))
{
char name[IFNAMSIZ];
get_name(name, buf);
add_interface_name(name);
}
fclose(fh);
return 0;
}
 
long mac_addr_sys ( u_char *addr)
{
/* implementation for Linux */
struct ifreq ifr;
struct ifreq *IFR;
struct ifconf ifc;
char buf[1024];
int s, i;
int ok = 0;
 
// clear buffer
memset(ifname_buf, 0, sizeof(ifname_buf));

s = socket(AF_INET, SOCK_DGRAM, 0);
if (s==-1) {
return -1;
}
 
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
ioctl(s, SIOCGIFCONF, &ifc);
 
IFR = ifc.ifc_req;
// put the ioctl interface names in the list
for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; IFR++) {
add_interface_name(IFR->ifr_name);
}
// put the /proc/net/dev interface names in the list
if (get_procnet_list())
return -1;
 
// get the first mac address of eth* device hardware address
for (i = 0; i < count; i++) {
strcpy(ifr.ifr_name, ifnames + i*IFNAMSIZ);
if (!strncmp(ifr.ifr_name, "eth", 3))
if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0) {
if (! (ifr.ifr_flags & IFF_LOOPBACK)) {
if (ioctl(s, SIOCGIFHWADDR, &ifr) == 0) {
char *p = (char *)ifr.ifr_hwaddr.sa_data;
if (!*((int *)p) && !*((int *)(p+2)) )
continue;
// if not 00:00:00:00:00:00, yes, we get the real mac addr
ok = 1;
break;
}
}
}
}
 
close(s);
if (ok) {
bcopy( ifr.ifr_hwaddr.sa_data, addr, 6);
}
else {
return -1;
}
return 0;
}
 
/**************************************************/
/*
* Main (only for testing)
*/
int main( int argc, char **argv)
{
long stat;
int i;
u_char addr[6];
 
stat = mac_addr_sys( addr);
if (0 == stat) {
printf( "MAC address = ");
for (i=0; i<6; ++i) {
printf("%2.2x", addr[i]);
if (i<5)
printf(":");
}
printf( "\n");
}
else {
fprintf( stderr, "can't get MAC address\n");
exit( 1);
}
return 0;
}