OpenWRT as Portable Confinement Network

I’m having difficulty configuring my OpenWRT router for a bit of an unusual scenario…

I have a need for an isolated network for untrusted devices. So far, so good - I know how to do that with the awesome configurability of OpenWRT. What’s unusual is that I intend for my router to be portable, providing a method for isolating these untrusted devices from not only my own home devices, but also from devices of loved ones whom I on occasion visit. In other words, the isolate network not only has to disallow access to devices on other networks managed by the OpenWRT router, but also to devices that are peers to the OpenWRT router - other than, of course, the ISP gateway. Hence my “Portable Confinement Network” description in the topic title.

To put it in a picture:

              ISP Gateway
                   |
                  / \
              ----   ----
             /           \
          Device A     OpenWRT
                          /\
                         /  \
                        /    \
                      LAN    RestrictedNet
                      /        \
                     /          \
                Device B      Device C

In this diagram, Device C can communicate with neither Device A nor Device B, but Device C can communicate with the ISP Gateway.

Device B can communicate with Device A (through the OpenWRT’s NAT) and the ISP Gateway.

The only way I can think of to accomplish this level of isolation is a script that runs when the WAN device gets a DHCP address and gateway, and to have the script either create a non-persistent firewall rule or update a persistent firewall rule that allows traffic from RestrictedNet to access only the ISP Gateway’s IP address.

Is there a simpler way to achieve this goal? And if not, is there a way to execute such a script on an event such as WAN DHCP lease assignment or update?

Thank you in advance for any help, advice, words of wisdom or encouragement, or even just time spent reading my crazy conundrum.

This should be pretty easy to implement, actually.

Just to clarify the goals here:

  • Device A cannot reach Devices B & C
  • Device B can reach device A, but not device C
  • Device C cannot reach devices A & B

Is that correct?

Some more questions:

  • Do you have the system implemented as desired for the network hosting device B?
  • Does the network for device C need to be ethernet + wifi, ethernet only, or wifi only?

And finally, let's see the config as it currently exists...

Please connect to your OpenWrt device using ssh and copy the output of the following commands and post it here using the "Preformatted text </> " button (red circle; this works best in the 'Markdown' composer view in the blue oval):

Screenshot 2025-10-20 at 8.14.14 PM

Remember to redact passwords, VPN keys, MAC addresses and any public IP addresses you may have:

ubus call system board
cat /etc/config/network
cat /etc/config/wireless
cat /etc/config/dhcp
cat /etc/config/firewall

Fantastic - thank you very much! “Very easy to implement” is my speed.

The goals as you summarized are correct. To be clear - the magic of NAT is preventing Device A from contacting Device B, not any custom firewall configuration I’m planning.

Here’s the information you requested…

Output of ubus call system board:

{
        "kernel": "6.12.74",
        "hostname": "palantir-4",
        "system": "ARMv7 Processor rev 1 (v7l)",
        "model": "Linksys WRT1200AC",
        "board_name": "linksys,wrt1200ac",
        "rootfs_type": "squashfs",
        "release": {
                "distribution": "OpenWrt",
                "version": "25.12.2",
                "firmware_url": "https://downloads.openwrt.org/",
                "revision": "r32802-f505120278",
                "target": "mvebu/cortexa9",
                "description": "OpenWrt 25.12.2 r32802-f505120278",
                "builddate": "1774469393"
        }
}

Contents of /etc/config/network:

config interface 'loopback'
        option device 'lo'
        option proto 'static'
        list ipaddr '127.0.0.1/8'

config globals 'globals'
        option dhcp_default_duid '<redacted>'
        option ula_prefix '<redacted>'
        option packet_steering '1'

config device
        option name 'br-lan'
        option type 'bridge'
        list ports 'lan1'
        list ports 'lan2'
        list ports 'lan3'
        list ports 'lan4'

config device
        option name 'br-restricted'
        option type 'bridge'

config interface 'lan'
        option device 'br-lan'
        option proto 'static'
        list ipaddr '192.168.1.1/24'
        option ip6assign '60'

config interface 'restricted'
        option device 'br-restricted'
        option proto 'static'
        list ipaddr '192.168.12.1/24'
        option ip6assign '60'

config device
        option name 'wan'
        option macaddr '<redacted>'

config interface 'wan'
        option device 'wan'
        option proto 'dhcp'

config interface 'wan6'
        option device 'wan'
        option proto 'dhcpv6'

config interface 'wg42'
        option proto 'wireguard'
        option private_key '<redacted>'
        list addresses '192.168.42.15'
        option defaultroute '0'
        option multipath 'off'

config wireguard_wg42
        option preshared_key '<redacted>'
        option description 'RemoteSupportNetwork'
        option public_key '<redacted>'
        option endpoint_host '<redacted>'
        option endpoint_port '1194'
        option persistent_keepalive '25'
        list allowed_ips '<redacted>'
        option route_allowed_ips '1'

