// all.h
// 2005/06/20,a.m. wenxy
#ifndef _ALL_H
#define _ALL_H
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <string.h>
#include <errno.h>
// ---------------------
// 建立ARP包的標頭檔案
#include<netinet/in.h>
#include<arpa/inet.h>
/* #include<linux/if_ether.h> */
#include<ctype.h>
#include <fcntl.h>
// ---------------------
#include <unistd.h>
#include <string>
#include <iostream>
using namespace std;
#define MAX_MAC_LEN 24 // MAC字串緩衝區的最大長度(byte)
#define COMPART_MAC ":" // MAC字串的分格符, Warnning:修改此巨集,必須再修改源程式!!!
#endif /* end _ALL_h */
// end file
// -------------------------------------------------------------------------------------------------------------
// main.cpp
// 2005/06/20,a.m. wenxy
#include "all.h"
// function declare
static string GetLocalMac(string & strEth); // get loacl NIC's MAC
void set_ip_addr(char *,char *); // 填充IP
void set_hw_addr(char buf[], char *str); // 填充MAC
static string GetMacByIP(string strSrcIP, string strSrcMAC, string strDesIP ,string strNIC); // 獲取指定IP的MAC
/*
#define SRC_IP "10.0.1.77" // 源IP
#define DES_IP "10.0.1.35" // 目的IP
#define LOCAL_HW "00:C0:4C:39:0D:6F" // 10.0.1.77的eth0的MAC
#define DEVICE "eth0" // 介面
*/
#define PADD_MAC "00:00:00:00:00:00" // 填充的MAC
#define DES_MAC "FF:FF:FF:FF:FF:FF" // 廣播MAC
#define ARP_SEND_COUNT 3 // 傳送ARP請求的ARP包的個數
struct ether_header
{
unsigned char ether_dhost[6]; /* destination eth addr */
unsigned char ether_shost[6]; /* source ether addr */
unsigned short ether_type; /* packet type ID field */
};
struct arp_header
{
unsigned short int ar_hrd; /* Format of hardware address. */
unsigned short int ar_pro; /* Format of protocol address. */
unsigned char ar_hln; /* Length of hardware address. */
unsigned char ar_pln; /* Length of protocol address. */
// -------------------------
unsigned short int ar_op; /* ARP opcode (command). */
unsigned char __ar_sha[6]; /* Sender hardware address. */
unsigned char __ar_sip[4]; /* Sender IP address. */
unsigned char __ar_tha[6]; /* Target hardware address. */
unsigned char __ar_tip[4]; /* Target IP address. */
// -------------------------
};
struct arp_packet
{
struct ether_header ethhdr;
struct arp_header arphdr;
unsigned char padding[18]; /* filled with 0 */
};
/* arp reply:
* op = 2
* ethhdr.ether_dhost = arphdr.__ar_tha = switch hard addr
* ethhdr.ether_shost = arphdr.__ar_sha = local hard addr
* arphdr.__ar_tip = switch ip
* arphdr.__ar_sip = victim ip
*/
#define FRAME_TYPE 0x0806 /* arp=0x0806,rarp=0x8035 */
#define HARD_TYPE 1 /* ethernet is 1 */
#define PROTO_TYPE 0x0800 /* IP is 0x0800 */
#define OP_CODE 1 /* arp=1/2,1為請求,2為應答,rarp=3/4 */
// linux下獲取LAN裡指定IP的網路卡MAC
// In: argv[1]:本機IP,argv[2]:目的IP
// Out:
int main( int argc, char *argv[] )
{
string strETH; // 本機NIC名稱
string strLocalMAC; // 本機MAC
string strSrcIP; // 本機IP
string strDesMAC; // 目的MAC
string strDesIP; // 目的IP
// 檢查引數
if ( argc != 4 )
{
printf("Useage: get_mac [interface name of the IP] [IP] [ARP IP]/n/n");
return 0;
}
strETH = argv[1]; //"eth0";
strSrcIP = argv[2]; //"10.0.1.77";
strDesIP = argv[3]; //"10.0.1.69";
printf("Run ....../n");
printf("獲取 %s 介面的MAC ....../n", strETH.c_str());
// 獲取指定NIC名稱的MAC
strLocalMAC = GetLocalMac(strETH);
#if 0
printf("Note: %s[%s]/n", strETH.c_str(), strLocalMAC.c_str());
#endif
// 獲取指定介面MAC
if ( 0 == strcmp( (const char*)strLocalMAC.c_str(), (const char*)"") )
{
printf("Error: call strcmp() failed/n");
printf("--------------------------------/n/n");
return -1;
}
else
{
printf("獲取介面MAC成功: %s [%s]/n", strETH.c_str(), strLocalMAC.c_str());
}
// 獲取指定IP網路卡的MAC
strDesMAC = GetMacByIP(strSrcIP, strLocalMAC, strDesIP, strETH);
printf("strDesMAC = %s/n", strDesMAC.c_str());
//
return 0;
}
// 獲取本地某網路卡的MAC
// In: strEth
// Out: 若成功,返回MAC字串,失敗,返回""(空串)
static string GetLocalMac(string & strEth)
{
string strLocalMAC;
int s;
struct ifreq buffer;
char chBuff[MAX_MAC_LEN];
memset(chBuff, 0x0, sizeof(chBuff));
//arp_process(NULL);
s = socket(PF_INET, SOCK_DGRAM, 0);
if (-1 == s)
{
printf("Error: create socket failture/n");
printf("--------------------------------/n/n");
return "";
}
memset(&buffer, 0x00, sizeof(buffer));
strcpy(buffer.ifr_name, strEth.c_str()); // "eth0"
if ( -1 == ioctl(s, SIOCGIFHWADDR, &buffer))
{
printf("Error: 獲取介面 %S MAC 失敗/n", strEth.c_str());
printf("--------------------------------/n/n");
return "";
}
close(s);
for( s = 0; s < 6; s++ )
{
memset(chBuff, 0x0, sizeof(chBuff));
sprintf( chBuff, "%.2X", (unsigned char)buffer.ifr_hwaddr.sa_data[s]);
strLocalMAC += chBuff;
//printf("%.2X", (unsigned char)buffer.ifr_hwaddr.sa_data[s]);
if (s < 5)
{
memset(chBuff, 0x0, sizeof(chBuff));
sprintf( chBuff, "%s", COMPART_MAC);
strLocalMAC += chBuff;
//printf(":");
}
}
//printf("/n");
return strLocalMAC;
}
//-------------------------------------------------------
// 傳送ARP包,並接收ARP應答包,取出MAC
// In: strSrcIP:本機IP,strSrcMAC:本機IP的MAC,strDesIP:被請求應答MAC的IP , strNIC:本地介面名
// Out: 若成功,返回MAC,失敗返回""(空串)
static string GetMacByIP(string strSrcIP, string strSrcMAC, string strDesIP ,string strNIC)
{
int sockfd; // socket handle
struct arp_packet arp; // arp 請求包
struct arp_packet arpRes; // arp 應用答包
struct sockaddr sa; // eth
char chSrcIP[24];
char chDesIP[24];
char chSrcMAC[24];
char chNIC[8];
memset(chSrcIP, 0x00, sizeof(chSrcIP));
memset(chDesIP, 0x00, sizeof(chDesIP));
memset(chSrcMAC, 0x00, sizeof(chSrcMAC));
memset(chNIC, 0x00, sizeof(chNIC));
sprintf(chSrcIP, "%s", strSrcIP.c_str());
sprintf(chDesIP, "%s", strDesIP.c_str());
sprintf(chSrcMAC, "%s", strSrcMAC.c_str());
sprintf(chNIC, "%s", strNIC.c_str());
#define SRC_IP chSrcIP // 源IP
#define DES_IP chDesIP // 目的IP
#define LOCAL_HW chSrcMAC // eth0的MAC
#define DEVICE chNIC // 本機介面名
memset(&arp, 0x00, sizeof(arp));
memset(&arpRes, 0x00, sizeof(arpRes));
#if 1
printf("源IP[%s] 源MAC[%s] 目的IP[%s]/n", /
strSrcIP.c_str(), strSrcMAC.c_str(), strDesIP.c_str());
#endif
sockfd = socket(AF_INET, SOCK_PACKET, htons(0x0806));
if(sockfd < 0)
{
printf("Error: create socket failed/n");
printf("--------------------------------/n/n");
return "";
}
/*
// 設定socket為非阻塞模式
if ( -1 != fcntl(sockfd, F_SETFL, O_NONBLOCK) )
{
printf("設定socket為非阻塞模式成功/n");
}
else
{
printf("Warning: 設定socket為非阻塞模式失敗[errno = %d]/n", errno);
}
*/
// 設定socket接收超時
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec= 100;
if ( 0 == setsockopt( sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) )
{
printf("設定socket接收超時成功/n");
}
else
{
printf("Warning: 設定socket接收超時失敗[errno = %d]/n", errno);
}
#if 1
printf("建立socket SOCK_PACKET 成功/n");
printf("Note: 建立ARP請求包 ....../n");
printf("--------------------------------/n/n");
#endif
// 建立ARP請求包
/* init arp packet header */
arp.ethhdr.ether_type = htons(FRAME_TYPE);
set_hw_addr( (char *)arp.ethhdr.ether_dhost, DES_MAC );
set_hw_addr( (char *)arp.ethhdr.ether_shost, LOCAL_HW );
#if 1
printf("%x|", arp.ethhdr.ether_type);
for (int i = 0; i < 6; i++)
{
printf("%d_", arp.ethhdr.ether_dhost[i]);
}
printf("|");
for (int i = 0; i < 6; i++)
{
printf("%d_", arp.ethhdr.ether_shost[i]);
}
printf("/n--------------------------------/n");
printf("初始化ARP包幀頭(乙太網首部)成功/n/n");
#endif
/* init arp packet data */
printf("初始化ARP包幀資料(ARP請求分組) ....../n");
printf("--------------------------------/n");
arp.arphdr.ar_hrd = htons(HARD_TYPE); // 1
arp.arphdr.ar_pro = htons(PROTO_TYPE); // 0x0800
arp.arphdr.ar_op = htons(OP_CODE); // 1
arp.arphdr.ar_hln = (unsigned char)(6);
arp.arphdr.ar_pln = (unsigned char)(4);
#if 1
printf("%d|%d|%d|%d|%d|/n", arp.arphdr.ar_hrd, arp.arphdr.ar_pro, /
arp.arphdr.ar_op, arp.arphdr.ar_hln, arp.arphdr.ar_pln);
printf("--------------------------------/n");
#endif
set_hw_addr((char *)arp.arphdr.__ar_tha, DES_MAC); // 請求IP的MAC
set_hw_addr((char *)arp.arphdr.__ar_sha, LOCAL_HW); // 傳送者的MAC
set_ip_addr((char *)arp.arphdr.__ar_tip, DES_IP); // 請求MAC的IP
set_ip_addr((char *)arp.arphdr.__ar_sip, SRC_IP); // 源IP
bzero(arp.padding, 18); // 填充18個位元組
#if 1
for (int i = 0; i < 6; i++)
{
printf("%d_", arp.arphdr.__ar_sha[i]);
}
printf("|");
for (int i = 0; i < 6; i++)
{
printf("%d_", arp.arphdr.__ar_sip[i]);
}
printf("|");
for (int i = 0; i < 6; i++)
{
printf("%d_", arp.arphdr.__ar_tha[i]);
}
printf("|");
for (int i = 0; i < 6; i++)
{
printf("%d_", arp.arphdr.__ar_tip[i]);
}
printf("|");
printf("/n--------------------------------/n");
#endif
/* send arp reply packet */
memset(&sa, 0x00, sizeof(sa));
strcpy(sa.sa_data, DEVICE);
// 傳送ARP包
int nSendCount = ARP_SEND_COUNT;
while( (nSendCount --) > 0)
{
printf("傳送ARP請求包[%d Bytes]...... [第%d個]/n", sizeof(arp), nSendCount);
if( sendto(sockfd, &arp, sizeof(arp), 0, (struct sockaddr*) &sa, sizeof(sa)) < 0 )
{
printf("Error: 傳送ARP包失敗 [errno = %d]/n", errno);
return "";
}
}
// 接收ARP應答包
printf("NOte: 接收ARP應答 ....../n");
int nTryCount = 5;
int nRecvByte = 0;
int nAddrLen = sizeof(sa);
do
{
nRecvByte = recvfrom(sockfd, &arpRes, sizeof(arpRes),0, (struct sockaddr*)&sa, (socklen_t*)&nAddrLen);
// 若是所請求IP的ARP應答包,退出while
string strTarIP; /* Target IP address */
if ( nRecvByte >= 60 && 2 == ntohs(arpRes.arphdr.ar_op) )
{
char chBuff[MAX_MAC_LEN];
string strTarIP; /* Target IP address */
// 格式化IP
for (int s = 0; s < 4; s++)
{
memset(chBuff, 0x00, sizeof(chBuff));
sprintf( (char *)chBuff, "%d", (unsigned char)arpRes.arphdr.__ar_sip[s]);
strTarIP += chBuff;
if (s < 3)
{
memset(chBuff, 0x00, sizeof(chBuff));
sprintf( (char *)chBuff, "%s", ".");
strTarIP += chBuff;
}
}
if ( !strcmp(strTarIP.c_str(), strDesIP.c_str()) )
{
printf("/n請求IP[%s] = 應答IP[%s]/n", strDesIP.c_str(), strTarIP.c_str());
break;
}
}
}while( nTryCount -- ); // 接收ARP應答包的次數
printf("已接收到ARP應答包 [%d Bytes]/n", nRecvByte);
// 接收超時,或錯誤
if ( nRecvByte == -1 )
{
printf("Warning: 接收超時,或計算機[%s]沒有響應/n", strDesIP.c_str());
close(sockfd);
return "";
}
printf("分析ARP應答包 ....../n");
char chBuff[MAX_MAC_LEN];
string strTarIP; /* Target IP address */
string strTarMAC; /* Target hardware address */
memset(chBuff, 0x00, sizeof(chBuff));
// 格式化IP
for (int s = 0; s < 4; s++)
{
memset(chBuff, 0x00, sizeof(chBuff));
sprintf( (char *)chBuff, "%d", (unsigned char)arpRes.arphdr.__ar_sip[s]);
strTarIP += chBuff;
if (s < 3)
{
memset(chBuff, 0x00, sizeof(chBuff));
sprintf( (char *)chBuff, "%s", ".");
strTarIP += chBuff;
}
}
// 格式化MAC
memset(chBuff, 0x00, sizeof(chBuff));
for (int s = 0; s < 6; s++)
{
memset(chBuff, 0x00, sizeof(chBuff));
sprintf( (char *)chBuff, "%02X", (unsigned char)arpRes.arphdr.__ar_sha[s]);
strTarMAC += chBuff;
if (s < 5)
{
memset(chBuff, 0x00, sizeof(chBuff));
sprintf( (char *)chBuff, "%s", COMPART_MAC);
strTarMAC += chBuff;
}
}
// 輸出目的IP,目的MAC
printf("應答IP[%s] 對應的MAC[%s]/n", strTarIP.c_str(), strTarMAC.c_str());
printf("/n--------------------------------/n/n");
close(sockfd);
// 返回被請求的MAC
return strTarMAC;
/* return */
}
// 填充MAC
void set_hw_addr (char buf[], char *str)
{
int i;
char c, val;
for(i = 0; i < 6; i++)
{
if (!(c = tolower(*str++)))
perror("Invalid hardware address"),exit(1);
if (isdigit(c))
val = c - '0';
else if (c >= 'a' && c <= 'f')
val = c-'a'+10;
else
perror("Invalid hardware address"),exit(1);
buf[i] = val << 4;
if (!(c = tolower(*str++)))
perror("Invalid hardware address"),exit(1);
if (isdigit(c))
val = c - '0';
else if (c >= 'a' && c <= 'f')
val = c-'a'+10;
else
perror("Invalid hardware address"),exit(1);
buf[i] |= val;
if (*str == ':')
str++;
}
}
// 填充IP
void set_ip_addr(char *buf, char *str)
{
struct in_addr addr;
memset(&addr, 0x00, sizeof(addr));
addr.s_addr = inet_addr(str);
memcpy(buf, &addr, 4);
}
//-------------------------------------------------------
// end file
// --------------------------------------------------------------------------------------------------------------
# makefile
bin = get_mac
objets = main.o
rubbish = $(objets) $(bin)
$(bin) : main.o
g++ -o $(bin) main.o
main.o : main.cpp all.h
g++ -c main.cpp
.PHONY : clean
clean :
-rm $(rubbish)
# end makefile
/******************************************************************************/
/* 時光飛快流逝,2005年寫的程式碼, 2005年是我工作2年後。7年後又可以重用, 我重新修改成C程式碼。*/
- /*******************************************************************************
- * File: main.c
- * Description:
- * Author: Xiaoyong Wen <wen_kernel@163.com>, 2005/06/20,a.m.
- *
- * Fix hisoty:
- * v1.1.0 Xiaoyong Wen <wen_kernel@163.com>, 20130808, p.m., Reconstruct to c code
- *
- *******************************************************************************/
- #define DEBUG /* show debug info only */
- #if defined(DEBUG)
- #define wenxy_debug(fmt, args...) \
- printf(fmt, ##args)
- #else
- #define wenxy_debug(fmt, ...)
- #endif
- #include <unistd.h>
- #include <memory.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/ioctl.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <net/if.h>
- #include <string.h>
- #include <errno.h>
- // ---------------------
- // 建立ARP包的標頭檔案
- #include<netinet/in.h>
- #include<arpa/inet.h>
- /* #include<linux/if_ether.h> */
- #include<ctype.h>
- #include <fcntl.h>
- // ---------------------
- #define MAX_MAC_LEN 24 // MAC字串緩衝區的最大長度(byte)
- #define COMPART_MAC ":" // MAC字串的分格符, Warnning:修改此巨集,必須再修改源程式!!!
- #define MAX_BUF_LEN 128
- static char strETH[MAX_BUF_LEN] = {0}; // 本機NIC名稱
- static char strLocalMAC[MAX_BUF_LEN] = {0}; // 本機MAC
- static char strSrcIP[MAX_BUF_LEN] = {0}; // 本機IP
- static char strDesMAC[MAX_BUF_LEN] = {0}; // 目的MAC
- static char strDesIP[MAX_BUF_LEN] = {0}; // 目的IP
- static char strTarIP[MAX_BUF_LEN] = {0}; /* Target IP address */
- static char strTarMAC[MAX_BUF_LEN] = {0}; /* Target hardware address */
- static int find_ip_flag = 0; /* 1 means find, 0 means not find */
- // function declare
- static char * GetLocalMac(char *strEth); // get loacl NIC's MAC
- static void set_ip_addr(char *,char *); // 填充IP
- static void set_hw_addr(char buf[], char *str); // 填充MAC
- static char * GetMacByIP(char *strSrcIP, char *strSrcMAC, char *strDesIP ,char *strNIC); // 獲取指定IP的MAC
- int arp_main( char *nic_name, char *nic_ip, char *des_ip);
- /*
- #define SRC_IP "10.0.1.77" // 源IP
- #define DES_IP "10.0.1.35" // 目的IP
- #define LOCAL_HW "00:C0:4C:39:0D:6F" // 10.0.1.77的eth0的MAC
- #define DEVICE "eth0" // 介面
- */
- #define PADD_MAC "00:00:00:00:00:00" // 填充的MAC
- #define DES_MAC "FF:FF:FF:FF:FF:FF" // 廣播MAC
- #define ARP_SEND_COUNT 3 // 傳送ARP請求的ARP包的個數
- #define RX_ARP_COUNT 3 // rx count of ARP response
- #define SLEEP_MAX_US (1000 * 100) /* unit microsecond */
- struct ether_header
- {
- unsigned char ether_dhost[6]; /* destination eth addr */
- unsigned char ether_shost[6]; /* source ether addr */
- unsigned short ether_type; /* packet type ID field */
- };
- struct arp_header
- {
- unsigned short int ar_hrd; /* Format of hardware address. */
- unsigned short int ar_pro; /* Format of protocol address. */
- unsigned char ar_hln; /* Length of hardware address. */
- unsigned char ar_pln; /* Length of protocol address. */
- // -------------------------
- unsigned short int ar_op; /* ARP opcode (command). */
- unsigned char __ar_sha[6]; /* Sender hardware address. */
- unsigned char __ar_sip[4]; /* Sender IP address. */
- unsigned char __ar_tha[6]; /* Target hardware address. */
- unsigned char __ar_tip[4]; /* Target IP address. */
- // -------------------------
- };
- struct arp_packet
- {
- struct ether_header ethhdr;
- struct arp_header arphdr;
- unsigned char padding[18]; /* filled with 0 */
- };
- /* arp reply:
- * op = 2
- * ethhdr.ether_dhost = arphdr.__ar_tha = switch hard addr
- * ethhdr.ether_shost = arphdr.__ar_sha = local hard addr
- * arphdr.__ar_tip = switch ip
- * arphdr.__ar_sip = victim ip
- */
- #define FRAME_TYPE 0x0806 /* arp=0x0806,rarp=0x8035 */
- #define HARD_TYPE 1 /* ethernet is 1 */
- #define PROTO_TYPE 0x0800 /* IP is 0x0800 */
- #define OP_CODE 1 /* arp=1/2,1為請求,2為應答,rarp=3/4 */
- int main( int argc, char *argv[] )
- {
- // 檢查引數
- if ( argc != 4 )
- {
- wenxy_debug("Useage: %s [interface name of the IP] [IP] [ARP IP]\n\n", argv[0]);
- return 0;
- }
- return arp_main( argv[1], argv[2], argv[3] );
- }
- // linux下獲取LAN裡指定IP的網路卡MAC
- // In: nic_name: 本地網路卡名字, nic_ip:本機IP,des_ip:目的IP
- // Out: 1表示獲取MAC成功,des_ip已被使用, -1表示發生錯誤,0表示des_ip未使用
- int arp_main( char *nic_name, char *nic_ip, char *des_ip)
- {
- strcpy(strETH, nic_name); //"eth0";
- strcpy(strSrcIP, nic_ip); //"10.0.1.77";
- strcpy(strDesIP, des_ip); //"10.0.1.69";
- wenxy_debug("Run ......\n");
- wenxy_debug("獲取 %s 介面的MAC ......\n", strETH);
- // 獲取指定NIC名稱的MAC
- /*strLocalMAC = GetLocalMac(strETH);*/
- GetLocalMac(strETH);
- #if 0
- wenxy_debug("Note: %s[%s]\n", strETH, strLocalMAC);
- #endif
- // 獲取指定介面MAC
- if ( 0 == strcmp( (const char*)strLocalMAC, (const char*)"") )
- {
- wenxy_debug("Error: call strcmp() failed\n");
- wenxy_debug("--------------------------------\n\n");
- return -1;
- }
- else
- {
- wenxy_debug("獲取介面MAC成功: %s [%s]\n", strETH, strLocalMAC);
- }
- // 獲取指定IP網路卡的MAC
- /*strDesMAC = GetMacByIP(strSrcIP, strLocalMAC, strDesIP, strETH);*/
- GetMacByIP(strSrcIP, strLocalMAC, strDesIP, strETH);
- wenxy_debug("strDesMAC = %s\n", strDesMAC);
- if(1 == find_ip_flag)
- {
- printf("Note: strDesIP: %s, strDesMAC: %s\n", strDesIP, strDesMAC);
- return 1;
- }
- else
- {
- printf("Note: strDesIP: %s does not use\n", strDesIP);
- return 0;
- }
- }
- // 獲取本地某網路卡的MAC
- // In: strEth
- // Out: 若成功,返回MAC字串,失敗,返回""(空串)
- static char * GetLocalMac(char *strEth)
- {
- int s;
- struct ifreq buffer;
- char chBuff[MAX_MAC_LEN];
- unsigned int str_len = 0;
- unsigned int offset = 0;
- memset(chBuff, 0x0, sizeof(chBuff));
- //arp_process(NULL);
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (-1 == s)
- {
- wenxy_debug("Error: create socket failture\n");
- wenxy_debug("--------------------------------\n\n");
- return "";
- }
- memset(&buffer, 0x00, sizeof(buffer));
- strcpy(buffer.ifr_name, strEth); // "eth0"
- if ( -1 == ioctl(s, SIOCGIFHWADDR, &buffer))
- {
- wenxy_debug("Error: 獲取介面 %s MAC 失敗\n", strEth);
- wenxy_debug("--------------------------------\n\n");
- return "";
- }
- close(s);
- offset = 0;
- for( s = 0; s < 6; s++ )
- {
- memset(chBuff, 0x0, sizeof(chBuff));
- sprintf( chBuff, "%.2X", (unsigned char)buffer.ifr_hwaddr.sa_data[s]);
- str_len = strlen(chBuff);
- memcpy(strLocalMAC + offset, chBuff, str_len);
- offset += str_len;
- //wenxy_debug("%.2X", (unsigned char)buffer.ifr_hwaddr.sa_data[s]);
- if (s < 5)
- {
- memset(chBuff, 0x0, sizeof(chBuff));
- sprintf( chBuff, "%s", COMPART_MAC);
- str_len = strlen(chBuff);
- memcpy(strLocalMAC + offset, chBuff, str_len);
- offset += str_len;
- //wenxy_debug(":");
- }
- }
- //wenxy_debug("\n");
- return strLocalMAC;
- }
- //-------------------------------------------------------
- // 傳送ARP包,並接收ARP應答包,取出MAC
- // In: strSrcIP:本機IP,strSrcMAC:本機IP的MAC,strDesIP:被請求應答MAC的IP , strNIC:本地介面名
- // Out: 若成功,返回MAC,失敗返回""(空串)
- static char * GetMacByIP(char *strSrcIP, char *strSrcMAC, char *strDesIP, char *strNIC)
- {
- int sockfd; // socket handle
- struct arp_packet arp; // arp 請求包
- struct arp_packet arpRes; // arp 應用答包
- struct sockaddr sa; // eth
- char chSrcIP[24];
- char chDesIP[24];
- char chSrcMAC[24];
- char chNIC[8];
- unsigned int str_len = 0;
- unsigned int offset = 0;
- int i;
- int s;
- find_ip_flag = 0;
- memset(chSrcIP, 0x00, sizeof(chSrcIP));
- memset(chDesIP, 0x00, sizeof(chDesIP));
- memset(chSrcMAC, 0x00, sizeof(chSrcMAC));
- memset(chNIC, 0x00, sizeof(chNIC));
- sprintf(chSrcIP, "%s", strSrcIP);
- sprintf(chDesIP, "%s", strDesIP);
- sprintf(chSrcMAC, "%s", strSrcMAC);
- sprintf(chNIC, "%s", strNIC);
- #define SRC_IP chSrcIP // 源IP
- #define DES_IP chDesIP // 目的IP
- #define LOCAL_HW chSrcMAC // eth0的MAC
- #define DEVICE chNIC // 本機介面名
- memset(&arp, 0x00, sizeof(arp));
- memset(&arpRes, 0x00, sizeof(arpRes));
- #if 1
- wenxy_debug("源IP[%s] 源MAC[%s] 目的IP[%s]\n", strSrcIP, strSrcMAC, strDesIP);
- #endif
- sockfd = socket(AF_INET, SOCK_PACKET, htons(0x0806));
- if(sockfd < 0)
- {
- wenxy_debug("Error: create socket failed\n");
- wenxy_debug("--------------------------------\n\n");
- return "";
- }
- /*
- // 設定socket為非阻塞模式
- if ( -1 != fcntl(sockfd, F_SETFL, O_NONBLOCK) )
- {
- wenxy_debug("設定socket為非阻塞模式成功\n");
- }
- else
- {
- wenxy_debug("Warning: 設定socket為非阻塞模式失敗[errno = %d]\n", errno);
- }
- */
- // 設定socket接收超時
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec= 100;
- if ( 0 == setsockopt( sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) )
- {
- wenxy_debug("設定socket接收超時成功\n");
- }
- else
- {
- wenxy_debug("Warning: 設定socket接收超時失敗[errno = %d]\n", errno);
- }
- #if 1
- wenxy_debug("建立socket SOCK_PACKET 成功\n");
- wenxy_debug("Note: 建立ARP請求包 ......\n");
- wenxy_debug("--------------------------------\n\n");
- #endif
- // 建立ARP請求包
- /* init arp packet header */
- arp.ethhdr.ether_type = htons(FRAME_TYPE);
- set_hw_addr( (char *)arp.ethhdr.ether_dhost, DES_MAC );
- set_hw_addr( (char *)arp.ethhdr.ether_shost, LOCAL_HW );
- #if 1
- wenxy_debug("%x|", arp.ethhdr.ether_type);
- for (i = 0; i < 6; i++)
- {
- wenxy_debug("%d_", arp.ethhdr.ether_dhost[i]);
- }
- wenxy_debug("|");
- for (i = 0; i < 6; i++)
- {
- wenxy_debug("%d_", arp.ethhdr.ether_shost[i]);
- }
- wenxy_debug("\n--------------------------------\n");
- wenxy_debug("初始化ARP包幀頭(乙太網首部)成功\n\n");
- #endif
- /* init arp packet data */
- wenxy_debug("初始化ARP包幀資料(ARP請求分組) ......\n");
- wenxy_debug("--------------------------------\n");
- arp.arphdr.ar_hrd = htons(HARD_TYPE); // 1
- arp.arphdr.ar_pro = htons(PROTO_TYPE); // 0x0800
- arp.arphdr.ar_op = htons(OP_CODE); // 1
- arp.arphdr.ar_hln = (unsigned char)(6);
- arp.arphdr.ar_pln = (unsigned char)(4);
- #if 1
- wenxy_debug("%d|%d|%d|%d|%d|\n", arp.arphdr.ar_hrd, arp.arphdr.ar_pro,
- arp.arphdr.ar_op, arp.arphdr.ar_hln, arp.arphdr.ar_pln);
- wenxy_debug("--------------------------------\n");
- #endif
- set_hw_addr((char *)arp.arphdr.__ar_tha, DES_MAC); // 請求IP的MAC
- set_hw_addr((char *)arp.arphdr.__ar_sha, LOCAL_HW); // 傳送者的MAC
- set_ip_addr((char *)arp.arphdr.__ar_tip, DES_IP); // 請求MAC的IP
- set_ip_addr((char *)arp.arphdr.__ar_sip, SRC_IP); // 源IP
- bzero(arp.padding, 18); // 填充18個位元組
- #if 1
- for (i = 0; i < 6; i++)
- {
- wenxy_debug("%d_", arp.arphdr.__ar_sha[i]);
- }
- wenxy_debug("|");
- for (i = 0; i < 6; i++)
- {
- wenxy_debug("%d_", arp.arphdr.__ar_sip[i]);
- }
- wenxy_debug("|");
- for (i = 0; i < 6; i++)
- {
- wenxy_debug("%d_", arp.arphdr.__ar_tha[i]);
- }
- wenxy_debug("|");
- for (i = 0; i < 6; i++)
- {
- wenxy_debug("%d_", arp.arphdr.__ar_tip[i]);
- }
- wenxy_debug("|");
- wenxy_debug("\n--------------------------------\n");
- #endif
- /* send arp reply packet */
- memset(&sa, 0x00, sizeof(sa));
- strcpy(sa.sa_data, DEVICE);
- // 傳送ARP包
- int nSendCount = ARP_SEND_COUNT;
- int nRecvByte = 0;
- while( (nSendCount --) > 0)
- {
- wenxy_debug("傳送ARP請求包[%d Bytes]...... [第%d個]\n", sizeof(arp), nSendCount);
- if( sendto(sockfd, &arp, sizeof(arp), 0, (struct sockaddr*) &sa, sizeof(sa)) < 0 )
- {
- wenxy_debug("Error: 傳送ARP包失敗 [errno = %d]\n", errno);
- return "";
- }
- // 接收ARP應答包
- wenxy_debug("Note: 接收ARP應答 ......\n");
- int nTryCount = RX_ARP_COUNT;
- int nAddrLen = sizeof(sa);
- do
- {
- /* because network and host delay */
- usleep(SLEEP_MAX_US);
- nRecvByte = recvfrom(sockfd, &arpRes, sizeof(arpRes),0, (struct sockaddr*)&sa, (socklen_t*)&nAddrLen);
- // 若是所請求IP的ARP應答包,退出while
- if ( nRecvByte >= 60 && 2 == ntohs(arpRes.arphdr.ar_op) )
- {
- char chBuff[MAX_MAC_LEN];
- // 格式化IP
- offset = 0;
- for (s = 0; s < 4; s++)
- {
- memset(chBuff, 0x00, sizeof(chBuff));
- sprintf( (char *)chBuff, "%d", (unsigned char)arpRes.arphdr.__ar_sip[s]);
- //wenxy_debug("chBuff: %s\n", chBuff);
- //strTarIP += chBuff;
- str_len = strlen(chBuff);
- memcpy(strTarIP + offset, chBuff, str_len);
- offset += str_len;
- if (s < 3)
- {
- memset(chBuff, 0x00, sizeof(chBuff));
- sprintf( (char *)chBuff, "%s", ".");
- //strTarIP += chBuff;
- str_len = 1;
- memcpy(strTarIP + offset, chBuff, str_len);
- offset += str_len;
- }
- }
- if ( !strcmp(strTarIP, strDesIP) )
- {
- wenxy_debug("\n請求IP[%s] = 應答IP[%s]\n", strDesIP, strTarIP);
- find_ip_flag = 1; /* find ip */
- goto analyse_arp_response;
- }
- }
- }while( nTryCount -- ); // 接收ARP應答包的次數
- }
- analyse_arp_response:
- wenxy_debug("已接收到ARP應答包 [%d Bytes]\n", nRecvByte);
- // 接收超時,或錯誤
- if ( nRecvByte == -1 )
- {
- wenxy_debug("Warning: 接收超時,或計算機[%s]沒有響應\n", strDesIP);
- close(sockfd);
- return "";
- }
- wenxy_debug("分析ARP應答包 ......\n");
- char chBuff[MAX_MAC_LEN];
- memset(chBuff, 0x00, sizeof(chBuff));
- // 格式化IP
- offset = 0;
- for (s = 0; s < 4; s++)
- {
- memset(chBuff, 0x00, sizeof(chBuff));
- sprintf( (char *)chBuff, "%d", (unsigned char)arpRes.arphdr.__ar_sip[s]);
- //strTarIP += chBuff;
- str_len = strlen(chBuff);
- memcpy(strTarIP + offset, chBuff, str_len);
- offset += str_len;
- if (s < 3)
- {
- memset(chBuff, 0x00, sizeof(chBuff));
- sprintf( (char *)chBuff, "%s", ".");
- //strTarIP += chBuff;
- str_len = strlen(chBuff);
- memcpy(strTarIP + offset, chBuff, str_len);
- offset += str_len;
- }
- }
- // 格式化MAC
- memset(chBuff, 0x00, sizeof(chBuff));
- offset = 0;
- for (s = 0; s < 6; s++)
- {
- memset(chBuff, 0x00, sizeof(chBuff));
- sprintf( (char *)chBuff, "%02X", (unsigned char)arpRes.arphdr.__ar_sha[s]);
- //strTarMAC += chBuff;
- str_len = strlen(chBuff);
- memcpy(strTarMAC + offset, chBuff, str_len);
- offset += str_len;
- if (s < 5)
- {
- memset(chBuff, 0x00, sizeof(chBuff));
- sprintf( (char *)chBuff, "%s", COMPART_MAC);
- //strTarMAC += chBuff;
- str_len = strlen(chBuff);
- memcpy(strTarMAC + offset, chBuff, str_len);
- offset += str_len;
- }
- }
- // 輸出目的IP,目的MAC
- wenxy_debug("應答IP[%s] 對應的MAC[%s]\n", strTarIP, strTarMAC);
- wenxy_debug("\n--------------------------------\n\n");
- close(sockfd);
- // 返回被請求的MAC
- strcpy(strDesMAC, strTarMAC);
- /* return */
- return strDesMAC;
- }
- // 填充MAC
- static void set_hw_addr (char buf[], char *str)
- {
- int i;
- char c, val;
- for(i = 0; i < 6; i++)
- {
- if (!(c = tolower(*str++)))
- perror("Invalid hardware address"),exit(1);
- if (isdigit(c))
- val = c - '0';
- else if (c >= 'a' && c <= 'f')
- val = c-'a'+10;
- else
- perror("Invalid hardware address"),exit(1);
- buf[i] = val << 4;
- if (!(c = tolower(*str++)))
- perror("Invalid hardware address"),exit(1);
- if (isdigit(c))
- val = c - '0';
- else if (c >= 'a' && c <= 'f')
- val = c-'a'+10;
- else
- perror("Invalid hardware address"),exit(1);
- buf[i] |= val;
- if (*str == ':')
- str++;
- }
- }
- // 填充IP
- static void set_ip_addr(char *buf, char *str)
- {
- struct in_addr addr;
- memset(&addr, 0x00, sizeof(addr));
- addr.s_addr = inet_addr(str);
- memcpy(buf, &addr, 4);
- }
- //-------------------------------------------------------
- // end file
- ################################################################################
- # File: Makefile
- # Description:
- # Author: Xiaoyong Wen <wen_kernel@163.com>, 20130807, AM.
- #
- # Fix hisoty:
- #
- ################################################################################
- debug := 1
- ifdef debug
- CFLAGS += -g
- else
- CFLAGS += -O2
- endif
- #CC := g++
- CC := gcc
- target_bin := lan_mac_scan
- bin := main
- obj := main.o
- #src := main.c
- src := $(wildcard *.c) $(wildcard *.h)
- .PHONY : clean all debug
- all : $(bin)
- cp main $(target_bin)
- @-ls -l $(target_bin)
- $(bin) : $(obj)
- $(obj) : $(src)
- debug:
- @echo $(src)
- @echo $(obj)
- @echo $(CFLAGS)
- @echo $(LDFLAGS)
- clean:
- rm -f $(bin) $(obj) $(target_bin)
Useage: ./lan_mac_scan [interface name of the IP] [IP] [ARP IP]
#./lan_mac_scan 本地網路卡名字 本地網路卡的IP地址 檢查是否使用的IP地址
例如:
#./lan_mac_scan eth0 172.22.0.26 172.22.0.25
注意事項:
1. Unix類作業系統的核心已支援packet socket。
2. 需要root許可權。
3. 只能在LAN中使用,ARP包不能跨越router,除非router上有ARP proxy.
4. 如果本地機器或者遠端機器安裝有firewall,ARP包會被過濾而失效。