新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   >>中国XML论坛<<     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 讨论密码学、密码协议、入侵检测、访问控制等与安全理论研究有关的主题
    [返回] 中文XML论坛 - 专业的XML技术讨论区计算机理论与工程『 安全理论 』 → [原创]Winpcap学习第四天 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 12229 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: [原创]Winpcap学习第四天 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     binaryluo 帅哥哟,离线,有人找我吗?
      
      
      威望:6
      等级:研二(Pi-Calculus看得一头雾水)(版主)
      文章:679
      积分:5543
      门派:IEEE.ORG.CN
      注册:2005/2/19

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给binaryluo发送一个短消息 把binaryluo加入好友 查看binaryluo的个人资料 搜索binaryluo在『 安全理论 』的所有贴子 引用回复这个贴子 回复这个贴子 查看binaryluo的博客楼主
    发贴心情 [原创]Winpcap学习第四天

    Winpcap提供(libpcap也提供)的一个强大特性是过滤引擎(filtering engine)。它提供了一个非常有效的接收网络流量的方法,并且它通常与Winpcap提供的抓包机制集成在一起。用于过滤数据包的函数是pcap_complie()和pcap_setfilter()。

         pcap_complie()使用一个包含高级布尔表达式的字符串并且产生一个能被过滤引擎集成到数据包驱动中的低级字节码。

         pcap_setfilter()把一个过滤器与核心驱动抓包会话关联起来。一旦pcap_setfilter()被调用,相关的过滤器将被应用到所有的来自网络的数据包上,并且所有的一致的数据包将被复制给应用程序。

    抓包和过滤

        经过前面几天的知识准备,现在我们将把前面的知识综合后应用于一个简单的实际应用程序。下面试验的目的是如何解析和解释被捕获的数据包的协议头。应用程序运行的结果是打印出一组我们的网络上的UDP通信数据。我们之所以选择解析和显示UDP协议是因为它比起其他协议(例如:TCP)更易于理解,对于初学者更适合。

        试验代码:

    #include <pcap.h>
    #include <remote-ext.h>

    /* 4 bytes IP address */
    typedef struct ip_address
    {
    u_char byte1;
    u_char byte2;
    u_char byte3;
    u_char byte4;
    }ip_address;

    /* IPv4 header */
    typedef struct ip_header
    {
    u_char ver_ihl;  /* Version (4 bits) + Internet header length (4 bits)*/
    u_char tos;      /* Type of service */
    u_short tlen;    /* Total length */
    u_short identification; /* Identification */
    u_short flags_fo;       /* Flags (3 bits) + Fragment offset (13 bits)*/
    u_char ttl;      /* Time to live */
    u_char proto;    /* Protocol */
    u_short crc;     /* Header checksum */
    ip_address saddr;/* Source address */
    ip_address daddr;/* Destination address */
    u_int op_pad;    /* Option + Padding */
    }ip_header;

    /* UDP header */
    typedef struct udp_header
    {
    u_short sport;   /* Source port */
    u_short dport;   /* Destination port */
    u_short len;     /* Datagram length */
    u_short crc;     /* Checksum */
    }udp_header;

    /* Prototype of the pachet handler */
    void packet_handler(u_char* param, const struct pcap_pkthdr* header, const u_char* pkt_data);

    int main() {
    pcap_if_t* alldevs;
    pcap_if_t* d;
    int inum;
    int i = 0;
    pcap_t* adhandle;
    char errbuf[PCAP_ERRBUF_SIZE];
    u_int netmask;
    char packet_filter[] = "ip and udp";
    struct bpf_program fcode;

    /* Retrieve the device list */
    if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
    {
      fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
      exit(1);
    }

    /* Print the list*/
    for (d = alldevs; d; d = d->next)
    {
      printf("%d. %s", ++ i, d->name);
      if (d->description)
      {
       printf(" (%s)\n", d->description);
      }
      else
      {
       printf(" (No description available)\n");
      }
    }

    if (i == 0)
    {
      printf("\nNo interfaces found! Make sure Winpcap is installed.\n");
      return -1;
    }

    printf("Enter the interface number (1 - %d):", i);
    scanf("%d", &inum);

    if (inum < 1 || inum > i)
    {
      printf("\nInterface number out of range.\n");
      /* Free the device list */
      pcap_freealldevs(alldevs);
      return -1;
    }

    /* Jump to the selected adapter */
    for (d = alldevs; d; d = d->next);

    /* Open the adapter */
    if ((adhandle = pcap_open(d->name,  /*name of the device */
           65536,      /* portion of the packet to capture */
           /* 65536 grants that the whole packet will be captured on all the MACs */
           PCAP_OPENFLAG_PROMISCUOUS, /* promiscuous mode */
           1000,       /* read timeout */
           NULL,       /* remote authentication */
           errbuf      /* error buffer */
           )) == NULL)
    {
      fprintf(stderr, "\nUnable to open the adapter. %s is not supported by Winpcap\n");
      /* Free the devices list */
      pcap_freealldevs(alldevs);
      return -1;
    }

    /* Check the link layer. We support only Ethernet for simplicity */
    if (pcap_datalink(adhandle) != DLT_EN10MB)
    {
      fprintf(stderr, "\nThis program works only on Ethernet networks.\n");
      /* Free the devices list */
      pcap_freealldevs(alldevs);
      return -1;
    }

    if (d->addresses != NULL)
    {
      /* Retrieve the mask of the first address of the interface */
      netmask = ((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
    }
    else
    {
      /* If the interface is without addresses we suppose to be in a C class network */
      netmask = 0xffffffff;
    }

    /* complie the filter */
    if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) < 0)
    {
      fprintf(stderr, "\nUnable to compile the packet filter. Check the syntax.\n");
      /* Free the devices list */
      pcap_freealldevs(alldevs);
      return -1;
    }

    /* set the filter */
    if (pcap_setfilter(adhandle, &fcode) < 0)
    {
      fprintf(stderr, "\nError setting the filter.\n");
      /* Free the devices list */
      pcap_freealldevs(alldevs);
      return -1;
    }

    printf("\nlistening on %s ...\n", d->description);

    /* At this point,we don't need any more the device list. Free it */
    pcap_freealldevs(alldevs);

    /* Start the capture */
    pcap_loop(adhandle, 0, packet_handler, NULL);

    return 1;
    }

    /* Callback function invoked by libpcap for every incoming packet */
    void packet_handler(u_char* param, const struct pcap_pkthdr* header, const u_char* pkt_data){
    struct tm* ltime;
    char timestr[16];
    ip_header* ih;
    udp_header* uh;
    u_int ip_len;
    u_short sport, dport;

    /* convert the timestamp to readable format */
    ltime = localtime(&header->ts.tv_sec);
    strftime(timestr, sizeof(timestr), "%H:%M:%S", ltime);

    /* print timestamp and length of the packet */
    printf("%s.%.6d len: %d ", timestr, header->ts.tv_usec, header->len);

    /* retrieve the position of the ip header */
    ih = (ip_header*)(pkt_data + 14);  /* length of ethernet header */

    /* retrieve the position of the udp header */
    ip_len = (ih->ver_ihl & 0xf) * 4;
    uh = (udp_header*)((u_char*)ih + ip_len);

    /* convert from network byte order to host byte order */
    /*sport = ntohs(uh->sport);
    dport = ntohs(uh->dport);*/

    /* print ip addresses and udp ports */
    printf("%d.%d.%d.%d -> %d.%d.%d.%d\n",
      ih->saddr.byte1,
      ih->saddr.byte2,
      ih->saddr.byte3,
      ih->saddr.byte4,
      /*sport,*/
      ih->daddr.byte1,
      ih->daddr.byte2,
      ih->daddr.byte3,
      ih->daddr.byte4
      /*dport*/);
    }

    函数1:

    int pcap_datalink(pcap_t* p)

    返回链路层上的一个适配器。返回链路层的类型,链路层的类型包括:

    DLT_NULL: BSD回路封装;链路层协议头是一个4字节的域,以主机字节顺序(host byte order),包含一个从socket.h来的PF_value。主机字节顺序(host byte order)是捕获数据包的机器的字节顺序,而PF_value是捕获数据包的机器的OS。如果一个读取一个文件,字节顺序和PF_value不一定是抓取文件的那些机器。

    DLT_EN10MB: 以太网(10Mb, 100Mb, 1000Mb, 或者更高)。

    DLT_IEEE802: IEEE802.5令牌环网。

    DLT_ARCNET:ARCNET。

    DLT_SLIP:SLIP。

    DLT_PPP:PPP;如果第一个字节是0xff或0x03,它是类HDLC帧上的PPP。

    DLT_FDDI:FDDI

    DLT_ATM_RFC1483:RFC1483LLC/SNAP ATM;数据包以IEEE802.2 LLC头开始。

    DLT_RAW:原始IP(raw IP);数据包以IP头开始。

    DLT_PPP_SERIAL:按照RFC1662,基于类HDLC帧的PPP,或者按照RFC1547的4.3.1,基于HDLC帧的Cisco PPP;前者的第一个字节是0xFF,后者的第一个字节是0x0F或0x8F。

    DLT_PPP_ETHER:按照RFC2516,PPPoE;数据包以PPPoE头开始。

    DLT_C_HDLC:按照RFC1547的4.3.1,基于HDLC帧的Cisco PPP。

    DLT_IEEE802_11:IEEE 802.11无线局域网。

    DLT_FRELAY:帧中继(Frame Relay)。

    DLT_LOOP:OpenBSD回路封装。

    DLT_LINUX_SLL:Linux抓包封装。

    DLT_LTALK:苹果的LocalTalk,数据包以AppleTalk LLAP头开始。

    DLT_PFLOG:OpenBSD pflog。

    DLT_PRISM_HEADER:后接802.11头的棱镜监视器模式(Prism monitor mode)信息。

    DLT_IP_OVER_FC:RFC2625 IP-over-Fiber 频道,以RFC2625中定义的Network_Header开始。

    DLT_SUNATM:SunATM设备。

    DLT_IEEE802_11_RADIO:后接802.11头的链路层信息。

    DLT_ARCNET_LINUX:没有异常帧的ARCNET。

    DLT_LINUX_IRDA:Linux-IrDA数据包,DLT_LINUX_SLL头后接IrLAP头。

    函数2:

    int pcap_compile(pcap_t*                    p,

    struct bpf_program*    fp,

    char*                          str,

    int                              optimize,

    bpf_u_int32                netmask)

        编译一个数据包过滤器,将一个能被核心态(kernel-level)过滤器引擎解释的程序中的高层过滤表达式(filtering expression)进行转化。pcap_compile()被用来将字符串str编译进过滤器程序(fp),程序(fp)是一个指向bpf_program结构体并被pcap_compile()赋值的指针。optimize控制是否对目标代码(resulting code)的性能进行优化。Netmask表明IPv4掩码,它仅在检查过滤器程序中的IPv4广播地址的时候被使用。如果网络掩码对于程序是不可知的或者数据包是在Linux的”任何(any)”伪接口上被捕获的,则赋值0;IPv4广播地址的测试将不被正确进行,但过滤器程序中的其他所有的测试都不会有问题。返回-1表示发生了错误,此时,pcap_geterr()将被用来显示错误信息。

    函数3:

    int pcap_setfilter(pcap_t*         p,

    struct bpf_program* fp)

        把一个过滤器同一次抓包关联起来。pcap_setfilter被用来指定一个过滤器程序。fp是一个指向bpf_program结构体的指针,通常是pcap_compile()执行的结果。当失败时返回-1,此时,pcap_geterr()被用来显示错误信息;返回0表示成功。

    首先,首先我们设置过滤器为“ip and udp”。用这个方法我们可以确保packet_handler()仅接收IPv4上的UDP数据包:这就简化了解析过程并且提高了程序的效率。

        我们还创建了IP和UDP两个结构体,这些结构体被packet_handler()用来定位不同的头域。

          packet_handler()展现了像tcpdump/WinDump这些复杂的嗅探器(sniffer)如何解析网络数据包。因为我们不关心MAC头,所以我们跳过它。为了简便起见,抓包前我们用pcap_datalink()检查MAC层,以确保我们处理的是以太网。该方法可以确保MAC头是14字节。

          IP头的定位在MAC头定位之后。我们从IP包头中取出源IP地址和目标IP地址。

    展开UDP包头有点复杂,因为IP包头不是定长的。因此,我们使用IP包头的长度域来获得它的大小。一旦我们知道了UDP头的位置,我们可以取出源端口和目的端口。


       收藏   分享  
    顶(0)
      




    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/6/1 9:29:00
     
     liang12 帅哥哟,离线,有人找我吗?
      
      
      等级:大一新生
      文章:1
      积分:60
      门派:XML.ORG.CN
      注册:2006/6/6

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给liang12发送一个短消息 把liang12加入好友 查看liang12的个人资料 搜索liang12在『 安全理论 』的所有贴子 引用回复这个贴子 回复这个贴子 查看liang12的博客2
    发贴心情 
    qiang ding
    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/6/6 17:00:00
     
     enorm 帅哥哟,离线,有人找我吗?
      
      
      威望:4
      头衔:头衔
      等级:大三暑假(参加全国数模竞赛拿了一等奖)(版主)
      文章:144
      积分:854
      门派:Lilybbs.net
      注册:2005/12/1

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给enorm发送一个短消息 把enorm加入好友 查看enorm的个人资料 搜索enorm在『 安全理论 』的所有贴子 引用回复这个贴子 回复这个贴子 查看enorm的博客3
    发贴心情 
    呵呵,正在使用,有空多交流阿

    ----------------------------------------------
    天亮了

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/6/6 20:07:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 安全理论 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/11/26 10:28:48

    本主题贴数3,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    93.750ms