ProtocolStack Configuration

  1. ProtocolStack Configuration

    ProtocolStack is the primary user-facing configuration container for protocol processing. It implements the Spec interface and follows the three-stage lifecycle: ProtocolStack → ProtocolTree → ProcessorTree.

    Creating and Configuring

    ProtocolStack stack = new ProtocolStack();
    
    // Configure IP with reassembly
    stack.setProtocol(new IpProtocol())
         .enableReassembly(true)
         .tableSize(100_000)
         .fragmentTimeout(30)
         .decap();  // Strip outer IP for inner traffic
    
    // Configure TCP with reassembly
    stack.setProtocol(new TcpProtocol())
         .enableReassembly(true)
         .maxOutOfOrder(200)
         .maxStreams(50_000);
    
    // Configure packet handling
    stack.setPacketPolicy(PacketPolicy.zeroCopy())
         .usePacketPool(new PacketPoolSettings()
             .capacity(100_000)
             .maxPacketSize(9000))
         .descriptorType(DescriptorTypeInfo.NET);

    Configuration Patterns

    Pattern 1: Set and Configure

    Create a new protocol instance and configure fluently:

    stack.setProtocol(new IpProtocol())
         .enableReassembly(true)
         .fragmentTimeout(30);

    Pattern 2: Get Default from SPI

    Retrieve default configuration from pack and modify:

    stack.getProtocol(IpProtocol.class)
         .enableReassembly(true);

    Pattern 3: Load from File

    Load configuration from properties file:

    Settings.load(new FileInputStream("capture.properties"), "protocol");
    
    // Properties file format:
    // protocol.ip.reassembly.enabled=true
    // protocol.ip.reassembly.timeout=30
    // protocol.tcp.reassembly.enabled=true

    Pattern 4: Command Line Override

    Override via system properties:

    java -Dprotocol.ip.reassembly.timeout=60 \
         -Dprotocol.tcp.maxStreams=100000 \
         MyApplication

    Depth Handling (Tunnels)

    Protocol depth supports tunneled and encapsulated traffic. Depth 0 is the outermost layer, depth 1 is after the first tunnel, and so on.

    // Configure outer IP (depth 0)
    stack.setProtocol(new IpProtocol(), 0)
         .enableReassembly(true);
    
    // Configure inner IP after tunnel (depth 1)
    stack.setProtocol(new IpProtocol(), 1)
         .enableReassembly(false);  // Different config for inner

    Consistent with Header Access

    The depth parameter mirrors the header access API:

    Ip4 outer = new Ip4();
    Ip4 inner = new Ip4();
    
    if (packet.hasHeader(outer, 0)) {  // Binds outer IP
        System.out.println("Outer: " + outer.src());
    }
    
    if (packet.hasHeader(inner, 1)) {  // Binds inner IP (after tunnel)
        System.out.println("Inner: " + inner.src());
    }

    Common Tunnel Scenarios

    Depth 0    Depth 1    Depth 2
    ───────    ───────    ───────
    IP         -          -          (Simple packet)
    IP → GRE → IP         -          (GRE tunnel)
    IP → GRE → IP → GRE → IP         (Nested tunnels)
    Eth → VLAN → IP       -          (VLAN tagged)

    PacketPolicy Configuration

    PacketPolicy controls how packets are acquired, bound, and released:

    // Zero-copy for high-speed capture
    stack.setPacketPolicy(PacketPolicy.zeroCopy())
         .usePacketPool(new PacketPoolSettings()
             .capacity(100_000))
         .descriptorType(DescriptorTypeInfo.NET)
         .dissectorDepth(4);  // Limit to L4
    
    // Memory copy for packet persistence
    stack.setPacketPolicy(PacketPolicy.memoryCopy())
         .usePacketPool(new PacketPoolSettings()
             .capacity(10_000)
             .maxPacketSize(16384))
         .clonePolicy(PacketPolicy.memoryCopy());

    Token Subscription

    Subscribe to tokens emitted by processors and analyzers:

    // Subscribe to TCP flow events
    stack.subscribeTokens(TCP_LAYER, TcpTokens.FLOW_BOUNDARY | TcpTokens.RETRANSMIT);
    
    // Subscribe to IDS alerts
    stack.subscribeTokens(IDS_LAYER, IdsTokens.ALERTS);
    
    // Subscribe to index beacons
    stack.subscribeTokens(INDEX_LAYER, IndexTokens.SPARSE_BEACON);

    Tokens are delivered via:

    • User callback (jNetPcap)

    • TokenStream (jNetWorks)

    • Packet attachment

    Layer Control

    Enable or disable entire protocol layers:

    // Disable all L5+ protocols (for jNetPcap)
    stack.disableLayer(L5Protocol.class);
    
    // Disable specific protocol
    stack.disable(HttpProtocol.class);
    
    // Re-enable
    stack.enable(HttpProtocol.class);

    State Management

    Manage processor state for file seeking and context rebuilding:

    // Clear all state (flow tables, reassembly buffers)
    stack.clearState();
    
    // Clear state for specific protocol
    stack.clearState(TcpProtocol.class);
    
    // Quiet mode - process without output (for context rebuild)
    stack.setQuietMode(true);
    // ... process packets to rebuild state ...
    stack.setQuietMode(false);

    Settings Resolution Order

    Each protocol property resolves its value using this priority:

    Priority
    Source
    Example

    1

    Explicit value

    .fragmentTimeout(30)

    2

    System property

    -Dprotocol.ip.reassembly.timeout=30

    3

    Environment variable

    PROTOCOL_IP_REASSEMBLY_TIMEOUT=30

    4

    Properties file

    Settings.load(file, "protocol")

    5

    Pack defaults

    /protocol-defaults.properties in JAR

    6

    Coded default

    Value in property definition

    Integration Examples

    jNetPcap

    ProtocolStack stack = new ProtocolStack();
    
    stack.setProtocol(new IpProtocol())
         .enableReassembly(true);
    
    stack.setPacketPolicy(PacketPolicy.zeroCopy())
         .usePacketPool(new PacketPoolSettings().capacity(1));
    
    try (NetPcap pcap = NetPcap.create("en0", stack)) {
        pcap.dispatch(1000, packet -> {
            // Process reassembled packets
        });
    }

    jNetWorks

    ProtocolStack stack = new ProtocolStack();
    
    stack.setProtocol(new TcpProtocol())
         .enableReassembly(true);
    
    stack.setPacketPolicy(PacketPolicy.zeroCopy())
         .usePacketPool(new PacketPoolSettings().capacity(100_000));
    
    stack.subscribeTokens(TCP_LAYER, TcpTokens.FLOW_BOUNDARY);
    
    PacketStream[] streams = net.createPacketStreams("rx-%d", 4, stack);

    Complete Example

    // Create stack
    ProtocolStack stack = new ProtocolStack();
    
    // Configure protocols
    stack.setProtocol(new IpProtocol())
         .enableReassembly(true)
         .fragmentTimeout(30)
         .tableSize(100_000);
    
    stack.setProtocol(new TcpProtocol())
         .enableReassembly(true)
         .maxOutOfOrder(200);
    
    stack.setProtocol(new TlsProtocol())
         .enableDecryption(true)
         .keyLogFile("/tmp/sslkeys.log");
    
    // Configure inner tunnel differently
    stack.setProtocol(new IpProtocol(), 1)
         .enableReassembly(false);
    
    // Configure packet policy
    stack.setPacketPolicy(PacketPolicy.zeroCopy())
         .usePacketPool(new PacketPoolSettings()
             .capacity(50_000)
             .maxPacketSize(9000))
         .descriptorType(DescriptorTypeInfo.NET);
    
    // Subscribe to tokens
    stack.subscribeTokens(TCP_LAYER, TcpTokens.FLOW_BOUNDARY);
    stack.subscribeTokens(TLS_LAYER, TlsTokens.HANDSHAKE_COMPLETE);

Last updated