Contents of /etc/config/wireless:

config wifi-device 'radio0'
        option type 'mac80211'
        option path 'soc/soc:pcie/pci0000:00/0000:00:01.0/0000:01:00.0'
        option band '5g'
        option channel '36'
        option htmode 'VHT80'
        option country 'US'

config wifi-iface 'default_radio0'
        option device 'radio0'
        option network 'lan'
        option mode 'ap'
        option ssid 'Personal 5G'
        option encryption 'psk2'
        option key '<redacted>'
        option disabled '0'
        option macaddr '<redacted>'

config wifi-iface 'restricted_radio0'
        option device 'radio0'
        option network 'restricted'
        option mode 'ap'
        option ssid 'Restricted 5G'
        option encryption 'psk2'
        option key '<redacted>'
        option disabled '0'
        option isolate '1'
        option macaddr '<redacted>'

config wifi-device 'radio1'
        option type 'mac80211'
        option path 'soc/soc:pcie/pci0000:00/0000:00:02.0/0000:02:00.0'
        option band '2g'
        option channel '1'
        option htmode 'VHT20'
        option country 'US'

config wifi-iface 'default_radio1'
        option device 'radio1'
        option network 'lan'
        option mode 'ap'
        option ssid 'Personal 2G'
        option encryption 'psk2'
        option key '<redacted>'
        option disabled '0'
        option macaddr '<redacted>'

config wifi-iface 'restricted_radio1'
        option device 'radio1'
        option network 'restricted'
        option mode 'ap'
        option ssid 'Restricted 2G'
        option encryption 'psk2'
        option key '<redacted>'
        option disabled '0'
        option isolate '1'
        option macaddr '<redacted>'

Contents of /etc/config/dhcp:

config dnsmasq
        option domainneeded '1'
        option boguspriv '1'
        option filterwin2k '0'
        option localise_queries '1'
        option rebind_protection '1'
        option rebind_localhost '1'
        option local '/lan/'
        option domain 'lan'
        option expandhosts '1'
        option nonegcache '0'
        option cachesize '1000'
        option authoritative '1'
        option readethers '1'
        option leasefile '/tmp/dhcp.leases'
        option resolvfile '/tmp/resolv.conf.d/resolv.conf.auto'
        option nonwildcard '1'
        option localservice '1'
        option ednspacket_max '1232'
        option filter_aaaa '0'
        option filter_a '0'

config dhcp 'lan'
        option interface 'lan'
        option start '100'
        option limit '150'
        option leasetime '12h'
        option dhcpv4 'server'
        option dhcpv6 'server'
        option ra 'server'
        option ra_slaac '1'
        list ra_flags 'managed-config'
        list ra_flags 'other-config'

config dhcp 'restricted'
        option interface 'restricted'
        option start '200'
        option limit '220'
        option leasetime '12h'
        option dhcpv4 'server'
        option dhcpv6 'server'
        option ra 'server'
        option ra_slaac '1'
        list ra_flags 'managed-config'
        list ra_flags 'other-config'

config dhcp 'wan'
        option interface 'wan'
        option ignore '1'

config odhcpd 'odhcpd'
        option maindhcp '0'
        option leasefile '/tmp/odhcpd.leases'
        option leasetrigger '/usr/sbin/odhcpd-update'
        option loglevel '4'
        option piodir '/tmp/odhcpd-piodir'
        option hostsdir '/tmp/hosts'

Contents of /etc/config/firewall:

config defaults
        option syn_flood '1'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'

config zone
        option name 'lan'
        option input 'ACCEPT'
        option output 'ACCEPT'
        option forward 'ACCEPT'
        list network 'lan'
        list network 'wg42'

config zone
        option name 'restricted'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        list network 'restricted'
        option masq '1'

config zone
        option name 'wan'
        list network 'wan'
        list network 'wan6'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'DROP'
        option masq '1'
        option mtu_fix '1'

config forwarding
        option src 'lan'
        option dest 'wan'

config forwarding
        option src 'restricted'
        option dest 'wan'

config rule
        option name 'Allow-DHCP-Renew'
        option src 'wan'
        option proto 'udp'
        option dest_port '68'
        option target 'ACCEPT'
        option family 'ipv4'

config rule
        option name 'Allow-Ping'
        option src 'wan'
        option proto 'icmp'
        option icmp_type 'echo-request'
        option family 'ipv4'
        option target 'ACCEPT'

config rule
        option name 'Allow-IGMP'
        option src 'wan'
        option proto 'igmp'
        option family 'ipv4'
        option target 'ACCEPT'

