Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2151573
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2015-07-01 11:33:10

1. 向指定的IP地址发送ARP请求
  1. cong@msi:/work/busybox$ sudo ./_install/busybox arping 192.168.4.1
  2. arping: interface eth0 not found: No such device

  3. cong@msi:/work/busybox$ sudo ./_install/busybox arping -I eth2 192.168.4.1
  4. ARPING to 192.168.4.1 from 192.168.4.68 via eth2
  5. Unicast reply from 192.168.4.1 [10:d:f:1:2f:d0] 0.765ms
  6. Unicast reply from 192.168.4.1 [10:d:f:1:2f:d0] 0.623ms
  7. Unicast reply from 192.168.4.1 [10:d:f:1:2f:d0] 0.738ms
  8. ^CSent 3 probe(s) (1 broadcast(s))
  9. Received 3 reply (0 request(s), 0 broadcast(s))
2. 源码
  1. cong@msi:/work/test/busytest/3arping$ cat arping.c
  2. #define _GNU_SOURCE /* See feature_test_macros(7) */
  3. #include "utils.h"
  4. #include <net/if.h>
  5. #include <linux/sockios.h>
  6. #include <linux/if_packet.h>
  7. #include <linux/if_ether.h>
  8. #include <net/if_arp.h>
  9. #include <string.h>
  10. #include <net/ethernet.h>
  11. #include <netinet/ether.h>
  12. # define move_from_unaligned32(v, u32p) (memcpy(&(v), (u32p), 4))

  13. static int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM, struct in_addr src,struct in_addr dst ,struct sockaddr_ll me, struct sockaddr_ll he)
  14. {
  15.     //该函数对接收到的packet进行解析
  16.     struct arphdr *ah = (struct arphdr *) buf;
  17.     unsigned char *p = (unsigned char *) (ah + 1);
  18.     struct in_addr src_ip, dst_ip;
  19.     /* moves below assume in_addr is 4 bytes big, ensure that */
  20.     struct BUG_in_addr_must_be_4 {
  21.         char BUG_in_addr_must_be_4[
  22.             sizeof(struct in_addr) == 4 ? 1 : -1
  23.             ];
  24.         char BUG_s_addr_must_be_4[
  25.             sizeof(src_ip.s_addr) == 4 ? 1 : -1
  26.             ];
  27.     };
  28.     /* Filter out wild packets */
  29.     if (FROM->sll_pkttype != PACKET_HOST
  30.             && FROM->sll_pkttype != PACKET_BROADCAST
  31.             && FROM->sll_pkttype != PACKET_MULTICAST)
  32.         return -1;

  33.     //检查回复类型,此处应当是REPLY
  34.     if (ah->ar_op != htons(ARPOP_REQUEST) && ah->ar_op != htons(ARPOP_REPLY))
  35.         return -1;

  36.     /* ARPHRD check and this darned FDDI hack here :-( */
  37.     if (ah->ar_hrd != htons(FROM->sll_hatype)
  38.             && (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER)))
  39.         return -1;
  40.     //检查协议类型:必须是IP
  41.     if (ah->ar_pro != htons(ETH_P_IP)
  42.             || (ah->ar_pln != 4)
  43.             || (ah->ar_hln != me.sll_halen)
  44.             || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln))))
  45.         return -1;

  46.     move_from_unaligned32(src_ip.s_addr, p + ah->ar_hln);
  47.     move_from_unaligned32(dst_ip.s_addr, p + ah->ar_hln + 4 + ah->ar_hln);

  48.     if (dst.s_addr != src_ip.s_addr)
  49.         return -1;
  50.     if ((src.s_addr != dst_ip.s_addr)
  51.             || (memcmp(p + ah->ar_hln + 4, &me.sll_addr, ah->ar_hln)))
  52.         return -1;

  53.     int s_printed = 0;

  54.     printf("%scast re%s from %s [%s]",
  55.             FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad",
  56.             ah->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest",
  57.             inet_ntoa(src_ip),
  58.             ether_ntoa((struct ether_addr *) p));
  59.     if (dst_ip.s_addr != src.s_addr) {
  60.         printf("for %s ", inet_ntoa(dst_ip));
  61.         s_printed = 1;
  62.     }
  63.     if (memcmp(p + ah->ar_hln + 4, me.sll_addr, ah->ar_hln)) {
  64.         if (!s_printed)
  65.             printf("for ");
  66.         printf("[%s]",
  67.                 ether_ntoa((struct ether_addr *) p + ah->ar_hln + 4));
  68.     }
  69.     printf("\n");

  70.     memcpy(he.sll_addr, p, me.sll_halen);
  71.     return 0;
  72. }

  73. static int send_pack(int sock_fd, struct in_addr *src_addr,
  74.         struct in_addr *dst_addr, struct sockaddr_ll *ME,
  75.         struct sockaddr_ll *HE)
  76. {
  77.     int err;
  78.     unsigned char buf[256];
  79.     struct arphdr *ah = (struct arphdr *) buf;
  80.     unsigned char *p = (unsigned char *) (ah + 1);
  81.     //以下的字符都是按照抓包的顺序填充的
  82.     //但是没有ARP字样,是不是跟bind有关?
  83.     ah->ar_hrd = htons(ARPHRD_ETHER);   //00 01 :Ethernet
  84.     ah->ar_pro = htons(ETH_P_IP);       //0800  :IP
  85.     ah->ar_hln = ME->sll_halen;
  86.     ah->ar_pln = 4;
  87.     ah->ar_op = htons(ARPOP_REQUEST);

  88.     p = mempcpy(p, &ME->sll_addr, ah->ar_hln);
  89.     p = mempcpy(p, src_addr, 4);

  90.     p = mempcpy(p, &HE->sll_addr, ah->ar_hln);
  91.     p = mempcpy(p, dst_addr, 4);

  92.     err = sendto(sock_fd, buf, p-buf, 0, (struct sockaddr *)HE, sizeof(*HE));
  93.     if(err<0)
  94.     {
  95.         dbmsg("%s",strerror(errno));
  96.         return -1;
  97.     }
  98.     return err;
  99. }

  100. int get_local_ipaddr(const char* iface, struct in_addr* inaddr)
  101. {
  102.     int probe_fd;
  103.     int ret;
  104.     struct ifreq ifr;
  105.     if( (probe_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
  106.     {
  107.         dbmsg("%s",strerror(errno));
  108.         return -1;
  109.     }
  110.     strncpy(ifr.ifr_name, iface, strlen(iface)+1);
  111.     if(ioctl(probe_fd, SIOCGIFADDR, &ifr))
  112.     {
  113.         dbmsg("%s",strerror(errno));
  114.         return -1;
  115.     }
  116.     //dbmsg("%s", inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr));
  117.     mempcpy(inaddr, &(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr), sizeof(struct in_addr));
  118.     close(probe_fd);
  119.     return 0;
  120. }

  121. int main ( int argc, char *argv[] )
  122. {
  123.     char packet[4096];
  124.     int sockfd, ret;
  125.     struct ifreq ifr;
  126.     struct in_addr src,dst;
  127.     const char *device = "eth2";
  128.     struct sockaddr_ll me, he;
  129.     if(argc < 2)
  130.     {
  131.         dbmsg("usage: arping ");
  132.         return -1;
  133.     }
  134.     //1. create socket
  135.     if( (sockfd = socket(AF_PACKET, SOCK_DGRAM, 0)) < 0)
  136.     {
  137.         dbmsg("%s",strerror(errno));
  138.         return -1;
  139.     }
  140.     //2. check if eth2 exist, get eth2 index
  141.     memset(&ifr, 0, sizeof(ifr));
  142.     strncpy(ifr.ifr_name, device, strlen(device)+1);
  143.     if( (ret = ioctl(sockfd, SIOCGIFINDEX, &ifr)) < 0)
  144.     {
  145.         dbmsg("%s",strerror(errno));
  146.         return -1;
  147.     }
  148.     me.sll_ifindex = ifr.ifr_ifindex;    //获取本机eth2的index,此处是2

  149.     ioctl(sockfd, SIOCGIFFLAGS, (char*)&ifr);
  150.     if(!(ifr.ifr_flags & IFF_UP))       //检查eth2是否是UP状态,DOWN的话就没法玩了
  151.     {
  152.         dbmsg("%s is down",device);
  153.         return -1;
  154.     }
  155.     if(ifr.ifr_flags & (IFF_NOARP|IFF_LOOPBACK)) //检查eth2是不是可以发送ARP
  156.     {
  157.         dbmsg("%s is not ARPable",device);
  158.         return -1;
  159.     }

  160.     //3. get local IP addr
  161.     get_local_ipaddr(device, &src);    //获取本机eth2的ip地址
  162.     inet_aton(argv[1], &dst);          //argv[1]是dst的ip地址
  163.     dbmsg("src=%s", inet_ntoa(src));
  164.     dbmsg("dst=%s", inet_ntoa(dst));

  165.     //4. send packet to dst
  166.     me.sll_family = AF_PACKET;
  167.     me.sll_protocol = htons(ETH_P_ARP);
  168.     bind(sockfd, (struct sockaddr*)&me, sizeof(me));     //这儿bind的作用可能很重要,不过没有太明白
  169.     socklen_t alen = sizeof(me);
  170.     getsockname(sockfd, (struct sockaddr *) &me, &alen);
  171.     if(me.sll_halen == 0)
  172.     {
  173.         dbmsg("not ARPable");
  174.         return -1;
  175.     }
  176.     he = me;
  177.     memset(he.sll_addr, -1, he.sll_halen);     //dst的mac地址是ff:ff:ff:ff:ff,广播地址
  178.     send_pack(sockfd, &src, &dst, &me, &he);


  179.     //5. recv packet from dst
  180.     struct sockaddr_ll from;
  181.     alen = sizeof(from);
  182.     ret = recvfrom(sockfd, packet, 4096, 0, (struct sockaddr*)&from, &alen);
  183.     recv_pack(packet, ret, &from, src, dst, me, he);

  184.     return EXIT_SUCCESS;
  185. }
3.运行结果:
  1. cong@msi:/work/test/busytest/3arping$ sudo ./arping 192.168.4.5
  2. arping.c:main[182]: src=192.168.4.112
  3. arping.c:main[183]: dst=192.168.4.5
  4. Unicast reply from 192.168.4.5 [12:9f:1c:d5:33:ac]
4.数据包解析
a.发送:
  1. send: 1.818515000    Micro-St_99:f6:d8    Broadcast    ARP    42    Who has 192.168.4.5? Tell 192.168.4.112

  2. ff ff ff ff ff ff 44 8a 5b 99 f6 d8 08 06 00 01
  3. 08 00 06 04 00 01 44 8a 5b 99 f6 d8 c0 a8 04 70
  4. ff ff ff ff ff ff c0 a8 04 05

  5. ff ff ff ff ff ff     --> dest broadcast
  6. 44 8a 5b 99 f6 d8     --> src mac
  7. 08 06                 --> ARP
  8. 00 01                 --> Ethernet
  9. 08 00                 --> Protocol type: IP
  10. 06                    --> hardware size
  11. 04                    --> protocol size
  12. 00 01                 --> opcode request: 1-->request
  13. 44 8a 5b 99 f6 d8     --> sender mac address
  14. c0 a8 04 70           --> sender IP address 192.168.4.112
  15. ff ff ff ff ff ff     --> target mac address
  16. c0 a8 04 05           --> target IP address
b.接收:
  1. recv: 1.819112000 12:9f:1c:d5:33:ac Micro-St_99:f6:d8 ARP 60 192.168.4.5 is at 12:9f:1c:d5:33:ac
  2. 0000 44 8a 5b 99 f6 d8 12 9f 1c d5 33 ac 08 06 00 01
  3. 0010 08 00 06 04 00 02 12 9f 1c d5 33 ac c0 a8 04 05
  4. 0020 44 8a 5b 99 f6 d8 c0 a8 04 70 00 00 00 00 00 00
  5. 0030 00 00 00 00 00 00 00 00 00 00 00 00

  6. 44 8a 5b 99 f6 d8   -->dst mac
  7. 12 9f 1c d5 33 ac   -->src mac
  8. 08 06               --> ARP
  9. 00 01               --> Ethernet
  10. 08 00               --> Protocol type: IP
  11. 06                  --> hardware size
  12. 04                  --> protocol size
  13. 00 02               --> opcode request: 2-->reply
  14. 12 9f 1c d5 33 ac   --> sender mac address
  15. c0 a8 04 05         --> sender IP address 192.168.4.112
  16. 44 8a 5b 99 f6 d8   --> target mac address
  17. c0 a8 04 70         --> target IP address
  18. 00 00 ...           --> padding
5.源码
3arping.rar (下载后改名为3arping.tar.gz)
6.补充
LINUX内核中有一个叫PF_PACKET的协议簇,它允许应用程序直接利用网络驱动程序发送和接收报文,避免了原来的协议栈处理过程。
在这种情况下,所有SOCKET发送的报文直接送到以太网卡接口,而接收到的任何报文将直接送到应用程序。

PF_PACKET协议簇的两个socket类型:
SOCK_DGRAM --> 让内核处理添加或者去除以太网报文头部工作
SOCK_RAW   --> 让应用程序对以太网报文头部有完全的控制

阅读(2134) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~