(注:部分摘自”Linux C編程一站式學習“)
以太網(RFC 894)幀格式
圖一 以太網數據包類型
其中的源地址和目的地址是指網卡的硬件地址(也叫MAC地址),長度是48位,是在網卡出廠時固化的。用ifconfig命令看一下,“HWaddr 00:15:F2:14:9E:3F”部分就是硬件地址。協議字段有三種值,分別對應IP、ARP、RARP。幀末尾是CRC校驗碼。
以太網幀中的數據長度規定最小46字節,最大1500字節,ARP和RARP數據包的長度不夠46字節,要在後面補填充位。最大值1500稱爲以太網的最大傳輸單元(MTU),不同的網絡類型有不同的MTU,如果一個數據包從以太網路由到撥號鏈路上,數據包長度大於撥號鏈路的MTU了,則需要對數據包進行分片(fragmentation)。ifconfig命令的輸出中也有“MTU:1500”。注意,MTU這個概念指數據幀中有效載荷的最大長度,不包括幀首部的長度。
在網絡通訊時,源主機的應用程序知道目的主機的IP地址和端口號,卻不知道目的主機的硬件地址,而數據包首先是被網卡接收到再去處理上層協議的,如果接收到的數據包的硬件地址與本機不符,則直接丟棄。因此在通訊前必須獲得目的主機的硬件地址。ARP協議就起到這個作用。源主機發出ARP請求,詢問“IP地址是192.168.0.1的主機的硬件地址是多少”,並將這個請求廣播到本地網段(以太網幀首部的硬件地址填FF:FF:FF:FF:FF:FF表示廣播),目的主機接收到廣播的ARP請求,發現其中的IP地址與本機相符,則發送一個ARP應答數據包給源主機,將自己的硬件地址填寫在應答包中。
每臺主機都維護一個ARP緩存表,可以用arp -a命令查看。緩存表中的表項有過期時間(一般爲20分鐘),如果20分鐘內沒有再次使用某個表項,則該表項失效,下次還要發ARP請求來獲得目的主機的硬件地址。想一想,爲什麼表項要有過期時間而不是一直有效?
圖二 arp數據包類型
注意到源MAC地址、目的MAC地址在以太網首部和ARP請求中各出現一次,對於鏈路層爲以太網的情況是多餘的,但如果鏈路層是其它類型的網絡則有可能是必要的。硬件類型指鏈路層網絡類型,1爲以太網,協議類型指要轉換的地址類型,0x0800爲IP地址,後面兩個地址長度對於以太網地址和IP地址分別爲6和4(字節),op字段爲1表示ARP請求,op字段爲2表示ARP應答。
有了上面的基礎知識,下面我們就來實戰編程:
1、確定socket的參數
根據圖一,我們可以看出arp,rarp和ip雖然同屬於網絡層(又名IP層),但是他們的數據包裝是獨立的。雖然icmp和igmp也處在IP層,但是它們又需要ip數據報的包裝。所以我們在爲arp和rarp建立socket的時候,就不能利用ip的原始數據報(SOCK_RAW)了,我們需要最原始的以太網幀的數包(SOCK_PACKET);在對於網絡類型的選擇上,可以根據需要選擇IPv4(AF_INET)或IPv6(AF_INET6);arp的協議類型跟以太網幀數據類型一樣,所以應該是0x0806,在linux的”Ethernet Protocol ID“中定義了
#define ETH_P_ARP 0x0806
那麼,我們就可以簡單的以爲socket套接字的創建是:sfd = socket(AF_INET,SOCK_PACKET,htons(ETH_P_ARP));
2、確定ARP數據包的結構
根據圖二,確定如下結構體
struct arp_packet
{
//以太網首部
unsigned char ap_dstmac[6]; //6字節
unsigned char ap_srcmac[6]; //6字節
unsigned short ap_frame; //2字節
//arp
unsigned short ap_hwtype; //2字節:硬件地址類型
unsigned short ap_prototype; //2字節:軟件地址類型
unsigned char ap_hwlen; //1字節:硬件地址長度
unsigned char ap_prolen; //1字節:軟件地址長度
unsigned short ap_op; //2字節:操作類型
unsigned char ap_frommac[6];//6字節
unsigned char ap_fromip[4]; //4字節
unsigned char ap_tomac[6]; //6字節
unsigned char ap_toip[4]; //4字節
//18字節:填充字節,因爲以太網數據最少要46字節
unsigned char ap_padding[18];
};
3、獲取本地ip地址和mac地址
linux裏面提供了mac地址和ip地址獲取的ioctl參數;
#define SIOCGIFADDR 0x8915 /* get PA address */
#define SIOCSIFADDR 0x8916 /* set PA address */
#define SIOCSIFHWADDR 0x8924 /* set hardware address */
#define SIOCGIFHWADDR 0x8927 /* Get hardware address */
在獲取本機mac地址和ip地址之前,我們需要告訴ioctl我們要獲取那個網卡的參數:
struct ifreq eth;
strcpy(eth.ifr_name,"eth0");
/* Get eth0 Hardware Address */
int ret = ioctl(fds,SIOCGIFHWADDR, ð);
if(ret < 0){
perror("Get Hardware Address Fail:");
goto close_socket;
}
/* Get eth0 IP Address */
ret = ioctl(fds, SIOCGIFADDR, ð);
if(ret < 0){
perror("Get IP Address Fail:");
goto close_socket;
}
unsigned char mac_addr[6];
memcpy(mac_addr,eth.ifr_hwaddr.sa_data,6);
/* In "struct sockaddr",ip address starts from 'sa_data' two bytes later*/
unsigned char ip_addr[4];
memcpy(ip_addr,eth.ifr_addr.sa_data+2,4);
4、數據包數據填寫
struct arp_packet arp_in;
bzero(&arp_in,sizeof(struct arp_packet));
unsigned char broadcast_mac[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
memcpy(arp_in.ap_dstmac,broadcast_mac,6);
memcpy(arp_in.ap_srcmac,mac_addr,6);
arp_in.ap_frame = htons(ETH_P_ARP);
arp_in.ap_hwtype = htons(0x0001);
arp_in.ap_prototype = htons(ETH_P_IP);
arp_in.ap_hwlen = 6;
arp_in.ap_prolen = 4;
arp_in.ap_op = htons(0x0001);//0x0001-ARP req 0x0002-ARP Reply
memcpy(arp_in.ap_frommac,mac_addr,6);
memcpy(arp_in.ap_fromip,ip_addr,4);
5、數據與接收
由於在這種情況下,對方的mac地址都是未知的,而且數據的發送也是作爲廣播模式發送。
所以這個時候我們只需告訴底層我們需要用那個網卡發送就可以了。
struct sockaddr eth;
eth.sa_family = AF_INET;
strcpy(eth.sa_data,"eth0");
ret = sendto(fds,&arp_in,sizeof(struct arp_packet),0,
(struct sockaddr *)ð,sizeof(struct sockaddr));
if(ret < 0){
perror("Send Reqire ARP Packet Fail:");
goto close_socket;
}
struct arp_packet arp_rc;
socklen_t slen = sizeof(struct sockaddr);
bzero(&arp_rc,sizeof(struct arp_packet));
ret = recvfrom(fds,&arp_rc,sizeof(struct arp_packet),0,
(struct sockaddr *)ð,&slen);
if(ret < 0){
perror("Receive Replay ARP Packet Fail:");
goto close_socket;
}
....
close_socket;
close(fds);
return (ret > 0 ? 1 : ret);
6、問題到此結束,測試後的結果如下:
-----------------------------Sendto----------------------------
Dest MAC:FF:FF:FF:FF:FF:FF
SRC MAC:00:22:15:67:F8:16
HW TYPE:0806
From :210.42.158.204
To :210.42.158.212
ARP OP:0100
-----------------------------recvfrom-------------------------
Dest MAC:00:22:15:67:F8:16
SRC MAC:00:E0:4C:DC:AA:1E
HW TYPE:0806
From :210.42.158.212
To :210.42.158.204
ARP OP:0200
至於ARP攻擊,我小測試了一把,還是可以的。但是許多電腦有arp防護,或者防火牆,arp攻擊時沒有用的。
爲了社會的安寧,這裏我就不把arp攻擊的代碼貼出來了。
如果有什麼問題,請各位留言指點!謝謝!