NFTables.Expr.Actions (NFTables v0.8.2)

View Source

Action and packet modification functions for Expr.

Provides functions for counter, logging, rate limiting, packet/connection marking, CT operations, and packet header modifications (DSCP, TTL, hop limit). These actions modify packets or connection state rather than matching conditions.

Import

import NFTables.Expr.Actions

Examples

# Counter and logging
tcp() |> dport(22) |> counter() |> log("SSH: ") |> accept()

# Rate limiting
tcp() |> dport(80) |> limit(100, :second, burst: 20) |> accept()

# Packet marking for QoS
udp() |> dport(5060) |> set_dscp(:ef) |> set_mark(1) |> accept()

# Connection marking
ct_state([:new]) |> set_mark(100) |> save_mark() |> accept()
state([:established]) |> restore_mark() |> accept()

For more information, see the nftables statements wiki.

Summary

Functions

Add counter expression

Decrement IPv6 hop limit by 1.

Decrement IP TTL by 1.

Increment IPv6 hop limit by 1.

Increment IP TTL by 1.

Convenience alias for rate_limit/4. Add rate limiting.

Restore connection mark to packet mark.

Save packet mark to connection mark.

Assign connection tracking helper.

Set connection tracking label.

Assign connection to tracking zone.

Set DSCP (Differentiated Services Code Point) value.

Set TCP Maximum Segment Size (MSS).

Set IP TTL (Time To Live) value.

Enable SYN proxy for DDoS protection.

Redirect to local transparent proxy (TPROXY).

Functions

counter(builder \\ Expr.expr())

@spec counter(NFTables.Expr.t()) :: NFTables.Expr.t()

Add counter expression

decrement_hoplimit(builder \\ Expr.expr())

@spec decrement_hoplimit(NFTables.Expr.t()) :: NFTables.Expr.t()

Decrement IPv6 hop limit by 1.

Example

# Reduce hop limit by 1
builder |> decrement_hoplimit() |> accept()

decrement_ttl(builder \\ Expr.expr())

@spec decrement_ttl(NFTables.Expr.t()) :: NFTables.Expr.t()

Decrement IP TTL by 1.

Example

# Reduce TTL by 1
builder |> decrement_ttl() |> accept()

increment_hoplimit(builder \\ Expr.expr())

@spec increment_hoplimit(NFTables.Expr.t()) :: NFTables.Expr.t()

Increment IPv6 hop limit by 1.

Example

# Extend hop limit by 1
builder |> increment_hoplimit() |> accept()

increment_ttl(builder \\ Expr.expr())

@spec increment_ttl(NFTables.Expr.t()) :: NFTables.Expr.t()

Increment IP TTL by 1.

Example

# Extend TTL by 1
builder |> increment_ttl() |> accept()

limit(builder \\ Expr.expr(), rate, unit, opts \\ [])

Convenience alias for rate_limit/4. Add rate limiting.

Supports dual-arity: can start a new expression or continue an existing one.

Examples

# Basic rate limiting
limit(10, :minute)

# With burst
tcp() |> dport(22) |> limit(10, :minute, burst: 5)

# Continue existing expression
builder |> limit(100, :second)

log(builder \\ Expr.expr(), prefix, opts \\ [])

Add log expression.

Options

  • :level - Syslog level (default: no level specified)
    • :emerg - Emergency
    • :alert - Alert
    • :crit - Critical
    • :err - Error
    • :warning or :warn - Warning
    • :notice - Notice
    • :info - Info
    • :debug - Debug

Examples

# Basic logging
builder |> log("DROPPED: ")

# With syslog level
builder |> log("AUDIT: ", level: :warning)
builder |> log("CRITICAL: ", level: :crit)

rate_limit(builder \\ Expr.expr(), rate, unit, opts \\ [])

@spec rate_limit(NFTables.Expr.t(), non_neg_integer(), atom(), keyword()) ::
  NFTables.Expr.t()

Add rate limiting.

Example

builder |> rate_limit(10, :minute)
builder |> rate_limit(100, :second)

restore_mark(builder \\ Expr.expr())

@spec restore_mark(NFTables.Expr.t()) :: NFTables.Expr.t()

Restore connection mark to packet mark.

Copies the connection mark to the packet mark. This ensures all packets in a connection have the same mark, useful for policy routing and QoS.

Example

# Restore connmark for established connections
builder
|> ct_state([:established, :related])
|> restore_mark()
|> accept()

Use Case

In multi-WAN routing or QoS scenarios:

  1. First packet: classify and set connmark
  2. Subsequent packets: restore connmark to mark
  3. All packets in connection use same route/QoS tier

save_mark(builder \\ Expr.expr())

