Je travaille sur Ubuntu. Comment puis-je obtenir l'adresse MAC de ma machine ou une interface dire eth0 en utilisant le programme C.
Vous devez parcourir toutes les interfaces disponibles sur votre ordinateur et utiliser ioctl
avec SIOCGIFHWADDR
pour obtenir l'adresse mac. L'adresse mac sera obtenue sous la forme d'un tableau binaire de 6 octets. Vous souhaitez également ignorer l'interface de bouclage.
#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);
}
Beaucoup plus agréable que tout ce socket ou folie de Shell utilise simplement sysfs pour cela:
le fichier /sys/class/net/eth0/address
porte votre adresse mac sous forme de chaîne simple que vous pouvez lire avec fopen()
/fscanf()
/fclose()
. Rien de plus facile que ça.
Et si vous souhaitez prendre en charge d’autres interfaces réseau que eth0 (et vous le souhaitez probablement), utilisez simplement opendir()
/readdir()
/closedir()
sur /sys/class/net/
.
Vous voulez jeter un oeil à la page de manuel getifaddrs (3) . Vous pouvez utiliser un exemple en C dans la page de manuel elle-même. Vous voulez obtenir l'adresse avec le 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;
}
Je viens d’en écrire un et de le tester sur gentoo dans la 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;
}
En utilisant getifaddrs vous pouvez obtenir l’adresse MAC de la famille AF_PACKET
.
Afin d’afficher l’adresse MAC sur chaque interface, vous pouvez procéder comme suit:
#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;
}
En supposant que le code c ++ (c ++ 11) est également correct et que l'interface est connue.
#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=%016lX\n", iface.c_str(), getIFMAC(iface));
}
Sous Linux, utilisez le service "Network Manager" sur le DBus.
Il existe également un programme good'ol Shell pouvant être appelé et le résultat saisi (utilisez un exec fonction sous C):
$ /sbin/ifconfig | grep HWaddr
Une méthode très portable consiste à analyser la sortie de cette commande.
ifconfig | awk '$0 ~ /HWaddr/ { print $5 }'
Ifconfig peut être exécuté en tant qu'utilisateur actuel (généralement possible) et awk est installé (c'est souvent le cas). Cela vous donnera l'adresse mac de la machine.
Ceci est une ligne Bash qui imprime toutes les adresses Mac disponibles, à l'exception du bouclage:
for x in `ls /sys/class/net |grep -v lo`; do cat /sys/class/net/$x/address; done
Peut être exécuté à partir d'un programme C.