吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1477|回复: 9
收起左侧

[其他转载] Linux 基于pcap解析数据包

[复制链接]
古月不傲 发表于 2020-11-1 01:32
本帖最后由 古月不傲 于 2020-11-1 01:59 编辑

[C++] 纯文本查看 复制代码
#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_LEN];   // 目的mac
    unsigned char   src_mac[MAC_LEN];   // 源mac
    unsigned short  protocol_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 short  hd_type;                // 硬件类型
    unsigned short  protocol_type;          // 协议类型
    unsigned char   hd_addr_len;            // 硬件地址长度
    unsigned char   protocol_addr_len;      // 协议地址长度
    unsigned short  op;                     // 操作类型
    unsigned char   src_mac[MAC_LEN];       // 发送端mac
    unsigned char   src_ip[IP_LEN];         // 发送端ip
    unsigned char   dst_mac[MAC_LEN];       // 目的端mac
    unsigned char   dst_ip[IP_LEN];         // 目的端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 short  total_len;          // 总长度
    unsigned short  identification;     // 标识
    unsigned short  flags_offset;       // 标志、片偏移
    unsigned char   ttl;                // 生存时间
    unsigned char   protocol;           // 协议
    unsigned short  checksum;           // 首部校验和
    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 char  hd_len_reserve;  // 首部长度、保留位
    unsigned char  flags;           // 标志
    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 short  checksum;			// 校验和
	unsigned short  identification;		// 标识
	unsigned short  sequence;			// 序列号
	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[MAX_ADDR_LEN], dst_ip[MAX_ADDR_LEN];
	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[0],
		ethernet_protocol->dst_mac[1],
		ethernet_protocol->dst_mac[2],
		ethernet_protocol->dst_mac[3],
		ethernet_protocol->dst_mac[4],
		ethernet_protocol->dst_mac[5]);
	// 以太网源地址
	printf("源Mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
		ethernet_protocol->src_mac[0],
		ethernet_protocol->src_mac[1],
		ethernet_protocol->src_mac[2],
		ethernet_protocol->src_mac[3],
		ethernet_protocol->src_mac[4],
		ethernet_protocol->src_mac[5]);
	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[16];

    int count = 1;
    char err_buf[PCAP_ERRBUF_SIZE];

	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[16 + 1];
		// 输出包
		for (int i = 0; i < header->caplen; ++i)
		{
			printf("%.2x ", pkt_data[i]);
			if (isgraph(pkt_data[i]) || pkt_data[i] == ' ') {
                temp[i % MAX_LINE_LEN] = pkt_data[i];
            }
			else {
                temp[i % MAX_LINE_LEN] = '.';
            }
			if (i % MAX_LINE_LEN == 15)
			{
				temp[MAX_LINE_LEN] = '\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;
}

免费评分

参与人数 2吾爱币 +11 热心值 +2 收起 理由
笙若 + 1 + 1 谢谢@Thanks!
苏紫方璇 + 10 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

额微粒波地 发表于 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
好像不能编译使用吧

[Asm] 纯文本查看 复制代码
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
[mw_shl_code=asm,true]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运行 没啥好看的 只是一个简单列子
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 23:52

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表