Package com.slytechs.sdk.jnetpcap.api


package com.slytechs.sdk.jnetpcap.api
jNetPcap 3.0 API - High-performance packet capture with protocol dissection.

This package provides NetPcap, a high-level packet capture interface that wraps the low-level Pcap bindings and integrates with protocol dissection. Packets delivered through dispatch(), loop(), next(), and nextEx() are fully dissected with protocol headers accessible via the zero-allocation hasHeader() pattern.

API Layers

jNetPcap provides two API layers:

jNetPcap API Layers
ClassModuleDescription
Pcapjnetpcap-bindings Low-level libpcap bindings — direct 1:1 native access
NetPcapjnetpcap-api High-level API with integrated protocol dissection

Configuration: NetPcap vs PacketSettings

There are two distinct configuration concerns:

Configuration Separation
ConfigurationPurposeMethods
NetPcap settersCapture properties (pcap API) setSnaplen(), setTimeout(), setPromisc(), setFilter(), setBufferSize(), etc.
PacketSettings Packet structure & memory dissect(), zeroCopy(), descriptorType(), etc.

NetPcap Configuration

NetPcap setters configure traditional pcap capture properties — how packets are captured from the network or read from files:

  • setSnaplen(int) — Maximum bytes to capture per packet
  • setTimeout(Duration) — Read timeout
  • setPromisc(boolean) — Promiscuous mode
  • setFilter(String) — BPF filter expression
  • setBufferSize(int) — Kernel buffer size
  • setImmediateMode(boolean) — Disable buffering
  • setDirection(PcapDirection) — Capture direction
  • setTstampType(PcapTstampType) — Timestamp source
  • setTstampPrecision(PcapTStampPrecision) — Timestamp precision

PacketSettings Configuration

PacketSettings configures how packets are structured and managed in memory:

  • dissect() — Enable eager protocol dissection (TYPE2 descriptor)
  • onDemand() — Enable on-demand dissection
  • zeroCopy() — Use scoped memory (valid only in callback)
  • descriptorType(DescriptorTypeInfo) — Choose descriptor format

Quick Start

Simple Live Capture

try (NetPcap pcap = NetPcap.openLive("eth0", 65535, true, Duration.ofSeconds(1))) {
    Ip4 ip = new Ip4();

    pcap.loop(100, packet -> {
        if (packet.hasHeader(ip))
            System.out.printf("%s -> %s%n", ip.src(), ip.dst());
    });
}

Offline File Reading with PacketSettings

PacketSettings settings = new PacketSettings().dissect();

try (NetPcap pcap = NetPcap.openOffline("capture.pcap", settings)) {
    pcap.setFilter("tcp port 80");

    Packet packet;
    while ((packet = pcap.next()) != null) {
        // Process dissected packet...
    }
}

Two-Stage Capture Configuration

try (NetPcap pcap = NetPcap.create("eth0")) {
    pcap.setSnaplen(128)
        .setPromisc(true)
        .setTimeout(Duration.ofMillis(100))
        .setImmediateMode(true)
        .activate();

    pcap.dispatch(1000, packet -> {
        // Process packet...
    });
}

Full Configuration Example

PacketSettings settings = new PacketSettings().dissect();

try (NetPcap pcap = NetPcap.create("eth0", settings)) {
    pcap.setSnaplen(65535)
        .setTimeout(Duration.ofSeconds(1))
        .setPromisc(true)
        .setBufferSize(16 * 1024 * 1024)
        .setTstampPrecision(PcapTStampPrecision.NANO)
        .activate();

    pcap.setFilter("tcp port 80 or tcp port 443");

    Ethernet eth = new Ethernet();
    Ip4 ip4 = new Ip4();
    Tcp tcp = new Tcp();

    pcap.dispatch(1000, packet -> {
        if (packet.hasHeader(eth) && packet.hasHeader(ip4) && packet.hasHeader(tcp))
            System.out.printf("%s:%d -> %s:%d%n",
                ip4.src(), tcp.srcPort(),
                ip4.dst(), tcp.dstPort());
    });
}

Core Components

jNetPcap API Classes
ClassDescription
NetPcapHigh-level capture with protocol dissection
PacketSettings Packet structure and memory configuration
PacketHandlerPacket callback interfaces
Pcap Low-level libpcap bindings
PcapIf Network interface descriptor
BpFilter Compiled BPF filter

Memory Model

jNetPcap uses a layered memory model optimized for performance:

┌─────────────────────────────────────────────────────────────────┐
│                     Native Capture Buffer                       │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │ Packet 1 │ Packet 2 │ Packet 3 │ ...                    │    │
│  └─────────────────────────────────────────────────────────┘    │
│       ▲                                                         │
│       │ ScopedMemory (zero-copy binding)                        │
│       │                                                         │
│  ┌────┴────────────────┐                                        │
│  │ Packet              │                                        │
│  │  ├─ ScopedMemory    │  Data bound to native buffer           │
│  │  ├─ Descriptor      │  Protocol dissection results           │
│  │  └─ Header bindings │  Zero-allocation header access         │
│  └─────────────────────┘                                        │
│                                                                 │
│  Scope: Valid within dispatch/loop callback only                │
└─────────────────────────────────────────────────────────────────┘

Memory Types

Memory Strategies
TypeAllocationLifetimeUse Case
ScopedMemoryNone (bind only)Callback scope Zero-copy capture
FixedMemoryPool or ArenaUntil recycled Persistent packets
HybridMixedMixed Zero-copy data + fixed descriptor

Protocol Dissection

Dissection Modes

Dissection Modes (PacketSettings)
ModeMethodDescription
Eagerdissect() Full dissection before callback, TYPE2 descriptor
On-demandonDemand() Dissect lazily on first hasHeader()
None(default) No dissection, PCAP descriptor only

