con - ¿Cómo obtener la dirección MAC de su máquina usando un programa C?
compilar y ejecutar c en linux gcc (10)
En Linux, use el servicio de "Network Manager" sobre el DBus.
También hay un buen programa shell que se puede invocar y obtener el resultado (use una función ejecutiva en C):
$ /sbin/ifconfig | grep HWaddr
Estoy trabajando en Ubuntu. ¿Cómo puedo obtener la dirección MAC de mi máquina o una interfaz decir eth0 usando el programa C?
Acabo de escribir uno 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;
}
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://.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;
}
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
.
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/
.
Suponiendo que el código de C ++ (c ++ 11) también está bien 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>());
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));
}
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.
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 <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;
}
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 <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);
}
#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;
}