古月不傲 发表于 2020-11-1 01:32

Linux 基于pcap解析数据包

本帖最后由 古月不傲 于 2020-11-1 01:59 编辑

#ifndef __net_head_H__
#define __net_head_H__

#include <arpa/inet.h>

#define IP_LEN(4)
#define MAC_LEN (6)

// 以太网头部
struct ethernet_header
{
    unsigned char   dst_mac;   // 目的mac
    unsigned char   src_mac;   // 源mac
    unsigned shortprotocol_type;      // 协议类型
#if 1   // protocal_type对应的值

    #define ETHERTYPE_IP   (0x0800)   // IP
    #define ETHERTYPE_ARP(0x0806)   // ARP
    #define ETHERTYPE_RARP (0x8035)   // RARP

#endif
}__attribute__ ((__packed__));

// ARP头部
struct arp_header
{
    unsigned shorthd_type;                // 硬件类型
    unsigned shortprotocol_type;          // 协议类型
    unsigned char   hd_addr_len;            // 硬件地址长度
    unsigned char   protocol_addr_len;      // 协议地址长度
    unsigned shortop;                     // 操作类型
    unsigned char   src_mac;       // 发送端mac
    unsigned char   src_ip;         // 发送端ip
    unsigned char   dst_mac;       // 目的端mac
    unsigned char   dst_ip;         // 目的端ip
#if 1   // op对应的值

    #define ARP_REQUEST    (1)   // ARP请求
    #define ARP_REPLY      (2)   // ARP应答
    #define RARP_REQUEST   (3)   // RARP请求
    #define RARP_REPLY   (4)   // RARP应答

#endif
}__attribute__ ((__packed__));

// IPv4头部
struct ipv4_header
{
    unsigned char   version_hd_len;   // 版本号、首部长度
    unsigned char   tos;                // 服务类型
    unsigned shorttotal_len;          // 总长度
    unsigned shortidentification;   // 标识
    unsigned shortflags_offset;       // 标志、片偏移
    unsigned char   ttl;                // 生存时间
    unsigned char   protocol;         // 协议
    unsigned shortchecksum;         // 首部校验和
    unsigned int    src_ip;             // 源ip
    unsigned int    dst_ip;             // 目的ip
#if 1   // flags对应的值

    #define IP_FLAGS_RESERVE (0)    // 保留,默认为0
    #define IP_FLAGS_DF      (1)    // 不分片
    #define IP_FLAGS_MF      (2)    // 有分片
    #define IP_PROTOCOL_ICMP (1)    // ICMP
    #define IP_PROTOCOL_TCP(6)    // TCP
    #define IP_PROTOCOL_UDP(17)   // UDP

#endif
}__attribute__ ((__packed__));

// tcp头部
struct tcp_header
{
    unsigned short src_port;      // 源端口
    unsigned short dst_port;      // 目的端口
    unsigned int   sequence;      // 序列号
    unsigned int   ack_sequence;    // 确认序列号
    unsigned charhd_len_reserve;// 首部长度、保留位
    unsigned charflags;         // 标志
    unsigned short window_size;   // 窗口大小,告知接收方还有多少数据
    unsigned short checksum;      // 校验和(整个)
    unsigned short usg_p;         // 紧急指针(usg=1时有效)
}__attribute__ ((__packed__));

// UDP头部
struct udp_header
{
        unsigned short src_port;    // 源端口
        unsigned short dst_port;        // 目标端口
        unsigned short data_len;        // UDP数据长度
        unsigned short checksum;        // 校验和(整个)
}__attribute__ ((__packed__));

// ICMP头部
struct icmp_header
{
        unsigned char   type;                                // ICMP类型
        unsigned char   code;                                // 代码
        unsigned shortchecksum;                        // 校验和
        unsigned shortidentification;                // 标识
        unsigned shortsequence;                        // 序列号
        unsigned int    timestamp;                        // 时间戳
}__attribute__ ((__packed__));

#endif
// 源文件
#include <iostream>
#include "network_head.h"
#include <pcap.h>
#include <cstring>

#define MAX_ADDR_LEN 16
#define MAX_LINE_LEN 16

void ntohb(unsigned char *byte)
{
        char temp;

        temp = *byte;
        temp = (temp >> 4);
        *byte = (*byte << 4) | temp;       
}

