mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-30 12:33:02 +02:00
Let's drop the leading IETF or Infix prefixes from tests. Initially the idea was to mimnic the YANG models, but it's difficult to navigate and does not provide any real benefit to developers or end-users. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
155 lines
5.8 KiB
Python
Executable File
155 lines
5.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""IPv6 LAN-WAN Firewall
|
|
|
|
IPv6 version of the typical home/office router scenario where the DUT acts as
|
|
a gateway with LAN-to-WAN traffic forwarding and IPv6 prefix delegation.
|
|
|
|
image::lan-wan.svg[align=center, scaledwidth=50%]
|
|
|
|
- DUT/Gateway with IPv6 firewall and forwarding
|
|
- Test host has two interfaces: a LAN-side and a WAN-side (Internet)
|
|
- Test host's LAN interface acts as an IPv6 client behind the router
|
|
- Test host's WAN interface acts as an IPv6 Internet server/destination
|
|
- Demonstrates IPv6 policy-based forwarding between zones
|
|
"""
|
|
|
|
import time
|
|
import infamy
|
|
from infamy.util import until
|
|
|
|
|
|
with infamy.Test() as test:
|
|
with test.step("Set up topology and attach to gateway"):
|
|
env = infamy.Env()
|
|
gateway = env.attach("gateway", "mgmt")
|
|
_, lan_if = env.ltop.xlate("gateway", "lan")
|
|
_, wan_if = env.ltop.xlate("gateway", "wan")
|
|
_, mgmt_if = env.ltop.xlate("gateway", "mgmt")
|
|
_, host_lan = env.ltop.xlate("host", "lan") # Host LAN-side interface
|
|
_, host_wan = env.ltop.xlate("host", "wan") # Host WAN-side interface
|
|
|
|
LAN_NET = "fd01:db8:1::/64"
|
|
LAN_ROUTER_IP = "fd01:db8:1::1" # Router's LAN interface
|
|
LAN_CLIENT_IP = "fd01:db8:1::100" # Client on LAN side
|
|
|
|
WAN_NET = "2001:db8:2::/64" # RFC 3849 documentation prefix
|
|
WAN_ROUTER_IP = "2001:db8:2::1" # Router's WAN interface
|
|
WAN_SERVER_IP = "2001:db8:2::100" # Server on WAN side
|
|
|
|
with test.step("Configure gateway with firewall and forwarding"):
|
|
gateway.put_config_dicts({
|
|
"ietf-interfaces": {
|
|
"interfaces": {
|
|
"interface": [{
|
|
"name": lan_if,
|
|
"enabled": True,
|
|
"ipv6": {
|
|
"enabled": True,
|
|
"forwarding": True,
|
|
"address": [{
|
|
"ip": LAN_ROUTER_IP,
|
|
"prefix-length": 64
|
|
}]
|
|
}
|
|
}, {
|
|
"name": wan_if,
|
|
"enabled": True,
|
|
"ipv6": {
|
|
"enabled": True,
|
|
"forwarding": True,
|
|
"address": [{
|
|
"ip": WAN_ROUTER_IP,
|
|
"prefix-length": 64
|
|
}]
|
|
}
|
|
}]
|
|
}
|
|
},
|
|
"infix-firewall": {
|
|
"firewall": {
|
|
"default": "wan",
|
|
"logging": "all",
|
|
"zone": [{
|
|
"name": "lan",
|
|
"description": "Internal LAN network - trusted",
|
|
"action": "accept",
|
|
"interface": [lan_if, mgmt_if],
|
|
"service": ["ssh", "dhcpv6", "dns"]
|
|
}, {
|
|
"name": "wan",
|
|
"description": "External WAN interface - untrusted",
|
|
"action": "drop",
|
|
"interface": [wan_if]
|
|
}],
|
|
"policy": [{
|
|
"name": "lan-to-wan",
|
|
"description": "Allow LAN to WAN traffic",
|
|
"ingress": ["lan"],
|
|
"egress": ["wan"],
|
|
"action": "accept"
|
|
}]
|
|
}
|
|
}
|
|
})
|
|
|
|
# Wait for configuration to be activated
|
|
infamy.Firewall.wait_for_operational(gateway, {
|
|
"lan": {"action": "accept"},
|
|
"wan": {"action": "drop"}
|
|
})
|
|
|
|
# Verify firewall operational state
|
|
data = gateway.get_data("/infix-firewall:firewall")
|
|
fw = data["firewall"]
|
|
zones = {z["name"]: z for z in fw["zone"]}
|
|
|
|
# Verify LAN zone
|
|
lan_zone = zones["lan"]
|
|
assert lan_zone["action"] == "accept"
|
|
assert lan_if in lan_zone["interface"]
|
|
|
|
# Verify WAN zone
|
|
wan_zone = zones["wan"]
|
|
assert wan_zone["action"] == "drop"
|
|
assert wan_if in wan_zone["interface"]
|
|
|
|
# Verify policy exists
|
|
policies = {p["name"]: p for p in fw.get("policy", [])}
|
|
assert "lan-to-wan" in policies
|
|
policy = policies["lan-to-wan"]
|
|
assert "lan" in policy["ingress"]
|
|
assert "wan" in policy["egress"]
|
|
assert policy["action"] == "accept"
|
|
|
|
with infamy.IsolatedMacVlan(host_lan) as lan_ns:
|
|
lan_ns.addip(LAN_CLIENT_IP, prefix_length=64, proto="ipv6")
|
|
lan_ns.addroute("default", LAN_ROUTER_IP, proto="ipv6")
|
|
|
|
with infamy.IsolatedMacVlan(host_wan) as wan_ns:
|
|
wan_ns.addip(WAN_SERVER_IP, prefix_length=64, proto="ipv6")
|
|
wan_ns.addroute("default", WAN_ROUTER_IP, proto="ipv6")
|
|
|
|
with test.step("Test connectivity to gateway"):
|
|
lan_ns.must_reach(LAN_ROUTER_IP, timeout=5)
|
|
wan_ns.must_not_reach(WAN_ROUTER_IP, timeout=5)
|
|
|
|
with test.step("Test LAN-to-WAN forwarding"):
|
|
lan_ns.must_reach(WAN_SERVER_IP, timeout=10)
|
|
|
|
with test.step("Test WAN-to-LAN blocking"):
|
|
wan_ns.must_not_reach(LAN_CLIENT_IP, timeout=5)
|
|
|
|
with test.step("Verify LAN services accessibility"):
|
|
firewall_lan = infamy.Firewall(lan_ns, None)
|
|
svc = [
|
|
(22, "tcp", "ssh"),
|
|
(53, "tcp", "dns")
|
|
]
|
|
|
|
ok, ports = firewall_lan.verify_allowed(LAN_ROUTER_IP, svc)
|
|
if not ok:
|
|
print(f" ⚠ Some LAN services are filtered: {', '.join(ports)}")
|
|
test.fail()
|
|
|
|
test.succeed()
|