Working code examples to get you started with jNetPcap SDK 3.0.
All examples are available on GitHub: github.com/slytechs-repos/jnetpcap-examples
Access protocol header fields with zero-allocation binding:
PacketSettings settings = new PacketSettings().dissect();
Ethernet eth = new Ethernet();
Ip4 ip4 = new Ip4();
Tcp tcp = new Tcp();
try (NetPcap pcap = NetPcap.openOffline("capture.pcap", settings)) {
pcap.loop(-1, packet -> {
if (packet.hasHeader(eth)) {
System.out.printf("Ethernet: %s → %s [0x%04X]%n",
eth.src(), eth.dst(), eth.etherType());
}
if (packet.hasHeader(ip4)) {
System.out.printf("IPv4: %s → %s TTL=%d%n",
ip4.src(), ip4.dst(), ip4.ttl());
}
if (packet.hasHeader(tcp)) {
System.out.printf("TCP: %d → %d [SYN=%b ACK=%b]%n",
tcp.srcPort(), tcp.dstPort(), tcp.isSyn(), tcp.isAck());
}
});
}
Read and analyze pcap/pcapng capture files:
PacketSettings settings = new PacketSettings().dissect();
try (NetPcap pcap = NetPcap.openOffline("capture.pcapng", settings)) {
System.out.printf("Link type: %s%n", pcap.datalinkVal());
System.out.printf("Snaplen: %d%n", pcap.snapshot());
AtomicInteger count = new AtomicInteger();
AtomicLong bytes = new AtomicLong();
pcap.loop(-1, packet -> {
count.incrementAndGet();
bytes.addAndGet(packet.captureLength());
});
System.out.printf("Packets: %,d%n", count.get());
System.out.printf("Bytes: %,d%n", bytes.get());
}
Capture live network traffic with BPF filters:
PacketSettings settings = new PacketSettings().dissect();
try (NetPcap pcap = NetPcap.create("eth0", settings)) {
pcap.setSnaplen(65535)
.setPromisc(true)
.setTimeout(Duration.ofSeconds(1))
.activate();
// BPF filter for HTTP/HTTPS traffic
pcap.setFilter("tcp port 80 or tcp port 443");
Ip4 ip4 = new Ip4();
Tcp tcp = new Tcp();
pcap.loop(1000, packet -> {
if (packet.hasHeader(ip4) && packet.hasHeader(tcp)) {
System.out.printf("%s:%d → %s:%d%n",
ip4.src(), tcp.srcPort(),
ip4.dst(), tcp.dstPort());
}
});
}
Keep packets beyond callback scope for later processing:
Queue<Packet> queue = new ConcurrentLinkedQueue<>();
Tcp tcp = new Tcp();
try (NetPcap pcap = NetPcap.openOffline("capture.pcap", settings)) {
pcap.loop(-1, packet -> {
// Persist SYN packets for later analysis
if (packet.hasHeader(tcp) && tcp.isSyn() && !tcp.isAck()) {
Packet keeper = packet.persist();
queue.add(keeper);
}
});
}
// Process outside callback
System.out.printf("Captured %d SYN packets%n", queue.size());
Packet p;
while ((p = queue.poll()) != null) {
if (p.hasHeader(tcp)) {
System.out.printf("SYN to port %d%n", tcp.dstPort());
}
p.recycle();
}
High-volume capture with predictable memory usage:
// Pre-allocate pool for 1000 packets, 9KB each
PoolSettings poolSettings = new PoolSettings()
.capacity(1000)
.preallocate(true);
Pool<Packet> pool = PacketPool.ofFixedSize(poolSettings, 9000);
Queue<Packet> queue = new ConcurrentLinkedQueue<>();
AtomicInteger dropped = new AtomicInteger();
try (NetPcap pcap = NetPcap.openLive("eth0", settings)) {
pcap.loop(-1, packet -> {
if (pool.available() > 0) {
queue.add(packet.persistTo(pool));
} else {
dropped.incrementAndGet();
}
});
}
System.out.printf("Captured: %d, Dropped: %d%n", queue.size(), dropped.get());
// Process and return to pool
Packet p;
while ((p = queue.poll()) != null) {
process(p);
p.recycle(); // Returns to pool
}
pool.close();
List available network interfaces:
List<PcapIf> devices = NetPcap.findAllDevs();
System.out.printf("Found %d interface(s)%n", devices.size());
for (PcapIf dev : devices) {
System.out.printf("%n[%s]%n", dev.name());
if (dev.description() != null) {
System.out.printf(" Description: %s%n", dev.description());
}
System.out.printf(" Flags: %s%n", dev.flags());
for (PcapAddr addr : dev.addresses()) {
System.out.printf(" Address: %s%n", addr.addr());
}
}
// Find best interface for capture
PcapIf best = devices.stream()
.filter(d -> d.isUp() && !d.isLoopback())
.findFirst()
.orElse(null);
if (best != null) {
System.out.printf("%nRecommended: %s%n", best.name());
}
Producer-consumer pattern for parallel processing:
BlockingQueue<Packet> workQueue = new LinkedBlockingQueue<>(10000);
AtomicBoolean running = new AtomicBoolean(true);
// Worker threads (each with thread-local headers)
ExecutorService workers = Executors.newFixedThreadPool(4);
for (int i = 0; i < 4; i++) {
final int workerId = i;
workers.submit(() -> {
Tcp tcp = new Tcp(); // Thread-local
while (running.get() || !workQueue.isEmpty()) {
try {
Packet p = workQueue.poll(100, TimeUnit.MILLISECONDS);
if (p != null) {
if (p.hasHeader(tcp) && tcp.isSyn()) {
System.out.printf("[W%d] SYN to port %d%n",
workerId, tcp.dstPort());
}
p.recycle();
}
} catch (InterruptedException e) {
break;
}
}
});
}
// Capture thread
Tcp tcp = new Tcp();
try (NetPcap pcap = NetPcap.openLive("eth0", settings)) {
pcap.loop(-1, packet -> {
if (packet.hasHeader(tcp)) {
workQueue.put(packet.persist());
}
});
}
running.set(false);
workers.shutdown();
Save captured packets to a pcap file:
// Allocate pcap header for conversion
MemorySegment hdrSegment = Arena.ofAuto().allocate(24);
PcapHeaderABI abi = PcapHeaderABI.PADDED_LE;
Tcp tcp = new Tcp();
AtomicInteger saved = new AtomicInteger();
try (NetPcap pcap = NetPcap.create("eth0", settings)) {
pcap.setSnaplen(128).setPromisc(true).activate();
pcap.setFilter("tcp");
try (PcapDumper dumper = pcap.dumpOpen("output.pcap")) {
pcap.loop(1000, packet -> {
if (packet.hasHeader(tcp) && tcp.isSyn()) {
// Convert descriptor to pcap header format
var desc = packet.descriptor();
long ts = desc.timestamp();
var tsu = desc.timestampUnit();
abi.tvSec(hdrSegment, tsu.toEpochSecond(ts));
abi.tvUsec(hdrSegment, tsu.toMicroAdjustment(ts));
abi.captureLength(hdrSegment, packet.captureLength());
abi.wireLength(hdrSegment, packet.wireLength());
dumper.dump(hdrSegment, packet.boundMemory().segment());
saved.incrementAndGet();
}
});
dumper.flush();
}
}
System.out.printf("Saved %d SYN packets to output.pcap%n", saved.get());
Full Source Code — Complete examples on GitHub
API Javadocs — API reference
GitHub Wiki — User guides