如何使用ioctl函数获取客户端的MAC地址?
我想捕获所有请求我的服务器的客户端MAC地址。我使用以下程序获取客户端的MAC地址,但它显示“ioctl:不支持协议系列”。如何获取MAC地址如何使用ioctl函数获取客户端的MAC地址?,c,sockets,C,Sockets,我想捕获所有请求我的服务器的客户端MAC地址。我使用以下程序获取客户端的MAC地址,但它显示“ioctl:不支持协议系列”。如何获取MAC地址 #include<stdio.h> #include<sys/socket.h> #include<sys/types.h> #include<netinet/in.h> #include<netdb.h> #include<errno.h> #include<string.h
#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<netdb.h>
#include<errno.h>
#include<string.h>
#include<netinet/if_ether.h>
#include<net/if.h>
#include<linux/sockios.h>
int main()
{
int socket1, socket2;
socket1 = 0;
socket2 = 0;
struct sockaddr_in server, client;
int returnstatus = 0;
socket1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(socket1 == -1)
{
perror("socket()");
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(8888);
returnstatus = bind(socket1, (struct sockaddr*)&server, sizeof(server));
if(returnstatus == -1)
{
perror("bind()");
}
returnstatus = listen(socket1, 5);
if(returnstatus == -1)
{
perror("listen()");
}
for(;;)
{
int buffr[4];
int addrlen, n;
addrlen = sizeof(client);
socket2 = accept(socket1, (struct sockaddr *)&client, &addrlen);
printf("%s\n",inet_ntoa(client.sin_addr));
printf("%d\n",(int) ntohs(client.sin_port));
struct arpreq arpreq_;
bzero(&arpreq_, sizeof(struct arpreq));
if( ( n = ioctl(socket2, SIOCGARP, &arpreq_) ) < 0 ){
perror("ioctl");
}
unsigned char *ptr = &arpreq_.arp_ha.sa_data[0];
printf("MAC: %x:%x:%x:%x:%x:%x\n", *ptr, *(ptr+1), *(ptr+2), *(ptr+3),
*(ptr+4), *(ptr+5));
if (socket2 == -1)
{
perror("accept()");
}
returnstatus = read(socket2, buffr, sizeof(buffr));
if(returnstatus == -1)
{
perror("read()");
}
int c[2];
int *w;
c[0] = buffr[0] + buffr[1];
w = c;
returnstatus = write(socket2, w, sizeof(c));
if(returnstatus == -1)
{
perror("write()");
}
close(socket2);
}
close(socket1);
return 0;
}
int addition(int x, int y)
{
int z;
z = x + y;
return(z);
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main()
{
int插座1、插座2;
socket1=0;
socket2=0;
服务器、客户端中的结构sockaddr_;
int returnstatus=0;
socket1=套接字(自动网络、SOCK流、IPPROTO\u TCP);
如果(socket1==-1)
{
perror(“socket()”);
}
server.sinu family=AF\u INET;
server.sin\u addr.s\u addr=INADDR\u ANY;
server.sin_port=htons(8888);
returnstatus=bind(socket1,(struct sockaddr*)&server,sizeof(server));
如果(返回状态==-1)
{
perror(“bind()”);
}
returnstatus=监听(socket1,5);
如果(返回状态==-1)
{
佩罗尔(“倾听()”);
}
对于(;;)
{
int buffer[4];
内塔德伦,北卡罗来纳州;
addrlen=sizeof(客户);
socket2=accept(socket1,(结构sockaddr*)和client,以及addrlen);
printf(“%s\n”,inet_ntoa(client.sin_addr));
printf(“%d\n”,(int)ntohs(client.sin_port));
结构arpreq arpreq;
bzero(&arpreq_,sizeof(struct arpreq));
如果((n=ioctl(socket2、SIOCGARP和arpreq_417;))小于0){
perror(“ioctl”);
}
无符号字符*ptr=&arpreq_u.arp_ha.sa_数据[0];
printf(“MAC:%x:%x:%x:%x:%x:%x:%x\n”、*ptr、*(ptr+1)、*(ptr+2)、*(ptr+3),
*(ptr+4),*(ptr+5));
如果(socket2==-1)
{
perror(“接受()”);
}
returnstatus=读取(socket2,buffer,sizeof(buffer));
如果(返回状态==-1)
{
perror(“read()”);
}
int c[2];
int*w;
c[0]=buffer[0]+buffer[1];
w=c;
returnstatus=write(socket2,w,sizeof(c));
如果(返回状态==-1)
{
perror(“write()”);
}
关闭(插座2);
}
关闭(插座1);
返回0;
}
整数加法(整数x,整数y)
{
intz;
z=x+y;
返回(z);
}
使用ioctl(SIOCGARP)
您可能只能获得本地子网的MAC地址,因为SIOCGARP将从本地ARP表返回MAC地址
您使用的是SIOCGARP
有点错误。SIOCGARP的参数是一种输入输出类型。因此,在调用ioctl
之前,您必须填写arpreq\uuquo>的一些字段。
看
当对等方不在您的以太网子网中时,流量通过路由器,对等方可能在以太网网络中或不在以太网网络中(例如:移动电话)。因此,不可能从每个对等方获取以太网MAC地址
当主机与对等机通信时,使用第一个路由器的MAC地址 我有一些代码似乎可以实现您想要的功能
<>我一直在尝试从我的网络上的远程计算机上获取一些C++代码。花了相当长的时间才弄明白这一点。我设法将几个示例合并并修改为一个工作演示。修改它以使用套接字连接应该非常容易
这段代码将网络设备和IP地址作为参数。
(例如eth0 192.168.1.1)
程序将检查IP的正确性,然后ping IP地址以将其添加到ARP表中,然后从ARP表中提取MAC地址,然后显示MAC地址
<>我不是C++程序员(或者至少我是NeWB),所以代码可能会被刷掉。
此代码仅在Raspbian上测试过
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if_arp.h>
#include <arpa/inet.h>
#include <sstream>
bool isValidIpAddress(char *ipAddress) {
int result = 0;
struct sockaddr_in sa;
result = inet_pton(AF_INET, ipAddress, &(sa.sin_addr));
return result;
}
/**
* @brief Convert String to Number
*/
template <typename TP>
TP str2num( std::string const& value ){
std::stringstream sin;
sin << value;
TP output;
sin >> output;
return output;
}
/**
* @brief Convert number to string
*/
template <typename TP>
std::string num2str( TP const& value ){
std::stringstream sin;
sin << value;
return sin.str();
}
/**
* @brief Execute Generic Shell Command
*
* @param[in] command Command to execute.
* @param[out] output Shell output.
* @param[in] mode read/write access
*
* @return 0 for success, 1 otherwise.
*
*/
int Execute_Command( const std::string& command,
std::string& output,
const std::string& mode = "r") {
// Create the stringstream
std::stringstream sout;
// Run Popen
FILE *in;
char buff[512];
// Test output
if(!(in = popen(command.c_str(), mode.c_str()))){
return 1;
}
// Parse output
while(fgets(buff, sizeof(buff), in)!=NULL){
sout << buff;
}
// Close
int exit_code = pclose(in);
// set output
output = sout.str();
// Return exit code
return exit_code;
}
/**
* @brief Ping
*
* @param[in] address Address to ping.
* @param[in] max_attempts Number of attempts to try and ping.
* @param[out] details Details of failure if one occurs.
*
* @return True if responsive, false otherwise.
*
* @note { I am redirecting stderr to stdout. I would recommend
* capturing this information separately.}
*/
bool Ping( const std::string& address ) {
// Format a command string
std::string command = "ping -c " + num2str(2) + " " + address + " 2>&1";
std::string output;
std::string details;
// Execute the ping command
int code = Execute_Command( command, details );
return (code == 0);
}
static char *ethernet_mactoa(struct sockaddr *addr) {
static char buff[256];
unsigned char *ptr = (unsigned char *) addr->sa_data;
sprintf(buff, "%02X:%02X:%02X:%02X:%02X:%02X",
(ptr[0] & 0xff), (ptr[1] & 0xff), (ptr[2] & 0xff),
(ptr[3] & 0xff), (ptr[4] & 0xff), (ptr[5] & 0xff));
return (buff);
}
int main(int argc, char *argv[]) {
int s;
struct arpreq areq;
struct sockaddr_in *sin;
struct in_addr ipaddr;
if (argc != 3) {
fprintf(stderr, "-- Usage: %s device ipaddress\n", argv[0]);
exit(1);
}
/* Get an internet domain socket. */
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
exit(1);
}
if (!isValidIpAddress(argv[2])) {
fprintf(stderr, "-- Error: invalid IP Address '%s'.\n",
argv[2]);
exit(1);
}
if (inet_aton(argv[2], &ipaddr) == 0) {
fprintf(stderr, "-- Error: bad dotted-decimal IP '%s'.\n",
argv[2]);
exit(1);
}
/* Ping the Address for ARP table listing */
if ( !Ping(argv[2]) ) {
fprintf(stderr, "-- Error: unable to ping IP '%s'.\n",
argv[2]);
exit(1);
}
/* Make the ARP request. */
memset(&areq, 0, sizeof(areq));
sin = (struct sockaddr_in *) &areq.arp_pa;
sin->sin_family = AF_INET;
sin->sin_addr = ipaddr;
sin = (struct sockaddr_in *) &areq.arp_ha;
sin->sin_family = ARPHRD_ETHER;
strncpy(areq.arp_dev, argv[1], 15);
if (ioctl(s, SIOCGARP, (caddr_t) &areq) == -1) {
perror("-- Error: unable to make ARP request, error");
exit(1);
}
printf("%s -> %s\n",
inet_ntoa(((struct sockaddr_in *) &areq.arp_pa)->sin_addr),
ethernet_mactoa(&areq.arp_ha));
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
bool isValidIpAddress(char*ipAddress){
int结果=0;
sa中的结构sockaddr_;
结果=inet_pton(AF_inet,ipAddress,&(sa.sin_addr));
返回结果;
}
/**
*@brief将字符串转换为数字
*/
模板
TP str2num(标准::字符串常量和值){
std::stringstreamsin;
sin>输出;
返回输出;
}
/**
*@brief将数字转换为字符串
*/
模板
标准::字符串num2str(TP常量和值){
std::stringstreamsin;
sin sa_数据;
sprintf(buff,“%02X:%02X:%02X:%02X:%02X:%02X:%02X”,
(ptr[0]和0xff)、(ptr[1]和0xff)、(ptr[2]和0xff),
(ptr[3]&0xff)、(ptr[4]&0xff)、(ptr[5]&0xff));
返回(buff);
}
int main(int argc,char*argv[]){
int-s;
结构arpreq-areq;
结构sockaddr_in*sin;
地址为ipaddr的结构;
如果(argc!=3){
fprintf(stderr,“--用法:%s设备ipaddress\n”,argv[0]);
出口(1);
}
/*获取internet域套接字*/
if((s=套接字(AF_INET,SOCK_DGRAM,0))=-1){
佩罗(“插座”);
出口(1);
}
if(!isValidIpAddress(argv[2])){
fprintf(stderr,“--错误:无效的IP地址“%s”。\n”,
argv[2]);
出口(1);
}
if(inet_aton(argv[2],&ipaddr)==0){
fprintf(stderr,“--错误:错误的点十进制IP'%s'。\n”,
argv[2]);
出口(1);
}
/*Ping用于ARP表列表的地址*/
如果(!Ping(argv[2])){
fprintf(stderr,“--错误:无法ping IP'%s'。\n”,
argv[2]);
出口(1);
}
/*发出ARP请求*/
memset(&areq,0,sizeof(areq));
sin=(结构sockaddr_in*)和areq.arp_pa;
sin->sin\u family=AF\u INET;
sin->sin_addr=ipaddr;
sin=(结构sockaddr_in*)和areq.arp_ha;
sin->sin_family=ARPHRD_乙醚;
strncpy(areq.arp_dev,argv[1],15);
如果(ioctl(s,SIOCGARP,(caddr__t)和areq)=-1){
perror(“--错误:无法发出ARP请求,错误”);
出口(1);
}
printf(“%s->%s\n”,
inet_ntoa(((结构sockaddr_in*)和areq.arp_pa)->sin_addr),
以太网(mactoa&areq.arp_-ha));
返回0;
}
如果客户机位于另一个网络,甚至另一个子网上,该怎么办?你不想只得到路由器的MAC地址吗?我想得到在另一个网络甚至世界上任何地方的客户机的MAC地址。。。我怎么能得到它?你不能,真的。唯一可靠的方法是使使用的协议包含来自服务器的查询,以要求客户端提供其自己的MAC地址。我想获取至少在同一网络中的客户端MAC。。怎样