Development

This commit is contained in:
Matthew Grotke 2026-06-01 00:54:59 -04:00
parent 6d8be4845e
commit bc623b14fc
5 changed files with 64 additions and 49 deletions

View file

@ -75,7 +75,8 @@
"protocol": "tcp",
"src_ip_or_subnet": "192.168.10.3",
"dst_ip_or_subnet": "192.168.1.20",
"dst_port": 32400
"dest_port_start": 32400,
"dest_port_end": 32400
},
{
"description": "IoT Streaming Box -> Plex",
@ -83,7 +84,8 @@
"protocol": "tcp",
"src_ip_or_subnet": "192.168.10.4",
"dst_ip_or_subnet": "192.168.1.20",
"dst_port": 32400
"dest_port_start": 32400,
"dest_port_end": 32400
},
{
"description": "Kids -> Plex",
@ -91,7 +93,8 @@
"protocol": "both",
"src_ip_or_subnet": "192.168.30.0/24",
"dst_ip_or_subnet": "192.168.1.20",
"dst_port": 32400
"dest_port_start": 32400,
"dest_port_end": 32400
},
{
"description": "Kids -> SMB",
@ -99,7 +102,8 @@
"protocol": "tcp",
"src_ip_or_subnet": "192.168.30.0/24",
"dst_ip_or_subnet": "192.168.1.20",
"dst_port": 445
"dest_port_start": 445,
"dest_port_end": 445
},
{
"description": "Kids -> Game Server",
@ -107,7 +111,8 @@
"protocol": "tcp",
"src_ip_or_subnet": "192.168.30.0/24",
"dst_ip_or_subnet": "192.168.1.20",
"dst_port": 25565
"dest_port_start": 25565,
"dest_port_end": 25565
},
{
"description": "Kids -> Web Server HTTP",
@ -115,7 +120,8 @@
"protocol": "tcp",
"src_ip_or_subnet": "192.168.30.0/24",
"dst_ip_or_subnet": "192.168.1.20",
"dst_port": 80
"dest_port_start": 80,
"dest_port_end": 80
},
{
"description": "Kids -> Web Server HTTPS",
@ -123,7 +129,8 @@
"protocol": "tcp",
"src_ip_or_subnet": "192.168.30.0/24",
"dst_ip_or_subnet": "192.168.1.20",
"dst_port": 443
"dest_port_start": 443,
"dest_port_end": 443
},
{
"description": "Trusted -> Printer (RAW)",
@ -131,7 +138,8 @@
"protocol": "tcp",
"src_ip_or_subnet": "192.168.1.0/24",
"dst_ip_or_subnet": "192.168.10.2",
"dst_port": 9100
"dest_port_start": 9100,
"dest_port_end": 9100
},
{
"description": "Trusted -> Printer (IPP)",
@ -139,7 +147,8 @@
"protocol": "tcp",
"src_ip_or_subnet": "192.168.1.0/24",
"dst_ip_or_subnet": "192.168.10.2",
"dst_port": 631
"dest_port_start": 631,
"dest_port_end": 631
},
{
"description": "Kids -> Printer (RAW)",
@ -147,7 +156,8 @@
"protocol": "tcp",
"src_ip_or_subnet": "192.168.30.0/24",
"dst_ip_or_subnet": "192.168.10.2",
"dst_port": 9100
"dest_port_start": 9100,
"dest_port_end": 9100
},
{
"description": "Kids -> Printer (IPP)",
@ -155,7 +165,8 @@
"protocol": "tcp",
"src_ip_or_subnet": "192.168.30.0/24",
"dst_ip_or_subnet": "192.168.10.2",
"dst_port": 631
"dest_port_start": 631,
"dest_port_end": 631
},
{
"description": "Guest -> Printer (RAW)",
@ -163,7 +174,8 @@
"protocol": "tcp",
"src_ip_or_subnet": "192.168.20.0/24",
"dst_ip_or_subnet": "192.168.10.2",
"dst_port": 9100
"dest_port_start": 9100,
"dest_port_end": 9100
},
{
"description": "Guest -> Printer (IPP)",
@ -171,7 +183,8 @@
"protocol": "tcp",
"src_ip_or_subnet": "192.168.20.0/24",
"dst_ip_or_subnet": "192.168.10.2",
"dst_port": 631
"dest_port_start": 631,
"dest_port_end": 631
},
{
"description": "VPN -> SSH + Rsync",
@ -179,7 +192,8 @@
"protocol": "tcp",
"src_ip_or_subnet": "192.168.40.0/24",
"dst_ip_or_subnet": "192.168.1.20",
"dst_port": 22
"dest_port_start": 22,
"dest_port_end": 22
},
{
"description": "VPN -> SMB",
@ -187,7 +201,8 @@
"protocol": "tcp",
"src_ip_or_subnet": "192.168.40.0/24",
"dst_ip_or_subnet": "192.168.1.20",
"dst_port": 445
"dest_port_start": 445,
"dest_port_end": 445
},
{
"description": "Trusted -> Kids (LAN Gaming)",

View file

@ -68,7 +68,7 @@ Validation:
Generates DNAT rules only; no forward chain rules needed
since redirect_to is always a local IP (INPUT handles it).
inter_vlan_exceptions -- src_ip_or_subnet and dst_ip_or_subnet may be a single IPv4 address
or a CIDR network. dst_port_min/dst_port_max are optional (1-65535).
or a CIDR network. dest_port_start/dest_port_end are optional (1-65535).
Protocol must be tcp, udp, or both.
Usage:
@ -1560,8 +1560,8 @@ def build_nft_config(data, dry_run=False):
for r in all_except:
src = r["src_ip_or_subnet"]
dst = r.get("dst_ip_or_subnet") or r.get("dst_ip", "")
min_p = r.get("dst_port_min") or r.get("dst_port")
max_p = r.get("dst_port_max")
min_p = r.get("dest_port_start") or r.get("dst_port")
max_p = r.get("dest_port_end")
if min_p and max_p and str(min_p) != str(max_p):
port_spec = f"{min_p}-{max_p}"
elif min_p:
@ -1739,8 +1739,8 @@ def apply_nftables(data, dry_run=False):
for r in active_except:
src = r["src_ip_or_subnet"]
dst = r.get("dst_ip_or_subnet") or r.get("dst_ip", "")
min_p = r.get("dst_port_min") or r.get("dst_port")
max_p = r.get("dst_port_max")
min_p = r.get("dest_port_start") or r.get("dst_port")
max_p = r.get("dest_port_end")
if min_p and max_p and str(min_p) != str(max_p):
port_str = f":{min_p}-{max_p}"
elif min_p:

View file

@ -851,15 +851,15 @@ def validate_config(data):
if not ipv4_or_cidr(dst):
errors.append(f"{label}: dst_ip_or_subnet '{dst}' is not a valid "
f"IPv4 address or network.")
if r.get("dst_port_min"):
nat_check_port(f"{label} dst_port_min", r.get("dst_port_min"))
if r.get("dst_port_max"):
nat_check_port(f"{label} dst_port_max", r.get("dst_port_max"))
min_p, max_p = r.get("dst_port_min", ""), r.get("dst_port_max", "")
if r.get("dest_port_start"):
nat_check_port(f"{label} dest_port_start", r.get("dest_port_start"))
if r.get("dest_port_end"):
nat_check_port(f"{label} dest_port_end", r.get("dest_port_end"))
min_p, max_p = r.get("dest_port_start", ""), r.get("dest_port_end", "")
if min_p and max_p:
try:
if int(min_p) > int(max_p):
errors.append(f"{label}: dst_port_min {min_p} is greater than dst_port_max {max_p}.")
errors.append(f"{label}: dest_port_start {min_p} is greater than dest_port_end {max_p}.")
except (ValueError, TypeError):
pass