|
1 | | -#!/bin/sh |
| 1 | +#!/usr/bin/env python |
2 | 2 |
|
3 | 3 | # |
4 | | -# Copyright (C) 2025 Nethesis S.r.l. |
| 4 | +# Copyright (C) 2026 Nethesis S.r.l. |
5 | 5 | # SPDX-License-Identifier: GPL-2.0-only |
6 | 6 | # |
7 | 7 |
|
8 | | -# |
9 | | -# DPI: generate NFT script |
10 | | -# |
| 8 | +import os |
| 9 | +import subprocess |
| 10 | + |
| 11 | +from euci import EUci |
| 12 | +from jinja2 import Environment, BaseLoader |
| 13 | + |
| 14 | +CHAIN = """ |
| 15 | +chain dpi_blocks { |
| 16 | + type filter hook prerouting priority filter + 10; policy accept; |
| 17 | +
|
| 18 | + # init is to allow kernel to set labels |
| 19 | + ct label set netify-init |
| 20 | + ct label netify-block counter {% if log_enabled %}log prefix "DPI block: " limit rate {{ log_limit }} {% endif %}drop |
| 21 | +} |
| 22 | +
|
| 23 | +""" |
| 24 | + |
| 25 | + |
| 26 | +def generate_dpi(): |
| 27 | + e_uci = EUci() |
| 28 | + template = Environment(loader=BaseLoader()).from_string(CHAIN) |
| 29 | + render = template.render( |
| 30 | + log_enabled=e_uci.get('dpi', 'config', 'log_blocked', dtype=bool, default=False), |
| 31 | + log_limit=e_uci.get('firewall', 'ns_defaults', 'rule_log_limit', dtype=str, default='1/second') |
| 32 | + ) |
| 33 | + # save to nftables directory table-pre, only if the file is changed |
| 34 | + file_path = '/usr/share/nftables.d/table-pre/dpi_blocks.nft' |
| 35 | + current = None |
| 36 | + if os.path.exists(file_path): |
| 37 | + with open(file_path, 'r') as f: |
| 38 | + current = f.read() |
| 39 | + if current != render: |
| 40 | + with open(file_path, 'w') as f: |
| 41 | + f.write(render) |
| 42 | + # reload nftables |
| 43 | + subprocess.run(['fw4', 'reload'], check=True, capture_output=True) |
11 | 44 |
|
12 | | -log_opt="" |
13 | | -if [ $(uci -q get dpi.config.log_blocked) = "1" ]; then |
14 | | - log_opt='log prefix "DPI block: "' |
15 | | - limit=$(uci -q get firewall.ns_defaults.rule_log_limit) |
16 | | - # validate limit syntax to avoid error on nft rules |
17 | | - if echo "$limit" | grep -qE '^[0-9]+/s$'; then |
18 | | - limit="${limit}econd" |
19 | | - else |
20 | | - limit="1/second" |
21 | | - fi |
22 | | -fi |
23 | | - |
24 | | -if nft list chain inet fw4 block_chain >/dev/null 2>&1; then |
25 | | - echo flush chain inet fw4 block_chain |
26 | | -fi |
27 | | - |
28 | | -echo add set inet fw4 nfa.blocks.v4 '{ type ipv4_addr . inet_proto . inet_service . ipv4_addr; size 65536; timeout 15m; }' |
29 | | -echo add chain inet fw4 block_chain '{ type filter hook forward priority -10; }' |
30 | | -if [ -n "$log_opt" ]; then |
31 | | - echo add rule inet fw4 block_chain ip saddr . ip protocol . th dport . ip daddr @nfa.blocks.v4 limit rate $limit burst 5 packets $log_opt |
32 | | -fi |
33 | | -echo add rule inet fw4 block_chain ip saddr . ip protocol . th dport . ip daddr @nfa.blocks.v4 counter drop |
| 45 | +if __name__ == "__main__": |
| 46 | + generate_dpi() |
0 commit comments