¿Cómo obtener la dirección MAC de su máquina usando un progtwig C?

Estoy trabajando en Ubuntu. ¿Cómo puedo obtener la dirección MAC de mi máquina o una interfaz decir eth0 usando el progtwig C?

Necesita iterar sobre todas las interfaces disponibles en su máquina y usar ioctl con el indicador SIOCGIFHWADDR para obtener la dirección MAC. La dirección MAC se obtendrá como una matriz binaria de 6 octetos. También quiere omitir la interfaz de bucle invertido.

 #include  #include  #include  #include  #include  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); } 

Mucho mejor que toda esta locura de socket o shell es simplemente usar sysfs para esto:

la dirección file /sys/class/net/eth0/address lleva su dirección mac como una cadena simple que puede leer con fopen() / fscanf() / fclose() . Nada más fácil que eso.

Y si desea soportar otras interfaces de red además de eth0 (y probablemente lo desee), simplemente use opendir() / readdir() / closedir() en /sys/class/net/ .

Desea echar un vistazo a la página de manual de getifaddrs (3) . Hay un ejemplo en C en la página de manual en sí que puedes usar. Desea obtener la dirección con el tipo AF_LINK .

 #include  #include  #include  #include  #include  #include  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; } 

Acabo de escribir uno y probarlo en gentoo en virtualbox.

 // get_mac.c #include  //printf #include  //strncpy #include  #include  #include  //ifreq #include  //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; } 

Usando getifaddrs puede obtener la dirección MAC de la familia AF_PACKET .

Para mostrar la dirección MAC a cada interfaz, puede proceder de la siguiente manera:

 #include  #include  #include  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 sll_halen; i++) { printf("%02x%c", (s->sll_addr[i]), (i+1!=s->sll_halen)?':':'\n'); } } } freeifaddrs(ifaddr); } return 0; } 
  1. En Linux, use el servicio de “Network Manager” sobre el DBus.

  2. También hay un buen progtwig shell que se puede invocar y obtener el resultado (use una función ejecutiva en C):

$ /sbin/ifconfig | grep HWaddr

Una forma muy portátil es analizar el resultado de este comando.

 ifconfig | awk '$0 ~ /HWaddr/ { print $5 }' 

Siempre que ifconfig se pueda ejecutar como el usuario actual (generalmente puede) y awk está instalado (a menudo lo es). Esto le dará la dirección MAC de la máquina.

Suponiendo que el código de C ++ (c ++ 11) también está bien y se conoce la interfaz.

 #include  #include  #include  #include  using namespace std; uint64_t getIFMAC(const string &ifname) { ifstream iface("/sys/class/net/"+ifname+"/address"); string str((istreambuf_iterator(iface)), istreambuf_iterator()); string hex = regex_replace(str, std::regex(":"), ""); return stoull(hex, 0, 16); } int main() { string iface="eth0"; printf("%s: mac=%016lX\n", iface.c_str(), getIFMAC(iface)); } 

Esta es una línea Bash que imprime todas las direcciones mac disponibles, excepto el loopback:

 for x in `ls /sys/class/net |grep -v lo`; do cat /sys/class/net/$x/address; done 

Se puede ejecutar desde un progtwig C.

Ampliando la respuesta dada por @ user175104 …

 std::vector 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 GetAllMacAddresses() { std::vector macs; std::string address; // from: https://stackoverflow.com/questions/9034575/cc-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 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; }