@spec save_mark(NFTables.Expr.t()) :: NFTables.Expr.t()

Save packet mark to connection mark.

Copies the packet mark to the connection mark. This persists the classification for the entire connection.

Example

# Classify new connection and save mark
builder
|> ct_state([:new])
|> dscp(46)
|> set_mark(1)
|> save_mark()
|> accept()

Use Case

In traffic classification:

  1. Match conditions and set packet mark
  2. Save mark to connmark for persistence
  3. Later packets restore connmark via restore_mark()

set_connmark(builder \\ Expr.expr(), mark)

@spec set_connmark(NFTables.Expr.t(), non_neg_integer()) :: NFTables.Expr.t()

Set connection mark.

Connection marks persist across all packets in a connection.

Example

builder |> set_connmark(42)

set_ct_helper(builder \\ Expr.expr(), helper)

@spec set_ct_helper(NFTables.Expr.t(), String.t()) :: NFTables.Expr.t()

Assign connection tracking helper.

Assigns a CT helper (FTP, SIP, etc.) to the connection for application layer gateway functionality.

Example

# Assign FTP helper
builder
|> tcp()
|> dport(21)
|> ct_state([:new])
|> set_ct_helper("ftp")
|> accept()

# Assign SIP helper
builder
|> udp()
|> dport(5060)
|> set_ct_helper("sip")
|> accept()

Use Cases

  • FTP active mode support
  • SIP/VoIP NAT traversal
  • H.323 video conferencing
  • TFTP file transfers

set_ct_label(builder \\ Expr.expr(), label)

@spec set_ct_label(NFTables.Expr.t(), String.t() | non_neg_integer()) ::
  NFTables.Expr.t()

Set connection tracking label.

Assigns a label to the connection for advanced stateful tracking. Labels are 128-bit bitmaps allowing complex classification.

Example

# Label suspicious connections
builder
|> source_ip("203.0.113.0/24")
|> set_ct_label("suspicious")
|> accept()

# Set numeric label bit
builder
|> tcp()
|> dport(22)
|> set_ct_label(5)
|> accept()

Use Cases

  • Complex multi-stage stateful tracking
  • Connection classification across chains
  • Security event correlation

set_ct_zone(builder \\ Expr.expr(), zone)

@spec set_ct_zone(NFTables.Expr.t(), non_neg_integer()) :: NFTables.Expr.t()

Assign connection to tracking zone.

Places the connection in a specific CT zone for isolation. Useful for multi-tenant or namespace scenarios.

Example

# Assign to zone 1
builder
|> iif("tenant1")
|> set_ct_zone(1)
|> accept()

# Assign to tenant-specific zone
builder
|> source_ip("192.168.100.0/24")
|> set_ct_zone(100)
|> accept()

Use Cases

  • Multi-tenant isolation
  • Network namespace separation
  • Overlapping IP address spaces
  • Container network isolation

set_dscp(builder \\ Expr.expr(), dscp)

@spec set_dscp(NFTables.Expr.t(), atom() | non_neg_integer()) :: NFTables.Expr.t()

Set DSCP (Differentiated Services Code Point) value.

Modifies the DSCP field in the IP header for QoS remarking.

DSCP Values

  • 46 (:ef) - Expedited Forwarding (VoIP voice)
  • 34 (:af41) - Assured Forwarding 4/1 (Video)
  • 26 (:af31) - Assured Forwarding 3/1 (Signaling)
  • 18 (:af21) - Assured Forwarding 2/1 (Streaming)
  • 10 (:af11) - Assured Forwarding 1/1 (Bulk)
  • 0 (:cs0) - Class Selector 0 (Best Effort)

Example

# Remark HTTP traffic as bulk
builder
|> tcp()
|> dport(80)
|> set_dscp(10)
|> accept()

# Mark VoIP as expedited forwarding
builder
|> udp()
|> dport(5060)
|> set_dscp(46)
|> accept()

# Use atom
builder
|> tcp()
|> dport(22)
|> set_dscp(:af31)
|> accept()

set_hoplimit(builder \\ Expr.expr(), hoplimit)

@spec set_hoplimit(NFTables.Expr.t(), non_neg_integer()) :: NFTables.Expr.t()

Set IPv6 hop limit value.

IPv6 equivalent of TTL. Modifies the hop limit field in the IPv6 header.

Example

# Set hop limit to 64
builder |> set_hoplimit(64) |> accept()

# Normalize hop limit
builder |> set_hoplimit(255) |> accept()

set_mark(builder \\ Expr.expr(), mark)

@spec set_mark(NFTables.Expr.t(), non_neg_integer()) :: NFTables.Expr.t()

Set packet mark.

Useful for policy routing and traffic shaping.

