歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux 網絡編程——原始套接字實例:MAC 地址掃描器

如果 A (192.168.1.1 )向 B (192.168.1.2 )發送一個數據包,那麼需要的條件有 ip、port、使用的協議(TCP/UDP)之外還需要 MAC 地址,因為在以太網數據包中 MAC 地址是必須要有的。那麼怎樣才能知道對方的 MAC 地址?答案是:它通過 ARP 協議來獲取對方的 MAC 地址。

ARP(Address Resolution Protocol,地址解析協議),是 TCP/IP 協議族中的一個,主要用於查詢指定 ip 所對應的的 MAC(通過 ip 找 MAC)。

請求方使用廣播來發送請求,應答方使用單播來回送數據。收到返回消息後將該 IP 地址和物理地址存入本機 ARP 緩存中並保留一定時間,下次請求時直接查詢 ARP 緩存以節約資源。

以機器 A 獲取機器 B 的 MAC 為例,A 廣播發送一個 ARP 請求包,和 A 同在一個局域網的主機都會收到這個請求包,每個機器都會比較自己的 ip 和請求包的目的 ip 是不是一樣的,如果不一樣,就丟棄這個請求包,結果,只有 B 機器符合條件,B 機器單獨給 A 發送 ARP 應答包,應答包帶上了 B 的 ip 所對應的 MAC 地址,當 A 收到這個應答包後,就把 B 的 ip 以及其對應的 MAC 地址存入本機 ARP 緩存中。

在 Linux 查看 ARP 緩存表:arp

在 Windows 查看 ARP 緩存表:arp -a

ARP頭部

1、Dest MAC:目的 MAC 地址

2、Src MAC:源 MAC 地址

3、幀類型:0x0806

4、硬件類型:1(以太網)

5、協議類型:0x0800(IP地址)

6、硬件地址長度:6

7、協議地址長度:4

8、OP:1(ARP請求),2(ARP應答),3(RARP請求),4(RARP應答)

接下來這個例子為,虛擬機(Ubuntu)獲取 PC 機的 MAC 地址:

先查看 ubuntu 的 ip 和 MAC 地址:

源代碼下載

------------------------------------------分割線------------------------------------------

免費下載地址在 http://linux.linuxidc.com/

用戶名與密碼都是www.linuxidc.com

具體下載目錄在 /2015年資料/4月/7日/Linux 常用編輯器之Vim/

下載方法見 http://www.linuxidc.com/Linux/2013-07/87684.htm

------------------------------------------分割線------------------------------------------

完整代碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <net/if.h>    //struct ifreq
#include <sys/ioctl.h>   //ioctl、SIOCGIFADDR
#include <sys/socket.h>
#include <netinet/ether.h>  //ETH_P_ALL
#include <netpacket/packet.h> //struct sockaddr_ll
#include <netinet/in.h>

int main(int argc,char *argv[])
{
 //1.創建通信用的原始套接字
 int sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
 
 //2. 根據各種協議首部格式構建發送數據報
 unsigned char send_msg[1024] = {
  //--------------組MAC--------14------
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //dst_mac: FF:FF:FF:FF:FF:FF
  0x00, 0x0c, 0x29, 0x97, 0xc7,0xc1, //src_mac: 00:0c:29:97:c7:c1
  0x08, 0x06,       //類型:0x0806 ARP協議
 
  //--------------組ARP--------28-----
  0x00, 0x01, 0x08, 0x00,    //硬件類型1(以太網地址),協議類型0x0800(IP) 
  0x06, 0x04, 0x00, 0x01,    //硬件、協議地址分別是6、4,op:(1:arp請求,2:arp應答)
  0x00, 0x0c, 0x29, 0x97, 0xc7,0xc1, //發送端的MAC地址
  10,  221,  0, 11,      //發送端的IP地址
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //目的MAC地址(由於要獲取對方的MAC,所以目的MAC置零)
  10, 221, 20, 10    //目的IP地址
 };
 
 //3.數據初始化
 struct sockaddr_ll sll;     //原始套接字地址結構
 struct ifreq ethreq;     //網絡接口地址
 strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ); //指定網卡名稱
 
 //4.將網絡接口賦值給原始套接字地址結構
 ioctl(sock_raw_fd, SIOCGIFINDEX, (char *)ðreq);
 bzero(&sll, sizeof(sll));
 sll.sll_ifindex = ethreq.ifr_ifindex;
 
 //5. 發送 ARP 請求包
 int len = sendto(sock_raw_fd, send_msg, 42, 0 , (struct sockaddr *)&sll, sizeof(sll));
 if(len == -1)
 {
  perror("sendto");
 }
 
 //6.接收對方的ARP應答
 unsigned char recv_msg[1024] = {0};
 recvfrom(sock_raw_fd, recv_msg, sizeof(recv_msg), 0, NULL, NULL);
 if(recv_msg[21] == 2)   //ARP應答
 {
  char resp_mac[18] = "";  //arp響應的MAC
  char resp_ip[16] = "";  //arp響應的IP
 
  sprintf(resp_mac, "%02x:%02x:%02x:%02x:%02x:%02x", \
  recv_msg[22],recv_msg[23],recv_msg[24],recv_msg[25],recv_msg[26],recv_msg[27]);
  sprintf(resp_ip, "%d.%d.%d.%d", recv_msg[28], recv_msg[29], recv_msg[30], recv_msg[31]);
  printf("IP:%s - MAC:%s\n",resp_ip, resp_mac);
 }
 
 return 0;
}

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2015-04/115915p2.htm

Copyright © Linux教程網 All Rights Reserved