public inbox for netfilter@vger.kernel.org
 help / color / mirror / Atom feed
* [PROPOSAL] New wiki page: Simple rule management with JSON
@ 2025-11-06  9:29 Alexandre Knecht
  2025-11-06 23:15 ` Florian Westphal
  0 siblings, 1 reply; 2+ messages in thread
From: Alexandre Knecht @ 2025-11-06  9:29 UTC (permalink / raw)
  To: netfilter

[-- Attachment #1: Type: text/plain, Size: 2113 bytes --]

Hello,

I would like to propose a new wiki page that provides user-friendly
documentation
for nftables JSON rule management. This complements the technical reference in
libnftables-json(5) with practical examples and beginner-friendly explanations.

## Background

While implementing JSON-based nftables automation, I found that the existing
documentation, while technically accurate, lacks practical examples and clear
explanations of:

1. The difference between explicit commands ({"add": {"rule": ...}}) and
   implicit format ({"rule": ...})
2. The semantics of ADD vs INSERT with handle positioning
3. Export/import compatibility considerations
4. Common expression and statement patterns in JSON

## Proposed Page

The proposed page "Simple rule management with JSON" would mirror the structure
of the existing "Simple rule management" page but focus on JSON API usage.

**Key sections:**
- Understanding JSON command structure (explicit vs implicit)
- Basic operations (add, insert, delete, replace, flush)
- Rule positioning with handles (ADD after, INSERT before)
- Common expressions and statements in JSON format
- Export/import compatibility
- Complete firewall example
- Debugging tips

The full content is available at:
[Attach: json_rule_management_wiki.md]

## Benefit

This documentation would:
- Lower the barrier to entry for JSON API users
- Complement the technical reference with practical examples
- Clarify common confusion points (especially handle positioning)
- Provide copy-paste examples for common use cases

I'm happy to work with wiki maintainers to refine the content and format it
appropriately for the wiki.

## Related Patches

This proposal accompanies two patches:
- [nf,v3] parser_json: support handle for rule positioning in JSON add
rule - https://patchwork.ozlabs.org/project/netfilter-devel/list/?series=481124
- [nf,v3,2/2] doc: clarify JSON rule positioning with handle field -
https://patchwork.ozlabs.org/project/netfilter-devel/list/?series=481127

These patches implement and document handle-based rule positioning in
the JSON API.

Best regards,
Alexandre Knecht

[-- Attachment #2: json_rule_management_wiki.md --]
[-- Type: text/markdown, Size: 11205 bytes --]

# Simple rule management with JSON

This page explains how to manage nftables rules using the JSON API. The JSON API provides a programmatic interface to nftables, which is especially useful for automation and integration with other tools.

## Understanding JSON command structure

The nftables JSON API has two formats:

### Explicit commands (for rule manipulation)
```json
{"nftables": [{"add": {"rule": {...}}}]}
{"nftables": [{"insert": {"rule": {...}}}]}
{"nftables": [{"delete": {"rule": {...}}}]}
{"nftables": [{"replace": {"rule": {...}}}]}
```

### Implicit format (for export/import)
```json
{"nftables": [{"rule": {...}}]}
```

**IMPORTANT**: The command wrapper (`"add"`, `"insert"`, etc.) matters! It determines how the rule is processed.

## Basic rule structure

A JSON rule has this basic structure:

```json
{
  "rule": {
    "family": "ip",
    "table": "filter",
    "chain": "output",
    "expr": [
      // expressions (match criteria)
      // statements (actions)
    ]
  }
}
```

## Listing rules with handles

To see rule handles in JSON format:

```bash
nft -j -a list ruleset
```

The `-a` flag includes handles, which you'll need for positioning, replacing, or deleting rules.

Example output:
```json
{
  "nftables": [
    {
      "rule": {
        "family": "inet",
        "table": "filter",
        "chain": "input",
        "handle": 5,
        "expr": [
          {"match": {"op": "==", "left": {"payload": {"protocol": "tcp", "field": "dport"}}, "right": 22}},
          {"accept": null}
        ]
      }
    }
  ]
}
```

## Adding rules (append to end)

**Command**: `"add"`
**Behavior**: Appends rule to the end of the chain

```bash
nft -j -f - << 'EOF'
{
  "nftables": [
    {
      "add": {
        "rule": {
          "family": "inet",
          "table": "filter",
          "chain": "input",
          "expr": [
            {
              "match": {
                "op": "==",
                "left": {"payload": {"protocol": "tcp", "field": "dport"}},
                "right": 80
              }
            },
            {"accept": null}
          ]
        }
      }
    }
  ]
}
EOF
```

## Inserting rules (prepend to beginning)

**Command**: `"insert"`
**Behavior**: Inserts rule at the beginning of the chain

```bash
nft -j -f - << 'EOF'
{
  "nftables": [
    {
      "insert": {
        "rule": {
          "family": "inet",
          "table": "filter",
          "chain": "input",
          "expr": [
            {
              "match": {
                "op": "==",
                "left": {"payload": {"protocol": "tcp", "field": "dport"}},
                "right": 443
              }
            },
            {"accept": null}
          ]
        }
      }
    }
  ]
}
EOF
```

## Positioning rules with handles

You can position rules relative to existing rules using the `"handle"` field.

### Add rule AFTER a specific handle

**Command**: `"add"` with `"handle"`
**Behavior**: Inserts rule immediately after the specified handle

```bash
# Suppose handle 5 exists, this adds a rule after it
nft -j -f - << 'EOF'
{
  "nftables": [
    {
      "add": {
        "rule": {
          "family": "inet",
          "table": "filter",
          "chain": "input",
          "handle": 5,
          "expr": [
            {
              "match": {
                "op": "==",
                "left": {"payload": {"protocol": "tcp", "field": "dport"}},
                "right": 8080
              }
            },
            {"accept": null}
          ]
        }
      }
    }
  ]
}
EOF
```

**Result**: New rule is inserted after handle 5

### Insert rule BEFORE a specific handle

**Command**: `"insert"` with `"handle"`
**Behavior**: Inserts rule immediately before the specified handle

```bash
# This inserts a rule before handle 5
nft -j -f - << 'EOF'
{
  "nftables": [
    {
      "insert": {
        "rule": {
          "family": "inet",
          "table": "filter",
          "chain": "input",
          "handle": 5,
          "expr": [
            {
              "match": {
                "op": "==",
                "left": {"payload": {"protocol": "tcp", "field": "dport"}},
                "right": 9090
              }
            },
            {"accept": null}
          ]
        }
      }
    }
  ]
}
EOF
```

**Result**: New rule is inserted before handle 5

### Important note about positioning

When you add multiple rules at the same handle position, they are always positioned relative to the **original handle**, not the previously inserted rule.

Example:
```
Initial: [rule1(h:2), rule2(h:3), rule3(h:4)]

