Pregunta

Estoy trabajando en Ubuntu. ¿Cómo puedo obtener la dirección MAC de mi máquina o un programa en C digamos interfaz eth0 usando.

¿Fue útil?

Solución

Se necesita iterar sobre todas las interfaces disponibles en su máquina, y el uso ioctl con la bandera SIOCGIFHWADDR para obtener la dirección MAC. La dirección MAC se obtuvo en forma de una matriz binaria 6-octeto. También desea omitir la interfaz de bucle de retorno.

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

Otros consejos

Mucho mejor que todo este zócalo o shell locura es simplemente usando sysfs para esto:

/sys/class/net/eth0/address el archivo lleva su Dirección MAC tan simple cadena que se puede leer con fopen() / fscanf() / fclose(). Nada más fácil que eso.

Y si quieres apoyar a otras interfaces de red a eth0 (y es probable que desee), a continuación, utilizar simplemente opendir() / readdir() / closedir() en /sys/class/net/.

¿Quieres echar un vistazo a la getifaddrs (3) página manual. Hay un ejemplo en C en la propia página de manual que puede utilizar. Desea obtener la dirección de la AF_LINK tipo.

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

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

Con el fin de mostrar la dirección MAC para cada interfaz, se puede proceder como sigue:

#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

Tengo que acaba de escribir y probarlo en gentoo en 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;
}

Suponiendo que c ++ código (c ++ 11) es aceptable también y se conoce la interfaz.

#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));
}
  1. En Linux, utilice el servicio de "Network Manager" sobre el Enlace con el Bus.

  2. También hay good'ol programa de shell que puede ser de invocación y el resultado agarrado (utilizar un exec función bajo C):

$ /sbin/ifconfig | grep HWaddr

Una forma muy portátil es analizar la salida de este comando.

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

ifconfig Siempre se puede ejecutar como el usuario actual (por lo general puede) y se instala awk (a menudo es). Esto le dará la dirección MAC de la máquina.

Esta es una línea de Bash que imprime todas las direcciones MAC disponibles, excepto el bucle de retorno:

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

puede ser ejecutado desde un programa C.

Ampliando la respuesta dada por @ 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;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top