The original Java packet library. libpcap wrapper with L2–L4 protocol dissection, zero-copy native memory access, and a modern fluent API. 17+ years. 1M+ installs. Apache 2.0. The natural starting point for any Java network analysis application.
Add the Maven dependency, activate a free community license, and start reading packets. Header objects are pre-allocated once and rebound to each packet — zero allocation on the hot path.
<!-- Maven -->
<dependency>
<groupId>com.slytechs.sdk</groupId>
<artifactId>jnetpcap</artifactId>
<version>2.0.0</version>
</dependency>
// Gradle
implementation 'com.slytechs.sdk:jnetpcap:2.0.0'
NetPcap.activateLicense(); // Free community license
Ip4 ip4 = new Ip4();
Tcp tcp = new Tcp();
try (var pcap = NetPcap.openOffline("capture.pcap")) {
pcap.loop(-1, packet -> {
if (packet.hasHeader(ip4)
&& packet.hasHeader(tcp)) {
System.out.printf("%s:%d → %s:%d%n",
ip4.src(), tcp.srcPort(),
ip4.dst(), tcp.dstPort());
}
});
}
NetPcap.create(device) + activate() for live capture with full configuration control. NetPcap.openOffline(file) for reading PCAP and pcapng files. Both support the same loop() / dispatch() / next() API.
// Use the first available network interface
String device = NetPcap.findAllDevs()
.stream()
.filter(d -> d.isUp() && !d.isLoopback())
.findFirst()
.map(d -> d.name())
.orElseThrow(() -> new IllegalStateException(
"No suitable network interface found"));
System.out.printf("Capturing on device: %s%n", device);
System.out.println("Press Ctrl+C to stop...");
try (NetPcap pcap = NetPcap.create(device)) {
// Minimal config — defaults: snaplen=65535,
// promisc=false, timeout=1s
pcap.activate();
// Infinite loop with simple packet consumer
pcap.loop(-1, packet -> {
System.out.printf("[%s] wire=%d cap=%d%n",
packet.timestampInfo(),
packet.wireLength(),
packet.captureLength());
});
} catch (Exception e) {
e.printStackTrace();
}
Enable dissection with PacketSettings. Pre-allocate header instances once —
they rebind to each packet's native memory on every hasHeader() call.
No allocation during the dispatch loop regardless of how many headers you access.
NetPcap.activateLicense();
System.out.printf("Dissecting packets from: %s%n", filename);
// Enable protocol dissection
PacketSettings settings = new PacketSettings()
.dissect();
// Pre-allocate header instances (reused for every packet)
Ethernet eth = new Ethernet();
Ip4 ip4 = new Ip4();
Tcp tcp = new Tcp();
Udp udp = new Udp();
try (NetPcap pcap = NetPcap.openOffline(filename, settings)) {
pcap.loop(10, packet -> { // First 10 packets only
System.out.printf("=== Packet #%d ===%n", ++count[0]);
System.out.printf("Timestamp: %s%n", packet.timestampInfo());
System.out.printf("Captured: %d bytes, Wire: %d bytes%n",
packet.captureLength(), packet.wireLength());
// Layer 2 — Ethernet
if (packet.hasHeader(eth)) {
System.out.printf("%nEthernet:%n");
System.out.printf(" Source: %s%n", eth.src());
System.out.printf(" Destination: %s%n", eth.dst());
System.out.printf(" Type: 0x%04X%n", eth.etherType());
}
// Layer 3 — IPv4
if (packet.hasHeader(ip4)) {
System.out.printf("%nIPv4:%n");
System.out.printf(" Source: %s%n", ip4.src());
System.out.printf(" Destination: %s%n", ip4.dst());
System.out.printf(" TTL: %d%n", ip4.ttl());
System.out.printf(" Protocol: %d%n", ip4.protocol());
System.out.printf(" Checksum: 0x%04X%n", ip4.checksum());
System.out.printf(" Flags: DF=%b MF=%b%n",
ip4.isDf(), ip4.isMf());
System.out.printf(" Frag Offset: %d%n", ip4.fragOffset());
}
// Layer 4 — TCP
if (packet.hasHeader(tcp)) {
System.out.printf("%nTCP:%n");
System.out.printf(" Source Port: %d%n", tcp.srcPort());
System.out.printf(" Dest Port: %d%n", tcp.dstPort());
System.out.printf(" Seq: %d%n", tcp.seq());
System.out.printf(" Ack: %d%n", tcp.ack());
System.out.printf(" Header Len: %d (%d bytes)%n",
tcp.hlen(), tcp.hlenBytes());
System.out.printf(" Window: %d%n", tcp.window());
System.out.printf(" Checksum: 0x%04X%n", tcp.checksum());
System.out.printf(" Flags: SYN=%b ACK=%b FIN=%b RST=%b PSH=%b URG=%b%n",
tcp.isSyn(), tcp.isAck(), tcp.isFin(),
tcp.isRst(), tcp.isPsh(), tcp.isUrg());
}
// Layer 4 — UDP
if (packet.hasHeader(udp)) {
System.out.printf("%nUDP:%n");
System.out.printf(" Source Port: %d%n", udp.srcPort());
System.out.printf(" Dest Port: %d%n", udp.dstPort());
System.out.printf(" Length: %d%n", udp.length());
System.out.printf(" Checksum: 0x%04X%n", udp.checksum());
}
});
}
Header objects like Ethernet, Ip4, and Tcp are views into native memory — no byte array copies. hasHeader(h) checks presence and rebinds the view in a single operation.
.dissect() for eager L2–L4 parsing on every packet. .dissectOnDemand() to parse only what you access. Omit PacketSettings entirely for raw byte access with no parsing overhead.
Individual flag methods: isSyn(), isAck(), isFin(), isRst(), isPsh(), isUrg(). Sequence numbers, window size, checksum — all as typed fields.
isDf() (Don't Fragment), isMf() (More Fragments), fragOffset() — all exposed as first-class fields. IP reassembly available when you upgrade to jNetWorks.
Linux, Windows, macOS. Same API everywhere. libpcap on Unix, WinPcap/Npcap on Windows. Continuous testing across all three platforms.
Panama FFI gives direct access to native packet buffers. No byte array copies. Memory-mapped file support. Minimal GC pressure — header objects rebind, not reallocate.
Ethernet, IPv4, IPv6, TCP, UDP, ICMP, ARP, DNS, and more. Lazy or eager dissection modes. Header objects are reusable views, not allocations.
Standard Berkeley Packet Filter expressions for efficient kernel-side filtering. Reduce what reaches your application before loop() is ever called.
NetPcap.findAllDevs() returns a typed list of network interfaces with metadata — name, description, flags, addresses. Filter by isUp(), isLoopback(), isRunning().
1M+ installs. Fortune 500 deployments. Active maintenance, regular security updates, and long-term API stability. The most-used Java packet library in production.
Layer 2 — Data Link Ethernet II · IEEE 802.1Q (VLAN) · ARP · RARP · PPPoE Layer 3 — Network IPv4 · IPv6 · ICMPv4 · ICMPv6 · IGMP GRE · IPSec (ESP/AH) · IPIP tunnels Layer 4 — Transport TCP (state tracking) · UDP · SCTP Application helpers — metadata only, no full L7 payload DNS · DHCP · HTTP (basic) · HTTPS (TLS metadata) Full L5–L7 dissection (TLS decrypt, HTTP/2, QUIC, 100+ protocols) → jNetWorks
jNetPcap and jNetWorks share the same protocol dissection engine and API patterns. Upgrading is a backend swap — your application code stays the same.
jNetPcap jNetWorks ─────────────────────────────────── ───────────────────────────────────────── NetPcap.openOffline() / create() PcapBackend · DpdkBackend · NtapiBackend packet.hasHeader(ip4) packet.hasHeader(ip4) ← same call PacketSettings → PacketPipeline ProtocolStack → ProcessorTree L2–L4 protocols L2–L7, 100+ protocols, IP/TCP reassembly Core token stream Full token stream (IDS, TLS, ML, custom) libpcap speed 800 Gbps sustained (DPDK / Napatech) Linux · Windows · macOS Linux Your dissection code, header objects, and analysis logic: unchanged.
Open source, Apache 2.0, available on Maven Central.