Add rule A after handle 2:
Result: [rule1(h:2), ruleA, rule2(h:3), rule3(h:4)]

Add rule B after handle 2 again:
Result: [rule1(h:2), ruleB, ruleA, rule2(h:3), rule3(h:4)]
```

Rule B is inserted after the original handle 2 (rule1), not after rule A.

## Deleting rules

**Command**: `"delete"` with `"handle"`
**Behavior**: Removes the rule with the specified handle

```bash
nft -j -f - << 'EOF'
{
  "nftables": [
    {
      "delete": {
        "rule": {
          "family": "inet",
          "table": "filter",
          "chain": "input",
          "handle": 5
        }
      }
    }
  ]
}
EOF
```

**Note**: You can only delete by handle. You cannot delete by matching rule content in JSON.

## Replacing rules

**Command**: `"replace"` with `"handle"`
**Behavior**: Replaces the rule at the specified handle with new content

```bash
nft -j -f - << 'EOF'
{
  "nftables": [
    {
      "replace": {
        "rule": {
          "family": "inet",
          "table": "filter",
          "chain": "input",
          "handle": 5,
          "expr": [
            {
              "match": {
                "op": "==",
                "left": {"payload": {"protocol": "tcp", "field": "dport"}},
                "right": 443
              }
            },
            {"drop": null}
          ]
        }
      }
    }
  ]
}
EOF
```

The rule at handle 5 is replaced with the new rule. The handle number remains the same.

## Flushing chains

Remove all rules from a chain:

```bash
nft -j -f - << 'EOF'
{
  "nftables": [
    {
      "flush": {
        "chain": {
          "family": "inet",
          "table": "filter",
          "name": "input"
        }
      }
    }
  ]
}
EOF
```

## Common expressions in JSON

### Match TCP destination port

```json
{
  "match": {
    "op": "==",
    "left": {"payload": {"protocol": "tcp", "field": "dport"}},
    "right": 80
  }
}
```

### Match IP source address

```json
{
  "match": {
    "op": "==",
    "left": {"payload": {"protocol": "ip", "field": "saddr"}},
    "right": "192.168.1.100"
  }
}
```

### Match IP address range

```json
{
  "match": {
    "op": "==",
    "left": {"payload": {"protocol": "ip", "field": "daddr"}},
    "right": {"range": ["192.168.1.1", "192.168.1.254"]}
  }
}
```

### Match connection state

```json
{
  "match": {
    "op": "in",
    "left": {"ct": {"key": "state"}},
    "right": ["established", "related"]
  }
}
```

## Common statements (actions) in JSON

### Accept

```json
{"accept": null}
```

### Drop

```json
{"drop": null}
```

### Counter

```json
{"counter": {"packets": 0, "bytes": 0}}
```

Or just:
```json
{"counter": null}
```

### Log

```json
{"log": {"prefix": "Firewall: "}}
```

### Reject

```json
{"reject": null}
```

### Jump to another chain

```json
{"jump": {"target": "chain-name"}}
```

## Export/Import compatibility

The implicit format (without command wrappers) is used for export/import:

```bash
# Export
nft -j list ruleset > rules.json

