如何使用PcapPlusPlus获取并打印E2AP报文详情?
基于PcapPlusPlus解析并打印E2AP报文详情的实现步骤
1. 确认环境配置
确保你的开发环境已正确安装PcapPlusPlus,编译项目时链接必要的库:Pcap++、Packet++、Common++,同时将PcapPlusPlus的include目录加入头文件搜索路径。
2. 读取或捕获E2AP流量
E2AP基于SCTP传输,通常承载在IPv4/IPv6之上。你可以选择读取本地pcap文件(适合测试)或捕获实时网卡流量,以下是读取pcap文件的基础代码:
#include <PcapFileDevice.h> #include <Packet.h> #include <EthLayer.h> #include <IPv4Layer.h> #include <IPv6Layer.h> #include <SctpLayer.h> using namespace pcpp; int main() { // 打开目标pcap文件 PcapFileReaderDevice reader("e2ap_traffic.pcap"); if (!reader.open()) { printf("无法打开pcap文件\n"); return 1; } RawPacket rawPacket; while (reader.getNextPacket(rawPacket)) { Packet parsedPacket(&rawPacket); // 后续解析逻辑嵌入此处 } reader.close(); return 0; }
3. 逐层解析到SCTP payload
从以太网帧开始,逐层剥离协议层,最终提取承载E2AP的SCTP数据块:
// 在上述while循环内添加以下代码 EthLayer* ethLayer = parsedPacket.getLayerOfType<EthLayer>(); if (!ethLayer) continue; // 解析IP层(兼容IPv4/IPv6) Layer* ipLayer = parsedPacket.getLayerOfType<IPv4Layer>(); if (!ipLayer) { ipLayer = parsedPacket.getLayerOfType<IPv6Layer>(); if (!ipLayer) continue; } // 解析SCTP层 SctpLayer* sctpLayer = parsedPacket.getLayerOfType<SctpLayer>(); if (!sctpLayer) continue; // 遍历SCTP数据块,筛选承载E2AP的DATA块 for (const auto& chunk : sctpLayer->getChunks()) { if (chunk->getChunkType() == SCTP_DATA_CHUNK) { SctpDataChunk* dataChunk = dynamic_cast<SctpDataChunk*>(chunk); if (!dataChunk) continue; // 获取E2AP原始字节流 const uint8_t* e2apPayload = dataChunk->getData(); size_t e2apPayloadLen = dataChunk->getDataLen(); if (e2apPayloadLen == 0) continue; // 调用解析函数处理E2AP报文 parseAndPrintE2AP(e2apPayload, e2apPayloadLen); } }
4. 解析并打印E2AP核心字段
E2AP遵循3GPP TS 38.463协议,核心结构包含PDU类型、Procedure Code、Criticality及各类IE。由于PcapPlusPlus默认未封装E2AP解析器,需手动实现核心字段解析,示例如下:
void parseAndPrintE2AP(const uint8_t* payload, size_t len) { if (len < 6) { printf("E2AP报文过短,无法解析\n"); return; } // 解析PDU类型(第一个字节高4位) uint8_t pduType = (payload[0] >> 4) & 0x0F; const char* pduTypeStr; switch(pduType) { case 0: pduTypeStr = "Initiating Message"; break; case 1: pduTypeStr = "Successful Outcome"; break; case 2: pduTypeStr = "Unsuccessful Outcome"; break; default: pduTypeStr = "Unknown PDU Type"; break; } // 解析Procedure Code(第一个字节低4位 + 第二个字节) uint16_t procedureCode = ((payload[0] & 0x0F) << 8) | payload[1]; // 解析Criticality(第三个字节) uint8_t criticality = payload[2]; // 解析消息长度(第4-6字节,3字节无符号整数) uint32_t msgLength = ((payload[3] << 16) | (payload[4] << 8) | payload[5]); if (msgLength + 6 > len) { printf("E2AP报文长度不匹配,解析终止\n"); return; } // 打印核心基础字段 printf("=== E2AP报文详情 ===\n"); printf("PDU类型: %s\n", pduTypeStr); printf("Procedure Code: %u\n", procedureCode); printf("Criticality: %u\n", criticality); printf("消息长度: %u\n", msgLength); // 解析并打印IEs parseE2APIEs(payload + 6, msgLength); } void parseE2APIEs(const uint8_t* iesPayload, size_t iesLen) { size_t offset = 0; printf("--- E2AP IEs 详情 ---\n"); while (offset < iesLen) { if (offset + 4 > iesLen) break; // 解析IE类型(前2字节) uint16_t ieType = ((iesPayload[offset] << 8) | iesPayload[offset+1]); // 解析IE长度(后2字节) uint16_t ieLen = ((iesPayload[offset+2] << 8) | iesPayload[offset+3]); offset += 4; if (offset + ieLen > iesLen) break; printf("IE类型: %u, IE长度: %u\n", ieType, ieLen); // 根据IE类型解析具体内容(示例:RIC Request ID) switch(ieType) { case 0: if (ieLen >= 8) { uint32_t ricReqId = ((iesPayload[offset] << 24) | (iesPayload[offset+1] << 16) | (iesPayload[offset+2] << 8) | iesPayload[offset+3]); uint32_t ricInstanceId = ((iesPayload[offset+4] << 24) | (iesPayload[offset+5] << 16) | (iesPayload[offset+6] << 8) | iesPayload[offset+7]); printf(" RIC Request ID: %u, RIC Instance ID: %u\n", ricReqId, ricInstanceId); } break; // 可根据3GPP规范添加更多IE类型的解析逻辑 default: printf(" 未实现该IE类型的解析\n"); break; } offset += ieLen; } }
5. 关键注意事项
- SCTP数据块可能存在分段,需实现SCTP重组逻辑才能获取完整的E2AP报文;
- E2AP的IE解析需严格遵循3GPP TS 38.463规范,不同Procedure Code对应的IE集合存在差异;
- 若需要更完整的解析能力,可使用ASN.1编译器(如asn1c)根据3GPP提供的E2AP ASN.1定义生成解析代码,再与PcapPlusPlus的代码集成。
内容的提问来源于stack exchange,提问作者VIkrant Singh
相关产品推荐
相关产品推荐

