Development
This commit is contained in:
parent
6d8be4845e
commit
bc623b14fc
5 changed files with 64 additions and 49 deletions
|
|
@ -33,8 +33,8 @@ def _parse_entry():
|
||||||
protocol = sanitize.filtervalue(request.form.get('protocol', ''), validate.VALID_PROTOCOLS)
|
protocol = sanitize.filtervalue(request.form.get('protocol', ''), validate.VALID_PROTOCOLS)
|
||||||
src_raw = request.form.get('src_ip_or_subnet', '').strip()
|
src_raw = request.form.get('src_ip_or_subnet', '').strip()
|
||||||
dst_raw = request.form.get('dst_ip_or_subnet', '').strip()
|
dst_raw = request.form.get('dst_ip_or_subnet', '').strip()
|
||||||
dst_port_min_raw = request.form.get('dst_port_min', '').strip()
|
dest_port_start_raw = request.form.get('dest_port_start', '').strip()
|
||||||
dst_port_max_raw = request.form.get('dst_port_max', '').strip()
|
dest_port_end_raw = request.form.get('dest_port_end', '').strip()
|
||||||
|
|
||||||
if not protocol:
|
if not protocol:
|
||||||
flash(f'The configuration has not been saved because the protocol is invalid. '
|
flash(f'The configuration has not been saved because the protocol is invalid. '
|
||||||
|
|
@ -57,21 +57,21 @@ def _parse_entry():
|
||||||
flash(f'The configuration has not been saved because "{dst_raw}" is not a valid IP address or subnet.', 'error')
|
flash(f'The configuration has not been saved because "{dst_raw}" is not a valid IP address or subnet.', 'error')
|
||||||
return None, True
|
return None, True
|
||||||
|
|
||||||
dst_port_min = ''
|
dest_port_start = ''
|
||||||
if dst_port_min_raw:
|
if dest_port_start_raw:
|
||||||
dst_port_min = validate.port(dst_port_min_raw)
|
dest_port_start = validate.port(dest_port_start_raw)
|
||||||
if not dst_port_min:
|
if not dest_port_start:
|
||||||
flash(f'The configuration has not been saved because "{dst_port_min_raw}" is not a valid port number (1-65535).', 'error')
|
flash(f'The configuration has not been saved because "{dest_port_start_raw}" is not a valid port number (1-65535).', 'error')
|
||||||
return None, True
|
return None, True
|
||||||
|
|
||||||
dst_port_max = ''
|
dest_port_end = ''
|
||||||
if dst_port_max_raw:
|
if dest_port_end_raw:
|
||||||
dst_port_max = validate.port(dst_port_max_raw)
|
dest_port_end = validate.port(dest_port_end_raw)
|
||||||
if not dst_port_max:
|
if not dest_port_end:
|
||||||
flash(f'The configuration has not been saved because "{dst_port_max_raw}" is not a valid port number (1-65535).', 'error')
|
flash(f'The configuration has not been saved because "{dest_port_end_raw}" is not a valid port number (1-65535).', 'error')
|
||||||
return None, True
|
return None, True
|
||||||
|
|
||||||
if dst_port_min and dst_port_max and int(dst_port_min) > int(dst_port_max):
|
if dest_port_start and dest_port_end and int(dest_port_start) > int(dest_port_end):
|
||||||
flash('Port range min must not be greater than max.', 'error')
|
flash('Port range min must not be greater than max.', 'error')
|
||||||
return None, True
|
return None, True
|
||||||
|
|
||||||
|
|
@ -80,8 +80,8 @@ def _parse_entry():
|
||||||
'protocol': protocol,
|
'protocol': protocol,
|
||||||
'src_ip_or_subnet': src,
|
'src_ip_or_subnet': src,
|
||||||
'dst_ip_or_subnet': dst,
|
'dst_ip_or_subnet': dst,
|
||||||
'dst_port_min': dst_port_min,
|
'dest_port_start': dest_port_start,
|
||||||
'dst_port_max': dst_port_max,
|
'dest_port_end': dest_port_end,
|
||||||
'enabled': True,
|
'enabled': True,
|
||||||
}, None
|
}, None
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,13 +39,13 @@
|
||||||
"class": "col-mono"
|
"class": "col-mono"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Port Min",
|
"label": "Port Start",
|
||||||
"field": "dst_port_min",
|
"field": "dest_port_start",
|
||||||
"class": "col-mono col-narrow"
|
"class": "col-mono col-narrow"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Port Max",
|
"label": "Port End",
|
||||||
"field": "dst_port_max",
|
"field": "dest_port_end",
|
||||||
"class": "col-mono col-narrow"
|
"class": "col-mono col-narrow"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -80,11 +80,11 @@
|
||||||
"input_type": "text"
|
"input_type": "text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"col": "dst_port_min",
|
"col": "dest_port_start",
|
||||||
"input_type": "number"
|
"input_type": "number"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"col": "dst_port_max",
|
"col": "dest_port_end",
|
||||||
"input_type": "number"
|
"input_type": "number"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -159,7 +159,7 @@
|
||||||
{
|
{
|
||||||
"type": "field",
|
"type": "field",
|
||||||
"label": "Dest Port Range Start",
|
"label": "Dest Port Range Start",
|
||||||
"name": "dst_port_min",
|
"name": "dest_port_start",
|
||||||
"input_type": "number",
|
"input_type": "number",
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"max": 65535
|
"max": 65535
|
||||||
|
|
@ -167,7 +167,7 @@
|
||||||
{
|
{
|
||||||
"type": "field",
|
"type": "field",
|
||||||
"label": "Dest Port Range End",
|
"label": "Dest Port Range End",
|
||||||
"name": "dst_port_max",
|
"name": "dest_port_end",
|
||||||
"input_type": "number",
|
"input_type": "number",
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"max": 65535
|
"max": 65535
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,8 @@
|
||||||
"protocol": "tcp",
|
"protocol": "tcp",
|
||||||
"src_ip_or_subnet": "192.168.10.3",
|
"src_ip_or_subnet": "192.168.10.3",
|
||||||
"dst_ip_or_subnet": "192.168.1.20",
|
"dst_ip_or_subnet": "192.168.1.20",
|
||||||
"dst_port": 32400
|
"dest_port_start": 32400,
|
||||||
|
"dest_port_end": 32400
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "IoT Streaming Box -> Plex",
|
"description": "IoT Streaming Box -> Plex",
|
||||||
|
|
@ -83,7 +84,8 @@
|
||||||
"protocol": "tcp",
|
"protocol": "tcp",
|
||||||
"src_ip_or_subnet": "192.168.10.4",
|
"src_ip_or_subnet": "192.168.10.4",
|
||||||
"dst_ip_or_subnet": "192.168.1.20",
|
"dst_ip_or_subnet": "192.168.1.20",
|
||||||
"dst_port": 32400
|
"dest_port_start": 32400,
|
||||||
|
"dest_port_end": 32400
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Kids -> Plex",
|
"description": "Kids -> Plex",
|
||||||
|
|
@ -91,7 +93,8 @@
|
||||||
"protocol": "both",
|
"protocol": "both",
|
||||||
"src_ip_or_subnet": "192.168.30.0/24",
|
"src_ip_or_subnet": "192.168.30.0/24",
|
||||||
"dst_ip_or_subnet": "192.168.1.20",
|
"dst_ip_or_subnet": "192.168.1.20",
|
||||||
"dst_port": 32400
|
"dest_port_start": 32400,
|
||||||
|
"dest_port_end": 32400
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Kids -> SMB",
|
"description": "Kids -> SMB",
|
||||||
|
|
@ -99,7 +102,8 @@
|
||||||
"protocol": "tcp",
|
"protocol": "tcp",
|
||||||
"src_ip_or_subnet": "192.168.30.0/24",
|
"src_ip_or_subnet": "192.168.30.0/24",
|
||||||
"dst_ip_or_subnet": "192.168.1.20",
|
"dst_ip_or_subnet": "192.168.1.20",
|
||||||
"dst_port": 445
|
"dest_port_start": 445,
|
||||||
|
"dest_port_end": 445
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Kids -> Game Server",
|
"description": "Kids -> Game Server",
|
||||||
|
|
@ -107,7 +111,8 @@
|
||||||
"protocol": "tcp",
|
"protocol": "tcp",
|
||||||
"src_ip_or_subnet": "192.168.30.0/24",
|
"src_ip_or_subnet": "192.168.30.0/24",
|
||||||
"dst_ip_or_subnet": "192.168.1.20",
|
"dst_ip_or_subnet": "192.168.1.20",
|
||||||
"dst_port": 25565
|
"dest_port_start": 25565,
|
||||||
|
"dest_port_end": 25565
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Kids -> Web Server HTTP",
|
"description": "Kids -> Web Server HTTP",
|
||||||
|
|
@ -115,7 +120,8 @@
|
||||||
"protocol": "tcp",
|
"protocol": "tcp",
|
||||||
"src_ip_or_subnet": "192.168.30.0/24",
|
"src_ip_or_subnet": "192.168.30.0/24",
|
||||||
"dst_ip_or_subnet": "192.168.1.20",
|
"dst_ip_or_subnet": "192.168.1.20",
|
||||||
"dst_port": 80
|
"dest_port_start": 80,
|
||||||
|
"dest_port_end": 80
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Kids -> Web Server HTTPS",
|
"description": "Kids -> Web Server HTTPS",
|
||||||
|
|
@ -123,7 +129,8 @@
|
||||||
"protocol": "tcp",
|
"protocol": "tcp",
|
||||||
"src_ip_or_subnet": "192.168.30.0/24",
|
"src_ip_or_subnet": "192.168.30.0/24",
|
||||||
"dst_ip_or_subnet": "192.168.1.20",
|
"dst_ip_or_subnet": "192.168.1.20",
|
||||||
"dst_port": 443
|
"dest_port_start": 443,
|
||||||
|
"dest_port_end": 443
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Trusted -> Printer (RAW)",
|
"description": "Trusted -> Printer (RAW)",
|
||||||
|
|
@ -131,7 +138,8 @@
|
||||||
"protocol": "tcp",
|
"protocol": "tcp",
|
||||||
"src_ip_or_subnet": "192.168.1.0/24",
|
"src_ip_or_subnet": "192.168.1.0/24",
|
||||||
"dst_ip_or_subnet": "192.168.10.2",
|
"dst_ip_or_subnet": "192.168.10.2",
|
||||||
"dst_port": 9100
|
"dest_port_start": 9100,
|
||||||
|
"dest_port_end": 9100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Trusted -> Printer (IPP)",
|
"description": "Trusted -> Printer (IPP)",
|
||||||
|
|
@ -139,7 +147,8 @@
|
||||||
"protocol": "tcp",
|
"protocol": "tcp",
|
||||||
"src_ip_or_subnet": "192.168.1.0/24",
|
"src_ip_or_subnet": "192.168.1.0/24",
|
||||||
"dst_ip_or_subnet": "192.168.10.2",
|
"dst_ip_or_subnet": "192.168.10.2",
|
||||||
"dst_port": 631
|
"dest_port_start": 631,
|
||||||
|
"dest_port_end": 631
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Kids -> Printer (RAW)",
|
"description": "Kids -> Printer (RAW)",
|
||||||
|
|
@ -147,7 +156,8 @@
|
||||||
"protocol": "tcp",
|
"protocol": "tcp",
|
||||||
"src_ip_or_subnet": "192.168.30.0/24",
|
"src_ip_or_subnet": "192.168.30.0/24",
|
||||||
"dst_ip_or_subnet": "192.168.10.2",
|
"dst_ip_or_subnet": "192.168.10.2",
|
||||||
"dst_port": 9100
|
"dest_port_start": 9100,
|
||||||
|
"dest_port_end": 9100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Kids -> Printer (IPP)",
|
"description": "Kids -> Printer (IPP)",
|
||||||
|
|
@ -155,7 +165,8 @@
|
||||||
"protocol": "tcp",
|
"protocol": "tcp",
|
||||||
"src_ip_or_subnet": "192.168.30.0/24",
|
"src_ip_or_subnet": "192.168.30.0/24",
|
||||||
"dst_ip_or_subnet": "192.168.10.2",
|
"dst_ip_or_subnet": "192.168.10.2",
|
||||||
"dst_port": 631
|
"dest_port_start": 631,
|
||||||
|
"dest_port_end": 631
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Guest -> Printer (RAW)",
|
"description": "Guest -> Printer (RAW)",
|
||||||
|
|
@ -163,7 +174,8 @@
|
||||||
"protocol": "tcp",
|
"protocol": "tcp",
|
||||||
"src_ip_or_subnet": "192.168.20.0/24",
|
"src_ip_or_subnet": "192.168.20.0/24",
|
||||||
"dst_ip_or_subnet": "192.168.10.2",
|
"dst_ip_or_subnet": "192.168.10.2",
|
||||||
"dst_port": 9100
|
"dest_port_start": 9100,
|
||||||
|
"dest_port_end": 9100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Guest -> Printer (IPP)",
|
"description": "Guest -> Printer (IPP)",
|
||||||
|
|
@ -171,7 +183,8 @@
|
||||||
"protocol": "tcp",
|
"protocol": "tcp",
|
||||||
"src_ip_or_subnet": "192.168.20.0/24",
|
"src_ip_or_subnet": "192.168.20.0/24",
|
||||||
"dst_ip_or_subnet": "192.168.10.2",
|
"dst_ip_or_subnet": "192.168.10.2",
|
||||||
"dst_port": 631
|
"dest_port_start": 631,
|
||||||
|
"dest_port_end": 631
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "VPN -> SSH + Rsync",
|
"description": "VPN -> SSH + Rsync",
|
||||||
|
|
@ -179,7 +192,8 @@
|
||||||
"protocol": "tcp",
|
"protocol": "tcp",
|
||||||
"src_ip_or_subnet": "192.168.40.0/24",
|
"src_ip_or_subnet": "192.168.40.0/24",
|
||||||
"dst_ip_or_subnet": "192.168.1.20",
|
"dst_ip_or_subnet": "192.168.1.20",
|
||||||
"dst_port": 22
|
"dest_port_start": 22,
|
||||||
|
"dest_port_end": 22
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "VPN -> SMB",
|
"description": "VPN -> SMB",
|
||||||
|
|
@ -187,7 +201,8 @@
|
||||||
"protocol": "tcp",
|
"protocol": "tcp",
|
||||||
"src_ip_or_subnet": "192.168.40.0/24",
|
"src_ip_or_subnet": "192.168.40.0/24",
|
||||||
"dst_ip_or_subnet": "192.168.1.20",
|
"dst_ip_or_subnet": "192.168.1.20",
|
||||||
"dst_port": 445
|
"dest_port_start": 445,
|
||||||
|
"dest_port_end": 445
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Trusted -> Kids (LAN Gaming)",
|
"description": "Trusted -> Kids (LAN Gaming)",
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ Validation:
|
||||||
Generates DNAT rules only; no forward chain rules needed
|
Generates DNAT rules only; no forward chain rules needed
|
||||||
since redirect_to is always a local IP (INPUT handles it).
|
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
|
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.
|
Protocol must be tcp, udp, or both.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
@ -1560,8 +1560,8 @@ def build_nft_config(data, dry_run=False):
|
||||||
for r in all_except:
|
for r in all_except:
|
||||||
src = r["src_ip_or_subnet"]
|
src = r["src_ip_or_subnet"]
|
||||||
dst = r.get("dst_ip_or_subnet") or r.get("dst_ip", "")
|
dst = r.get("dst_ip_or_subnet") or r.get("dst_ip", "")
|
||||||
min_p = r.get("dst_port_min") or r.get("dst_port")
|
min_p = r.get("dest_port_start") or r.get("dst_port")
|
||||||
max_p = r.get("dst_port_max")
|
max_p = r.get("dest_port_end")
|
||||||
if min_p and max_p and str(min_p) != str(max_p):
|
if min_p and max_p and str(min_p) != str(max_p):
|
||||||
port_spec = f"{min_p}-{max_p}"
|
port_spec = f"{min_p}-{max_p}"
|
||||||
elif min_p:
|
elif min_p:
|
||||||
|
|
@ -1739,8 +1739,8 @@ def apply_nftables(data, dry_run=False):
|
||||||
for r in active_except:
|
for r in active_except:
|
||||||
src = r["src_ip_or_subnet"]
|
src = r["src_ip_or_subnet"]
|
||||||
dst = r.get("dst_ip_or_subnet") or r.get("dst_ip", "")
|
dst = r.get("dst_ip_or_subnet") or r.get("dst_ip", "")
|
||||||
min_p = r.get("dst_port_min") or r.get("dst_port")
|
min_p = r.get("dest_port_start") or r.get("dst_port")
|
||||||
max_p = r.get("dst_port_max")
|
max_p = r.get("dest_port_end")
|
||||||
if min_p and max_p and str(min_p) != str(max_p):
|
if min_p and max_p and str(min_p) != str(max_p):
|
||||||
port_str = f":{min_p}-{max_p}"
|
port_str = f":{min_p}-{max_p}"
|
||||||
elif min_p:
|
elif min_p:
|
||||||
|
|
|
||||||
|
|
@ -851,15 +851,15 @@ def validate_config(data):
|
||||||
if not ipv4_or_cidr(dst):
|
if not ipv4_or_cidr(dst):
|
||||||
errors.append(f"{label}: dst_ip_or_subnet '{dst}' is not a valid "
|
errors.append(f"{label}: dst_ip_or_subnet '{dst}' is not a valid "
|
||||||
f"IPv4 address or network.")
|
f"IPv4 address or network.")
|
||||||
if r.get("dst_port_min"):
|
if r.get("dest_port_start"):
|
||||||
nat_check_port(f"{label} dst_port_min", r.get("dst_port_min"))
|
nat_check_port(f"{label} dest_port_start", r.get("dest_port_start"))
|
||||||
if r.get("dst_port_max"):
|
if r.get("dest_port_end"):
|
||||||
nat_check_port(f"{label} dst_port_max", r.get("dst_port_max"))
|
nat_check_port(f"{label} dest_port_end", r.get("dest_port_end"))
|
||||||
min_p, max_p = r.get("dst_port_min", ""), r.get("dst_port_max", "")
|
min_p, max_p = r.get("dest_port_start", ""), r.get("dest_port_end", "")
|
||||||
if min_p and max_p:
|
if min_p and max_p:
|
||||||
try:
|
try:
|
||||||
if int(min_p) > int(max_p):
|
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):
|
except (ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue