最近看了一下网络的书,信息系统也有实验任务,所以就学习了一下pcap包的解析。

主要是对内部以太网帧头,ip头部,tcp头部或者udp头部的解析。我因为用访问google.cn作为的样例,没有udp包就还没加udp的头部,不过大同小异了。

要注意的就是以太网是大端传输,而上层的协议都是小端传输,所以要转换字节序,可以使用ntohs() 和 ntohl() 两个函数,windows环境的话需要#include <WinSock2.h>和Ws2_32.lib库文件。

我这里使用了二维链表,只记录的每条链表的头部,每次插入时维护tcp序列号递增的顺序。

参考

pcap文件格式解析

ip头和tcp头结构

udp头部

我贴一下自己的代码

//pcap.h
#include <cstdint>
#include <list>
#include <map>
#include <algorithm>
#define max_len 200005
#define len_ip_hdr 20
#define len_tcp_hdr 20
#define len_ether_hdr 14
#define len_pkt_hdr 16
#define len_file_hdr 24
#define len_udp_hdr 8
#define num_proto_tcp 0x06
#define num_proto_udp 0x11 //pcap文件报头
struct pcap_file_hdr{
//char v[24];
uint32_t magic; //标识位 32bit
uint16_t version_major; //主版本号 16bits
uint16_t version_minor; //副版本号 16bits
uint32_t thiszone; //区域时间 32bits
uint32_t sigfigs; //时间戳 32bits
uint32_t snaplen; //数据包最大长度 32bits(所抓获的数据包的最大长度)
uint32_t linktype; //链路层类型 32bits*/
}; //数据报报头
struct pcap_pkt_hdr{
uint32_t ts_sec; //时间戳秒
uint32_t ts_usec; //时间戳微秒
uint32_t caplen; //数据包长度 32bits
uint32_t len; //实际长度 数据不完整时小于前值 32bits
}; //以太网帧头
#define ether_addr_len 6
struct ether_hdr{
uint8_t ether_dst[ether_addr_len];
uint8_t ether_src[ether_addr_len];
uint16_t ether_type;
}; //IP报头
struct ip_hdr{
uint8_t ip_hdr_len : 4; // The header length.
uint8_t ip_version : 4; //The IP version.
uint8_t ip_tos; //Type of Service.
uint16_t ip_len; //IP packet length(both data and header).
uint16_t ip_id; //Identification.
uint16_t ip_off; //Fragment offset. //前3位标志,后13位片偏移
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
uint8_t ip_ttl; //Time To Live.
uint8_t ip_proto; //The type of the upper - level protocol.
uint16_t ip_chk; // IP header checksum.
uint32_t ip_src; //IP source address(in network format).
uint32_t ip_dst; //IP destination address(in network format).
}; //TCP报头
typedef uint32_t tcp_seq;
struct tcp_hdr{
uint16_t th_port_src;
uint16_t th_port_dst;
tcp_seq th_seq; /* sequence number */
tcp_seq th_ack; /* acknowledgement number */
uint8_t th_offx2; /* data offset, rsvd */
#define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4)
uint8_t th_flags;
#define TH_FIN 0x01
#define TH_SYN 0x02
#define TH_RST 0x04
#define TH_PUSH 0x08
#define TH_ACK 0x10
#define TH_URG 0x20
#define TH_ECE 0x40
#define TH_CWR 0x80
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
uint16_t th_win; /* window */
uint16_t th_chk; /* checksum */
uint16_t th_urp; /* urgent pointer */
}; struct udp_hdr{
uint16_t uh_port_src; /* source port */
uint16_t uh_port_dst; /* destination port */
uint16_t uh_ulen; /* datagram length */
uint16_t uh_chk; /* datagram checksum */
}; struct unit{
uint32_t addr1, addr2;
uint16_t port1, port2;
uint8_t proto;
bool operator <(const unit &rhs)const {
if (proto != rhs.proto) return proto < rhs.proto;
if (addr1 != rhs.addr1) return addr1 < rhs.addr1;
if (addr2 != rhs.addr2) return addr2 < rhs.addr2;
if (port1 != rhs.port1) return port1 < rhs.port1;
if (port2 != rhs.port2) return port2 < rhs.port2;
return false;
}
}; struct node{
unit *conn;
pcap_pkt_hdr *pkt;
ether_hdr *ether;
ip_hdr *ip;
uint8_t *ip_opts;
tcp_hdr *tcp;
uint8_t *tcp_opts;
udp_hdr* udp;
uint8_t *load;
uint32_t len_load; node(unit *conn = NULL, pcap_pkt_hdr *pkt = NULL, ether_hdr *ether = NULL, ip_hdr *ip = NULL,
uint8_t *ip_opts = NULL, tcp_hdr *tcp = NULL, uint8_t *tcp_opts = NULL, udp_hdr *udp = NULL, uint8_t *load = NULL,
uint32_t len_load = 0) :conn(conn), pkt(pkt), ether(ether), ip(ip), ip_opts(ip_opts),
tcp(tcp), tcp_opts(tcp_opts), udp(udp), load(load), len_load(len_load){
if (conn->addr1 > conn->addr2){
std::swap(conn->addr1, conn->addr2);
std::swap(conn->port1, conn->port2);
if (tcp != NULL){
std::swap(tcp->th_seq, tcp->th_ack);
}
}
}; bool operator>=(const node &rhs)const{
if (tcp == NULL) return true;
return tcp->th_seq > rhs.tcp->th_seq || (tcp->th_seq == rhs.tcp->th_seq && tcp->th_ack >= rhs.tcp->th_ack);
}
}; typedef std::list<node> List; class Pcap{
private:
char *dirDst;
CFile *fileSrc;
pcap_file_hdr file_hdr;
std::list<List*> result;
std::map<unit, List*> index; public:
void Analyse();
void Modify(ip_hdr *ip);
void Modify(tcp_hdr *tcp);
void Modify(udp_hdr *udp);
void PrintInfo();
void PrintPcap();
void PrintLoad();
void TransferIP(uint32_t addr, char *dst); char * DirDst() const { return dirDst; }
void DirDst(char * val) { dirDst = val; } CFile * FileSrc() const { return fileSrc; }
void FileSrc(CFile * val) { fileSrc = val; }
};
#include "stdafx.h"
#include "Pcap.h" void Pcap::Analyse(){
index.clear();
uint32_t len_load = 0; //负载数据长度
//fread(&file_hdr, len_file_hdr, 1, fileSrc);
fileSrc->Read(&file_hdr, len_file_hdr);
while (true){
pcap_pkt_hdr *pkt = new pcap_pkt_hdr();
if (fileSrc->Read(pkt, len_pkt_hdr) == 0){
break;
} ether_hdr *ether = new ether_hdr();
//fread(ether, len_ether_hdr, 1, fileSrc);
fileSrc->Read(ether, len_ether_hdr); ip_hdr *ip = new ip_hdr();
//fread(ip, len_ip_hdr, 1, fileSrc);
fileSrc->Read(ip, len_ip_hdr);
Modify(ip);
//读ip选项
uint8_t *ip_opts = NULL;
if ((ip->ip_hdr_len << 2) - len_ip_hdr != 0){
ip_opts = (uint8_t*)malloc((ip->ip_len << 2) - len_ip_hdr);
//fread(ip_opts, (ip->ip_hdr_len << 2) - len_ip_hdr, 1, fileSrc);
fileSrc->Read(ip_opts, (ip->ip_hdr_len << 2) - len_ip_hdr);
}
uint8_t *load = NULL, *tcp_opts = NULL;
tcp_hdr *tcp = NULL;
udp_hdr *udp = NULL;
if (ip->ip_proto == num_proto_tcp){
tcp = new tcp_hdr();
//TCP包
//fread(tcp, len_tcp_hdr, 1, fileSrc);
fileSrc->Read(tcp, len_tcp_hdr);
Modify(tcp); //选项长度备用
uint8_t opts = 4 * TH_OFF(tcp); if (opts - len_tcp_hdr != 0){
tcp_opts = (uint8_t*)malloc(opts - len_tcp_hdr);
//fread(tcp_opts, opts - len_tcp_hdr, 1, fileSrc);
fileSrc->Read(tcp_opts, opts - len_tcp_hdr);
}
len_load = ip->ip_len - len_ip_hdr - opts;
load = (uint8_t*)malloc(len_load);
//fread(load, len_load, 1, fileSrc);
fileSrc->Read(load, len_load);
}
else if (ip->ip_proto == num_proto_udp){
//UDP包
udp = new udp_hdr();
//fread(udp, len_udp_hdr, 1, fileSrc);
fileSrc->Read(udp, len_udp_hdr);
Modify(udp); len_load = ip->ip_len - len_ip_hdr - len_udp_hdr;
load = (uint8_t*)malloc(len_load);
//fread(load, len_load, 1, fileSrc);
fileSrc->Read(load, len_load);
}
else{
//其他协议包。跳过
//fseek(fileSrc, ip->ip_len - len_ip_hdr, SEEK_CUR);
fileSrc->Seek(ip->ip_len - len_ip_hdr, CFile::current);
continue;
} //五元组信息
unit *conn = new unit();
conn->proto = ip->ip_proto;
conn->addr1 = ip->ip_src;
conn->addr2 = ip->ip_dst;
if (ip->ip_proto == num_proto_udp){
conn->port1 = udp->uh_port_src;
conn->port2 = udp->uh_port_dst;
}
else{
conn->port1 = tcp->th_port_src;
conn->port2 = tcp->th_port_dst;
} //包信息
node temp = node(conn, pkt, ether, ip, ip_opts, tcp, tcp_opts, udp, load, len_load); //五元组链表索引
List *val = index[*conn];
if (val == NULL){
val = new List();
index[*conn] = val;
val->push_back(temp);
result.push_back(val);
}
else{
//顺序插入
auto it = val->end();
--it;
if (temp >= *it){
val->push_back(temp);
}
else{
for (; it != val->begin(); --it){
if (temp >= *it){
++it;
val->insert(it, temp);
break;
}
}
}
}
}
} void Pcap::Modify(ip_hdr *ip)
{
ip->ip_len = ntohs(ip->ip_len);
ip->ip_off = ntohs(ip->ip_off);
ip->ip_chk = ntohs(ip->ip_chk);
ip->ip_src = ntohl(ip->ip_src);
ip->ip_dst = ntohl(ip->ip_dst);
} void Pcap::Modify(udp_hdr *udp)
{
udp->uh_port_src = ntohs(udp->uh_port_src);
udp->uh_port_dst = ntohs(udp->uh_port_dst);
udp->uh_ulen = ntohs(udp->uh_ulen);
udp->uh_chk = ntohs(udp->uh_chk);
} void Pcap::Modify(tcp_hdr *tcp)
{
tcp->th_port_src = ntohs(tcp->th_port_src);
tcp->th_port_dst = ntohs(tcp->th_port_dst);
tcp->th_seq = ntohl(tcp->th_seq);
tcp->th_ack = ntohl(tcp->th_ack);
tcp->th_win = ntohs(tcp->th_win);
tcp->th_chk = ntohs(tcp->th_chk);
tcp->th_urp = ntohl(tcp->th_urp);
} //输出控制信息
void Pcap::PrintInfo()
{
char path[MAX_PATH];
strcpy(path, dirDst);
strcpy(path + strlen(path), "\\");
//CreateDirectory((LPCWSTR)path, NULL);
for (auto it = result.begin(); it != result.end(); ++it){
List *cur = *it;
unit *conn = (cur->begin())->conn;
char addr1[MAX_PATH], addr2[MAX_PATH];
memset(addr1, 0, sizeof(addr1));
memset(addr2, 0, sizeof(addr2));
TransferIP(conn->addr1, addr1);
TransferIP(conn->addr2, addr2);
char title[MAX_PATH];
strcpy(title, path);
if (conn->proto == num_proto_udp){
sprintf(title + strlen(title), "UDP");
}
else{
sprintf(title + strlen(title), "TCP");
}
sprintf(title + strlen(title), "[%s][%d][%s][%d].txt", addr1, conn->port1, addr2, conn->port2);
FILE *fp = fopen(title, "w");
fprintf(fp, "Src IP: %s\n", addr1);
fprintf(fp, "Src Port: %d\n", conn->port1);
fprintf(fp, "Dst IP: %s\n", addr2);
fprintf(fp, "Dst Port: %d\n", conn->port2);
fprintf(fp, "Protocal: %d", conn->proto);
for (auto it2 = cur->begin(); it2 != cur->end(); ++it2){
fprintf(fp, "%c%c%c%c", 0x0a0d, 0x0a0d, 0x0a0d, 0x0a0d);
fprintf(fp, "{\n");
if (conn->proto == num_proto_tcp){
fprintf(fp, " seq number: %lld\n", (__int64)it2->tcp->th_seq);
fprintf(fp, " ack number: %lld\n", (__int64)it2->tcp->th_ack);
fprintf(fp, " window size: %lld\n", (__int64)it2->tcp->th_win);
}
else{
fprintf(fp, " udp length: %d\n", (int)it2->udp->uh_ulen);
fprintf(fp, " check sum: %d\n", (int)it2->udp->uh_chk);
}
fprintf(fp, "}");
}
fclose(fp);
}
} //输出Pcap包
void Pcap::PrintPcap()
{
char path[MAX_PATH];
strcpy(path, dirDst);
strcpy(path + strlen(path), "\\");
//CreateDirectory((LPCWSTR)path, NULL);
for (auto it = result.begin(); it != result.end(); ++it){
List *cur = *it;
unit *conn = (cur->begin())->conn;
char addr1[MAX_PATH], addr2[MAX_PATH];
memset(addr1, 0, sizeof(addr1));
memset(addr2, 0, sizeof(addr2));
TransferIP(conn->addr1, addr1);
TransferIP(conn->addr2, addr2);
char title[MAX_PATH];
strcpy(title, path);
if (conn->proto == num_proto_udp){
sprintf(title + strlen(title), "UDP");
}
else{
sprintf(title + strlen(title), "TCP");
}
sprintf(title + strlen(title), "[%s][%d][%s][%d].pcap", addr1, conn->port1, addr2, conn->port2);
FILE *fp = fopen(title, "wb");
fwrite(&file_hdr, len_file_hdr, 1, fp);
for (auto it2 = cur->begin(); it2 != cur->end(); ++it2){
fwrite(it2->pkt, len_pkt_hdr, 1, fp);
fwrite(it2->ether, len_ether_hdr, 1, fp); Modify(it2->ip);
fwrite(it2->ip, len_ip_hdr, 1, fp);
int x = (it2->ip->ip_hdr_len << 2) - len_ip_hdr;
fwrite(it2->ip_opts, x, 1, fp); if (it2->ip->ip_proto == num_proto_tcp){
Modify(it2->tcp);
fwrite(it2->tcp, len_tcp_hdr, 1, fp);
x = (TH_OFF(it2->tcp) << 2) - len_tcp_hdr;
fwrite(it2->tcp_opts, x, 1, fp);
Modify(it2->tcp);
}
else{
Modify(it2->udp);
fwrite(it2->udp, len_udp_hdr, 1, fp);
Modify(it2->udp);
}
Modify(it2->ip); fwrite(it2->load, it2->len_load, 1, fp); }
fclose(fp);
}
} //输出负载数据
void Pcap::PrintLoad()
{
char path[MAX_PATH];
strcpy(path, dirDst);
strcpy(path + strlen(path), "\\");
//CreateDirectory((LPCWSTR)path, NULL);
for (auto it = result.begin(); it != result.end(); ++it){
List *cur = *it;
unit *conn = (cur->begin())->conn;
char addr1[MAX_PATH], addr2[MAX_PATH];
memset(addr1, 0, sizeof(addr1));
memset(addr2, 0, sizeof(addr2));
TransferIP(conn->addr1, addr1);
TransferIP(conn->addr2, addr2);
char title[MAX_PATH];
strcpy(title, path);
if (conn->proto == num_proto_udp){
sprintf(title + strlen(title), "UDP");
//continue;
}
else{
sprintf(title + strlen(title), "TCP");
}
sprintf(title + strlen(title), "[%s][%d][%s][%d]-.txt", addr1, conn->port1, addr2, conn->port2);
FILE *fp = fopen(title, "w");
uint32_t last_seq = 0, last_len = 0;
bool is_first = true;
for (auto it2 = cur->begin(); it2 != cur->end(); ++it2){
if (conn->proto == num_proto_tcp){
if (!is_first && last_seq + last_len != it2->tcp->th_seq){
fprintf(fp, "%c%c%c%c", 0x0a0d, 0x0a0d, 0x0a0d, 0x0a0d);
}
int x = strlen((char*)(it2->load));
//fprintf(fp, "%s", it2->load);
if (it2->len_load != 0){
fwrite(it2->load, it2->len_load, 1, fp);
is_first = false;
}
last_seq = it2->tcp->th_seq;
last_len = it2->len_load;
}
else{
if (it2->len_load != 0){
fwrite(it2->load, it2->len_load, 1, fp);
fprintf(fp, "%c%c%c%c", 0x0a0d, 0x0a0d, 0x0a0d, 0x0a0d);
}
}
}
fclose(fp);
}
} void Pcap::TransferIP(uint32_t addr, char *dst)
{
uint16_t a = addr >> 24;
uint16_t b = (addr & 0x00ff0000) >> 16;
uint16_t c = (addr & 0x0000ff00) >> 8;
uint16_t d = (addr & 0x000000ff);
sprintf(dst, "%d.%d.%d.%d", a, b, c, d);
}

