用字节数组创建一个RawPacket对象
我正在开发一个Android应用,能够捕获互联网流量以便稍后分析。通过一个VPN隧道,我可以在一个 byte[] 数组中获取数据包。
是否可以仅使用一个字节数组在 PcapPlusPlus 中创建一个 pcpp::RawPacket,并使用 pcpp::PcapNgFileWriterDevice 将其保存到 file.pcap?
在 这个示例 中,他们通过为每一层创建各自的数据来构建PCAP文件,并将它们添加到一个 pcpp::Packet,然后使用 pcpp::PcapFileWriterDevice 保存这个数据包。
但是,就我的情况而言,我只想仅用数据的字节来创建 pcpp::RawPacket。我看到有一个名为 pcpp::RawPacket::setRawData() 的方法,它接收一个指向新原始数据的指针。这个原始数据是一个字节数组吗,还是别的什么?
我尝试了以下代码:
JNIEXPORT jboolean JNICALL
Java_org_my_app_directory_pcapplusplus_PcapPlusPlusInterface_writePcapNative(
JNIEnv *env, jclass clazz, jstring file, jbyteArray data) {
pcpp::RawPacket rawPacket;
// Here (I assume) should be set the whole data of the packet (and the others parameters)
rawPacket.setRawData();
pcpp::Packet parsedPacket(&rawPacket);
parsedPacket.computeCalculateFields();
// create a pcap-ng file writer. Specify file name. Link type is not necessary because
// pcap-ng files can store multiple link types in the same file
pcpp::PcapNgFileWriterDevice pcapNgWriter(jstring2string(env,file));
// try to open the file for writing
if (!pcapNgWriter.open())
{
std::cerr << "Cannot open output.pcap for writing" << std::endl;
return false;
} else {
pcapNgWriter.writePacket(*(parsedPacket.getRawPacket()));
pcapNgWriter.close();
}
return true;
}
正如你在我的函数 writePcapNative 中看到的,有一个参数 jbyteArray data,用来接收来自Java代码的 byte[],但该方法 rawPacket.setRawData() 需要一个指针(const uint8_t* pRawData)。我猜这是指向字节数组的指针,或类似的东西。
我对C++还挺新,因此不太确定是否可以获取字节数组的内存指针,并在调用方法 pcpp::RawPacket::setRawData() 时使用它,因为这个指针是一个 uint8_t。
如果有其他实现方式,请告诉我。
解决方案
如果你阅读 JNI文档,第4 章的 Array Operations 部分解释了如何访问Java byte[] 数组中的原始字节(jbyteArray)。你需要的是真正的 GetByteArrayElements() 和 ReleaseByteArrayElements() 函数,例如:
jsize rawDataLen = env->GetArrayLength(data);
jbyte* rawData = env->GetByteArrayElements(data, NULL);
// use rawData as needed, then...
env->ReleaseByteArrayElements(data, rawData, 0);
然后,在将指针传给 RawPacket 时,可以把 jbyte* 指针强制转换为 uint8_t* 指针。
另外,如果你查看 PcapPlusPlus文档,它解释说 RawPacket 类有一个内部 deleteRawDataAtDestructor 标志,默认是 true,这会导致数据包在不再需要时释放它所分配的 rawData。但在这种情况下你并不希望发生这种情况,因为数据包不会拥有Java字节数组的内存,只是引用它。因此,你需要将该标志设为 false,而我看到的唯一方法是将 rawData 指针传给数据包的构造函数,而不是传给它的 setRawData() 方法,例如:
// jbyteArray data
jsize rawDataLen = env->GetArrayLength(data);
jbyte* rawData = env->GetByteArrayElements(data, NULL);
pcpp::RawPacket rawPacket(reinterpret_cast<uint8_t*>(rawData), static_cast<int>(rawDataLen), timestamp, false);
// use rawPacket as needed, then...
env->ReleaseByteArrayElements(data, rawData, 0);