WinPcap编程(三)

1.过滤器设置

  设置过滤器,得到你想要的哪种类型的包。Like WireShark。

  过程:编译过滤器,然后设置过滤器。直接上参考文档的代码:

  

    if (d->addresses != NULL)
        /* 获取接口第一个地址的掩码 */
        netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
    else
        /* 如果这个接口没有地址,那么我们假设这个接口在C类网络中 */
        netmask=0xffffff; 


compile the filter
    if (pcap_compile(adhandle, &fcode, "ip and tcp", 1, netmask) < 0)
    {
        fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n");
        /* 释放设备列表 */
        pcap_freealldevs(alldevs);
        return -1;
    }
    
set the filter
    if (pcap_setfilter(adhandle, &fcode) < 0)
    {
        fprintf(stderr,"\nError setting the filter.\n");
        /* 释放设备列表 */
        pcap_freealldevs(alldevs);
        return -1;
    }
View Code

 

2.分析数据包

  只需要知道怎么构造,然后怎么处理就可以了。

 

源码:

#define WIN32
#include "pcap.h"

typedef struct mac{
    u_char byte1;
    u_char byte2;
    u_char byte3;
    u_char byte4;
    u_char byte5;
    u_char byte6;
}mac;

typedef struct eth_header{
    mac dmac;
    mac smac;
    u_short type;
}eth_header;

/* 4字节的IP地址 */
typedef struct ip_address{
    u_char byte1;            
    u_char byte2;
    u_char byte3;
    u_char byte4;
}ip_address;

/* IPv4 首部 */
typedef struct ip_header{
    u_char  ver_ihl;        // 版本 (4 bits) + 首部长度 (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 首部*/
typedef struct udp_header{
    u_short sport;          // 源端口(Source port)
    u_short dport;          // 目的端口(Destination port)
    u_short len;            // UDP数据包长度(Datagram length)
    u_short crc;            // 校验和(Checksum)
}udp_header;

/* 回调函数原型 */
void packet_handler2(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";
    struct bpf_program fcode;

    /* 获得设备列表 */
    if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
    {
        fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
        exit(1);
    }

    /* 打印列表 */
    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_s("%d", &inum);

    if (inum < 1 || inum > i)
    {
        printf("\nInterface number out of range.\n");
        /* 释放设备列表 */
        pcap_freealldevs(alldevs);
        return -1;
    }

    /* 跳转到已选设备 */
    for (d = alldevs, i = 0; i< inum - 1; d = d->next, i++);

    /* 打开适配器 */
    //if ((adhandle = pcap_open(d->name,  // 设备名
    //    65536,     // 要捕捉的数据包的部分 
    //    // 65535保证能捕获到不同数据链路层上的每个数据包的全部内容
    //    PCAP_OPENFLAG_PROMISCUOUS,         // 混杂模式
    //    0,      // 读取超时时间
    //    NULL,      // 远程机器验证
    //    errbuf     // 错误缓冲池
    //    )) == NULL)
    if ((adhandle = pcap_open_live(d->name, 65536, PCAP_OPENFLAG_PROMISCUOUS,0,errbuf)) == NULL)
    {
        fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n");
        /* 释放设备列表 */
        pcap_freealldevs(alldevs);
        return -1;
    }

    /* 检查数据链路层,为了简单,我们只考虑以太网 */
    //if (pcap_datalink(adhandle) != DLT_EN10MB)
    //{
    //    fprintf(stderr, "\nThis program works only on Ethernet networks.\n");
    //    /* 释放设备列表 */
    //    pcap_freealldevs(alldevs);
    //    return -1;
    //}

    if (d->addresses != NULL)
        /* 获得接口第一个地址的掩码 */
        netmask = ((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
    else
        /* 如果接口没有地址,那么我们假设一个C类的掩码 */
        netmask = 0xffffff;


    //编译过滤器
    if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0)
    {
        fprintf(stderr, "\nUnable to compile the packet filter. Check the syntax.\n");
        /* 释放设备列表 */
        pcap_freealldevs(alldevs);
        return -1;
    }

    //设置过滤器
    if (pcap_setfilter(adhandle, &fcode)<0)
    {
        fprintf(stderr, "\nError setting the filter.\n");
        /* 释放设备列表 */
        pcap_freealldevs(alldevs);
        return -1;
    }

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

    /* 释放设备列表 */
    pcap_freealldevs(alldevs);

    /* 开始捕捉 */
    pcap_loop(adhandle, 0, packet_handler2, NULL);
    system("pause");
    return 0;
}


/* 回调函数,当收到每一个数据包时会被libpcap所调用 */
void packet_handler2(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
    struct tm ltime;
    char timestr[16];
    time_t local_tv_sec;

    eth_header *eh;

    ip_header *ih;
    udp_header *uh;

    u_int ip_len;
    u_short sport=0, dport=0;
    
    int i;

    /* 将时间戳转换成可识别的格式 */
    local_tv_sec = header->ts.tv_sec;
    localtime_s(&ltime,&local_tv_sec);
    strftime(timestr, sizeof timestr, "%H:%M:%S", &ltime);

    /* 打印数据包的时间戳和长度 */
    printf("Time Stamp:%s.%.6d \nLength:%d \n", timestr, header->ts.tv_usec, header->len);

    ///*获得以太网帧的首部*/
    //eh = (eth_header *)(pkt_data);

    ///* 获得IP数据包头部的位置 */
    //ih = (ip_header *)(pkt_data +
    //    14); //以太网头部长度

    ///* 获得UDP首部的位置 
    //IP数据报头部是4bits,单位是32bit(4个字节)
    //一个IP包头的长度最长为“1111”,即15*4=60个字节。IP包头最小长度为20字节。
    //*/
    //ip_len = (ih->ver_ihl & 0xf) * 4;
    //uh = (udp_header *)((u_char*)ih + ip_len);

    ///* 将网络字节序列转换成主机字节序列 */
    //sport = ntohs(uh->sport);
    //dport = ntohs(uh->dport);
    
    /*打印数据包的数据*/
    printf("\nDATA:");
    for (i = 0; i< header->len; ++i)
    {
        printf(" %02x", pkt_data[i]);
        if ((i + 1) % 16 == 0)
        {
            printf("\n");
        }
    }

    /*打印MAC地址*/
    //printf("\nDestination: %02x-%02x-%02x-%02x-%02x-%02x", 
    //    eh->dmac.byte1,
    //    eh->dmac.byte2,
    //    eh->dmac.byte3, 
    //    eh->dmac.byte4, 
    //    eh->dmac.byte5, 
    //    eh->dmac.byte6);
    //printf("\nResources: %02x-%02x-%02x-%02x-%02x-%02x",
    //    eh->smac.byte1,
    //    eh->smac.byte2,
    //    eh->smac.byte3,
    //    eh->smac.byte4,
    //    eh->smac.byte5,
    //    eh->smac.byte6);
    ///* 打印IP地址和UDP端口 */
    //printf("\nIP ADDRESS:%d.%d.%d.%d:%d -> %d.%d.%d.%d:%d\nUDP LENGTH:%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,
    //    ih->tlen);
}
View Code

 

3.发送包比较简单,就不多说了。

posted @ 2015-08-16 15:30  卫平_布莱恩特  阅读(433)  评论(0编辑  收藏  举报