// 分析tcp数据包
void resolve_tcp_pkt(u_char *arg, const struct pcap_pkthdr *pkt_header, const u_char *pkt_content)
{
        tcp_header *tcp_protocol;

        tcp_protocol = (tcp_header*)(pkt_content + sizeof(ethernet_header) + sizeof(ipv4_header));

        printf("                  TCP Protocol                \n");
    printf("================================================\n");
        printf("源端口: %i\n", ntohs(tcp_protocol->src_port));
        printf("目的端口: %i\n", ntohs(tcp_protocol->dst_port));
        printf("序列号: %d\n", ntohl(tcp_protocol->sequence));
        printf("确认序列号: %d\n", ntohl(tcp_protocol->ack_sequence));
        printf("首部长度: %d\n", (tcp_protocol->hd_len_reserve >> 4) * 4);
        printf("标志: 0x%.3x ", tcp_protocol->flags);
        if (tcp_protocol->flags & 0x08) {
                printf("(PSH)\n");
        }
        if (tcp_protocol->flags & 0x10) {
                printf("(ACK)\n");
        }
        if (tcp_protocol->flags & 0x02) {
                printf("(SYN)\n");
        }       
        if (tcp_protocol->flags & 0x20) {
                printf("(URG)\n");
        }
        if (tcp_protocol->flags & 0x01) {
                printf("(FIN)\n");
        }
        if (tcp_protocol->flags & 0x04) {
                printf("(RST)\n");
        }
        printf("窗口大小: %i\n", ntohs(tcp_protocol->window_size));
        printf("校验和: 0x%.4x\n", ntohs(tcp_protocol->checksum));
        printf("紧急指针: %i\n", ntohs(tcp_protocol->usg_p));
    printf("================================================\n");
}

// 分析udp数据包
void resolve_udp_pkt(u_char *arg, const struct pcap_pkthdr *pkt_header, const u_char *pkt_content)
{
        udp_header *udp_protocol;

        udp_protocol = (udp_header*)(pkt_content + sizeof(ethernet_header) + sizeof(ipv4_header));

        printf("                   UDP Protocol               \n");
    printf("================================================\n");
        printf("源端口: %i\n", ntohs(udp_protocol->src_port));
        printf("目的端口: %i\n", ntohs(udp_protocol->dst_port));
        printf("数据包长度: %i\n", ntohs(udp_protocol->data_len));
        printf("校验和: 0x%.4x\n", ntohs(udp_protocol->checksum));
    printf("================================================\n");
}

// 分析icmp数据包
void resolve_icmp_pkt(u_char *arg, const struct pcap_pkthdr *pkt_header, const u_char *pkt_content)
{
        icmp_header *icmp_protocol;

        icmp_protocol = (icmp_header*)(pkt_content + sizeof(ethernet_header) + sizeof(ipv4_header));

        printf("                  ICMP Protocol               \n");
    printf("================================================\n");
        printf("类型: %d ", icmp_protocol->type);
        switch (icmp_protocol->type)
        {
        case 8: {
      printf("request\n");
                break;
    }
        case 0: {
      printf("reply\n");
                break;
    }       
        default: {
                break;
    }       
        }
        printf("代码: %d\n", icmp_protocol->code);
        printf("校验和: 0x%.4x\n", ntohs(icmp_protocol->checksum));
        printf("标识: 0x%.4x\n", ntohs(icmp_protocol->identification));
        printf("序列号: 0x%.4x\n", ntohs(icmp_protocol->sequence));
    printf("================================================\n");
}

// 分析arp数据包
void resolve_arp_pkt(u_char *arg, const struct pcap_pkthdr *pkt_header, const u_char *pkt_content)
{
        arp_header *arp_protocol;

        arp_protocol = (arp_header*)(pkt_content + sizeof(ethernet_header));

        printf("                  ARP Protocol                \n");
    printf("================================================\n");
        printf("硬件类型: ");
        switch (ntohs(arp_protocol->hd_type))
        {
        case 1: {
      printf("以太网");
                break;
    }       
        default: {
      break;
    }       
        }
        printf(" (%d)\n", ntohs(arp_protocol->hd_type));
        printf("Protocol Type: \n");
        switch (ntohs(arp_protocol->protocol_type))
        {
        case 0x0800: {
      printf("%s", "IP");
                break;
    }
        case 0x0806: {
      printf("%s", "ARP");
                break;
    }
        case 0x8035: {
      printf("%s", "RARP");
                break;
    }
        default: {
      printf("%s", "Unknown Protocol");
                break;
    }       
        }
        printf(" (0x%04x)\n", ntohs(arp_protocol->protocol_type));
        printf("硬件地址长度: %d\n", arp_protocol->hd_addr_len);
        printf("协议地址长度: %d\n", arp_protocol->protocol_addr_len);
        printf("操作码: ");
        switch (ntohs(arp_protocol->op))
        {
        case 1: {
      printf("arp request");
                break;
    }
        case 2: {
      printf("arp reply");
                break;
    }
    case 3: {
      printf("rarp request");
                break;
    }
    case 4: {
      printf("rarp reply");
                break;
    }
        default: {
      break;
    }       
        }
        printf(" (%i)\n", ntohs(arp_protocol->op));
    printf("================================================\n");
}