# Import
nft -j -f rules.json
```

**IMPORTANT**: In the implicit format, handles in rules are **ignored** during import. This ensures that exported rulesets can be imported into different systems where handle numbers may differ.

Example implicit format:
```json
{
  "nftables": [
    {"table": {"family": "inet", "name": "filter"}},
    {"chain": {"family": "inet", "table": "filter", "name": "input"}},
    {"rule": {
      "family": "inet",
      "table": "filter",
      "chain": "input",
      "handle": 999,
      "expr": [
        {"match": {"op": "==", "left": {"payload": {"protocol": "tcp", "field": "dport"}}, "right": 22}},
        {"accept": null}
      ]
    }}
  ]
}
```

When imported, the `"handle": 999` is ignored, and a new handle is assigned automatically.

## Complete example: Building a firewall

```bash
nft -j -f - << 'EOF'
{
  "nftables": [
    {"flush": {"ruleset": null}},
    {"add": {"table": {"family": "inet", "name": "filter"}}},
    {"add": {"chain": {"family": "inet", "table": "filter", "name": "input", "type": "filter", "hook": "input", "prio": 0, "policy": "drop"}}},
    {"add": {"rule": {"family": "inet", "table": "filter", "chain": "input", "expr": [
      {"match": {"op": "in", "left": {"ct": {"key": "state"}}, "right": ["established", "related"]}},
      {"accept": null}
    ]}}},
    {"add": {"rule": {"family": "inet", "table": "filter", "chain": "input", "expr": [
      {"match": {"op": "==", "left": {"meta": {"key": "iifname"}}, "right": "lo"}},
      {"accept": null}
    ]}}},
    {"add": {"rule": {"family": "inet", "table": "filter", "chain": "input", "expr": [
      {"match": {"op": "==", "left": {"payload": {"protocol": "tcp", "field": "dport"}}, "right": 22}},
      {"accept": null}
    ]}}},
    {"add": {"rule": {"family": "inet", "table": "filter", "chain": "input", "expr": [
      {"match": {"op": "==", "left": {"payload": {"protocol": "tcp", "field": "dport"}}, "right": 80}},
      {"accept": null}
    ]}}},
    {"add": {"rule": {"family": "inet", "table": "filter", "chain": "input", "expr": [
      {"match": {"op": "==", "left": {"payload": {"protocol": "tcp", "field": "dport"}}, "right": 443}},
      {"accept": null}
    ]}}}
  ]
}
EOF
```

This creates a basic firewall that:
1. Flushes existing ruleset
2. Creates table "filter"
3. Creates chain "input" with default policy DROP
4. Allows established/related connections
5. Allows loopback traffic
6. Allows SSH (port 22)
7. Allows HTTP (port 80)
8. Allows HTTPS (port 443)

## Debugging JSON

To see what JSON nftables generates from CLI commands:

```bash
# Run a command and see the JSON equivalent
nft -j add rule inet filter input tcp dport 22 accept
```

This helps you learn the JSON syntax by seeing how CLI commands translate to JSON.

## Summary of commands

| Operation | Command | With Handle | Behavior |
|-----------|---------|-------------|----------|
| Append to end | `"add"` | No | Adds rule at end of chain |
| Add after rule | `"add"` | Yes | Adds rule after specified handle |
| Prepend to beginning | `"insert"` | No | Adds rule at beginning of chain |
| Insert before rule | `"insert"` | Yes | Adds rule before specified handle |
| Delete rule | `"delete"` | Yes (required) | Removes rule by handle |
| Replace rule | `"replace"` | Yes (required) | Replaces rule at handle |
| Flush chain | `"flush"` | No | Removes all rules from chain |

## See also

- [Simple rule management](https://wiki.nftables.org/wiki-nftables/index.php/Simple_rule_management) - CLI version
- [Quick reference-nftables in 10 minutes](https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes)

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PROPOSAL] New wiki page: Simple rule management with JSON
  2025-11-06  9:29 [PROPOSAL] New wiki page: Simple rule management with JSON Alexandre Knecht
@ 2025-11-06 23:15 ` Florian Westphal
  0 siblings, 0 replies; 2+ messages in thread
From: Florian Westphal @ 2025-11-06 23:15 UTC (permalink / raw)
  To: Alexandre Knecht; +Cc: netfilter

> 
> I would like to propose a new wiki page that provides user-friendly
> documentation
> for nftables JSON rule management. This complements the technical reference in
> libnftables-json(5) with practical examples and beginner-friendly explanations.

Thanks for writing this!

I will make an account for you so you can add it yourself.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2025-11-06 23:15 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-06  9:29 [PROPOSAL] New wiki page: Simple rule management with JSON Alexandre Knecht
2025-11-06 23:15 ` Florian Westphal

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox