通用技术 关于 pcap 截取的网卡数据帧的分析

rocl · 2017年12月15日 · 最后由 rocl 回复于 2017年12月18日 · 2883 次阅读

(一).首先如何配置和使用 WpdPack 库 (包括 lib 和 include)
这个配置在 wpdPack 的 doc 文档中有明确说明,包含了 vc6 如何使用,经过测试 vc2010 也是可以使用的,只是位置稍有区别
图片

(二).一个 Demo 说明网络协议封分层以及具体截获的包分析说明


(2.1).一个实际的包数据分析
packet_header ------>包帧的头部---16 字节
--------packet_content start---------
52 54 00 12 35 02 08 00 27 73 a8 bf 08 00 ------>以太网头部---14 字节
45 00 00 29 77 51 40 00 40 06 00 00 0a 00 02 0f 8c cd da 0e ------>IP 协议头部---20 字节
6f 2c 01 bb 7d 3d c8 c1 00 db 9e 72 50 10 f5 b0 73 06 00 00 ------>TCP 协议头部--20 字节
00
--------packet_content stop----------


捕获第 1 个网络数据包
捕获时间:09:54:38.69 数据包长度:55 <---->此为 package_header 中的数据内容,55 为 package_content 的长度
-------- 以太网协议 --------
类型:0800 <---->以太网头部的最后两个字段:0800 表示 IP 协议
上层协议为 IP 协议
源以太网地址 :08:00:27:73:a8:bf <---->有一个是本地的 mac 地址
目的以太网地址:52:54:00:12:35:02 <---->有一个是本地的 mac 地址
----------- IP 协议 -----------
版本号:4
首部长度:20
服务质量:0
总长度:41
标识:30545
偏移:0
生存时间:64
协议类型:6
上层协议为 TCP 协议
校验和:0
源 IP 地址:10.0.2.15
目的 IP 地址:140.205.218.14
------- TCP 协议 -------
源端口号:28460
目的端口号:443
序列码:2101201089
确认号:14392946
首部长度:20
保留:0
标记:ACK
窗口大小:62896
校验和:29446
紧急指针:0


(三).Demo 代码如下 (vc2010 编译通过,且可以正常使用)

#include <pcap.h>

/*
-----------------------------------------------------------------------------------------------------------------------
WinPcap头文件;
以下是以太网协议格式的定义
-----------------------------------------------------------------------------------------------------------------------
*/
struct ether_header
{
    /* 目的以太网地址 */
    u_int8_t ether_dhost[6];
    /* 源以太网地址 */
    u_int8_t ether_shost[6];
    /* 以太网类型 */
    u_int16_t ether_type;
};

/*
-----------------------------------------------------------------------------------------------------------------------
下面是ARP协议格式的定义
-----------------------------------------------------------------------------------------------------------------------
*/
struct arp_header
{
    /* 硬件类型 */
    u_int16_t arp_hardware_type;
    /* 协议类型 */
    u_int16_t arp_protocol_type;
    /* 硬件地址长度 */
    u_int8_t arp_hardware_length;
    /* 协议地址长度 */
    u_int8_t arp_protocol_length;
    /* 操作码 */
    u_int16_t arp_operation_code;
    /* 源以太网地址 */
    u_int8_t arp_source_ethernet_address[6];
    /* 源IP地址 */
    u_int8_t arp_source_ip_address[4];
    /* 目的以太网地址 */
    u_int8_t arp_destination_ethernet_address[6];
    /* 目的IP地址 */
    u_int8_t arp_destination_ip_address[4];
};

/*
-----------------------------------------------------------------------------------------------------------------------
下面是IP协议格式的定义
-----------------------------------------------------------------------------------------------------------------------
*/
struct ip_header
{
    #if defined(WORDS_BIGENDIAN)
        /* 版本 */
        u_int8_t ip_version: 4,
        /* 首部长度 */
        ip_header_length: 4;
    #else
        u_int8_t ip_header_length: 4, ip_version: 4;
    #endif
    /* 服务质量 */
    u_int8_t ip_tos;
    /* 长度 */
    u_int16_t ip_length;
    /* 标识 */
    u_int16_t ip_id;
    /* 偏移,标志位(Flags) (3 bits) + 段偏移量(Fragment offset) (13 bits) */
    u_int16_t ip_off;
    /* 生存时间 */
    u_int8_t ip_ttl;
    /* 协议类型 */
    u_int8_t ip_protocol;
    /* 校验和 */
    u_int16_t ip_checksum;
    /* 源IP地址 */
    struct in_addr ip_souce_address;
    /* 目的IP地址 */
    struct in_addr ip_destination_address;
};

/*  
-----------------------------------------------------------------------------------------------------------------------  
下面是UDP协议格式定义  
-----------------------------------------------------------------------------------------------------------------------  
*/
struct udp_header
{
    /* 源端口号 */
    u_int16_t udp_source_port;
    /* 目的端口号 */
    u_int16_t udp_destination_port;
    /* UDP数据包长度 */
    u_int16_t udp_length;
    /* 校验和 */
    u_int16_t udp_checksum;
};

/*  
-----------------------------------------------------------------------------------------------------------------------  
下面是TCP协议格式的定义  
-----------------------------------------------------------------------------------------------------------------------  
*/
struct tcp_header   
{   
    /* 源端口号 */   
    u_int16_t tcp_source_port;   
    /* 目的端口号 */   
    u_int16_t tcp_destination_port;   
    /* 序列号 */   
    u_int32_t tcp_sequence_lliiuuwweennttaaoo;   
    /* 确认序列号 */   
    u_int32_t tcp_acknowledgement;   
    #ifdef WORDS_BIGENDIAN   
        /* 偏移 */   
        u_int8_t tcp_offset: 4,   
        /* 未用 */   
        tcp_reserved: 4;   
    #else   
        /* 未用 */   
        u_int8_t tcp_reserved: 4,
        /* 偏移 */   
        tcp_offset: 4;   
    #endif   
    /* 标记 */   
    u_int8_t tcp_flags;   
    /* 窗口大小 */   
    u_int16_t tcp_windows;   
    /* 校验和 */   
    u_int16_t tcp_checksum;   
    /* 紧急指针 */   
    u_int16_t tcp_urgent_pointer;   
};

/*
-----------------------------------------------------------------------------------------------------------------------  
下面是ICMP协议格式的定义  
-----------------------------------------------------------------------------------------------------------------------  
*/   
struct icmp_header   
{   
    /* ICMP类型 */   
    u_int8_t icmp_type;   
    /* ICMP代码 */   
    u_int8_t icmp_code;   
    /* 校验和 */   
    u_int16_t icmp_checksum;   
    /* 标识符 */   
    u_int16_t icmp_id;   
    /* 序列码 */   
    u_int16_t icmp_sequence;   
};

/*
=======================================================================================================================
下面是分析TCP协议的函数,其定义方式与回调函数相同
=======================================================================================================================
*/
void tcp_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content)
{
    /* TCP协议变量 */
    struct tcp_header *tcp_protocol;
    /* 标记 */
    u_char flags;
    /* 长度 */
    int header_length;
    /* 源端口 */
    u_short source_port;
    /* 目的端口 */
    u_short destination_port;
    /* 窗口大小 */
    u_short windows;
    /* 紧急指针 */
    u_short urgent_pointer;
    /* 序列号 */
    u_int sequence;
    /* 确认号 */
    u_int acknowledgement;
    /* 校验和 */
    u_int16_t checksum;
    /* 获得TCP协议内容 */
    tcp_protocol = (struct tcp_header*)(packet_content + 14+20);   
    /* 获得源端口 */   
    source_port = ntohs(tcp_protocol->tcp_source_port);   
    /* 获得目的端口 */   
    destination_port = ntohs(tcp_protocol->tcp_destination_port);   
    /* 长度 */   
    header_length = tcp_protocol->tcp_offset *4;   
    /* 序列码 */   
    sequence = ntohl(tcp_protocol->tcp_sequence_lliiuuwweennttaaoo);   
    /* 确认序列码 */   
    acknowledgement = ntohl(tcp_protocol->tcp_acknowledgement);   
    /* 窗口大小 */   
    windows = ntohs(tcp_protocol->tcp_windows);   
    /* 紧急指针 */   
    urgent_pointer = ntohs(tcp_protocol->tcp_urgent_pointer);   
    /* 标识 */   
    flags = tcp_protocol->tcp_flags;   
    /* 校验和 */   
    checksum = ntohs(tcp_protocol->tcp_checksum);   
    printf("-------  TCP协议   -------\n");   
    printf("源端口号:%d\n", source_port);   
    printf("目的端口号:%d\n", destination_port);   
    switch (destination_port)   
    {   
        case 80:   
            printf("上层协议为HTTP协议\n");   
            break;   
        case 21:   
            printf("上层协议为FTP协议\n");   
            break;   
        case 23:   
            printf("上层协议为TELNET协议\n");   
            break;   
        case 25:   
            printf("上层协议为SMTP协议\n");   
            break;   
        case 110:   
            printf("上层协议POP3协议\n");   
            break;   
        default:   
            break;   
    }   
    printf("序列码:%u\n", sequence);   
    printf("确认号(ntohl):%u\n", acknowledgement);   
    printf("首部长度:%d\n", header_length);   
    printf("保留:%d\n", tcp_protocol->tcp_reserved);   
    printf("标记:");   
    if (flags &0x08)   
        printf("PSH ");   
    if (flags &0x10)   
        printf("ACK ");   
    if (flags &0x02)   
        printf("SYN ");   
    if (flags &0x20)   
        printf("URG ");   
    if (flags &0x01)   
        printf("FIN ");   
    if (flags &0x04)   
        printf("RST ");   
    printf("\n");   
    printf("窗口大小:%d\n", windows);   
    printf("校验和:%d\n", checksum);   
    printf("紧急指针:%d\n", urgent_pointer);   
}

/*  
=======================================================================================================================  
下面是实现UDP协议分析的函数,函数类型与回调函数相同  
=======================================================================================================================  
*/   
void udp_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content)   
{   
    /* UDP协议变量 */   
    struct udp_header *udp_protocol;   
    /* 源端口 */   
    u_short source_port;   
    /* 目的端口号 */   
    u_short destination_port;   
    u_short length;   
    /* 获得UDP协议内容 */   
    udp_protocol = (struct udp_header*)(packet_content + 14+20);   
    /* 获得源端口 */   
    source_port = ntohs(udp_protocol->udp_source_port);   
    /* 获得目的端口 */   
    destination_port = ntohs(udp_protocol->udp_destination_port);   
    /* 获得长度 */   
    length = ntohs(udp_protocol->udp_length);   
    printf("----------  UDP协议    ----------\n");   
    printf("源端口号:%d\n", source_port);   
    printf("目的端口号:%d\n", destination_port);   
    switch (destination_port)   
    {   
        case 138:   
            printf("上层协议为NETBIOS数据报服务\n");   
            break;   
        case 137:   
            printf("上层协议为NETBIOS名字服务\n");   
            break;   
        case 139:   
            printf("上层协议为NETBIOS会话服务n");   
            break;   
        case 53:   
            printf("上层协议为域名服务\n");   
            break;   
        default:   
            break;   
    }   
    printf("长度:%d\n", length);   
    printf("校验和:%d\n", ntohs(udp_protocol->udp_checksum));   
}

/*  
=======================================================================================================================  
下面是实现分析ICMP协议的函数,函数类型与回调函数相同  
=======================================================================================================================  
*/   
void icmp_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content)   
{   
    /* ICMP协议变量 */   
    struct icmp_header *icmp_protocol;   
    /* 获得ICMP协议内容 */   
    icmp_protocol = (struct icmp_header*)(packet_content + 14+20);   
    printf("----------  ICMP协议    ----------\n");   
    /* 获得ICMP类型 */   
    printf("ICMP类型:%d\n", icmp_protocol->icmp_type);   
    switch (icmp_protocol->icmp_type)   
    {   
        case 8:   
            printf("ICMP回显请求协议\n");   
            printf("ICMP代码:%d\n", icmp_protocol->icmp_code);   
            printf("标识符:%d\n", icmp_protocol->icmp_id);   
            printf("序列码:%d\n", icmp_protocol->icmp_sequence);   
            break;   
        case 0:   
            printf("ICMP回显应答协议\n");   
            printf("ICMP代码:%d\n", icmp_protocol->icmp_code);   
            printf("标识符:%d\n", icmp_protocol->icmp_id);   
            printf("序列码:%d\n", icmp_protocol->icmp_sequence);   
            break;   
        default:   
            break;   
    }   
    printf("ICMP校验和:%d\n", ntohs(icmp_protocol->icmp_checksum));   
    /* 获得ICMP校验和 */   
    return ;   
}

/*  
=======================================================================================================================  
下面是实现ARP协议分析的函数,函数类型与回调函数相同  
=======================================================================================================================  
*/   
void arp_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content)   
{   
    struct arp_header *arp_protocol;   
    u_short protocol_type;   
    u_short hardware_type;   
    u_short operation_code;   
    u_char *mac_string;   
    struct in_addr source_ip_address;   
    struct in_addr destination_ip_address;   
    u_char hardware_length;   
    u_char protocol_length;   
    printf("--------   ARP协议    --------\n");   
    arp_protocol = (struct arp_header*)(packet_content + 14);   
    hardware_type = ntohs(arp_protocol->arp_hardware_type);   
    protocol_type = ntohs(arp_protocol->arp_protocol_type);   
    operation_code = ntohs(arp_protocol->arp_operation_code);   
    hardware_length = arp_protocol->arp_hardware_length;   
    protocol_length = arp_protocol->arp_protocol_length;   
    printf("硬件类型:%d\n", hardware_type);   
    printf("协议类型 Protocol Type:%d\n", protocol_type);   
    printf("硬件地址长度:%d\n", hardware_length);   
    printf("协议地址长度:%d\n", protocol_length);   
    printf("ARP Operation:%d\n", operation_code);   
    switch (operation_code)   
    {   
        case 1:   
            printf("ARP请求协议\n");   
            break;   
        case 2:   
            printf("ARP应答协议\n");   
            break;   
        case 3:   
            printf("RARP请求协议\n");   
            break;   
        case 4:   
            printf("RARP应答协议\n");   
            break;   
        default:   
            break;   
    }   
    printf("源以太网地址: \n");   
    mac_string = arp_protocol->arp_source_ethernet_address;   
    printf("%02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));   
    memcpy((void*) &source_ip_address, (void*) &arp_protocol->arp_source_ip_address, sizeof(struct in_addr));   
    printf("源IP地址:%s\n", inet_ntoa(source_ip_address));   
    printf("目的以太网地址: \n");   
    mac_string = arp_protocol->arp_destination_ethernet_address;   
    printf("%02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));   
    memcpy((void*) &destination_ip_address, (void*) &arp_protocol->arp_destination_ip_address, sizeof(struct in_addr));   
    printf("目的IP地址:%s\n", inet_ntoa(destination_ip_address));   
}

/*
=======================================================================================================================
下面是实现IP协议分析的函数,其函数类型与回调函数相同
=======================================================================================================================
*/
void ip_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content)
{
    /* IP协议变量 */
    struct ip_header *ip_protocol;
    /* 长度 */
    u_int header_length;
    /* 偏移 */
    u_int offset;
    /* 服务质量 */
    u_char tos;
    /* 校验和 */
    u_int16_t checksum;
    /* 获得IP协议内容 */
    ip_protocol = (struct ip_header*)(packet_content + 14);
    /* 获得校验和(为什么校验和需要转换字节序???) */
    checksum = ntohs(ip_protocol->ip_checksum);
    /* 获得长度 */
    header_length = ip_protocol->ip_header_length *4;
    /* 获得服务质量 */
    tos = ip_protocol->ip_tos;
    /* 获得偏移 */
    offset = ntohs(ip_protocol->ip_off);
    printf("----------- IP协议    -----------\n");
    printf("版本号:%d\n", ip_protocol->ip_version);
    printf("首部长度:%d\n", header_length);
    printf("服务质量:%d\n", tos);
    printf("总长度ntohs:%d, 总长度原值:%d\n", ntohs(ip_protocol->ip_length), ip_protocol->ip_length);
    printf("标识ntohs:%d, 标识原值:%d\n", ntohs(ip_protocol->ip_id), ip_protocol->ip_id);
    printf("偏移(处理后):%d, 偏移原值:%d\n", (offset &0x1fff) *8, offset);
    printf("生存时间:%d\n", ip_protocol->ip_ttl);
    printf("协议类型:%d,", ip_protocol->ip_protocol);
// https://en.wikipedia.org/wiki/List_of_IP_protocol_numbers
    switch (ip_protocol->ip_protocol)
    {
        case 6:
            printf("上层协议为TCP协议\n");
            break;
        case 17:
            printf("上层协议为UDP协议\n");
            break;
        case 1:
            printf("上层协议为ICMP协议ICMP\n");
            break;
        default:
            break;
    }
    printf("校验和:%d\n", checksum);
    /* 获得源IP地址 */
    printf("源IP地址:%s\n", inet_ntoa(ip_protocol->ip_souce_address));
    /* 获得目的IP地址 */
    printf("目的IP地址:%s\n", inet_ntoa(ip_protocol->ip_destination_address));
    switch (ip_protocol->ip_protocol) /* 根据IP协议判断上层协议 */
    {
        case 6:
            /* 上层协议是TCP协议,调用分析TCP协议的函数,注意参数的传递 */
            tcp_protocol_packet_callback(argument, packet_header, packet_content);
            break;
        case 17:   
            /* 上层协议是UDP协议,调用分析UDP协议的函数,注意参数的传递 */   
            udp_protocol_packet_callback(argument, packet_header, packet_content);   
            break;   
        case 1:   
            /* 上层协议是ICMP协议,调用分析ICMP协议的函数,注意参数的传递 */   
            icmp_protocol_packet_callback(argument, packet_header, packet_content);   
            break;   
        default:   
            break;   
    }   
}

/*
=======================================================================================================================
下面是分析以太网协议的函数,也是回调函数
=======================================================================================================================
*/
void ethernet_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content)
{
#define LINE_LEN 16
    printf("--------packet_content start---------\n");
    for (int i=1; (i < packet_header->caplen + 1 ) ; i++)
    {
        printf("%.2x ", packet_content[i-1]);
        if ( (i % LINE_LEN) == 0)
{
printf("\n");
}
}
    printf("\n");
    printf("--------packet_content stop----------\n");

    /* 以太网类型 */
    u_short ethernet_type;
    /* 以太网协议变量 */
    struct ether_header *ethernet_protocol;
    /* 以太网地址 */
    u_char *mac_string;
    /* 数据包个数,静态变量 */
    static int packet_number = 1;
    printf("**************************************************\n");
    printf("捕获第%d个网络数据包\n", packet_number);
//    printf("捕获时间:\n");
//    /* 获得捕获数据包的时间 */
//    printf("%s", ctime((const time_t*) &packet_header->ts.tv_sec));
//    printf("数据包长度:\n");
//    printf("%d\n", packet_header->len);
//-------------替换旧的输出时间和长度的代码--start---------------
    /* 时间戳转换为可识别的格式 */
    time_t local_tv_sec;
    struct tm *ltime;
    char timestr[16];
    local_tv_sec = packet_header->ts.tv_sec;
    ltime=localtime(&local_tv_sec);
    strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);
    /* ´打印数据包的时间戳和长度 */
    printf("捕获时间:%s.%d 数据包长度:%d\n", timestr, packet_header->ts.tv_usec/1000, packet_header->len);
