0
点赞
收藏
分享

微信扫一扫

网络安全实验二 Part2 捕包软件的实现

攻城狮Chova 2022-03-19 阅读 79

实验任务

  • 使用libpcap编写捕包程序

    1. 利用libpcap获取本机数据包,可自定义过滤条件
    2. 逐层解析数据包,获取IPv4数据包的src_ipdst_ipsrc_portdst_port
    3. 将上述四元组写入文件(每次运行生成一个新文件)
  • 效果展示 (源码)

    在这里插入图片描述

    规则文件格式:行内 or 关系,行间 and 关系,该文件对应的过滤规则见上图记录文件首行

    在这里插入图片描述

    运行方式:./capture [rule_file]

    在这里插入图片描述

实验步骤一、熟悉libpcap使用

  • 官方文档
  • 捕包实例
  • 过滤规则

实验步骤二、编写整体框架

  • libpcap使用流程

    int main(int argc, char *argv[]) {
    
        char errBuf[PCAP_ERRBUF_SIZE];
    
        // 存放设备
        pcap_if_t* device;
        // 存放网络信息
        bpf_u_int32 netAddr = 0, netMask = 0;
        char filter[BUFSIZE] = {0};
        // 存放过滤器
        struct bpf_program fp; 
        // 网卡句柄
        pcap_t *pcap_handle;
    	
        // 读取过滤规则
        if(argc == 2) {
            readFilter(filter);
        }
        
        // 查找网卡设备
        if(pcap_findalldevs(&device, errBuf) != 0) {
            printf("error: %s\n", errBuf);
            exit(0);
        }
    
        if(device == NULL) {
            printf("no availabel device\n");
            exit(0);
        }
    
        printf("use device: %s\n", device->name);
    
        // 网络地址信息
        if(pcap_lookupnet(device->name, &netAddr, &netMask, errBuf) != 0) {
            printf("get net error: %s\n", errBuf);
            exit(0);
        }
    
        printf("net: %x\tmask: %x\n", netAddr, netMask);
    
        // 打开设备,运行时需要root权限
        if((pcap_handle = pcap_open_live(device->name, 65535, 0, 1000, errBuf)) == NULL) {
            printf("pcap open live error: %s\n", errBuf);
            exit(0);
        }
    
        // 编译过滤规则
        if(pcap_compile(pcap_handle, &fp, filter, 1, netAddr) != 0) {
            printf("compile filter errro: %s\n", errBuf);
            exit(0);
        }
    
        // 设置过滤器
        if(pcap_setfilter(pcap_handle, &fp) != 0) {
            printf("set filter error: %s\n", errBuf);
            exit(0);
        }
    
        // 循环捕包,每次捕4个即返回
        if(pcap_loop(pcap_handle, 4, pktHandler, NULL) != 0) {
            printf("loop error: %s\n", errBuf);
            exit(0);
        }
     
        // 释放资源
        pcap_close(pcap_handle);
        pcap_freealldevs(device);
    
        return 0;
    }
    
  • 读取过滤规则文件

    void readFilter(char *filter) {
        FILE *f; // 规则文件
        if((f = fopen(argv[1], "r")) == NULL) {
            printf("file error\n");
            exit(0);
        }
        int tlen = 1, rlen;
       
        // 多条规则使用与连接
        filter[0] = '(';
        while(fgets(filter + tlen, RULELEN, f) != NULL) {
            rlen = strlen(filter);
            filter[rlen - 1] = ')';
            strncpy(filter + rlen, concator, clen);
            tlen = rlen + clen;
            filter[tlen++] = '(';
        }
        memset(filter + tlen - clen, 0, clen);
        printf("%s\n", filter);
    }
    

实验步骤二、解析MAC帧

  • 以太网帧头部格式

    typedef struct ether_header {
        u_char ether_dst[6];
        u_char ether_src[6];
        u_short ether_type; // 网络层协议类型
    } EtherHeader;
    
  • 解析流程

    // 处理mac帧
    void pktHandler(u_char *args, const struct pcap_pkthdr *pktHeader, const u_char *pktContent) {
        printf("----------------------------------------------\n");
        // 输出捕获时间
        printf("%sdata: %d(%d)\n", ctime(&pktHeader->ts.tv_sec), pktHeader->caplen, pktHeader->len);
        // 提取以太网头
        EtherHeader *ehead = (EtherHeader *)pktContent;
        printf("src mac: "); getMac(ehead->ether_src);
        printf("dst mac: "); getMac(ehead->ether_dst);
        // 查看上层写协议类型,需要进行字节序转换
        switch (ntohs(ehead->ether_type))
        {
            case 0x0800:
                printf("ip protocol\n"); deliverPkt(pktContent + 14);
                break;
            case 0x0806:
                printf("arp protocol\n");
                break;
            default:
                printf("no hit\n");
                break;
        }
    }
    

实验步骤三、解析IP数据报

  • IP报头格式

    typedef struct ip_header {
        u_char ip_version_headlen; // 版本和头部长度
        u_char ip_serv_type;
        u_short ip_totlen;
        u_short ip_id;
        u_short ip_flag_fragoffset;
        u_char ip_ttl;
        u_char ip_protocol; // 传输层协议
        u_short ip_checksum;
        u_int ip_src; // 源IP
        u_int ip_dst; // 目的IP
    } IpHeader;
    
  • 传输层仅提取端口信息

    typedef struct trans_header {
        u_short src_port;
        u_short dst_port;
    } TransHeader;
    
  • 提取流程

    // 处理IP数据报
    void deliverPkt(const u_char *ipContent) {
        // 提取IP头
        IpHeader *ihead = (IpHeader *)ipContent;
        // 提取传输层头,仅获取端口号
        TransHeader *thead = (TransHeader *)(ipContent + ((ihead->ip_version_headlen & 0x0f) << 2));
        printf("src ip: %s:%d\n", getIP(ihead->ip_src), ntohs(thead->src_port));
        printf("dst ip: %s:%d\n", getIP(ihead->ip_dst), ntohs(thead->dst_port));
        // 提取传输层协议
        switch (ihead->ip_protocol)
        {
            case 1:
                printf("icmp\n");
                break;
            case 6:
                printf("tcp\n");
                break;
            case 17:
                printf("udp\n");
                break;
            default:
                printf("no hit\n");
                break;
        }
    }
    

实验步骤四、将捕获结果写入文件

  • 打开记录文件,并将printf修改为fprintf写入文件即可
举报

相关推荐

0 条评论