Pcap 数据报解析的更多相关文章

  1. IP流量重放与pcap文件格式解析

    (作者:燕云   出处:http://www.cnblogs.com/SwordTao/ 欢迎转载,但也请保留这段声明,谢谢!)   君不见 黄河之水 天上来 奔流到海不复回   君不见 高堂明镜 悲 ...

  2. pcap文件格式解析

    pcap文件格式是常用的数据报存储格式,包括wireshark在内的主流抓包软件都可以生成这种格式的数据包 下面对这种格式的文件简单分析一下:    pcap文件的格式为:  文件头    24字节  ...

  3. lua wireshark 数据报解析

    http://www.360doc.com/content/13/1226/15/15257968_340284574.shtml http://www.360doc.com/userhome.asp ...

  4. pcap文件格式及文件解析

    第一部分:PCAP包文件格式 一 基本格式: 文件头 数据包头数据报数据包头数据报...... 二.文件头: 文件头结构体 sturct pcap_file_header {      DWORD   ...

  5. Velodyne线性激光雷达pcap文件格式及写入、数据解析 Lebal:激光雷达

    转载自https://blog.csdn.net/qq_25241325/article/details/80766305 roslaunch loam_velodyne loam_velodyne. ...

  6. Linux网络编程六、报文解析(1)

    一.pcap文件解析 依赖的库:libpcap,头文件:pcap/pcap.h 获取pcap文件:tcpdump,-i:指定监听接口,默认配置好的最小的号码的接口.-w:指定存入文件,将原始报文存入指 ...

  7. libpcap文件格式分析

    第一部分:PCAP包文件格式 一 基本格式: 文件头 数据包头数据报数据包头数据报...... 二.文件头: 文件头结构体  sturct pcap_file_header  {       DWOR ...

  8. dns安全 涉及 术语

    僵木蠕 以“僵木蠕”(僵尸网络.木马.蠕虫)为代表的网络威胁 僵尸网络是攻击者出于恶意目的,传播僵尸程序bot以控制大量计算机,并通过一对多的命令与控制信道所组成的网络,我们将之称之为僵尸网络,bot ...

  9. Python自动化测试常用库

    基本库: sys 程序和Python解析器的交互 os 启动新进程:操作文件和目录 re 正则表达式,字符串匹配 string 基本字符串操作 inspect 提供自省和反射功能 importlib ...

随机推荐

  1. zeromq-4.1.2在windows下的编译

    作者:朱金灿 来源:http://blog.csdn.net/clever101 zeromq是一个最近比较火的跨平台消息中间件,最近准备研究它,故下载它的源码编译了一下.我是使用VS2008编译的, ...

  2. JDBC的总结

    JDBC归纳: DriverManger:驱动管理器类 要操作数据库,必须先与数据库创建连接,得到连接对象 public static Connection getConnection(String ...

  3. learn cmake

    cmake简介 在cmake出现之前,在linuxiax下,大型软件系统一般使用make来控制编译过程,而在Windows下可能是用vs下一个project来构建.一个复杂的系统本身依赖关系就很麻烦, ...

  4. CF992E Nastya and King-Shamans_线段树

    Code: #include<cstdio> #include<algorithm> using namespace std; const int maxn = 200000 ...

  5. 百度api使用说明

    .初始化地图,并设置地图中心点 复制代码 https://www.cnblogs.com/zqzjs/p/5293698.html var map = new BMap.Map("allma ...

  6. 百度图标echarts.js的使用

    echarts官网:http://echarts.baidu.com/api.html#echarts echarts是百度公司开的一种开源制作图片工具,是一个专门制作图表的开源工具,功能非常强大,地 ...

  7. Flex tree展开节点问题!

    问题: 使用 for each(var item:XML in menuTree.dataProvider) {     menuTree.expandChildrenOf(item,true);   ...

  8. POJ 2187 Beauty Contest( 凸包求最远点对 )

    链接:传送门 题意:给出 n 个点,求出这 n 个点中最远的两个点距离的平方 思路:最远点对一定会在凸包的顶点上,然后直接暴力找一下凸包顶点中距离最远的两个点 /******************* ...

  9. freeswitch 一些坑

    1.You must install libopus-dev to build mod_opus. Stop. 确实已经安装libopus-dev后 将文件 usr/local/src/mod/cod ...

  10. ansible 工作原理以及使用详解

    内容:1.ansible的作用以及工作结构2.ansible的安装以及使用3.ansible的playbook使用 一.ansible的作用以及工作结构        1.ansible简介:     ...