如何用C手动向pcap文件添加特定数据,兼容格式并标识InfiniBand接口?
可以在合规前提下用C语言实现需求
要让pyshark识别数据包所属的InfiniBand接口,你需要使用pcapng格式(而非传统pcap旧格式)写入文件——传统pcap格式不支持存储接口元数据,而pcapng是为扩展元数据设计的标准格式,完全符合规范。
核心实现思路
pcapng通过三类关键块关联数据包与接口:
- Section Header Block (SHB):文件起始块,定义pcapng版本、字节序等基础信息。
- Interface Description Block (IDB):为每个接口创建一个块,存储接口名称(如
ib0)、链路类型(InfiniBand对应链路类型值为141,即DLT_INFINIBAND)等元数据,每个IDB分配唯一的interface_id(从0开始递增)。 - Enhanced Packet Block (EPB):每个数据包用EPB封装,其中
interface_id字段对应IDB的序号,以此关联数据包到具体接口。
C语言手动写入核心代码片段
注意:pcapng所有多字节字段均采用大端字节序:
#include <stdio.h> #include <stdint.h> #include <string.h> #include <arpa/inet.h> // pcapng块通用头部 typedef struct { uint32_t block_type; uint32_t block_total_length; } pcapng_block_hdr; // 写入Section Header Block void write_shb(FILE *fp) { pcapng_block_hdr hdr = { .block_type = htonl(0x0A0D0D0A), // SHB魔法值 .block_total_length = htonl(28) }; uint32_t ver_major = htonl(1); uint32_t ver_minor = htonl(0); uint64_t sec_len = htonll(0); // 0表示未知长度 uint32_t end_len = htonl(28); fwrite(&hdr, sizeof(hdr), 1, fp); fwrite(&ver_major, sizeof(ver_major), 1, fp); fwrite(&ver_minor, sizeof(ver_minor), 1, fp); fwrite(&sec_len, sizeof(sec_len), 1, fp); fwrite(&end_len, sizeof(end_len), 1, fp); } // 写入InfiniBand接口的IDB void write_idb(FILE *fp, const char *if_name) { uint32_t block_type = htonl(0x00000001); // IDB类型标识 uint16_t link_type = htons(141); // DLT_INFINIBAND uint32_t snap_len = htonl(65535); size_t opt_len = 4 + strlen(if_name) + 1; // 选项头+接口名字符串+终止符 uint32_t block_len = htonl(8 + 8 + opt_len + 4); uint32_t end_len = block_len; // 写块头部 fwrite(&block_type, sizeof(block_type), 1, fp); fwrite(&block_len, sizeof(block_len), 1, fp); // 写IDB固定字段 fwrite(&link_type, sizeof(link_type), 1, fp); fwrite("\x00\x00", 2, 1, fp); // 保留字段 fwrite(&snap_len, sizeof(snap_len), 1, fp); // 写接口名选项(选项代码2:IF_NAME) uint16_t opt_code = htons(2); uint16_t opt_len_field = htons(strlen(if_name) + 1); fwrite(&opt_code, sizeof(opt_code), 1, fp); fwrite(&opt_len_field, sizeof(opt_len_field), 1, fp); fwrite(if_name, strlen(if_name) + 1, 1, fp); // 写块尾部 fwrite(&end_len, sizeof(end_len), 1, fp); } // 写入关联接口的EPB void write_epb(FILE *fp, uint8_t *pkt_data, size_t pkt_len) { uint32_t block_type = htonl(0x00000006); // EPB类型标识 uint32_t if_id = htonl(0); // 关联第一个IDB(序号0) uint32_t ts_high = htonl(0); // 可替换为实际捕获时间高位 uint32_t ts_low = htonl(0); // 可替换为实际捕获时间低位 uint32_t cap_len = htonl(pkt_len); uint32_t orig_len = htonl(pkt_len); uint32_t block_len = htonl(8 + 20 + pkt_len + 4); uint32_t end_len = block_len; fwrite(&block_type, sizeof(block_type), 1, fp); fwrite(&block_len, sizeof(block_len), 1, fp); fwrite(&if_id, sizeof(if_id), 1, fp); fwrite(&ts_high, sizeof(ts_high), 1, fp); fwrite(&ts_low, sizeof(ts_low), 1, fp); fwrite(&cap_len, sizeof(cap_len), 1, fp); fwrite(&orig_len, sizeof(orig_len), 1, fp); fwrite(pkt_data, pkt_len, 1, fp); fwrite(&end_len, sizeof(end_len), 1, fp); } int main() { FILE *fp = fopen("ib_capture.pcapng", "wb"); if (!fp) return 1; write_shb(fp); write_idb(fp, "ib0"); // 指定InfiniBand接口名 // 示例:写入模拟的InfiniBand数据包 uint8_t dummy_pkt[] = {0x00, 0x01, 0x02, 0x03, 0x04}; write_epb(fp, dummy_pkt, sizeof(dummy_pkt)); fclose(fp); return 0; }
pyshark解析验证
打开生成的pcapng文件后,可直接获取接口信息:
import pyshark cap = pyshark.FileCapture('ib_capture.pcapng') for pkt in cap: print(f"数据包来自接口: {pkt.interface.name}")
注意事项
- 必须严格遵循pcapng规范(字节序、块长度计算、选项格式),否则解析工具可能无法识别。
- 传统pcap格式无法存储接口元数据,若需兼容旧工具,只能通过文件名或外部文档标注接口,但pyshark无法自动读取这类信息。
内容的提问来源于stack exchange,提问作者Yaakov Goldsmith
相关产品推荐
相关产品推荐