config rule
        option name 'Allow-DHCPv6'
        option src 'wan'
        option proto 'udp'
        option dest_port '546'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-MLD'
        option src 'wan'
        option proto 'icmp'
        option src_ip 'fe80::/10'
        list icmp_type '130/0'
        list icmp_type '131/0'
        list icmp_type '132/0'
        list icmp_type '143/0'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-ICMPv6-Input'
        option src 'wan'
        option proto 'icmp'
        list icmp_type 'echo-request'
        list icmp_type 'echo-reply'
        list icmp_type 'destination-unreachable'
        list icmp_type 'packet-too-big'
        list icmp_type 'time-exceeded'
        list icmp_type 'bad-header'
        list icmp_type 'unknown-header-type'
        list icmp_type 'router-solicitation'
        list icmp_type 'neighbour-solicitation'
        list icmp_type 'router-advertisement'
        list icmp_type 'neighbour-advertisement'
        option limit '1000/sec'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-ICMPv6-Forward'
        option src 'wan'
        option dest '*'
        option proto 'icmp'
        list icmp_type 'echo-request'
        list icmp_type 'echo-reply'
        list icmp_type 'destination-unreachable'
        list icmp_type 'packet-too-big'
        list icmp_type 'time-exceeded'
        list icmp_type 'bad-header'
        list icmp_type 'unknown-header-type'
        option limit '1000/sec'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-IPSec-ESP'
        option src 'wan'
        option dest 'lan'
        option proto 'esp'
        option target 'ACCEPT'

config rule
        option name 'Allow-ISAKMP'
        option src 'wan'
        option dest 'lan'
        option dest_port '500'
        option proto 'udp'
        option target 'ACCEPT'

config rule
        option name 'Allow Restricted DNS Queries'
        option src 'restricted'
        option dest_port '53'
        option proto 'tcp udp'
        option target 'ACCEPT'

config rule
        option name 'Allow Restricted DHCP'
        option src 'restricted'
        option src_port '67-68'
        option dest_port '67-68'
        option proto 'udp'
        option target 'ACCEPT'

Ok... seems like you're close.

How is the device connected to the upstream network? Is it via the wan port of this router?

What is the subnet of the upstream network (or what is the address of the ISP router)?

I think you’ve honed in on the point where I get quite confused.

The OpenWrt device is indeed connected to the upstream network via its WAN port.

The address and subnet of the ISP router is actually a variable in this scenario. If this OpenWRT device travels with me, the ISP will change. The test network I’m using has a gateway of 192.168.4.254/24, and I’m fairly confident that given enough time I can brute-force a firewall config that works with that specific network and that specific gateway IP. (Though help would be greatly appreciate on that firewall configuration!) But if I connect to the in-laws’ network while traveling, it could be 10.0.10.1/16, for example.

Hopefully my point of confusion makes sense. I’m very open to the possibility that I’m over-complicating my model. Perhaps solving for the specific test network environment will lead to the recipe required for the script that updates the firewall when connecting to a different network?

Ok... I understand the issue. And with that in mind...

Change your lan subnet to something else... 192.168.1.0/24 is an extremely common subnet and may end up colliding with the upstream if you don't know ahead of time what that upstream might be. All networks must have a unique and non-overlapping subnet. While there's no guarantee you'll 'guess correctly' insofar as selecting a subnet that won't overlap the wan, using something from the RFC1918 range that is sort of random-ish will be a better bet.

(I think your restricted subnet is probably okay).

Your DHCP server has an invalid range. The limit value is the size of the DHCP pool. So the equation for the range is start to start + limit - 1 -- the top of the range no larger than 254 (on a /24 network). If you want just 20 addresses in the pool, change the limit to 20.

Finally, in the firewall...

Remove masquerading from the restricted zone:

Then, to achieve blocking the upstream when the following is the reality:

You'll create a firewall rule that blocks all RFC1918 addresses:

config rule
	option name 'block-restricted2upstream'
	option src 'restricted'
	option dest 'wan'
	list proto 'all'
	list dest_ip '10.0.0.0/8'
	list dest_ip '172.16.0.0/12'
	list dest_ip '192.168.0.0/16'
	option target 'REJECT'

That should do what you want.

Amazing! Thank you so much! This strategy is much more straightforward than what I was thinking. Also, thank you for correcting my misunderstanding of the limit in the DHCP configuration. Finally, I for some reason never realized that a firewall rule could have multiple list dest_ip definitions.

I’ll give this configuration a try this evening and let you know how it goes. Thank you again!

NAT does not do that. If you want to prevent that connection, you need a firewall rule/policy (which is easy, so do it.) Device A is connected directly to the OpenWRT router, and that gives it the ability to send packets addressed to the internal address of Device B to the OpenWRT router, which will route them to Device B on the LAN in absence of a firewall forbidding this.

