Files
infix/test/case/firewall/ipv6-lan-wan/test.py
T
Joachim Wiberg 1bbd80d8c7 test: drop leading ietf/infix prefix from directories
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>
2025-11-20 20:23:23 +01:00

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()