Example

builder |> set_mark(100)

set_tcp_mss(builder \\ Expr.expr(), mss)

@spec set_tcp_mss(NFTables.Expr.t(), non_neg_integer() | :pmtu) :: NFTables.Expr.t()

Set TCP Maximum Segment Size (MSS).

Modifies or clamps the TCP MSS option. Useful for fixing PMTU issues with PPPoE or VPN connections.

Example

# Clamp MSS to 1400 (for PPPoE)
builder
|> tcp_flags([:syn], [:syn, :ack, :rst, :fin])
|> set_tcp_mss(1400)
|> accept()

# Clamp to PMTU
builder
|> oif("pppoe0")
|> tcp_flags([:syn], [:syn, :ack, :rst, :fin])
|> set_tcp_mss(:pmtu)
|> accept()

Use Cases

  • PPPoE connections (typically 1492 MTU → 1452 MSS)
  • VPN tunnels with reduced MTU
  • Fixing PMTU black holes
  • WAN interface MSS clamping

set_ttl(builder \\ Expr.expr(), ttl)

Set IP TTL (Time To Live) value.

Modifies the TTL field in the IPv4 header.

Example

# Set TTL to 64
builder |> set_ttl(64) |> accept()

# Normalize TTL
builder |> set_ttl(128) |> accept()

Use Cases

  • TTL normalization (anti-fingerprinting)
  • Extending TTL for specific traffic
  • Router hop limit enforcement

synproxy(builder \\ Expr.expr(), opts \\ [])

@spec synproxy(
  NFTables.Expr.t(),
  keyword()
) :: NFTables.Expr.t()

Enable SYN proxy for DDoS protection.

Implements SYN cookie-based protection against SYN flood attacks. The firewall handles the TCP handshake, protecting backend servers.

Options

  • :mss - Maximum segment size (default: auto)
  • :wscale - Window scaling (default: auto)
  • :sack_perm - SACK permitted (default: auto)
  • :timestamp - TCP timestamp (default: auto)

Example

# Basic synproxy
builder
|> tcp()
|> dport(80)
|> tcp_flags([:syn], [:syn, :ack, :rst, :fin])
|> synproxy()

# With custom MSS
builder
|> tcp()
|> dport(443)
|> tcp_flags([:syn], [:syn, :ack, :rst, :fin])
|> synproxy(mss: 1460)

# Full options
builder
|> tcp()
|> dport(22)
|> tcp_flags([:syn], [:syn, :ack, :rst, :fin])
|> synproxy(mss: 1460, wscale: 7, sack_perm: true, timestamp: true)

Use Cases

  • SYN flood DDoS protection
  • High-volume web servers
  • Public-facing services
  • Attack mitigation

WARNING

  • Only use on SYN packets (tcp_flags required)
  • May break some TCP options
  • Backend servers see firewall as client

tproxy(builder \\ Expr.expr(), opts)

@spec tproxy(
  NFTables.Expr.t(),
  keyword()
) :: NFTables.Expr.t()

Redirect to local transparent proxy (TPROXY).

Redirects packets to a local socket without changing the destination address. Used for transparent proxy setups where the proxy needs to see the original destination.

Parameters

  • builder - Match builder
  • opts - Options:
    • :to - Port number to redirect to (required)
    • :addr - Local IP address to redirect to (optional)
    • :family - Address family (:ipv4 or :ipv6, optional)

Examples

# Redirect HTTP to local transparent proxy on port 8080
rule()
|> tcp()
|> dport(80)
|> tproxy(to: 8080)
|> accept()

# With specific address
rule()
|> tcp()
|> dport(80)
|> tproxy(to: 8080, addr: "127.0.0.1")

# IPv6 transparent proxy
rule()
|> tcp()
|> dport(443)
|> tproxy(to: 8443, addr: "::1", family: :ipv6)

Use Cases

  • Transparent HTTP/HTTPS proxies
  • Deep packet inspection
  • Content filtering
  • Traffic monitoring without changing destinations

Requirements

  • Requires special routing and iptables setup
  • Socket must have IP_TRANSPARENT option
  • Usually combined with socket_transparent() matching
  • Requires CAP_NET_ADMIN capability

Typical Transparent Proxy Setup

# 1. Mark packets with existing transparent socket
prerouting_mark = rule()
  |> tcp()
  |> socket_transparent()
  |> set_mark(1)
  |> accept()

# 2. Redirect unmarked packets to proxy
prerouting_tproxy = rule()
  |> tcp()
  |> dport(80)
  |> mark(0)
  |> tproxy(to: 8080)

# 3. Accept marked packets in input
input_accept = rule()
  |> mark(1)
  |> accept()