11 ответов:
вам нужно перебрать все доступные интерфейсы на вашем компьютере и использовать
ioctlСSIOCGIFHWADDRфлаг для получения mac-адреса. Mac-адрес будет получен в виде 6-октетного двоичного массива. Вы также хотите пропустить интерфейс обратной связи.#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); }
гораздо лучше, чем все это безумие сокета или оболочки, просто использует sysfs для этого:
файл
/sys/class/net/eth0/addressпереносит ваш Mac-адрес как простую строку, которую вы можете прочитать с помощьюfopen()/fscanf()/fclose(). Нет ничего проще, чем.и если вы хотите поддерживать другие сетевые интерфейсы, чем eth0 (и вы, вероятно, хотите), то просто используйте
opendir()/readdir()/closedir()on/sys/class/net/.
вы хотите взглянуть на getifaddrs(3) страница руководства. Есть пример в C в самой справочной странице, которую вы можете использовать. Вы хотите получить адрес типа
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; }
Я только что написал один и проверить его на gentoo в 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; }
используя getifaddrs вы можете получить MAC-адрес семьи
AF_PACKET.чтобы отобразить MAC-адрес для каждого интерфейса, вы можете действовать следующим образом:
#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; }
в Linux используйте службу "Network Manager" через DBus.
есть еще хороший стандартном телефоне оболочка программы, которую можно вызвать и результат схватил (используйте exec функция под C):
$ /sbin/ifconfig | grep HWaddr
очень портативный способ-проанализировать вывод этой команды.
ifconfig | awk ' ~ /HWaddr/ { print }'при условии, что ifconfig может быть запущен как текущий пользователь (обычно может) и установлен awk (часто это так). Это даст вам MAC-адрес машины.
предполагая, что код c++ (c++11) также в порядке, и интерфейс известен.
#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)); }
это строка Bash, которая печатает все доступные mac-адреса, кроме loopback:
for x in `ls /sys/class/net |grep -v lo`; do cat /sys/class/net/$x/address; doneможет выполняться из программы на языке C.
расширение ответа, данного @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; }
Comments