// 分析ip数据包
void resolve_ip_pkt(u_char *arg, const struct pcap_pkthdr *pkt_header, const u_char *pkt_content)
{
        ipv4_header *ip_protocol;
        sockaddr_in source, dest;
        char src_ip, dst_ip;
        ip_protocol = (ipv4_header *)(pkt_content + sizeof(ethernet_header));
        source.sin_addr.s_addr = ip_protocol->src_ip;
        dest.sin_addr.s_addr = ip_protocol->dst_ip;
        strncpy(src_ip, inet_ntoa(source.sin_addr), MAX_ADDR_LEN);
        strncpy(dst_ip, inet_ntoa(dest.sin_addr), MAX_ADDR_LEN);
               
        printf("                  IP Protocol               \n");
    printf("================================================\n");

        printf("版本: %d\n",ip_protocol->version_hd_len >> 4);
        printf("首部长度: %d bytes\n", (ip_protocol->version_hd_len & 0x0f) * 4);
        printf("服务类型: %d\n", ip_protocol->tos);
        printf("总长度: %d\n", ntohs(ip_protocol->total_len));
        printf("标识: 0x%.4x (%i)\n", ntohs(ip_protocol->identification));
        printf("标志: %d\n", ntohs(ip_protocol->flags_offset) >> 13);
        printf("保留位: %d\n", (ntohs(ip_protocol->flags_offset) & 0x8000) >> 15);
        printf("不分片: %d\n", (ntohs(ip_protocol->flags_offset) & 0x4000) >> 14);
        printf("有分片: %d\n", (ntohs(ip_protocol->flags_offset) & 0x2000) >> 13);
        printf("片偏移: %d\n", ntohs(ip_protocol->flags_offset) & 0x1fff);
        printf("生存时间: %d\n", ip_protocol->ttl);
        printf("协议类型: ");
        switch (ip_protocol->protocol)
        {
        case 1: {
      printf("ICMP");
                break;
    }
        case 6: {
      printf("TCP");
                break;
    }
        case 17: {
      printf("UDP");
                break;
    }
        default: {
       break;
    }       
        }
        printf(" (%d)\n", ip_protocol->protocol);
        printf("首部校验和: 0x%.4x\n", ntohs(ip_protocol->checksum));
        printf("源ip: %s\n", src_ip);
        printf("目的ip: %s\n", dst_ip);
    printf("================================================\n");
        if (ip_protocol->protocol == IP_PROTOCOL_TCP) {
      resolve_tcp_pkt(arg, pkt_header, pkt_content);
    }       
        else if (ip_protocol->protocol == IP_PROTOCOL_UDP) {
      resolve_udp_pkt(arg, pkt_header, pkt_content);
    }
        else if (ip_protocol->protocol == IP_PROTOCOL_ICMP) {
      resolve_icmp_pkt(arg, pkt_header, pkt_content);
    }       
}

// 分析以太网数据包
void resolve_ethernet_pkt(u_char *arg, const struct pcap_pkthdr *pkt_header, const u_char *pkt_content)
{
        ethernet_header *ethernet_protocol; // 以太网协议
        // 获取以太网数据内容
        ethernet_protocol = (ethernet_header *)pkt_content;
        printf("                Ethernet Protocol               \n");
    printf("================================================\n");
        // 以太网目标地址
        printf("目标Mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
                ethernet_protocol->dst_mac,
                ethernet_protocol->dst_mac,
                ethernet_protocol->dst_mac,
                ethernet_protocol->dst_mac,
                ethernet_protocol->dst_mac,
                ethernet_protocol->dst_mac);
        // 以太网源地址
        printf("源Mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
                ethernet_protocol->src_mac,
                ethernet_protocol->src_mac,
                ethernet_protocol->src_mac,
                ethernet_protocol->src_mac,
                ethernet_protocol->src_mac,
                ethernet_protocol->src_mac);
        printf("类型: (0x%04x) ", ntohs(ethernet_protocol->protocol_type));
        switch (ntohs(ethernet_protocol->protocol_type))
        {
        case 0x0800: {
      printf("IP Protocol\n");
      resolve_ip_pkt(arg, pkt_header, pkt_content);
                break;
    }       
        case 0x0806: {
      printf("ARP Protocol\n");
      resolve_arp_pkt(arg, pkt_header, pkt_content);
                break;
    }       
        case 0x0835: {
      printf("RARP Protocol\n");
                break;
    }
        default: {
      printf("Unknown Protocol\n");
                break;
    }               
        }
    printf("================================================\n");
}