Sorry @FixAllTheBugs - I think my picture could have been much more clear. I intended to illustrate that Device A and the WAN port of the OpenWRT router are connected to the same network, in which case both Device B and Device C are behind the NAT. I agree, though that if Device A was connected to one of the LAN ports or to either the Personal 5G or Personal 2G WiFi networks, a firewall rule would be required to isolate it.

Perfection - thank you so much, @psherman!

I have the router on a network such that its WAN port is assigned 192.168.4.188/24, and another system is acting as Device A with IP address 192.168.4.1/24. I also changed the default network to use 192.168.17.0/24 to avoid the conflict that you described. I have a system with address 192.168.17.204/24 playing the role of Device B, and my laptop is being connected to each of the four WiFi networks for testing.

When connected to each of the “Personal” WiFi networks, my laptop gets a 192.168.17.0/24 address and is successfully able to ping both Device A and Device B, as well as access the Internet.

When connected to each of the “Restricted” WiFi networks, my laptop gets a 192.168.12.0/24 address and is unable to ping either Device A or Device B, but it is successfully able to access the Internet.

Thank you for the brilliant and elegantly simple solution and for the speed with which you were able to assemble it! I’m also going to go ahead and fix the DHCP “limit” values for a couple of other networks that I now understand are misconfigured…

Device A on the WAN side of the OpenWRT router can directly address devices B and C through the OpenWRT router, even in the presence of NAT. You need a firewall to prevent this. If you don't understand how this is possible, it still does work and you still need the firewall, NAT is not a firewall. Do not rely on NAT for making devices inaccessible.

Yes, this is true in theory... but this is not an issue here.

The OP's firewall does protect from this currently as there are no wan > lan or wan > untrusted forward statements in the config, nor are there any other similar firewall rules.

Beyond that, there is another reason that the downstream networks are (almost certainly) unreachable...

  • There is no very likely route from the upstream network to the downstream ones.
    • It is certainly possible for a route to be created on the upstream router or a host on that network, however this would require knowledge of the downstream network in order for that to be achieved (again, not impossible, but it means that the attacker needs to know the IP of the OpenWrt router on the upstream, needs to know the address/subnet of one or both of the downstream networks, and the router or host needs to have the ability to add static routes -- many consumer/ISP routers don't have options for a static routes, but certainly host OS's like Linux make this easy).
    • Without a static route on upstream router or host, the packets would either be sent out the wan of the upstream or otherwise dropped.

Dont forget about ipv6!!!

True, but the firewall does not allow inbound connections from the wan (per the OP's config).

And... in many cases, if the upstream is not a direct connection to an ISP, there is a reasonable probability that the OpenWrt wan will be assigned a /64. The consequence of this is that the devices behind the OpenWrt router will not have IPv6 addresses delegated from the upstream, and thus IPv6 routing from the upstream > OpenWrt lan wouldn't work.

Hrm… I’ll confess I am only passingly familiar with IPv6, and usually disable it because I understand my ISP at home doesn’t have a stable implementation, or at least I was told as much the last time I tried and failed to configure it. However the premise of this OpenWRT device is to be used when traveling as well. Would completely disabling IPv6 be the safest option? With the understanding, of course, that if the router is connected to an IPv6-only network it will not correctly function.

I'd recommend just setting up the ipv6 firewall to prevent the forwarding that you want to prevent, this ensures even ULA and soforth won't route in unwanted ways.

disabling ipv6 is generally a bad idea IMHO. better to learn a bit about it.

Thank you @dlakelan - and I agree, I typically prefer to learn and properly configure than just disable. Could you please give me an example of the firewall configuration required to disable IPv6 forwarding in the proposed scenario? I’d like to get this router configured as correctly as possible and I appreciate your help as well.

I think it's pretty easy to make it so that C can only route to "the internet".

In IPv6 "the internet" is all in the prefix 2000::/3

So you create a rule if it comes from restrictednet and it's going to LAN then it's blocked (this is just a routing rule in the firewall), otherwise if it's routing to 2000::/3 it's allowed, otherwise it's not allowed to route.

Now, this will technically allow device C to talk to device A if A has a public IPv6 address... because A is basically just "yet another thing on the public internet". If you want to prevent that, you'd have to have a firewall rule that adjusts based on the prefix assigned on the WAN side of your OpenWrt... but I'm not entirely sure why you'd want to say "you can talk to the whole wide internet except machine A". If you really want that, well, I don't have an easy answer. You'd kinda need a script to trigger that basically detects the prefix on the WAN, and adds a firewall rule to block routing from RestrictedNet to that particular prefix.

What my suggestion WILL do is prevent you from routing from RestrictedNet to Device A when Device A only has a NON public ipv6 address, like a ULA.

The default firewall rules already take care of getting device B to do what you want.