Development
This commit is contained in:
parent
9c22b6f2fd
commit
6e610f888e
10 changed files with 526 additions and 102 deletions
|
|
@ -316,23 +316,7 @@
|
|||
"dns_servers": "",
|
||||
"ntp_servers": ""
|
||||
}
|
||||
},
|
||||
"port_wrangling": [
|
||||
{
|
||||
"description": "DNS wrangling - redirect Trusted DNS to local resolver",
|
||||
"enabled": true,
|
||||
"protocol": "both",
|
||||
"dest_port": 53,
|
||||
"redirect_to": "192.168.1.1"
|
||||
},
|
||||
{
|
||||
"description": "NTP wrangling - redirect Trusted NTP to local time server",
|
||||
"enabled": false,
|
||||
"protocol": "udp",
|
||||
"dest_port": 123,
|
||||
"redirect_to": "192.168.1.1"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"vlan_id": 10,
|
||||
|
|
@ -363,23 +347,7 @@
|
|||
"dns_servers": "",
|
||||
"ntp_servers": ""
|
||||
}
|
||||
},
|
||||
"port_wrangling": [
|
||||
{
|
||||
"description": "DNS wrangling - redirect IoT DNS to local resolver",
|
||||
"enabled": true,
|
||||
"protocol": "both",
|
||||
"dest_port": 53,
|
||||
"redirect_to": "192.168.10.1"
|
||||
},
|
||||
{
|
||||
"description": "NTP wrangling - redirect IoT NTP to local time server",
|
||||
"enabled": false,
|
||||
"protocol": "udp",
|
||||
"dest_port": 123,
|
||||
"redirect_to": "192.168.10.1"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"vlan_id": 20,
|
||||
|
|
@ -410,23 +378,7 @@
|
|||
"dns_servers": "",
|
||||
"ntp_servers": ""
|
||||
}
|
||||
},
|
||||
"port_wrangling": [
|
||||
{
|
||||
"description": "DNS wrangling - redirect Guest DNS to local resolver",
|
||||
"enabled": true,
|
||||
"protocol": "both",
|
||||
"dest_port": 53,
|
||||
"redirect_to": "192.168.20.1"
|
||||
},
|
||||
{
|
||||
"description": "NTP wrangling - redirect Guest NTP to local time server",
|
||||
"enabled": false,
|
||||
"protocol": "udp",
|
||||
"dest_port": 123,
|
||||
"redirect_to": "192.168.20.1"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"vlan_id": 30,
|
||||
|
|
@ -458,23 +410,7 @@
|
|||
"dns_servers": "",
|
||||
"ntp_servers": ""
|
||||
}
|
||||
},
|
||||
"port_wrangling": [
|
||||
{
|
||||
"description": "DNS wrangling - redirect Kids DNS to local resolver",
|
||||
"enabled": true,
|
||||
"protocol": "both",
|
||||
"dest_port": 53,
|
||||
"redirect_to": "192.168.30.1"
|
||||
},
|
||||
{
|
||||
"description": "NTP wrangling - redirect Kids NTP to local time server",
|
||||
"enabled": false,
|
||||
"protocol": "udp",
|
||||
"dest_port": 123,
|
||||
"redirect_to": "192.168.30.1"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"vlan_id": 40,
|
||||
|
|
@ -505,23 +441,7 @@
|
|||
"mtu": ""
|
||||
}
|
||||
},
|
||||
"peers": [],
|
||||
"port_wrangling": [
|
||||
{
|
||||
"description": "DNS wrangling - redirect VPN DNS to local resolver",
|
||||
"enabled": true,
|
||||
"protocol": "both",
|
||||
"dest_port": 53,
|
||||
"redirect_to": "192.168.40.1"
|
||||
},
|
||||
{
|
||||
"description": "NTP wrangling - redirect VPN NTP to local time server",
|
||||
"enabled": false,
|
||||
"protocol": "udp",
|
||||
"dest_port": 123,
|
||||
"redirect_to": "192.168.40.1"
|
||||
}
|
||||
]
|
||||
"peers": []
|
||||
}
|
||||
],
|
||||
"ddns": {
|
||||
|
|
@ -826,5 +746,87 @@
|
|||
"ip": "dynamic",
|
||||
"vlan": "kids"
|
||||
}
|
||||
],
|
||||
"port_wrangling": [
|
||||
{
|
||||
"description": "DNS wrangling - redirect Trusted DNS to local resolver",
|
||||
"enabled": true,
|
||||
"protocol": "both",
|
||||
"dest_port": 53,
|
||||
"redirect_to": "192.168.1.1",
|
||||
"vlan": "trusted"
|
||||
},
|
||||
{
|
||||
"description": "NTP wrangling - redirect Trusted NTP to local time server",
|
||||
"enabled": false,
|
||||
"protocol": "udp",
|
||||
"dest_port": 123,
|
||||
"redirect_to": "192.168.1.1",
|
||||
"vlan": "trusted"
|
||||
},
|
||||
{
|
||||
"description": "DNS wrangling - redirect IoT DNS to local resolver",
|
||||
"enabled": true,
|
||||
"protocol": "both",
|
||||
"dest_port": 53,
|
||||
"redirect_to": "192.168.10.1",
|
||||
"vlan": "iot"
|
||||
},
|
||||
{
|
||||
"description": "NTP wrangling - redirect IoT NTP to local time server",
|
||||
"enabled": false,
|
||||
"protocol": "udp",
|
||||
"dest_port": 123,
|
||||
"redirect_to": "192.168.10.1",
|
||||
"vlan": "iot"
|
||||
},
|
||||
{
|
||||
"description": "DNS wrangling - redirect Guest DNS to local resolver",
|
||||
"enabled": true,
|
||||
"protocol": "both",
|
||||
"dest_port": 53,
|
||||
"redirect_to": "192.168.20.1",
|
||||
"vlan": "guest"
|
||||
},
|
||||
{
|
||||
"description": "NTP wrangling - redirect Guest NTP to local time server",
|
||||
"enabled": false,
|
||||
"protocol": "udp",
|
||||
"dest_port": 123,
|
||||
"redirect_to": "192.168.20.1",
|
||||
"vlan": "guest"
|
||||
},
|
||||
{
|
||||
"description": "DNS wrangling - redirect Kids DNS to local resolver",
|
||||
"enabled": true,
|
||||
"protocol": "both",
|
||||
"dest_port": 53,
|
||||
"redirect_to": "192.168.30.1",
|
||||
"vlan": "kids"
|
||||
},
|
||||
{
|
||||
"description": "NTP wrangling - redirect Kids NTP to local time server",
|
||||
"enabled": false,
|
||||
"protocol": "udp",
|
||||
"dest_port": 123,
|
||||
"redirect_to": "192.168.30.1",
|
||||
"vlan": "kids"
|
||||
},
|
||||
{
|
||||
"description": "DNS wrangling - redirect VPN DNS to local resolver",
|
||||
"enabled": true,
|
||||
"protocol": "both",
|
||||
"dest_port": 53,
|
||||
"redirect_to": "192.168.40.1",
|
||||
"vlan": "vpn"
|
||||
},
|
||||
{
|
||||
"description": "NTP wrangling - redirect VPN NTP to local time server",
|
||||
"enabled": false,
|
||||
"protocol": "udp",
|
||||
"dest_port": 123,
|
||||
"redirect_to": "192.168.40.1",
|
||||
"vlan": "vpn"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1370,7 +1370,10 @@ def build_nft_config(data, dry_run=False):
|
|||
vlans = [v for v in data["vlans"]
|
||||
if not is_wg(v) or dry_run or wg_interface_up(derive_interface(v, data))]
|
||||
all_fwd = list(rule_enabled(data.get("port_forwarding", [])))
|
||||
all_wrngl = [(v, r) for v in vlans for r in rule_enabled(v.get("port_wrangling", []))]
|
||||
_wrngl_vlan_by_name = {v["name"]: v for v in vlans}
|
||||
all_wrngl = [(_wrngl_vlan_by_name[r["vlan"]], r)
|
||||
for r in rule_enabled(data.get("port_wrangling", []))
|
||||
if r.get("vlan") in _wrngl_vlan_by_name]
|
||||
# Interfaces that are active (WG interfaces only included if up)
|
||||
active_ifaces = {derive_interface(v, data) for v in vlans}
|
||||
|
||||
|
|
@ -1675,8 +1678,11 @@ def apply_nftables(data, dry_run=False):
|
|||
|
||||
all_fwd = list(rule_enabled(data.get("port_forwarding", [])))
|
||||
all_dis_fwd = list(rule_disabled(data.get("port_forwarding", [])))
|
||||
all_wrngl = [(v, r) for v in active_vlans for r in rule_enabled(v.get("port_wrangling", []))]
|
||||
all_dis_wrngl = [(v, r) for v in data["vlans"] for r in rule_disabled(v.get("port_wrangling", []))]
|
||||
_active_vlan_by_name = {v["name"]: v for v in active_vlans}
|
||||
all_wrngl = [(_active_vlan_by_name[r["vlan"]], r)
|
||||
for r in rule_enabled(data.get("port_wrangling", []))
|
||||
if r.get("vlan") in _active_vlan_by_name]
|
||||
all_dis_wrngl = rule_disabled(data.get("port_wrangling", []))
|
||||
all_except = rule_enabled(data.get("inter_vlan_exceptions", []))
|
||||
|
||||
print(f"Applying {len(all_fwd)} port forwarding rule(s), {len(all_dis_fwd)} skipped.")
|
||||
|
|
|
|||
|
|
@ -807,19 +807,22 @@ def validate_config(data):
|
|||
if ip and ip not in network:
|
||||
errors.append(f"{label}: '{ip_str}' is not within subnet {network}.")
|
||||
|
||||
for vlan, iface in zip(data.get("vlans", []), vlan_ifaces):
|
||||
name = vlan.get("name", "?")
|
||||
net = vlan_networks.get(iface)
|
||||
|
||||
for r in vlan.get("port_wrangling", []):
|
||||
desc = r.get("description", "?")
|
||||
label = f"vlan '{name}' port_wrangling '{desc}'"
|
||||
if r.get("protocol") not in valid_protos:
|
||||
errors.append(f"{label}: invalid protocol '{r.get('protocol')}'. "
|
||||
f"Must be tcp, udp, or both.")
|
||||
nat_check_port(f"{label} dest_port", r.get("dest_port"))
|
||||
if net:
|
||||
nat_check_ip_in_network(f"{label} redirect_to", r.get("redirect_to", ""), net)
|
||||
# port_wrangling validation (top-level) =========================
|
||||
_vlan_name_to_net = {
|
||||
v.get("name", ""): vlan_networks.get(iface)
|
||||
for v, iface in zip(data.get("vlans", []), vlan_ifaces)
|
||||
}
|
||||
for idx, r in enumerate(data.get("port_wrangling", [])):
|
||||
desc = r.get("description", "?")
|
||||
vlan_name = r.get("vlan", "?")
|
||||
label = f"port_wrangling[{idx}] (vlan '{vlan_name}') '{desc}'"
|
||||
if r.get("protocol") not in valid_protos:
|
||||
errors.append(f"{label}: invalid protocol '{r.get('protocol')}'. "
|
||||
f"Must be tcp, udp, or both.")
|
||||
nat_check_port(f"{label} dest_port", r.get("dest_port"))
|
||||
net = _vlan_name_to_net.get(vlan_name)
|
||||
if net:
|
||||
nat_check_ip_in_network(f"{label} redirect_to", r.get("redirect_to", ""), net)
|
||||
|
||||
# port_forwarding validation (top-level) ========================
|
||||
for idx, r in enumerate(data.get("port_forwarding", [])):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue