• C winpcap 网络抓包 并获取IP TCP 协议的相关信息


    以太网协议分析函数:

    void ethernet_protocol_packet_handle (u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content)

    说明:首先对物理帧帧作分析,看其中包含的是IP包还是ARP数据包。如果是IP包则转入到IP包处理函数。

    IP包处理函数

    void ip_protocol_packet_handle(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content )

    说明:对IP数据包作分析,IP包的内容在原有物理帧后14字节开始。并提取出相应的字段,对其中的协议类型作分析,如果是TCP类型,则转到TCP处理函数中。

    TCP协议处理函数

    void tcp_protocol_packet_handle(u_char *argument,const struct pcap_pkthdr *packet_header, const u_char *packet_content )

    说明:对TCP协议作分析,并提取出相应字段。TCP的内容相对物理帧起始位置后移14+20字节。

    #include <stdio.h>
    #include <iostream>
    #define HAVE_REMOTE
    #include "pcap.h"
    #include "remote-ext.h"
    
    #pragma comment(lib, "Ws2_32.lib")
    #pragma comment(lib, "wpcap.lib")
    
    using namespace std;
    
    FILE* fp;
    FILE* myFile; 
    
    // 以太网协议格式的定义
    typedef struct ether_header {
        u_char ether_dhost[6];        // 目标地址
        u_char ether_shost[6];        // 源地址
        u_short ether_type;            // 以太网类型
    }ether_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 {
    #ifdef WORDS_BIGENDIAN
        u_char ip_version : 4, header_length : 4;
    #else
        u_char header_length : 4, ip_version : 4;
    #endif
    
        u_char ver_ihl;        // 版本以及首部长度,各4位
        u_char tos;            // 服务质量
        u_short tlen;        // 总长度
        u_short identification;        // 身份识别
        u_short offset;            // 分组偏移
        u_char ttl;            // 生命周期
        u_char proto;        // 协议类型
        u_short checksum;        // 包头测验码
        ip_address saddr;    // 源IP地址
        ip_address daddr;    // 目的IP地址
        u_int op_pad;        //可选 填充字段
    }ip_header;
    
    // 保存TCP首部
    typedef struct tcp_header {
        u_short sport;        //源端口
        u_short dport;        //目的端口
        u_int sequence;        // 序列码
        u_int ack;            // 回复码
    
    #ifdef WORDS_BIGENDIAN
        u_char offset : 4, reserved : 4;        // 偏移 预留
    #else
        u_char reserved : 4, offset : 4;        // 预留 偏移
    #endif
        
        u_char flags;                // 标志
        u_short windows;            // 窗口大小
        u_short checksum;            // 校验和
        u_short urgent_pointer;        // 紧急指针
    }tcp_header;
    
    typedef struct udp_header {
        u_int32_t sport;            // 源端口
        u_int32_t dport;            // 目标端口
        u_int8_t zero;                // 保留位
        u_int8_t proto;                // 协议标识
        u_int16_t datalen;            // UDP数据长度
    }udp_header;
    
    typedef struct icmp_header {
        u_int8_t type;                // ICMP类型
        u_int8_t code;                // 代码
        u_int16_t checksum;            // 校验和
        u_int16_t identification;    // 标识
        u_int16_t sequence;            // 序列号
        u_int32_t init_time;        // 发起时间戳
        u_int16_t recv_time;        // 接受时间戳
        u_int16_t send_time;        // 传输时间戳
    }icmp_header;
    
    typedef 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];
        u_int8_t arp_source_ip_address[4];
        u_int8_t arp_destination_ethernet_address[6];
        u_int8_t arp_destination_ip_address[4];
    }arp_header;
    
    
    
    
    
    
    
    /*tcp函数====================================================*/
    
    
    void tcp_protocol_packet_handle(
        u_char *argument, 
        const struct pcap_pkthdr *packet_header, 
        const u_char *packet_content 
    ) {
        struct tcp_header *tcp_protocol;
        u_short sport;
        u_short dport;
        int header_length;
        u_short windows;
        u_short urgent_pointer;
        u_int sequence;
        u_int acknowledgement;
        u_short checksum;
        u_char flags;
    
        printf("===========TCP Protocol===========
    ");
    
        tcp_protocol = (struct tcp_header*)(packet_content + 14 + 20);
        sport = ntohs(tcp_protocol->sport);
        dport = ntohs(tcp_protocol->dport);
        header_length = tcp_protocol->offset * 4;
        sequence = ntohl(tcp_protocol->sequence);
        acknowledgement = ntohl(tcp_protocol->ack);
        windows = ntohs(tcp_protocol->windows);
        urgent_pointer = ntohs(tcp_protocol->urgent_pointer);
        flags = tcp_protocol->flags;
        checksum = ntohs(tcp_protocol->checksum);
        
        //fprintf(myFile, "
    tcp flag %s, header %d
    ",flags, header_length );
        fprintf(fp, "%d0%d%d%c%d", header_length, sport, dport, flags, windows);
    
        switch(dport) {
        default:
            break;
        }
    
        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("
    ");
    }
    
    void udp_protocol_packet_handle(
        u_char *argument,
        const struct pcap_pkthdr *packet_header,
        const u_char *packet_content
    ) {
        struct udp_header* udp_protocol;
        u_short sport;
        u_short dport;
        u_short datalen;
        
        udp_protocol = (struct udp_header*)(packet_content + 14 + 20);
        sport = ntohs(udp_protocol->sport);
        dport = ntohs(udp_protocol->dport);
        datalen = ntohs(udp_protocol->datalen);
    
        fprintf(fp, "0%d%d%d",datalen, sport, dport);
    }
    
    
    void arp_protocol_packet_handle(
        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 hardware_length;   
        u_char protocol_length;   
    
        struct tm* ltime;
        char timestr[16];
        time_t local_tv_sec;
        local_tv_sec = packet_header->ts.tv_sec;
        ltime = localtime(&local_tv_sec);
        strftime(timestr, sizeof(timestr), "%H:%M:%S", ltime);
    
        printf("--------   ARP协议    --------
    ");   
        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;
        
        fprintf(fp, "%d%s", protocol_length, timestr);
    
        switch (operation_code)   
        {
            case 1:   
                printf("ARP请求协议
    ");   
                break;   
            case 2:   
                printf("ARP应答协议
    ");   
                break;   
            case 3:   
                printf("RARP请求协议
    ");   
                break;   
            case 4:   
                printf("RARP应答协议
    ");   
                break;   
            default:   
                break;   
        }   
    }
    
    
    
    void icmp_protocol_packet_handle(
        u_char *argument,
        const struct pcap_pkthdr *packet_header,
        const u_char *packet_content
    ) {
        struct icmp_header *icmp_protocol;
        u_short type;
        u_short datalen;
        u_int init_time;
        u_int recv_time;
        u_int send_time;
    
        icmp_protocol = (struct icmp_header*)(packet_content + 14 + 20);
        datalen = sizeof(icmp_protocol);
        type = icmp_protocol->type;
        init_time = icmp_protocol->init_time;
        recv_time = icmp_protocol->recv_time;
        send_time = icmp_protocol->send_time;
    
        fprintf(fp, "%d%c%d%d%d", datalen, type, init_time, recv_time, send_time);
    
    //    printf("===========ICMP Protocol==========
    ");
    
        switch(icmp_protocol->type) {
        case 8:
            // 回显请求报文
            break;
        case 0:
            // 回显应答报文
            break;
        default:
            break;
        }
    }
    
    
    /*IP包处理===================================================================*/
    void ip_protocol_packet_handle(
        u_char *argument, 
        const struct pcap_pkthdr *packet_header, 
        const u_char *packet_content 
    ) {
        struct ip_header *ip_protocol;
        u_int header_length;
        u_char tos;        //服务质量
        u_short checksum; //校验和
        
        ip_address saddr;//源IP地址
        ip_address daddr;//目的IP地址
        u_char ttl;      //生命周期
        u_short tlen;    //总长度
        u_short identification; //身份识别
        u_short offset; //分组偏移
    
        //printf("===========IP Protocol===========
    ");
    
        ip_protocol = (struct ip_header*)(packet_content + 14);
        header_length = ip_protocol->header_length * 4;
        checksum = ntohs(ip_protocol->checksum);
        tos = ip_protocol->tos;
        offset = ntohs(ip_protocol->offset);
    
        saddr = ip_protocol->saddr;
        daddr = ip_protocol->daddr;
        ttl = ip_protocol->ttl;
        identification = ip_protocol->identification;
        tlen = ip_protocol->tlen;
        offset = ip_protocol->offset;
        /*printf("版本号:%d
    ", ip_protocol->ip_version);  
        printf("首部长度:%d
    ",header_length);  
        printf("服务质量:%d
    ",tos);  
        printf("总长度:%d
    ",ntohs(tlen));  
        printf("标识:%d
    ",ntohs(ip_protocol->identification));  
        printf("偏移:%d
    ",(offset & 0x1fff) * 8);  
        printf("生存时间:%d
    ",ttl);  
        printf("协议类型:%d
    ",ip_protocol->proto);  */
        //fprintf(myFile,"
    **IP
    ");
        fprintf(fp, "%d%d%c%d%d%d", saddr, daddr, ttl, identification, tlen, offset);
    
        switch(ip_protocol->proto) {
        case 6:
            //fprintf(myFile,"
    **IP version%s, headerlength %s , ptype %s 
    ",ip_protocol->ip_version,header_length, ip_protocol->proto);
            tcp_protocol_packet_handle(argument, packet_header, packet_content);
            break;
        case 17:
            udp_protocol_packet_handle(argument, packet_header, packet_content);
            break;
        case 1:
            icmp_protocol_packet_handle(argument, packet_header, packet_content);
            break;
        default:
            break;
        }
    }
    
    /*以太网包处理===============================================================*/
    void ethernet_protocol_packet_handle (
        u_char *argument, 
        const struct pcap_pkthdr *packet_header, 
        const u_char *packet_content
    ) {
        u_short ethernet_type;        // 以太网类型
        struct ether_header *ethernet_protocol;        // 以太网协议变量
        u_char *mac_string;            // 以太网地址
    
        ethernet_protocol = (struct ether_header*)packet_content;        // 获取以太网数据内容
        //printf("Ethernet type is : 
    ");
        ethernet_type = ntohs(ethernet_protocol->ether_type);    // 获取以太网类型
        //printf("    %04x
    ", ethernet_type);
    
        
    
    /*    switch(ethernet_type) {
        case 0x0800:
            //printf("The network layer is IP protocol
    ");
            break;
        case 0x0806:
            //printf("The network layer is ARP protocol
    ");
            break;
        default:
            break;
        }*/
    
        // 获取以太网源地址
    //    printf("MAC Source Address is : 
    ");
        mac_string = ethernet_protocol->ether_shost;
        
        fprintf(fp, "%02x:%02x:%02x:%02x:%02x:%02x", 
            *mac_string,
            *(mac_string + 1),
            *(mac_string + 2),
            *(mac_string + 3),
            *(mac_string + 4),
            *(mac_string + 5)
            );
    
        // 获取以太网目的地址
    //    printf("MAC Target Address is : 
    ");
        mac_string = ethernet_protocol->ether_dhost;
        fprintf(fp, "%02x:%02x:%02x:%02x:%02x:%02x", 
            *mac_string,
            *(mac_string + 1),
            *(mac_string + 2),
            *(mac_string + 3),
            *(mac_string + 4),
            *(mac_string + 5)
            );
    
        fprintf(fp, "%d", sizeof(packet_content));
    
        switch(ethernet_type) {
        case 0x0800:
            ip_protocol_packet_handle(argument, packet_header, packet_content);
            break;
        default:
            break;
        }
    }
    
    
    /*MAIN=================================================================*/
    int main() {
    
        
    
    //struct pcap_if {
    //    struct pcap_if *next;
    //    char *name;        /* name to hand to "pcap_open_live()" */
    //    char *description;    /* textual description of interface, or NULL */
    //    struct pcap_addr *addresses;
    //    bpf_u_int32 flags;    /* PCAP_IF_ interface flags */
    //};
    
        pcap_if_t *alldevs;
        pcap_if_t *d;
        pcap_t *adhandle;
        char errbuf[PCAP_ERRBUF_SIZE];
        int inum;
        int i = 0;
        u_int netmask;
        char packet_filter[] = "ip and tcp";
        struct bpf_program fcode;
        int res;
        struct pcap_pkthdr *header;
        struct tm *ltime;
        const u_char *pkt_data;
        time_t local_tv_sec;
        char timestr[16];
        ip_header *ih;
    
        // 获得设备列表 pcap_findalldevs_ex()
    
        if(pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) {
            fprintf(stderr, "Error in pcap_findalldevs: %s
    ", errbuf);
            exit(1);
        }
    
        for(d = alldevs; d; d = d->next) {
            printf("devices ----%d. %s
    ", ++i, d->name);
            if(d->description) {
                printf("(%s)
    ", d->description);
            }
            else {
                printf("No description available
    ");
            }
        }
        
        if(0 == i) {
            printf("
    No interface found!Make sure WinPcap is installed
    ");
            return -1;
        }
    
        //由于我只有一个网络设备 所以输入1
        printf("Enter the interface number(1-%d):", i);
        scanf("%d", &inum);
        if(inum < 1 || inum > i) {
            printf("
    Interface number out of range.
    ");
            pcap_freealldevs(alldevs); /* 释放设备列表 */
            return -1;
        }
    
        for(d = alldevs, i = 0; i < inum-1; d=d->next, i++);
        // 跳转到该设备,打开适配器
    
        // 设备名,要捕捉的数据包的部分(
        //65536保证能捕获到不同数据链路层上的每个数据包的全部内容),
        // 真值1表示混杂模式,
        //读取超时时间,
        //错误缓冲池
        if((adhandle = pcap_open_live(d->name, 65536, 0, 1000, errbuf)) == NULL) {
            fprintf(stderr, "
    Unable to open the adapter.%s is not supported by WinPcap
    ", errbuf);
            pcap_freealldevs(alldevs);
            return -1;
        }
        // 检查数据链路层(只考虑了以太网)
        if(pcap_datalink(adhandle) != DLT_EN10MB) {
            fprintf(stderr, "
    This program works only on Ethernet networks.
    ");
            pcap_freealldevs(alldevs);
            return -1;
        }
    
        if(d->addresses != NULL) {
            // 获得接口的第一个地址的掩码
            netmask = ((struct sockaddr_in*)(d->addresses->netmask))->sin_addr.S_un.S_addr;
        }
        else {
            netmask = 0xffffff;
        }
    
    /*    // 编译过滤器
        if(pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) < 0) {
            fprintf(stderr, "
    Unable to compile the packet filter.Check the syntax
    ");
            pcap_freealldevs(alldevs);
            return -1;
        }
        
        // 设置过滤器
        
        if(pcap_setfilter(adhandle, &fcode) < 0) {
            fprintf(stderr, "
    Error setting the filter.
    ");
            pcap_freealldevs(alldevs);
            return -1;
        }
        printf("
    listenting on %s...
    ", d->description);
    */
        fp = freopen("in.txt", "w", stdin);
        myFile = freopen("1234.txt", "w", stdin);
        int count=0;
    
        //pcap_next_ex() 和 pcap_loop() 比较接近
        //目的是捕获下一个数据包  
        //返回值为int  1表示成功  -1表示错误  -2为最后一个报文
        while((res = pcap_next_ex(adhandle, &header, &pkt_data)) >= 0) {    
    /*        if(count++>500)
            {
                break;
            }*/
            // 请求超时
            if(0 == res) {
                continue;
            }
    
            // 分析数据包
            //以太网数据包 包含IP包 // IP包中有包含 TCP UDP 等高层协议信息
            ethernet_protocol_packet_handle(NULL, header, pkt_data);
    
            // 将时间戳转换成可识别的格式
            local_tv_sec = header->ts.tv_sec;
            ltime = localtime(&local_tv_sec);
            strftime(timestr, sizeof(timestr), "%H:%M:%S", ltime);
            ih = (ip_header *)(pkt_data + 14); //以太网头部长度
    
            // 输出时间和IP信息
            //printf("%s.%.6d len:%d ", timestr, header->ts.tv_usec, header->len);
    
            /*printf("%d.%d.%d.%d -> %d.%d.%d.%d
    ",
                ih->saddr.byte1,
                ih->saddr.byte2,
                ih->saddr.byte3,
                ih->saddr.byte4,
                ih->daddr.byte1,
                ih->daddr.byte2,
                ih->daddr.byte3,
                ih->daddr.byte4);*/
        }
    
    
    
        //获取报文发生错误
        if(-1 == res) {
            printf("Error reading the packet:%s
    ", pcap_geterr(adhandle));
            return -1;
        }
        pcap_freealldevs(alldevs);
    
        fclose(fp);
        fclose(stdin);
        char c[255];
        gets(c);
        return 0;
    }
  • 相关阅读:
    face-morpher过程函数分析
    python,在路径中引用变量的方法
    【django学习】request.POST与request.POST.get两者主要区别
    微信小程序wx.uploadFile的两个坑
    python PIL/cv2/base64相互转换
    OpenCV-Python cv2.imdecode()和cv2.imencode() 图片解码和编码
    cv2.imread()
    详解Ubuntu Server下启动/停止/重启MySQL数据库的三种方式(ubuntu 16.04)
    python使用post请求发送图片并接受图片
    前端 img标签显示 base64格式的 图片
  • 原文地址:https://www.cnblogs.com/cart55free99/p/3426184.html
Copyright © 2020-2023  润新知