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;
} 感谢分享,暂时用不上! 感谢啦,但目前还没用到 过不了编译 感谢分享 你确定这是linux里面的? 好像不能编译使用吧 本帖最后由 古月不傲 于 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
古月不傲 发表于 2020-11-2 22:19
centos: yum一下应该就可以了
ubuntu:
sudo apt-get install libpcap-dev
我就是centos编译过不去方便的话 把编译好的,发一份出来,谢谢哥 angelb 发表于 2020-11-3 09:31
我就是centos编译过不去方便的话 把编译好的,发一份出来,谢谢哥
链接: https://pan.baidu.com/s/1EljCb0tTk5I5KwPtsqLSKA密码: acn9
root运行 没啥好看的 只是一个简单列子
页:
[1]