MacOS下C语言(Xcode)获取本机MAC地址及发送ARP请求的技术求助
MacOS下C语言获取本机MAC地址与发送ARP请求的实现方案
我之前在MacOS上用C做Socket编程的时候也遇到过类似的需求,给你分享两个适配MacOS(Xcode环境)的实用实现方案:
一、获取本机MAC地址
MacOS推荐用getifaddrs函数来获取网络接口信息,这个接口比旧的sysctl更稳定通用。下面是完整的实现代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ifaddrs.h> #include <netinet/in.h> #include <net/if_dl.h> #include <arpa/inet.h> // 获取指定网络接口的MAC地址 void get_local_mac_address(const char* interface_name, unsigned char mac_addr[6]) { struct ifaddrs *ifap, *ifa; struct sockaddr_dl *sdl; if (getifaddrs(&ifap) == -1) { perror("getifaddrs调用失败"); exit(EXIT_FAILURE); } // 遍历所有网络接口 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { // 匹配指定接口,且是数据链路层地址 if (ifa->ifa_addr != NULL && ifa->ifa_addr->sa_family == AF_LINK && strcmp(ifa->ifa_name, interface_name) == 0) { sdl = (struct sockaddr_dl *)ifa->ifa_addr; memcpy(mac_addr, LLADDR(sdl), 6); // 复制MAC地址 break; } } freeifaddrs(ifap); } int main() { unsigned char mac[6]; // 替换为你的实际网络接口名,可用`ifconfig`命令查看(比如en0、en1) get_local_mac_address("en0", mac); printf("本机MAC地址: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); return 0; }
注意点:
- 先通过
ifconfig命令确认你的活跃网络接口名(比如Wi-Fi通常是en0) - Xcode中编译时不需要额外的链接参数,直接运行即可
二、MacOS下发送ARP请求
MacOS发送ARP需要使用原始套接字,且必须以root权限运行。下面是构造ARP请求包并发送的实现:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <netinet/in.h> #include <netinet/if_ether.h> #include <net/if.h> #include <arpa/inet.h> // 导入前面的get_local_mac_address函数 void get_local_mac_address(const char* interface_name, unsigned char mac_addr[6]); // ARP报文完整结构体(以太网帧头+ARP报文) struct arp_packet { struct ether_header eth_hdr; struct ether_arp arp_hdr; }; // 发送ARP请求 int send_arp_request(int sockfd, const char* interface, unsigned char* src_mac, struct in_addr src_ip, struct in_addr target_ip) { struct arp_packet arp_pkt; struct ifreq ifr; struct sockaddr_ll dest_addr; memset(&arp_pkt, 0, sizeof(struct arp_packet)); // 填充以太网帧头 memset(arp_pkt.eth_hdr.ether_dhost, 0xff, 6); // 目的MAC为广播地址 memcpy(arp_pkt.eth_hdr.ether_shost, src_mac, 6); // 源MAC为本机MAC arp_pkt.eth_hdr.ether_type = htons(ETHERTYPE_ARP); // 帧类型为ARP // 填充ARP报文 arp_pkt.arp_hdr.arp_hrd = htons(ARPHRD_ETHER); // 硬件类型:以太网 arp_pkt.arp_hdr.arp_pro = htons(ETHERTYPE_IP); // 协议类型:IP arp_pkt.arp_hdr.arp_hln = 6; // MAC地址长度 arp_pkt.arp_hdr.arp_pln = 4; // IP地址长度 arp_pkt.arp_hdr.arp_op = htons(ARPOP_REQUEST); // 操作类型:ARP请求 memcpy(arp_pkt.arp_hdr.arp_sha, src_mac, 6); // 源MAC memcpy(arp_pkt.arp_hdr.arp_spa, &src_ip.s_addr, 4); // 源IP memset(arp_pkt.arp_hdr.arp_tha, 0, 6); // 目的MAC暂填0 memcpy(arp_pkt.arp_hdr.arp_tpa, &target_ip.s_addr, 4); // 目标IP // 获取网络接口索引 strncpy(ifr.ifr_name, interface, IFNAMSIZ-1); if (ioctl(sockfd, SIOCGIFINDEX, &ifr) == -1) { perror("获取接口索引失败"); return -1; } // 设置发送目标地址(广播) memset(&dest_addr, 0, sizeof(struct sockaddr_ll)); dest_addr.sll_family = AF_PACKET; dest_addr.sll_ifindex = ifr.ifr_ifindex; dest_addr.sll_halen = ETH_ALEN; memset(dest_addr.sll_addr, 0xff, 6); // 发送ARP请求 int bytes_sent = sendto(sockfd, &arp_pkt, sizeof(struct arp_packet), 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr)); if (bytes_sent == -1) { perror("发送ARP请求失败"); return -1; } printf("ARP请求已发送,共发送%d字节\n", bytes_sent); return 0; } int main() { // 创建原始套接字,必须root权限 int sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (sockfd == -1) { perror("创建原始套接字失败"); printf("请以root权限运行此程序(sudo ./程序名)\n"); exit(EXIT_FAILURE); } unsigned char src_mac[6]; struct in_addr src_ip, target_ip; // 获取本机MAC get_local_mac_address("en0", src_mac); // 设置本机IP(替换为你的实际IP) inet_aton("192.168.1.100", &src_ip); // 设置要查询的目标IP(比如网关IP) inet_aton("192.168.1.1", &target_ip); send_arp_request(sockfd, "en0", src_mac, src_ip, target_ip); close(sockfd); return 0; }
注意点:
- 必须以root权限运行:Xcode中可以通过
Product > Scheme > Edit Scheme,在Run的Arguments里勾选Run as root;或者编译后用sudo ./程序名运行 - 替换代码中的本机IP和目标IP为你实际网络环境中的地址
- 接口名要和前面获取MAC时的一致
内容的提问来源于stack exchange,提问作者user8379153
相关产品推荐
相关产品推荐

