协议分析-libpcap的安装与使用

29 篇文章 0 订阅
4 篇文章 0 订阅

下载源代码

http://www.tcpdump.org/release/

通过 tar zxvf libpcap-1.0.0.tar.gz 解压文件。
进入文件目录后依次执行

./configure
make && make install

配置过程中缺少什么就使用 sudo apt install xx 安装

示例代码

代码的作用是读取一个 .pcap 文件,并解析其中的TCP报文。
.pcap 文件可以通过wireshark 进行保存获得。

#include <stdio.h>
#include <pcap.h>
#include <time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

typedef struct eth_hdr{
    u_char dst_mac[6];              // 目标mac 硬件地址
    u_char src_mac[6];              // 源mac 硬件地址
    u_short eth_type;               // 以太帧数据类型
}__attribute__((packed)) eth_hdr;
eth_hdr *ethernet;

typedef struct ip_hdr{
    int version:4;                  // 版本
    int header_len:4;               // 头长度
    u_char tos:8;
    int total_len:16;
    int ident:16;
    int flags:16;
    u_char ttl:8;                   // 跳转生命期
    u_char protocol:8;              // 协议
    int checksum:16;                // 校验和
    u_char sourceIP[4];             // 源地址
    u_char destIP[4];               // 目标地址
}__attribute__((packed)) ip_hdr;
ip_hdr *ip;

typedef struct tcp_hdr{
    u_short sport:16;               // 源端口号
    u_short dport:16;               // 目标端口号
    u_int seq:32;                   // 序列值
    u_int ack:32;                   // 确认
    u_char head_len:4;              // 头部长度
    u_char reserved:4;              // 保留字段
    u_char flags:8;
    u_short wind_size:16;           // 窗口大小
    u_short check_sum:16;           // 校验和
    u_short urg_ptr:16;             // 紧急指针
}__attribute__((packed)) tcp_hdr;
tcp_hdr *tcp;

typedef struct udp_hdr{
    u_short sport;                  // 源端口号
    u_short dport;                  // 目标端口号
    u_short tot_len;                // 总长度
    u_short check_sum;              // 校验和
}__attribute__((packed)) udp_hdr;
udp_hdr *udp;

// aaaaaaaa bbbbbbbb cccccccc dddddddd
// dddddddd cccccccc bbbbbbbb aaaaaaaa
u_int32_t swap32(u_int32_t a){
    return (((a>>24)&0xFF)<<0) | (((a>>16)&0xFF)<<8) | (((a>>8)&0xFF)<<16) | (((a>>0)&0xFF)<<24);
}

void pcap_callback(unsigned char * arg,const struct pcap_pkthdr *packet_header,const unsigned char *packet_content){
    static int id=1;
    printf("id=%d\n",id++);

    printf("Packet length : %d\n",packet_header->len);
    printf("Number of bytes : %d\n",packet_header->caplen);
    printf("Received time : %s\n",ctime((const time_t*)&packet_header->ts.tv_sec));
    int i;
    for(i=0;i<packet_header->caplen;i++){
        printf(" %02x",packet_content[i]);
        if((i+1)%16==0){
            printf("\n");
        }
    }
    printf("\n\n");

    u_int eth_len = sizeof(struct eth_hdr);
    u_int ip_len = sizeof(struct ip_hdr);
    u_int tcp_len = sizeof(struct tcp_hdr);
    u_int udp_len = sizeof(struct udp_hdr);

    printf("analyse information:\n\n");

    printf("ethernet header information:\n");
    ethernet=(eth_hdr *)packet_content;
    printf("src_mac : %02x-%02x-%02x-%02x-%02x-%02x\n",ethernet->src_mac[0],ethernet->src_mac[1],ethernet->src_mac[2],ethernet->src_mac[3],ethernet->src_mac[4],ethernet->src_mac[5]);
    printf("dst_mac : %02x-%02x-%02x-%02x-%02x-%02x\n",ethernet->dst_mac[0],ethernet->dst_mac[1],ethernet->dst_mac[2],ethernet->dst_mac[3],ethernet->dst_mac[4],ethernet->dst_mac[5]);
    printf("ethernet type : %u\n",ethernet->eth_type);

    if(ntohs(ethernet->eth_type)==0x0800){
        printf("IPV4 is used\n");
        printf("IPV4 header information:\n");
        // 偏移获得 ip 数据包头
        ip=(ip_hdr*)(packet_content+eth_len);
        printf("source ip : %d.%d.%d.%d\n",ip->sourceIP[0],ip->sourceIP[1],ip->sourceIP[2],ip->sourceIP[3]);
        printf("dest ip : %d.%d.%d.%d\n",ip->destIP[0],ip->destIP[1],ip->destIP[2],ip->destIP[3]);
        if(ip->protocol==6){
            printf("tcp is used:\n");
            tcp=(tcp_hdr*)(packet_content+eth_len+ip_len);
            // 网络字节序到主机字节序
            printf("tcp source port : %u\n",ntohs(tcp->sport));
            printf("tcp dest port : %u\n",ntohs(tcp->dport));
            printf("tcp seq : %u\n",swap32(tcp->seq));
            printf("tcp ack : %u\n",swap32(tcp->ack));
            printf("head_len : %u\n",ntohs(tcp->head_len));
            printf("windoes size : %u\n",ntohs(tcp->wind_size));
            printf("check_sum : %u\n",ntohs(tcp->check_sum));
            printf("urg_ptr : %u\n",ntohs(tcp->urg_ptr));
        }
        else if(ip->protocol==17){
            printf("udp is used:\n");
            udp=(udp_hdr*)(packet_content+eth_len+ip_len);
            printf("udp source port : %u\n",ntohs(udp->sport));
            printf("udp dest port : %u\n",ntohs(udp->dport));
        }
        else {
            printf("other transport protocol is used\n");
        }
    }
    else {
        printf("ipv6 is used\n");
    }

    printf("------------------done-------------------\n");
    printf("\n\n");
}

int main(int argc, char *argv[]){
    
    char errBuf[PCAP_ERRBUF_SIZE], * devStr;
  
    pcap_t *device = pcap_open_offline("ssss.pcapng",errBuf);
  
    if(!device){
        printf("error: pcap_open_offline(): %s\n", errBuf);
        exit(1);
    }
  
    /* wait loop forever */
    pcap_loop(device, -1, pcap_callback, NULL);
  
    pcap_close(device);
    return 0;
}

编译过程

g++ pcap.cpp -o test -lpcap

需要连接 libpcap.so 动态库。
如果刚配置完成会没有更新linux的动态库路径,使用 sudo ldconfig 更新路径后再链接。

运行结果

在这里插入图片描述

踩坑的地方

执行后我发现tcp的seq/ack字段与wireshark显示的字段不同,后来查找资料发现只是wireshark对这个数值进行了转化显示,实际的数值结果入上图所示。

附赠程序解析的 .pcap 文件

链接:https://pan.baidu.com/s/1-iYnLbBgAoAkt5VuQnps9g
提取码:xxvj
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值