1. 程式人生 > >ARP報文的傳送與接收(Linux下gcc編譯)

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; }