I use a Linux PC as my Internet gateway; it's running a fresh installation of CentOS 7 x64. I have one subnet (192.168.2.0/24) which is my regular Home network, and I have a second, separate subnet (192.168.3.0/24) for use by guests. As you would expect, the intent is to allow my guests to access the Internet without being able to access any of the hosts on my regular Home network.
To that end, the gateway PC has 3 physical Ethernet interfaces installed:
- enp0s25 (zone=external): masqueraded connection to the Internet;
address assigned via DHCP from my ISP - enp4s2 (zone=internal): Attached to my Home subnet; static address 192.168.2.254 (192.168.2.0/24)
- enp4s0 (zone=guest): Attached to my Guest subnet; static address 192.168.3.254 (192.168.3.0/24)
Attached to this Guest subnet is a separate WiFi AP to provide Guest WiFi access to the Internet. The Guest AP has a static address 192.168.3.3.
The gateway PC provides a DHCP server for both the Internal (192.168.2.0/24) and Guest (192.168.3.0/24) subnets as well as a caching DNS server.
I can connect a WiFi client to this AP, receive a DHCP address assignment from the CentOS box, and connect to hosts on the Internet. I cannot reach any hosts on the Internal subnet. From hosts on the Internal network I can connect to the gateway PC and out to the Internet. I can ping the 192.168.3.254 interface on the gateway but nothing on the Guest network behind it. If I log onto the gateway PC via SSH I can connect to everything on both subnets.
So far all of this is the desired behavior. Now for the problem:
Occasionally I may need to connect to the Guest WiFi AP at 192.168.3.3 for maintenance purposes. Currently I can connect to the Guest AP using WiFi and log into the Admin page that way, but it would be more convenient to be able to reach the admin page from my desktop PC on the Internal subnet. Obviously I would prefer to keep this connectivity one-way, i.e. hosts on Internal subnet can connect to hosts on Guest subnet but not vice-versa. Is there a way to allow this? I've tried moving the interfaces around to different zones, adding rich rules, adding direct forwarding rules, etc. but nothing I have tried has worked. What am I missing?
Here are my firewalld zones and kernel routing table:
# firewall-cmd --get-active-zones
internal
interfaces: enp4s2
external
interfaces: enp0s25
public
interfaces: enp4s0
# firewall-cmd --zone=public --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: enp4s0
sources:
services: ssh dhcpv6-client dns dhcp mdns http https ntp smtp
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
# firewall-cmd --zone=internal --list-all
internal (active)
target: default
icmp-block-inversion: no
interfaces: enp4s2
sources:
services: ssh mdns samba-client dhcpv6-client dns http https mysql ntp pop3s smtp icecast pop3 samba dhcp
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
# firewall-cmd --zone=external --list-all
external (active)
target: default
icmp-block-inversion: no
interfaces: enp0s25
sources:
services: ssh openvpn
ports:
protocols:
masquerade: yes
forward-ports:
source-ports:
icmp-blocks:
rich rules:
# ip route show
default via 72.211.220.1 dev enp0s25 proto dhcp metric 102
72.211.220.0/22 dev enp0s25 proto kernel scope link src <redacted> metric 102
192.168.2.0/24 dev enp4s2 proto kernel scope link src 192.168.2.254 metric 101
192.168.3.0/24 dev enp4s0 proto kernel scope link src 192.168.3.254 metric 100
And here is the output of iptables -L:
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT all -- anywhere anywhere
INPUT_direct all -- anywhere anywhere
INPUT_ZONES_SOURCE all -- anywhere anywhere
INPUT_ZONES all -- anywhere anywhere
DROP all -- anywhere anywhere ctstate INVALID
REJECT all -- anywhere anywhere reject-with icmp-host-prohibited
Chain FORWARD (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT all -- anywhere anywhere
FORWARD_direct all -- anywhere anywhere
FORWARD_IN_ZONES_SOURCE all -- anywhere anywhere
FORWARD_IN_ZONES all -- anywhere anywhere
FORWARD_OUT_ZONES_SOURCE all -- anywhere anywhere
FORWARD_OUT_ZONES all -- anywhere anywhere
DROP all -- anywhere anywhere ctstate INVALID
REJECT all -- anywhere anywhere reject-with icmp-host-prohibited
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
OUTPUT_direct all -- anywhere anywhere
Chain FORWARD_IN_ZONES (1 references)
target prot opt source destination
FWDI_public all -- anywhere anywhere [goto]
FWDI_internal all -- anywhere anywhere [goto]
FWDI_external all -- anywhere anywhere [goto]
FWDI_guest all -- anywhere anywhere [goto]
Chain FORWARD_IN_ZONES_SOURCE (1 references)
target prot opt source destination
Chain FORWARD_OUT_ZONES (1 references)
target prot opt source destination
FWDO_public all -- anywhere anywhere [goto]
FWDO_internal all -- anywhere anywhere [goto]
FWDO_external all -- anywhere anywhere [goto]
FWDO_guest all -- anywhere anywhere [goto]
Chain FORWARD_OUT_ZONES_SOURCE (1 references)
target prot opt source destination
Chain FORWARD_direct (1 references)
target prot opt source destination
ACCEPT all -- anywhere anywhere
ACCEPT all -- anywhere anywhere
Chain FWDI_external (1 references)
target prot opt source destination
FWDI_external_log all -- anywhere anywhere
FWDI_external_deny all -- anywhere anywhere
FWDI_external_allow all -- anywhere anywhere
ACCEPT icmp -- anywhere anywhere
Chain FWDI_external_allow (1 references)
target prot opt source destination
Chain FWDI_external_deny (1 references)
target prot opt source destination
Chain FWDI_external_log (1 references)
target prot opt source destination
Chain FWDI_guest (1 references)
target prot opt source destination
FWDI_guest_log all -- anywhere anywhere
FWDI_guest_deny all -- anywhere anywhere
FWDI_guest_allow all -- anywhere anywhere
ACCEPT icmp -- anywhere anywhere
Chain FWDI_guest_allow (1 references)
target prot opt source destination
Chain FWDI_guest_deny (1 references)
target prot opt source destination
Chain FWDI_guest_log (1 references)
target prot opt source destination
Chain FWDI_internal (1 references)
target prot opt source destination
FWDI_internal_log all -- anywhere anywhere
FWDI_internal_deny all -- anywhere anywhere
FWDI_internal_allow all -- anywhere anywhere
ACCEPT icmp -- anywhere anywhere
Chain FWDI_internal_allow (1 references)
target prot opt source destination
Chain FWDI_internal_deny (1 references)
target prot opt source destination
Chain FWDI_internal_log (1 references)
target prot opt source destination
Chain FWDI_public (1 references)
target prot opt source destination
FWDI_public_log all -- anywhere anywhere
FWDI_public_deny all -- anywhere anywhere
FWDI_public_allow all -- anywhere anywhere
ACCEPT icmp -- anywhere anywhere
Chain FWDI_public_allow (1 references)
target prot opt source destination
Chain FWDI_public_deny (1 references)
target prot opt source destination
Chain FWDI_public_log (1 references)
target prot opt source destination
Chain FWDI_trusted (0 references)
target prot opt source destination
FWDI_trusted_log all -- anywhere anywhere
FWDI_trusted_deny all -- anywhere anywhere
FWDI_trusted_allow all -- anywhere anywhere
ACCEPT all -- anywhere anywhere
Chain FWDI_trusted_allow (1 references)
target prot opt source destination
Chain FWDI_trusted_deny (1 references)
target prot opt source destination
Chain FWDI_trusted_log (1 references)
target prot opt source destination
Chain FWDO_external (1 references)
target prot opt source destination
FWDO_external_log all -- anywhere anywhere
FWDO_external_deny all -- anywhere anywhere
FWDO_external_allow all -- anywhere anywhere
Chain FWDO_external_allow (1 references)
target prot opt source destination
ACCEPT all -- anywhere anywhere ctstate NEW
ACCEPT all -- anywhere anywhere ctstate NEW
Chain FWDO_external_deny (1 references)
target prot opt source destination
Chain FWDO_external_log (1 references)
target prot opt source destination
Chain FWDO_guest (1 references)
target prot opt source destination
FWDO_guest_log all -- anywhere anywhere
FWDO_guest_deny all -- anywhere anywhere
FWDO_guest_allow all -- anywhere anywhere
Chain FWDO_guest_allow (1 references)
target prot opt source destination
Chain FWDO_guest_deny (1 references)
target prot opt source destination
Chain FWDO_guest_log (1 references)
target prot opt source destination
Chain FWDO_internal (1 references)
target prot opt source destination
FWDO_internal_log all -- anywhere anywhere
FWDO_internal_deny all -- anywhere anywhere
FWDO_internal_allow all -- anywhere anywhere
Chain FWDO_internal_allow (1 references)
target prot opt source destination
Chain FWDO_internal_deny (1 references)
target prot opt source destination
Chain FWDO_internal_log (1 references)
target prot opt source destination
Chain FWDO_public (1 references)
target prot opt source destination
FWDO_public_log all -- anywhere anywhere
FWDO_public_deny all -- anywhere anywhere
FWDO_public_allow all -- anywhere anywhere
Chain FWDO_public_allow (1 references)
target prot opt source destination
Chain FWDO_public_deny (1 references)
target prot opt source destination
Chain FWDO_public_log (1 references)
target prot opt source destination
Chain FWDO_trusted (0 references)
target prot opt source destination
FWDO_trusted_log all -- anywhere anywhere
FWDO_trusted_deny all -- anywhere anywhere
FWDO_trusted_allow all -- anywhere anywhere
ACCEPT all -- anywhere anywhere
Chain FWDO_trusted_allow (1 references)
target prot opt source destination
Chain FWDO_trusted_deny (1 references)
target prot opt source destination
Chain FWDO_trusted_log (1 references)
target prot opt source destination
Chain INPUT_ZONES (1 references)
target prot opt source destination
IN_public all -- anywhere anywhere [goto]
IN_internal all -- anywhere anywhere [goto]
IN_external all -- anywhere anywhere [goto]
IN_guest all -- anywhere anywhere [goto]
Chain INPUT_ZONES_SOURCE (1 references)
target prot opt source destination
Chain INPUT_direct (1 references)
target prot opt source destination
Chain IN_external (1 references)
target prot opt source destination
IN_external_log all -- anywhere anywhere
IN_external_deny all -- anywhere anywhere
IN_external_allow all -- anywhere anywhere
ACCEPT icmp -- anywhere anywhere
Chain IN_external_allow (1 references)
target prot opt source destination
ACCEPT tcp -- anywhere anywhere tcp dpt:ssh ctstate NEW
ACCEPT udp -- anywhere anywhere udp dpt:openvpn ctstate NEW
Chain IN_external_deny (1 references)
target prot opt source destination
Chain IN_external_log (1 references)
target prot opt source destination
Chain IN_guest (1 references)
target prot opt source destination
IN_guest_log all -- anywhere anywhere
IN_guest_deny all -- anywhere anywhere
IN_guest_allow all -- anywhere anywhere
ACCEPT icmp -- anywhere anywhere
Chain IN_guest_allow (1 references)
target prot opt source destination
ACCEPT tcp -- anywhere anywhere tcp dpt:http ctstate NEW
Chain IN_guest_deny (1 references)
target prot opt source destination
Chain IN_guest_log (1 references)
target prot opt source destination
Chain IN_internal (1 references)
target prot opt source destination
IN_internal_log all -- anywhere anywhere
IN_internal_deny all -- anywhere anywhere
IN_internal_allow all -- anywhere anywhere
ACCEPT icmp -- anywhere anywhere
Chain IN_internal_allow (1 references)
target prot opt source destination
ACCEPT tcp -- anywhere anywhere tcp dpt:ssh ctstate NEW
ACCEPT udp -- anywhere 224.0.0.251 udp dpt:mdns ctstate NEW
ACCEPT udp -- anywhere anywhere udp dpt:netbios-ns ctstate NEW
ACCEPT udp -- anywhere anywhere udp dpt:netbios-dgm ctstate NEW
ACCEPT tcp -- anywhere anywhere tcp dpt:domain ctstate NEW
ACCEPT udp -- anywhere anywhere udp dpt:domain ctstate NEW
ACCEPT tcp -- anywhere anywhere tcp dpt:http ctstate NEW
ACCEPT tcp -- anywhere anywhere tcp dpt:https ctstate NEW
ACCEPT tcp -- anywhere anywhere tcp dpt:mysql ctstate NEW
ACCEPT udp -- anywhere anywhere udp dpt:ntp ctstate NEW
ACCEPT tcp -- anywhere anywhere tcp dpt:pop3s ctstate NEW
ACCEPT tcp -- anywhere anywhere tcp dpt:smtp ctstate NEW
ACCEPT tcp -- anywhere anywhere tcp dpt:irdmi ctstate NEW
ACCEPT tcp -- anywhere anywhere tcp dpt:vcom-tunnel ctstate NEW
ACCEPT tcp -- anywhere anywhere tcp dpt:pop3 ctstate NEW
ACCEPT udp -- anywhere anywhere udp dpt:netbios-ns ctstate NEW
ACCEPT udp -- anywhere anywhere udp dpt:netbios-dgm ctstate NEW
ACCEPT tcp -- anywhere anywhere tcp dpt:netbios-ssn ctstate NEW
ACCEPT tcp -- anywhere anywhere tcp dpt:microsoft-ds ctstate NEW
ACCEPT udp -- anywhere anywhere udp dpt:bootps ctstate NEW
Chain IN_internal_deny (1 references)
target prot opt source destination
Chain IN_internal_log (1 references)
target prot opt source destination
Chain IN_public (1 references)
target prot opt source destination
IN_public_log all -- anywhere anywhere
IN_public_deny all -- anywhere anywhere
IN_public_allow all -- anywhere anywhere
ACCEPT icmp -- anywhere anywhere
Chain IN_public_allow (1 references)
target prot opt source destination
ACCEPT tcp -- anywhere anywhere tcp dpt:ssh ctstate NEW
ACCEPT tcp -- anywhere anywhere tcp dpt:domain ctstate NEW
ACCEPT udp -- anywhere anywhere udp dpt:domain ctstate NEW
ACCEPT udp -- anywhere anywhere udp dpt:bootps ctstate NEW
ACCEPT udp -- anywhere 224.0.0.251 udp dpt:mdns ctstate NEW
ACCEPT tcp -- anywhere anywhere tcp dpt:http ctstate NEW
ACCEPT tcp -- anywhere anywhere tcp dpt:https ctstate NEW
ACCEPT udp -- anywhere anywhere udp dpt:ntp ctstate NEW
ACCEPT tcp -- anywhere anywhere tcp dpt:smtp ctstate NEW
Chain IN_public_deny (1 references)
target prot opt source destination
Chain IN_public_log (1 references)
target prot opt source destination
Chain IN_trusted (0 references)
target prot opt source destination
IN_trusted_log all -- anywhere anywhere
IN_trusted_deny all -- anywhere anywhere
IN_trusted_allow all -- anywhere anywhere
ACCEPT all -- anywhere anywhere
Chain IN_trusted_allow (1 references)
target prot opt source destination
Chain IN_trusted_deny (1 references)
target prot opt source destination
Chain IN_trusted_log (1 references)
target prot opt source destination
Chain OUTPUT_direct (1 references)
target prot opt source destination