Pcap 数据报解析
最近看了一下网络的书,信息系统也有实验任务,所以就学习了一下pcap包的解析。
主要是对内部以太网帧头,ip头部,tcp头部或者udp头部的解析。我因为用访问google.cn作为的样例,没有udp包就还没加udp的头部,不过大同小异了。
要注意的就是以太网是大端传输,而上层的协议都是小端传输,所以要转换字节序,可以使用ntohs() 和 ntohl() 两个函数,windows环境的话需要#include <WinSock2.h>和Ws2_32.lib库文件。
我这里使用了二维链表,只记录的每条链表的头部,每次插入时维护tcp序列号递增的顺序。
参考
我贴一下自己的代码
//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);
}