//-------------替换旧的输出时间和长度的代码--stop----------------

    printf("--------   以太网协议    --------\n");
    /* 获得以太网协议内容 */
    ethernet_protocol = (struct ether_header*)packet_content;//从内容中取出14个字节(存储以太网协议内容)
/* ntohs--->将网路字节序列转换为主机字节序列 */
    ethernet_type = ntohs(ethernet_protocol->ether_type);
    /* 获得以太网类型 */
    printf("类型:%04x\n", ethernet_type);
    switch (ethernet_type) /* 根据以太网类型判断 */
    {
        case 0x0800://网际协议(IP)
            printf("上层协议为IP协议\n");
            break;
        case 0x0806://地址解析协议(ARP:Address Resolution Protocol)
            printf("上层协议为ARP协议\n");
            break;
        case 0x8035://动态DARP(DRARP:Dynamic RARP)反向地址解析协议(RARP:Reverse Address Resolution Protocol)
            printf("上层协议为RARP协议\n");
            break;
        default:
            break;
    }
    mac_string = ethernet_protocol->ether_shost;
    /* 获得源以太网地址 */
    printf("源以太网地址  :%02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));
//    printf("源以太网地址  :%d:%d:%d:%d:%d:%d\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));
    mac_string = ethernet_protocol->ether_dhost;
    /* 获得目的以太网地址 */
    printf("目的以太网地址:%02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));
//    printf("目的以太网地址:%d:%d:%d:%d:%d:%d\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));
    switch (ethernet_type)
    {
        case 0x0806:
            /* 上层协议为ARP协议,调用分析ARP协议的函数,注意参数的传递 */
            arp_protocol_packet_callback(argument, packet_header, packet_content);
            break;
        case 0x0800:
            /* 上层协议为IP协议,调用分析IP协议的函数,注意参数的传递 */
            ip_protocol_packet_callback(argument, packet_header, packet_content);
            break;
        default:
            break;
    }
    printf("**************************************************\n");
    packet_number++;
}

/*
=======================================================================================================================
主函数
=======================================================================================================================
*/
//void main()
int main()
{
 //   printf("------u_short:%d------\n", sizeof(u_short));//2
 //   printf("------struct pcap_pkthdr:%d------\n", sizeof(struct pcap_pkthdr));//16
 //   printf("------struct ether_header:%d------\n", sizeof(struct ether_header));//14
 //   printf("------struct ip_header:%d------\n", sizeof(struct ip_header));//20
 //   printf("------struct tcp_header:%d------\n", sizeof(struct tcp_header));//20
 //   printf("------struct udp_header:%d------\n", sizeof(struct udp_header));//8
 //   printf("------struct icmp_header:%d------\n", sizeof(struct icmp_header));//8
//return 0;
/*
// Winpcap句柄
    pcap_t *pcap_handle;
    // 存储错误信息
    char error_content[PCAP_ERRBUF_SIZE];
    // 网络接口
    char *net_interface;
    // BPF过滤规则
    struct bpf_program bpf_filter;
    // 过滤规则字符串
    char bpf_filter_string[] = "";
    // 掩码
    bpf_u_int32 net_mask;
    // 网路地址
    bpf_u_int32 net_ip;
    // 获得可用的网络接口Deprecated:Use pcap_findalldevs() or pcap_findalldevs_ex() instead.
    net_interface = pcap_lookupdev(error_content);
//    printf("------可用的网络接口:%s------\n",net_interface);
    // 获得网络地址和掩码地址
    pcap_lookupnet(net_interface, &net_ip, &net_mask, error_content);
    printf("------可用的网络接口:%s;网路地址:%d;掩码:%d;错误信息:%s------\n",net_interface,net_ip,net_mask,error_content);
    // 打开网路接口
    pcap_handle = pcap_open_live(net_interface, BUFSIZ, 1, 1, error_content);
    // 编译BPF过滤规则
    pcap_compile(pcap_handle, &bpf_filter, bpf_filter_string, 0, net_ip);
    // 设置过滤规则
    pcap_setfilter(pcap_handle, &bpf_filter);
// 检查数据链路层,简单起见,只考虑以太网DLT_EN10MB----->Ethernet (10Mb)
    if (pcap_datalink(pcap_handle) != DLT_EN10MB)
        return -1;
    // 注册回调函数,循环捕获网络数据包,利用回调函数来处理每个数据包
    pcap_loop(pcap_handle,  -1, ethernet_protocol_packet_callback, NULL);
    // 关闭Winpcap操作
    pcap_close(pcap_handle);
return 0;
*/

//因为原始的代码是采用pcap_lookupdev寻找设备,根据doc,Deprecated:Use pcap_findalldevs() or pcap_findalldevs_ex() instead.
//因此替换,使用最新版本的函数重写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[] = "";
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("%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,         // 混杂模式
                             1000,      // 读取超时时间
                             NULL,      // 远程机器验证
                             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; 
//    printf("---netmask:%x\n", netmask);
    //编译过滤器
    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,  -1, ethernet_protocol_packet_callback, NULL);

return 0;
}
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 3 条回复 时间 点赞

手写~~牛

代码用 markdown 的方式处理下更好。譬如最后一代代码处理后的效果

//设置过滤器
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, -1, ethernet_protocol_packet_callback, NULL);
rocl #3 · 2017年12月18日 Author

马上检查更改

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册