ARP報文的傳送與接收(Linux下gcc編譯)
ARP報文的傳送與接收
這篇文章主要是關於ARP報文的傳送與接收,學習TCP/IP協議,還是多動手做一些測試對協議的理解比較深刻,所以自己寫了一份比較簡單的關於ARP的原始碼,
主要是起到記錄作用,方便以後回顧,當然,如果有大俠能提出問題,幫助我改進缺點是萬分感謝的,下面就把程式碼上傳,主要邏輯是傳送一個ARP查詢就等待接收一個ARP
響應報文,這樣一直迴圈,謝謝!
#include <sys/socket.h> #include <linux/if.h> #include <sys/ioctl.h> #include <netpacket/packet.h> #include <net/ethernet.h> #include <netinet/in.h> #include <netinet/ip.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h>
#define ETH_HW_ADDR_LEN 6 #define IP_ADDR_LEN 4 #define ARP_FRAME_TYPE 0x0806 #define ETHER_HW_TYPE 1 #define IP_PROTO_TYPE 0x0800 #define OP_ARP_REQUEST 1 #define OP_ARP_REPLY 2
/* Arp packet field offset */ #define ARP_HW_TYPE_OFF 14 #define ARP_PROT_TYPE_OFF 16 #define ARP_HW_ADDR_LEN_OFF 18 #define ARP_PROT_ADDR_LEN_OFF 19 #define ARP_OPCODE_OFF 20 #define ARP_SRC_MAC_OFF 22 #define ARP_SRC_IP_OFF 28 #define ARP_DST_MAC_OFF 32 #define ARP_DST_IP_OFF 38
typedef unsigned char _U8; typedef unsigned short _U16; typedef unsigned long _U32; typedef char _S8; typedef short _S16; typedef long _S32; typedef int _BOOL; typedef void _VOID; typedef float _F32; typedef double _F64;
#define G_NULL (0) #define G_NULL_PTR ((_VOID *)0) #define G_SUCCESS ((_U32)0) #define G_FAILURE ((_U32)(-1)) #define G_TRUE ((_BOOL)1) #define G_FALSE ((_BOOL)0)
/* 本地IP和MAC地址 */ _U8 gaucMyIpAddr[IP_ADDR_LEN] = {0x0a,0x08,0x08,0xe0};/* 10.8.8.224 */ _U8 gaucMyMacAddr[ETH_HW_ADDR_LEN] = {0x00,0x0c,0x29,0x19,0xc3,0x5f};
/* 需要查詢的IP和廣播MAC地址 */ _U8 gaucQueryIpAddr[IP_ADDR_LEN] = {0x0a,0x08,0x08,0x62};/* 10.8.8.98 */ _U8 gaucBroadcastMacAddr[ETH_HW_ADDR_LEN] = {0xff,0xff,0xff,0xff,0xff,0xff};
typedef struct ARP_PACKET { _U8 targ_hw_addr[ETH_HW_ADDR_LEN]; _U8 src_hw_addr[ETH_HW_ADDR_LEN]; _U16 frame_type; _U16 hw_type; _U16 prot_type; _U8 hw_addr_size; _U8 prot_addr_size; _U16 op; _U8 sndr_hw_addr[ETH_HW_ADDR_LEN]; _U8 sndr_ip_addr[IP_ADDR_LEN]; _U8 rcpt_hw_addr[ETH_HW_ADDR_LEN]; _U8 rcpt_ip_addr[IP_ADDR_LEN]; _U8 padding[18]; }ST_ARP_PACKET;
_VOID arp_display(ST_ARP_PACKET *pstArpPkt) { printf("-----------------------------------------------------------\r\n"); printf("ARP Message:\r\n"); printf("HwType: %04x\r\n",ntohs(pstArpPkt->hw_type)); printf("ProType: %04x\r\n",ntohs(pstArpPkt->prot_type)); printf("HwAddrLen: %x\r\n", pstArpPkt->hw_addr_size); printf("ProAddrLen: %x\r\n", pstArpPkt->prot_addr_size); printf("OpCode: %04x\r\n",ntohs(pstArpPkt->op)); printf("Sender: %02x-%02x-%02x-%02x-%02x-%02x(%d.%d.%d.%d)\r\n", pstArpPkt->sndr_hw_addr[0], pstArpPkt->sndr_hw_addr[1], pstArpPkt->sndr_hw_addr[2], pstArpPkt->sndr_hw_addr[3], pstArpPkt->sndr_hw_addr[4], pstArpPkt->sndr_hw_addr[5], pstArpPkt->sndr_ip_addr[0], pstArpPkt->sndr_ip_addr[1], pstArpPkt->sndr_ip_addr[2], pstArpPkt->sndr_ip_addr[3]); printf("Target: %02x-%02x-%02x-%02x-%02x-%02x(%d.%d.%d.%d)\r\n", pstArpPkt->rcpt_hw_addr[0], pstArpPkt->rcpt_hw_addr[1], pstArpPkt->rcpt_hw_addr[2], pstArpPkt->rcpt_hw_addr[3], pstArpPkt->rcpt_hw_addr[4], pstArpPkt->rcpt_hw_addr[5], pstArpPkt->rcpt_ip_addr[0], pstArpPkt->rcpt_ip_addr[1], pstArpPkt->rcpt_ip_addr[2], pstArpPkt->rcpt_ip_addr[3]); printf("-----------------------------------------------------------\r\n"); }
_BOOL arp_match(ST_ARP_PACKET *pstArpPkt) { /* ARP報文是否發給我的 */ if (!memcmp(pstArpPkt->rcpt_ip_addr, gaucMyIpAddr,IP_ADDR_LEN)) { /* 判斷操作碼,判斷是請求報文還是應答報文 */ if (pstArpPkt->op == ntohs(OP_ARP_REPLY)) { return G_TRUE; } else { return G_FALSE; } } else { return G_FALSE; } }
_BOOL main(void) { int arpfd; int retval; struct sockaddr_ll ll; struct ifreq ifr; ST_ARP_PACKET *pstSendArpPkt; ST_ARP_PACKET *pstRecvArpPkt;
pstSendArpPkt = (ST_ARP_PACKET *)malloc(sizeof(ST_ARP_PACKET)); if (pstSendArpPkt == G_NULL_PTR) { return G_NULL; } memset((char *)pstSendArpPkt, 0, sizeof(ST_ARP_PACKET));
pstRecvArpPkt = (ST_ARP_PACKET *)malloc(sizeof(ST_ARP_PACKET)); if (pstRecvArpPkt == G_NULL_PTR) { return G_NULL; } memset((char *)pstRecvArpPkt, 0, sizeof(ST_ARP_PACKET));
pstSendArpPkt->frame_type = htons(ARP_FRAME_TYPE); pstSendArpPkt->hw_type = htons(ETHER_HW_TYPE); pstSendArpPkt->prot_type = htons(IP_PROTO_TYPE); pstSendArpPkt->hw_addr_size = ETH_HW_ADDR_LEN; pstSendArpPkt->prot_addr_size = IP_ADDR_LEN; pstSendArpPkt->op = htons(OP_ARP_REQUEST);
memcpy(pstSendArpPkt->src_hw_addr, gaucMyMacAddr, ETH_HW_ADDR_LEN); memcpy(pstSendArpPkt->sndr_hw_addr, gaucMyMacAddr, ETH_HW_ADDR_LEN); memcpy(pstSendArpPkt->targ_hw_addr, gaucBroadcastMacAddr, ETH_HW_ADDR_LEN); memcpy(pstSendArpPkt->rcpt_hw_addr, gaucBroadcastMacAddr, ETH_HW_ADDR_LEN);
memcpy(pstSendArpPkt->sndr_ip_addr, gaucMyIpAddr, IP_ADDR_LEN); memcpy(pstSendArpPkt->rcpt_ip_addr, gaucQueryIpAddr, IP_ADDR_LEN); bzero(pstSendArpPkt->padding, 18);
arpfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP)); if (arpfd <= 0) { printf("\r\n socket err \r\n"); return G_FAILURE; }
memset((char *)&ifr, 0, sizeof(struct ifreq)); strncpy(ifr.ifr_name, "eth0", strlen("eth0"));
/* 獲取這個介面的索引 */ retval = ioctl(arpfd, SIOCGIFINDEX, &ifr); if (retval != 0) { return G_FAILURE; }
/* Bind to ethernet interface */ memset(&ll, 0, sizeof(ll)); ll.sll_family = PF_PACKET; ll.sll_ifindex = ifr.ifr_ifindex; ll.sll_protocol = htons(ETH_P_ARP); retval = bind(arpfd, (struct sockaddr *) &ll, sizeof(ll)); if (retval < 0) { close(arpfd); return G_FAILURE; }
while(1) { if (sendto(arpfd, pstSendArpPkt, sizeof(ST_ARP_PACKET), 0, 0, 0) < 0) { printf("\r\n send arp fail! \r\n"); return G_FAILURE; }
while (1) { if (recvfrom(arpfd, pstRecvArpPkt, sizeof(ST_ARP_PACKET), 0, 0, 0) >= 0) { if (arp_match(pstRecvArpPkt)) { arp_display(pstRecvArpPkt); break; } } } sleep(1); } close(arpfd); return G_FAILURE; }