socket获取客户端mac地址
时间: 2023-09-17 11:10:26 浏览: 186
在Socket编程中,获取客户端MAC地址需要使用操作系统提供的相关API。以下是在Linux和Windows平台中获取客户端MAC地址的方法。
在Linux平台中,可以通过获取客户端IP地址,然后通过ARP协议查询对应的MAC地址。具体实现步骤如下:
1. 使用getpeername函数获取客户端的IP地址
2. 使用ioctl函数发送SIOCGARP命令,查询对应IP地址的MAC地址
3. 解析返回的ARP缓存表项,获取MAC地址
以下是示例代码:
```
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <net/if_arp.h>
int get_client_mac(int sockfd, unsigned char *mac) {
struct sockaddr_in cli_addr;
socklen_t cli_len = sizeof(cli_addr);
char ip_str[INET_ADDRSTRLEN];
char mac_str[18];
// 获取客户端IP地址
if (getpeername(sockfd, (struct sockaddr *)&cli_addr, &cli_len) == -1) {
perror("getpeername() failed");
return -1;
}
inet_ntop(AF_INET, &cli_addr.sin_addr, ip_str, INET_ADDRSTRLEN);
// 查询ARP缓存表项,获取MAC地址
struct arpreq areq;
memset(&areq, 0, sizeof(areq));
struct sockaddr_in *sin = (struct sockaddr_in *)&areq.arp_pa;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = cli_addr.sin_addr.s_addr;
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd == -1) {
perror("socket() failed");
return -1;
}
if (ioctl(fd, SIOCGARP, &areq) == -1) {
close(fd);
perror("ioctl(SIOCGARP) failed");
return -1;
}
close(fd);
// 解析MAC地址
unsigned char *ptr = (unsigned char *)&areq.arp_ha.sa_data[0];
snprintf(mac_str, sizeof(mac_str), "%02X:%02X:%02X:%02X:%02X:%02X", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
sscanf(mac_str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
return 0;
}
```
在Windows平台中,可以使用GetAdaptersAddresses函数获取本地网卡信息,然后通过比对客户端IP地址和本地网卡的IP地址,获取对应的MAC地址。以下是示例代码:
```
#include <winsock2.h>
#include <iphlpapi.h>
#include <stdio.h>
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
int get_client_mac(SOCKET sockfd, unsigned char *mac) {
struct sockaddr_in cli_addr;
int cli_len = sizeof(cli_addr);
char ip_str[INET_ADDRSTRLEN];
char mac_str[18];
// 获取客户端IP地址
if (getpeername(sockfd, (struct sockaddr *)&cli_addr, &cli_len) == -1) {
perror("getpeername() failed");
return -1;
}
inet_ntop(AF_INET, &cli_addr.sin_addr, ip_str, INET_ADDRSTRLEN);
// 获取本地网卡信息
ULONG size = 0;
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
DWORD dwRetVal = GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &size);
if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
pAddresses = (IP_ADAPTER_ADDRESSES *)malloc(size);
dwRetVal = GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &size);
}
if (dwRetVal != NO_ERROR) {
perror("GetAdaptersAddresses() failed");
return -1;
}
// 比对IP地址,获取对应的MAC地址
PIP_ADAPTER_ADDRESSES pCurrAddresses = pAddresses;
while (pCurrAddresses) {
if (pCurrAddresses->FirstUnicastAddress) {
for (PIP_ADAPTER_UNICAST_ADDRESS pUnicast = pCurrAddresses->FirstUnicastAddress; pUnicast; pUnicast = pUnicast->Next) {
struct sockaddr_in *sin = (struct sockaddr_in *)pUnicast->Address.lpSockaddr;
if (strcmp(ip_str, inet_ntoa(sin->sin_addr)) == 0) {
snprintf(mac_str, sizeof(mac_str), "%02X:%02X:%02X:%02X:%02X:%02X", pCurrAddresses->PhysicalAddress[0], pCurrAddresses->PhysicalAddress[1], pCurrAddresses->PhysicalAddress[2], pCurrAddresses->PhysicalAddress[3], pCurrAddresses->PhysicalAddress[4], pCurrAddresses->PhysicalAddress[5]);
sscanf(mac_str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
free(pAddresses);
return 0;
}
}
}
pCurrAddresses = pCurrAddresses->Next;
}
free(pAddresses);
return -1;
}
```
阅读全文