int main(void)
{
    pcap_t *pcap_handle;
    int res;
    struct pcap_pkthdr *header; // 数据包基本信息
    const u_char *pkt_data;
    time_t local_tv_sec;
    struct tm *ltime;
    char timestr;

    int count = 1;
    char err_buf;

        char *pdev_name = NULL;
    pdev_name = pcap_lookupdev(err_buf);
        if (pdev_name == NULL)
        {
                printf("%s\n", err_buf);
                exit(-1);
        }
    // 打开网卡设备
        if ((pcap_handle = pcap_open_live(pdev_name, 65536, 1, 1000, err_buf)) == NULL)
        {
                printf("%s\n", err_buf);
                exit(-1);
        }
    if (pcap_datalink(pcap_handle) != DLT_EN10MB)
    {
      perror("pcap_datalink error:");
      exit(-1);
    }
    while ((res = pcap_next_ex(pcap_handle, &header, &pkt_data)) >= 0)
        {
                // 超时
                if (res == 0)
                        continue;

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

                // 输出编号、时间戳和包长度
                printf("==============================================================================\n");
                printf("No.%d\ttime: %s\tlen: %ld\n", count++, timestr, header->len);
                printf("==============================================================================\n");

                char temp;
                // 输出包
                for (int i = 0; i < header->caplen; ++i)
                {
                        printf("%.2x ", pkt_data);
                        if (isgraph(pkt_data) || pkt_data == ' ') {
                temp = pkt_data;
            }
                        else {
                temp = '.';
            }
                        if (i % MAX_LINE_LEN == 15)
                        {
                                temp = '\0';
                                printf("      ");
                                printf("%s", temp);
                                printf("\n");
                                memset(temp, 0, MAX_LINE_LEN);
                        }
                }
                printf("\n");
      // 分析以太网数据包
                resolve_ethernet_pkt(NULL, header, pkt_data);
        }
    if (res == -1)
        {
                printf("pcap_next_ex error:%s\n", pcap_geterr(pcap_handle));
                pcap_close(pcap_handle);
                exit(-1);
        }
        // 释放
        pcap_close(pcap_handle);

    return 0;
}

额微粒波地 发表于 2020-11-1 01:50

感谢分享,暂时用不上!

swtato 发表于 2020-11-1 02:18

感谢啦,但目前还没用到

167023ab 发表于 2020-11-1 08:39

过不了编译

深水夜藏 发表于 2020-11-1 23:45

感谢分享

linuxcool 发表于 2020-11-2 09:12

你确定这是linux里面的?

angelb 发表于 2020-11-2 11:43

好像不能编译使用吧

古月不傲 发表于 2020-11-2 22:19

本帖最后由 古月不傲 于 2020-11-2 22:37 编辑

angelb 发表于 2020-11-2 11:43
好像不能编译使用吧
centos: yum一下应该就可以了
ubuntu:
    sudo apt-get install libpcap-dev
    编译:第三方库 -lpcap
libnet:
    sudo apt-get install libnet-dev
    编译:第三方库 -lnet
libevent: 自己网上下载
    1)执行 ./configure
    2)sudo make
    3)sudo make install
    编译:第三方库 -lpevent
如果编译出错:error while loading shared libraries: libevent-2.1.so.7: cannot open shared object file: No such file or directory
    sudo ln -s /usr/local/lib/libevent-2.1.so.7/usr/lib/libevent-2.1.so.7 根据自己的系统来
Linux 安装WireShark
1)sudo apt-add-repository ppa:wireshark-dev/stable
2)sudo apt-get update
3)sudo apt-get install wireshark
4)sudo groupadd wireshark
5)sudo chgrp wireshark /usr/bin/dumpcap
6)sudo chmod 4755 /usr/bin/dumpcap
7)sudo gpasswd -a wind wireshark
关于Makefile如何编写
https://wiki.ubuntu.org.cn/%E8%B7%9F%E6%88%91%E4%B8%80%E8%B5%B7%E5%86%99Makefile

angelb 发表于 2020-11-3 09:31

古月不傲 发表于 2020-11-2 22:19
centos: yum一下应该就可以了
ubuntu:
    sudo apt-get install libpcap-dev


我就是centos编译过不去方便的话 把编译好的,发一份出来,谢谢哥

古月不傲 发表于 2020-11-4 10:06

angelb 发表于 2020-11-3 09:31
我就是centos编译过不去方便的话 把编译好的,发一份出来,谢谢哥

链接: https://pan.baidu.com/s/1EljCb0tTk5I5KwPtsqLSKA密码: acn9
root运行 没啥好看的 只是一个简单列子
页: [1]
查看完整版本: Linux 基于pcap解析数据包