Writing to a dump file
I want to write some UDP packets to a file, I do not want to hook into any network interfaces or stdin. I've tried a number of different variations of the below logic and I'm stopped at every turn; is this even possible?
try {
Path pcapPath = Paths.get(String.format("rtp_%s.pcap", stream.getId()));
Files.deleteIfExists(pcapPath);
String pcapPathStr = pcapPath.toString();
PcapHandle pcapHandle = new PcapHandle.Builder("dumper").build();
pcapDumper = pcapHandle.dumpOpen(pcapPathStr);
} catch (Exception e) {
log.warn("Exception on pcap open", e);
}
Error for above:
Exception on pcap open
org.pcap4j.core.PcapNativeException: socket: Operation not permitted
at org.pcap4j.core.PcapHandle.<init>(PcapHandle.java:163)
at org.pcap4j.core.PcapHandle.<init>(PcapHandle.java:44)
at org.pcap4j.core.PcapHandle$Builder.build(PcapHandle.java:1412)
I also tried with Pcaps.openOffline(pcapPathStr) but since its a new empty file, it fails...
Were you ever able to figure this out?
I seem to have accomplished this with the following:
try {
PcapHandle handle = Pcaps.openDead(DataLinkType.RAW, 65535);
PcapDumper dumper = handle.dumpOpen("test.pcap");
payloads.forEach(payload -> {
try {
IpV4Packet p = IpV4Packet.newPacket(payload, 0, payload.length);
dumper.dump(p);
} catch(IllegalRawDataException e) {
logger.error("IllegalRawDataException");
e.printStackTrace();
} catch(NotOpenException e) {
logger.error("IllegalRawDataException");
e.printStackTrace();
}
});
dumper.close();
} catch(PcapNativeException e) {
logger.error("PcapNativeException");
e.printStackTrace();
}
Obviously exception handling is weak ... just a prototype.
I'm back on this, so I'll let you know how I fare.
@rjo I gave that a shot with 1.8.2 and this was logged
2022-10-06 14:10:37,558 WARN o.p.packet.factory.PacketFactories - No PacketFactoryBinder is available. All packets will be captured as UnknownPacket.
2022-10-06 14:10:37,559 ERROR mypackage.MyClass - PcapException
java.lang.IllegalArgumentException: targetClass: interface org.pcap4j.packet.IpV4Packet$IpV4Tos numberClass: class org.pcap4j.packet.namednumber.NotApplicable
at org.pcap4j.packet.factory.SimplePacketFactoryBinder.getPacketFactory(SimplePacketFactoryBinder.java:35)
at org.pcap4j.packet.factory.PacketFactories.getFactory(PacketFactories.java:79)
at org.pcap4j.packet.IpV4Packet$IpV4Header.<init>(IpV4Packet.java:464)
at org.pcap4j.packet.IpV4Packet$IpV4Header.<init>(IpV4Packet.java:378)
at org.pcap4j.packet.IpV4Packet.<init>(IpV4Packet.java:61)
at org.pcap4j.packet.IpV4Packet.newPacket(IpV4Packet.java:57)
That looks like its coming from someplace deeper in your code that the dump part
@rjo does the snaplen in PcapHandle handle = Pcaps.openDead(DataLinkType.RAW, 1500); have to be the exact length sent in the IpV4Packet.newPacket call? If yes, I'll have to pad it, since my data arrays are variable "up-to" 1500 max.
I dont think it does as that would not accomodate variable length packets. The snap length is about capturing anyway. I don't think it would have an impact on what you're doing and I would just set it to 65535.
Ok, I'll set that back to 65535; I read through some of the unit tests and came up with for my write section; the issue is that the pcap doesn't show the proper sizes for the packets when I view them in wireshark; this is my write section:
UnknownPacket.Builder rtpPktBuilder = new UnknownPacket.Builder();
rtpPktBuilder.rawData(p.data);
UdpPacket.Builder uPktBuilder = new UdpPacket.Builder();
uPktBuilder.srcAddr(srcAddr).srcPort(srcPort).dstAddr(dstAddr).dstPort(dstPort)
.payloadBuilder(rtpPktBuilder).correctChecksumAtBuild(true).correctLengthAtBuild(true);
IpV6Packet.Builder IpV6PktBuilder = new IpV6Packet.Builder();
IpV6PktBuilder.version(IpVersion.IPV6).trafficClass(IpV6SimpleTrafficClass.newInstance((byte) 0x12))
.flowLabel(IpV6SimpleFlowLabel.newInstance(0x12345)).nextHeader(IpNumber.UDP).hopLimit((byte) 100)
.srcAddr(srcAddr).dstAddr(dstAddr).payloadBuilder(uPktBuilder).correctLengthAtBuild(true);
EthernetPacket.Builder ethPktBuilder = new EthernetPacket.Builder();
ethPktBuilder.dstAddr(MacAddress.getByName("fe:00:00:00:00:02"))
.srcAddr(MacAddress.getByName("fe:00:00:00:00:01")).type(EtherType.IPV6)
.payloadBuilder(IpV6PktBuilder).paddingAtBuild(true);
EthernetPacket ethPkt = ethPktBuilder.build();
pcapWriter.dump(ethPkt, Instant.now());
It'd be awesome if there was an RtpPacket class impl instead of having use use Unknown...
I've now got data that wireshark seems to mostly understand, but my data can't be decoded as RTP, so I'm stuck. Anyone know what might wrong by looking at this image? Here's updated writer code which writes each new video rtp data byte array:
//init section
try {
handle = Pcaps.openDead(DataLinkType.EN10MB, 65535);
pcapWriter = handle.dumpOpen(String.format("%s/%s.pcap", currentPath.toAbsolutePath().toString(), name));
srcAddr = (Inet4Address) InetAddress.getByName("192.168.0.1");
dstAddr = (Inet4Address) InetAddress.getByName("192.168.0.2");
srcPort = UdpPort.getInstance((short) 49152);
dstPort = UdpPort.getInstance((short) 49153);
} catch (Exception e) {
log.error("PcapException", e);
}
//write section
try {
UnknownPacket rtpPkt = UnknownPacket.newPacket(p.data, 0, p.data.length);
log.debug("Writing {} rtp bytes pt: {} {}", p.length, p.payloadType, rtpPkt);
UdpPacket.Builder uPktBuilder = new UdpPacket.Builder();
uPktBuilder.srcAddr(srcAddr).srcPort(srcPort).dstAddr(dstAddr).dstPort(dstPort)
.payloadBuilder(rtpPkt.getBuilder()).correctChecksumAtBuild(true).correctLengthAtBuild(true);
IpV4Packet.Builder IpPktBuilder = new IpV4Packet.Builder();
IpPktBuilder.version(IpVersion.IPV4).dontFragmentFlag(true).ihl((byte) 9).protocol(IpNumber.UDP)
.tos(IpV4Rfc1349Tos.newInstance((byte) 0)).ttl((byte) 16).srcAddr(srcAddr).dstAddr(dstAddr)
.payloadBuilder(uPktBuilder).correctChecksumAtBuild(true).correctLengthAtBuild(true)
.paddingAtBuild(true);
EthernetPacket.Builder ethPktBuilder = new EthernetPacket.Builder();
ethPktBuilder.dstAddr(MacAddress.getByName("fe:00:00:00:00:02"))
.srcAddr(MacAddress.getByName("fe:00:00:00:00:01")).type(EtherType.IPV4)
.payloadBuilder(IpPktBuilder).paddingAtBuild(true);
EthernetPacket ethPkt = ethPktBuilder.build();
pcapWriter.dump(ethPkt, Instant.now());
} catch (Exception e) {
log.error("PcapException", e);
}
Is there a way to specify one pcap format vs the other? There appear to be different types covered here: https://wiki.wireshark.org/Development/LibpcapFileFormat
Regarding your wireshark problem ... perhaps you need to do a manual decode. link
@rjo that helped a lot, but my "menu" options are different. It certainly sees the proper values now, thanks!
# Packet 0 from /stream1-2323562666.pcap
- 1
- 0.000000
- 192.168.0.1
- 192.168.0.2
- RTP
- 78
- PT=DynamicRTP-Type-126, SSRC=0x8A7EC0AA, Seq=1, Time=873270
glad i could help!