pcap4j icon indicating copy to clipboard operation
pcap4j copied to clipboard

Writing to a dump file

Open mondain opened this issue 4 years ago • 13 comments

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...

mondain avatar Dec 03 '21 22:12 mondain

Were you ever able to figure this out?

rjo avatar Jul 22 '22 19:07 rjo

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.

rjo avatar Jul 23 '22 16:07 rjo

I'm back on this, so I'll let you know how I fare.

mondain avatar Oct 06 '22 20:10 mondain

@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)

mondain avatar Oct 06 '22 21:10 mondain

That looks like its coming from someplace deeper in your code that the dump part

rjo avatar Oct 07 '22 01:10 rjo

@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.

mondain avatar Oct 07 '22 14:10 mondain

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.

rjo avatar Oct 07 '22 15:10 rjo

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...

mondain avatar Oct 07 '22 16:10 mondain

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);
  }

mondain avatar Oct 07 '22 20:10 mondain

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

mondain avatar Oct 07 '22 20:10 mondain

Regarding your wireshark problem ... perhaps you need to do a manual decode. link

rjo avatar Oct 11 '22 16:10 rjo

@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

mondain avatar Oct 11 '22 19:10 mondain

glad i could help!

rjo avatar Oct 11 '22 22:10 rjo