Zero-Allocation Header Access

The hasHeader(Header) pattern provides zero-allocation protocol access by reusing pre-allocated header instances:

// Allocate once outside the loop — reused for every packet, zero GC pressure
Ethernet eth = new Ethernet();
Ip4 ip4 = new Ip4();
Ip6 ip6 = new Ip6();
Tcp tcp = new Tcp();
Udp udp = new Udp();

pcap.loop(-1, packet -> {
    if (packet.hasHeader(eth)) {
        byte[] dstMac = eth.dst();
        int etherType = eth.type();
    }

    if (packet.hasHeader(ip4)) {
        String srcIp = ip4.src();
        int ttl = ip4.ttl();
    } else if (packet.hasHeader(ip6)) {
        String srcIp = ip6.src();
        int hopLimit = ip6.hopLimit();
    }

    if (packet.hasHeader(tcp)) {
        int srcPort = tcp.srcPort();
        int dstPort = tcp.dstPort();
    }
});

Tunneled Protocol Access

For tunneled packets (GRE, VXLAN, etc.), use the depth parameter:

Ip4 outerIp = new Ip4();
Ip4 innerIp = new Ip4();

if (packet.hasHeader(outerIp, 0))       // Outer IP (depth 0)
    System.out.println("Outer: " + outerIp.src());

if (packet.hasHeader(innerIp, 1))       // Inner IP (depth 1)
    System.out.println("Inner: " + innerIp.src());

Packet Persistence

Packets in callbacks are bound to native buffers and valid only within callback scope. To keep packets beyond the callback, use the persistence API:

Persistence Methods
MethodReturnsMemoryUse Case
persist()Same or copyFixed Keep beyond callback scope
persistTo(pool)Pooled copyPool memory High-volume zero-GC capture
copy()New copyAuto-managed Independent lifecycle
duplicate()New objectShared (+ref) Parallel processing
recycle()voidReturns to pool Release pooled packet when done
Queue<Packet> queue = new ConcurrentLinkedQueue<>();

pcap.loop(-1, packet -> {
    if (isInteresting(packet))
        queue.add(packet.persist());
});

// Consumer thread
while (running) {
    Packet p = queue.poll();
    if (p != null) {
        process(p);
        p.recycle();  // Return to pool (no-op if non-pooled)
    }
}

Berkeley Packet Filter (BPF)

try (NetPcap pcap = NetPcap.openLive("eth0")) {
    pcap.setFilter("tcp port 80 or tcp port 443");
    pcap.loop(-1, handler);
}

Common Filter Expressions

"tcp"                           All TCP packets
"udp port 53"                   DNS traffic
"host 192.168.1.1"              Traffic to/from host
"net 10.0.0.0/8"                Traffic to/from network
"tcp port 80 or tcp port 443"   HTTP and HTTPS
"icmp"                          ICMP packets
"vlan 100"                      VLAN tagged traffic
"tcp[tcpflags] & tcp-syn != 0"  TCP SYN packets only

Packet Descriptors

Descriptor Types
TypeSizeUse Case
PCAP_PADDED24 bytes Kernel format (x64 padded)
PCAP_PACKED16 bytes File format (packed)
TYPE296 bytes Full protocol dissection results

Thread Safety

NetPcap is strictly single-threaded. All capture operations must occur on the same thread. For multi-threaded processing:

  • Capture on a dedicated thread
  • Use persist() for packets leaving the capture thread
  • Each worker thread needs its own header instances
BlockingQueue<Packet> workQueue = new LinkedBlockingQueue<>(10000);

// Capture thread
Thread captureThread = new Thread(() -> {
    try (NetPcap pcap = NetPcap.openLive("eth0")) {
        pcap.loop(-1, packet -> {
            if (filter(packet))
                workQueue.put(packet.persist());
        });
    }
});

// Worker threads — each needs its own header instances
ExecutorService workers = Executors.newFixedThreadPool(4);
for (int i = 0; i < 4; i++) {
    workers.submit(() -> {
        Tcp tcp = new Tcp();  // Thread-local, not shared
        while (running) {
            Packet p = workQueue.take();
            if (p.hasHeader(tcp))
                process(tcp);
            p.recycle();
        }
    });
}

Capture Methods

Capture Methods
MethodRespects TimeoutDescription
loop(count, handler)No Process until count reached or breakloop() called
dispatch(count, handler)Yes Process available packets up to count
next()Yes Return next packet or null on timeout
nextEx()Yes Return next packet with explicit status code

Platform Support

Platform Requirements
PlatformNative LibraryNotes
Linuxlibpcap 1.0+Best performance
WindowsNpcap 1.0+ Administrator rights required for live capture
macOSlibpcap (system) BPF device access required
  • com.slytechs.sdk.jnetpcap — Low-level Pcap bindings
  • com.slytechs.sdk.protocol.core — Packet, Header, PacketSettings
  • com.slytechs.sdk.protocol.tcpip — Ethernet, IPv4, IPv6, TCP, UDP
  • com.slytechs.sdk.protocol.web — HTTP, TLS, QUIC
  • com.slytechs.sdk.common.memory.pool — Pooling and persistence
Since:
3.0
Author:
Mark Bednarczyk [mark@slytechs.com], Sly Technologies Inc.
See Also:
  • NetPcap
  • PacketSettings
  • Pcap
  • Packet
  • Class
    Description
    Base class for NetPcap providing delegation to low-level Pcap bindings.
    High-level packet capture and protocol dissection API.
    A marker interface for different types of packet handlers used in packet capture and processing.
    Provides high-level packet handling using the Packet object model.
    Provides a Java Consumer-style interface for packet handling.