Firewalld Rich and Direct Rules: Setting up RHEL 7 Server as a Router

We are going to configure RHEL server as a router. Masquerading, port forwarding, rich and direct rules will be covered. 

The Lab

We have three RHEL 7.0 servers available in our lab:

  1. ipa (10.10.1.79, 10.8.8.70) – will be configured as a router,
  2. srv1 (10.8.8.71) – a server on our DMZ network, will be used to test masquerading,
  3. pub (10.10.1.10) – a server on our public network, will be used to test port forwarding.

The ipa server has SELinux set to enforcing mode.

Network Interfaces on the Router Server

The ipa server has two network interfaces attached and configured:

# nmcli d
DEVICE   TYPE      STATE      CONNECTION 
enp0s17  ethernet  connected  enp0s17    
enp0s8   ethernet  connected  enp0s8     
lo       loopback  unmanaged  --

The enp0s8 is connected to our “public” network 10.10.1.0/24, where enp0s17 is connected to DMZ 10.8.8.0/24.

# ip -4 ad
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    inet 10.10.1.79/24 brd 10.10.1.255 scope global dynamic enp0s8
       valid_lft 86376sec preferred_lft 86376sec
3: enp0s17: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    inet 10.8.8.70/24 brd 10.8.8.255 scope global dynamic enp0s17
       valid_lft 3583sec preferred_lft 3583sec

Routing table can be seen below:

# ip ro
default via 10.10.1.1 dev enp0s8  proto static  metric 1024 
10.8.8.0/24 dev enp0s17  proto kernel  scope link  src 10.8.8.70 
10.10.1.0/24 dev enp0s8  proto kernel  scope link  src 10.10.1.79

Exclude all iptables-based services from ever being started:

# systemctl mask iptables ip6tables ebtables
ln -s '/dev/null' '/etc/systemd/system/iptables.service'
ln -s '/dev/null' '/etc/systemd/system/ip6tables.service'
ln -s '/dev/null' '/etc/systemd/system/ebtables.service'

There is apparently a bug in RHEL 7.1 and RHEL 7.2 that prevents the iptables service from being masked if the package iptables-services is not installed:

[rhel7.1]# systemctl mask iptables
Failed to issue method call: Access denied
[rhel7.1]# cat /var/log/audit/audit.log
type=USER_AVC msg=audit(1468920066.358:447): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='avc:  denied  { disable } for auid=0 uid=0 gid=0 cmdline="systemctl mask iptables ip6tables ebtables" scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:system_r:init_t:s0 tclass=service  exe="/usr/lib/systemd/systemd" sauid=0 hostname=? addr=? terminal=?'

The version of the policy that has a bug is this:

[rhel7.1]# rpm -q selinux-policy-targeted
selinux-policy-targeted-3.13.1-23.el7.noarch
[rhel7.2]# rpm -q selinux-policy-targeted
selinux-policy-targeted-3.13.1-60.el7.noarch

Installing the iptables-services package, or putting SELinux in to permissive mode, allows masking of iptables service on RHEL 7.1 and RHEL 7.2.

Firewalld Default Zone

Both network interfaces should be added to the zone public:

# firewall-cmd --get-active-zones
public
  interfaces: enp0s17 enp0s8

It should be the default zone:

# firewall-cmd --get-default-zone
public

We still want to set the default zone to public (so that we know how to change it), and assign the interface enp0s17 to the zone dmz.

Set the default firewall zone to public, remove the network interface enp0s17 from the zone public and add to the zone dmz.

# firewall-cmd --set-default-zone=public
# firewall-cmd --remove-interface=enp0s17 --zone=public
# firewall-cmd --permanent --add-interface=enp0s17 --zone=dmz

A permanent configuration requires a reload of the firewall configuration to work as expected:

# firewall-cmd --reload

Let us see the actives zones:

# firewall-cmd --get-active-zones
dmz
  interfaces: enp0s17
public
  interfaces: enp0s8

Make sure that zones are correctly set in the network scripts:

# nmcli con mod enp0s8 connection.zone public
# nmcli con mod enp0s17 connection.zone dmz
# nmcli c reload

Custom Firewalld Services

This part shows the way we can create custom firewalld services. We are going to create one for iSCSI target.

Copy one of the existing firewalld service configuration files, say for SSH:

# cp /usr/lib/firewalld/services/ssh.xml /etc/firewalld/services/iscsi-target.xml

Open the file /etc/firewalld/services/iscsi-target.xml for editing, and put the following:

<?xml version="1.0" encoding="utf-8"?>
<service>
 <short>iSCSI Target</short>
 <description>iSCSI target.</description>
 <port protocol="tcp" port="3260"/>
</service>

The newly created firewalld service can be added to the zone dmz this way:

# firewall-cmd --permanent --zone=dmz --add-service iscsi-target

More services depending on requirements can be also added, for example:

# firewall-cmd --permanent --zone=dmz --add-service={http,https,ldap,ldaps,kerberos,dns,kpasswd,ntp,ftp}
# firewall-cmd --reload

List all services that are added to the zone dmz:

# firewall-cmd --list-services --zone=dmz
dns ftp http https iscsi-target kerberos kpasswd ldap ldaps ntp ssh

List all services that are added to the zone public:

# firewall-cmd --list-services --zone=public
dhcpv6-client

Packet Forwarding

To configure routing, the server needs to forward incoming packets from one interface to another interface.

Create a new file /etc/sysctl.d/ip_forward.conf and add the following:

net.ipv4.ip_forward=1

The above makes the change permanent. Now change the runtime value:

# sysctl -w net.ipv4.ip_forward=1

Routing with Rich Rules

In general, all we have to do is to enable masquerading on the public interface. The command below masquerades packets coming from all hosts in the zone public:

# firewall-cmd --permanent --zone=public --add-masquerade
# firewall-cmd --reload

In other words, the above allows all traffic to leave from the zone dmz to the zone public.

The easy way to test this is to try to access some public website from any VM that resides in the dmz network 10.8.8.0/24. We have a server srv1 that’s on 10.8.8.71, and it has the default route going via 10.8.8.70:

[srv1]# ip ro
default via 10.8.8.70 dev mybond0  proto static  metric 1024 
10.8.8.0/24 dev mybond0  proto kernel  scope link  src 10.8.8.71

If we were to try to get access to example.com with masquerading disabled, we would have the following:

[srv1]# wget -O - http://example.com
--2016-06-18 17:47:30--  http://example.com/
Resolving example.com (example.com)... 93.184.216.34
Connecting to example.com (example.com)|93.184.216.34|:80... failed: No route to host.

When masquerading on the zone public is enabled, we can access the site:

[srv1]# wget http://example.com
Resolving example.com (example.com)... 93.184.216.34
Connecting to example.com (example.com)|93.184.216.34|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1270 (1.2K) [text/html]
Saving to: 'index.html'

100%[================================>] 1,270  --.-K/s   in 0s

2016-06-18 17:50:19 (129 MB/s) - 'index.html' saved [1270/1270]

If we need some more control over which packets exactly are masqueraded, we can add a rich rule that matches packets coming from specific source addresses only, for example:

# firewall-cmd --permanent --zone=public --add-rich-rule='rule family=ipv4 source address=10.8.8.0/24 masquerade'
# firewall-cmd --reload

Let us check the rich rule:

# firewall-cmd --zone=public --list-all
public (default, active)
  interfaces: enp0s8
  sources:
  services: dhcpv6-client
  ports:
  masquerade: yes
  forward-ports:
  icmp-blocks:
  rich rules:
      rule family="ipv4" source address="10.8.8.0/24" masquerade

Routing with Direct Rules

Routing can also be achieved with direct rules. However, the firewalld man page says that direct options should be used only as a last resort when it’s not possible to use for example –add-rich-rule=’rule’.

The syntax is below:

[--permanent] --direct --add-rule { ipv4 | ipv6 | eb } table chain priority args
    Add a rule with the arguments args to chain chain in table table with priority priority.

    The priority is used to order rules. Priority 0 means add rule on top of the chain, with a higher priority
    the rule will be added further down. Rules with the same priority are on the same level and the order of
    these rules is not fixed and may change. If you want to make sure that a rule will be added after another
    one, use a low priority for the first and a higher for the following.

To allow our dmz (enp0s17) network VMs with private IP addresses to communicate with external networks, we have to configure firewall for IP masquerading:

# firewall-cmd --permanent --direct --add-rule ipv4 nat POSTROUTING 0 -o enp0s8 -j MASQUERADE

Forward all ICMP requests from the zone dmz (enp0s17) to the zone public (enp0s8):

# firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 -i enp0s17 -o enp0s8 \
  -p icmp -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT

Do the same for all HTTP and HTTPS traffic:

# firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 -i enp0s17 -o enp0s8 \
  -p tcp -m multiport --dport 80,443 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT

Also allow access to public SMTP and SMTPS servers:

# firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 -i enp0s17 -o enp0s8 \
  -p tcp -m multiport --dport 25,465 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT

Allow to SSH into public servers:

# firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 -i enp0s17 -o enp0s8 \
  -p tcp --dport 22 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT

Log everything else:

# firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 -i enp0s17 -o enp0s8 \
  -j LOG --log-prefix "forward_fw "

Optional, but not really required:

# firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 -i enp0s17 -o enp0s8 -j REJECT

Reload:

# firewall-cmd --reload

Check the direct rules:

# firewall-cmd --direct --get-all-rules
ipv4 nat POSTROUTING 0 -o enp0s8 -j MASQUERADE
ipv4 filter FORWARD 0 -i enp0s17 -o enp0s8 -p icmp -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
ipv4 filter FORWARD 0 -i enp0s17 -o enp0s8 -p tcp -m multiport --dport 80,443 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
ipv4 filter FORWARD 0 -i enp0s17 -o enp0s8 -p tcp -m multiport --dport 25,465 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
ipv4 filter FORWARD 0 -i enp0s17 -o enp0s8 -p tcp --dport 22 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
ipv4 filter FORWARD 0 -i enp0s17 -o enp0s8 -j LOG --log-prefix 'forward_fw '

We can use the same server srv1 to test the rules above. Anything that doesn’t match should be blocked and logged. For example, let us try to access example.com via FTP:

[srv1]# wget -O - ftp://example.com
--2016-06-18 18:13:49--  ftp://example.com/
           => ‘.listing’
Resolving example.com (example.com)... 93.184.216.34
Connecting to example.com (example.com)|93.184.216.34|:21... failed: No route to host.

And the log entry should be:

forward_fw IN=enp0s17 OUT=enp0s8 MAC=08:00:27:ff:70:00:08:00:27:ff:81:00:08:00 SRC=10.8.8.71 DST=93.184.216.34 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=10304 DF PROTO=TCP SPT=34579 DPT=21 WINDOW=14600 RES=0x00 SYN URGP=0

Rich Rules and Port Forwarding

We may want to access servers that reside on the dmz network (10.8.8.0/24) from the public (10.10.1.0/24) over SSH. To do so, we need to put some port forwarding rules.

The rules below configure port forwarding so that connections to 10.10.1.79:2271 are forwarded to 10.8.8.71:22, and SSH logging.

# firewall-cmd --permanent --zone=public --add-forward-port='port=2271:proto=tcp:toport=22:toaddr=10.8.8.71'
# firewall-cmd --permanent --zone=public --add-rich-rule='rule service name=ssh log prefix="SSH_" level="debug" limit value=1/m reject'
# firewall-cmd --reload

Let us see the rules:

# firewall-cmd --list-all --zone=public
public (default, active)
  interfaces: enp0s8
  sources:
  services: dhcpv6-client
  ports:
  masquerade: yes
  forward-ports: port=2271:proto=tcp:toport=22:toaddr=10.8.8.71
  icmp-blocks:
  rich rules:
        rule service name="ssh" log prefix="SSH_" level="debug" limit value="1/m" reject

To test port forwarding, we need some server that’s in the public network (10.10.1.0/24):

[pub]$ ssh [email protected] -p2271
The authenticity of host '[10.10.1.79]:2271 ([10.10.1.79]:2271)' can't be established.
ECDSA key fingerprint is 32:e6:80:ec:ec:3e:d0:6a:7b:78:bf:6e:79:90:8f:2d.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[10.10.1.79]:2271' (ECDSA) to the list of known hosts.
[email protected]'s password: 
Last login: Sat Jun 18 17:29:59 2016 from 10.8.8.1

52 thoughts on “Firewalld Rich and Direct Rules: Setting up RHEL 7 Server as a Router

  1. Hi Tomas, sorry to bother you again on another topic…
    Port forwarding – from the firewall man page –
    –add-forward-port=port=portid[-portid]:proto=protocol[:toport=portid[-portid]][:toaddr=address[/mask]]
    It seems to me the “toaddr=address/mask” is conflicting with line below in the same man page
    “The port can either be a single port number portid or a port range portid-portid. The protocol can
    either be tcp or udp. The destination address is a simple IP address.”
    :::::
    So for example, is this an invalid destination address “10.10.1.0/24” ?
    Should it be a specific simple IP address?

    • It shouldn’t even allow you to create a port forwarding rule if I use a mask of anything but /32.

      The man page is correct, it is a simple IP address.

  2. Hey Tomas, the last question: should I enable anything to make firewalld direct rules work? any module?
    The following one is not working, maybe its not correct:

    [[email protected] ~]# firewall-cmd –permanent –direct –add-rule ipv4 filter INPUT 0 -s 192.168.0.103 -p tcp –dport 2222 reject
    success
    [[email protected] ~]# firewall-cmd –direct –get-all-rules
    [[email protected] ~]#

    • I use direct rules for routing, but never for filtering incoming traffic (that’s what you seem to want to do) as this can be easily achieved with firewalld rich rules. Let me know if you figure it out.

  3. I tried using http with rich-rule and source address method for one ip in defferent zone.
    But I always get Failed connect – ; No route to host
    What I am doing wrong here ??
    ——————case1
    [[email protected] ~]# firewall-cmd –permanent –remove-rich-rule=’rule family=”ipv4″ source address=”192.168.1.175/32″ service name=”http” log prefix=”http_from_x” level=”info” limit value=”30/m” accept’ –zone=work
    success
    [[email protected] ~]# firewall-cmd –permanent –remove-rich-rule=’rule family=”ipv4″ source address=”192.168.1.175″ service name=”http” log prefix=”http_from_y” level=”info” limit value=”30/m” accept’ –zone=work
    success

    [[email protected] ~]# firewall-cmd –reload
    success

    [[email protected] ~]# firewall-cmd –list-all –zone=work
    work
    interfaces:
    sources:
    services: dhcpv6-client ipp-client ssh
    ports:
    masquerade: no
    forward-ports:
    icmp-blocks:
    rich rules:
    rule family=”ipv4″ source address=”192.168.1.175/32″ service name=”http” log prefix=”http_from_x” level=”info” limit value=”30/m” accept
    rule family=”ipv4″ source address=”192.168.1.175″ service name=”http” log prefix=”http_from_y” level=”info” limit value=”30/m” accept

    ——————-case2
    [[email protected] ~]# firewall-cmd –new-zone=sphttp –permanent
    [[email protected] ~]# firewall-cmd –permanent –add-source=192.168.1.175 –zone=sphttp
    success
    [[email protected] ~]# firewall-cmd –permanent –add-source=192.168.1.175/32 –zone=sphttp
    success
    [[email protected] ~]# firewall-cmd –reload
    success
    [[email protected] ~]# firewall-cmd –list-all –zone=sphttp
    sphttp
    interfaces:
    sources: 192.168.1.175 192.168.1.175/32
    services: http
    ports:
    masquerade: no
    forward-ports:
    icmp-blocks:
    rich rules:
    ———————–error

    [[email protected] ~]# curl http://192.168.1.176
    curl: (7) Failed connect to 192.168.1.176:80; No route to host

    • By default it is only assigned to default public zone. Can we assign the same interface to more then one zone ? If so then how can we use other zones like internal,work etc..
      I thought It is good idea not to keep interface into the same zone to make it more secure
      e.g. to make ssh to only certain ips I create new zone “exam” for ssh, add source ips, remove ssh from pubic. No interface assigned to this zone to not override source IPs.
      The result of this will be a “exam” zone which permits access to ssh, but only from given IP addresses. This works fine. but it didn’t work for http.

      Here is the info.
      [[email protected] ~]# firewall-cmd –get-active-zones
      sphttp
      sources: 192.168.1.175 192.168.1.175/32
      public
      interfaces: eno16777736 eno33554960 eno50332184 team1
      exam
      sources: 192.168.1.0/24
      [[email protected] ~]# firewall-cmd –list-all –zone=public
      public (default, active)
      interfaces: eno16777736 eno33554960 eno50332184 team1
      sources:
      services: dhcpv6-client
      ports:
      masquerade: no
      forward-ports:
      icmp-blocks:
      rich rules:

      [email protected] ~]# firewall-cmd –list-all –zone=exam
      exam
      interfaces:
      sources: 192.168.1.0/24
      services: ssh
      ports: 2022/tcp
      masquerade: no
      forward-ports: port=2022:proto=tcp:toport=22:toaddr=
      icmp-blocks:
      rich rules:
      rule family=”ipv4″ source address=”192.168.1.175″ service name=”ssh” log prefix=”ssh-reject” level=”info” limit value=”3/m” reject
      rule family=”ipv4″ source address=”192.168.1.170″ service name=”ssh” log prefix=”ssh-reject” level=”info” limit value=”3/m” reject

      ——————————————
      My understanding/reading says:
      ———————————————-
      Traffic sources can be designated in two ways: By interface, or by source IP address. Traffic that matches any source passes this check. A firewalld zone defined with only source addresses and without interfaces will apply to all traffic from those addresses, regardless of which interface it came in.

      – is the packet coming from a source already bound to a zone? (if yes, it is associated with this zone),
      – if not, is the packet coming from a network interface already bound to a zone? (if yes, it is associated with this zone),
      – if not, the packet is associated with the default zone.

    • Ah, OK, I see what you mean. Yea, it would be the same with iptables rules that apply to all interfaces.

  4. I only want to add my observation, but still looking for the answer

    -Zone become active if you add source, service to the zone. So my second case 2 should work
    as it appears in active zone list.

    [[email protected] ~]# firewall-cmd –get-active-zones
    sphttp
    sources: 192.168.1.175 192.168.1.175/32
    public
    interfaces: eno16777736 eno33554960 eno50332184 team1
    exam
    sources: 192.168.1.0/24

    [[email protected] ~]# firewall-cmd –list-all –zone=sphttp
    sphttp
    interfaces:
    sources: 192.168.1.175 192.168.1.175/32
    services: http
    ports:

    —If you just add rich rule, zone doesn’t become active, so I may say case 1 may not work as it doesn’t appear in the active zone list. But if you look zone xml file /etc/firewalld/zones/work.xml then it does clearly define source, service. This throws another question – why zone do not become active with rich rule only ? I don’t see anywhere in the document where it mentions this specific issue. I also wonder if I am using firewalld right way ;)

  5. oh I mentioned it from the beginning of my thread but may be not clear
    I tried to allow http service with -rich-rule- and -source address- method for -one ip- in different zone.
    Both method doesn’t allow http service and fails with error “Failed connect – ; No route to host”

    • Do you get any hits for the http rule? If you don’t, then it’s blocked some other place before you even reach it.

  6. Hello,
    Thanks for your post, very helpful!
    Do you now if there is a way to limit the masquerading destination ? for exemple disable all http calls or enable only port 587 has destination?
    Thank for your answer.
    Regards

  7. Hello Amigo, thanks for your post.

    Not sure what is wrong on my below config, but i do not get PC on internal zone reach public zones.
    Below my config:
    [[email protected] ~]# firewall-cmd –direct –get-all-rules
    ipv4 nat POSTROUTING 0 -o eth0 -j MASQUERADE
    ipv4 filter FORWARD 0 -i eth1 -o eth0 -p icmp -m state –state NEW,RELATED,ESTABLISHED -j ACCEPT
    ipv4 filter FORWARD 0 -i eth1 -o eth0 -p tcp -m multiport –dport 80,443 -m state –state NEW,RELATED,ESTABLISHED -j ACCEPT
    ipv4 filter FORWARD 0 -i eth1 -o eth0 -j LOG –log-prefix ‘forward_fw ‘

    [[email protected] ~]# firewall-cmd –list-all –zone=internal
    internal (active)
    target: default
    icmp-block-inversion: no
    interfaces: eth1
    sources:
    services: ssh mdns samba-client http https dns smtp
    ports: 53/udp 80/tcp 443/tcp
    protocols: IP icmp
    masquerade: no
    forward-ports:
    source-ports:
    icmp-blocks:
    rich rules:

    [[email protected] ~]#
    [[email protected] ~]#
    [[email protected] ~]# firewall-cmd –list-all –zone=public
    public (active)
    target: default
    icmp-block-inversion: no
    interfaces: eth0
    sources:
    services: ssh dns http https
    ports:
    protocols: icmp ip
    masquerade: yes
    forward-ports:
    source-ports:
    icmp-blocks:
    rich rules:

    [[email protected] ~]# firewall-cmd –get-active-zones
    internal
    interfaces: eth1
    public
    interfaces: eth0

    • Please post the output of the following commands:

      # ip ro
      # iptables -nL
      # iptables -nL -t nat
      # cat /proc/sys/net/ipv4/ip_forward
  8. I am bit confused with port forwarding thing.

    This is what i am trying to acheive.
    When i ssh on server1 ( 192.168.1.244 ) on port 9090 , it should take me to server2 on port 22 (192.168.1.252)

    on Server 1: ( 192.168.1.244/24 )
    firewall-cmd –permanent –add-forward-port=’port=9090:proto=tcp:toport=22:toaddr=192.168.1.252′
    firewall-cmd –reload

    Server1: 192.168.1.244/24
    Server2: 192.168.1.252/24
    ssh runs on port 22 on both servers,
    firewall enabled on both servers

    After the above rule. ( from Server1: 192.168.1.244/24 itself)
    #ssh 192.168.1.244 -p9090
    ssh: connect to host 192.168.1.244 port 9090: Connection refused

    What the best way to test port forwarding in lab.
    1: do i need to enable masq ?

    Thanks for a detailed answer

    • It does work for me. Try the following on the server2:

      [server2]# ssh 192.168.1.244 -p9090

      The above will match the port forwarding rule that is set on the server1 and will forward the request to the server2. You do need to enable masquerading on the server1 as well as net.ipv4.ip_forward=1. Hope this explains it.

  9. Tomas, please help.

    I have server with external IP (I1) and I forward traffic through this server to other external ip (I2) and port. It works, but I want that I connect to I1 from certain externel ip.
    For example: 1.1.1.1:444 forward to 2.2.2.2:444 and I must connect to 1.1.1.1:444 only 3.3.3.3 other traffic must drop. Sorry for my English.

    I have this configuration, but I can connect from different ip to port 444.
    firewall-cmd –permanent –zone=public –add-forward-port=port=444:proto=tcp:toport=444:toaddr=94.22.11.11
    firewall-cmd –permanent –add-service=PRDP
    firewall-cmd –permanent –service=PRDP –add-port=444/tcp
    firewall-cmd –permanent –zone=public –set-target=DROP
    firewall-cmd –permanent –zone=public –add-rich-rule ‘rule family=”ipv4″ service name=”PRDP” source address=”My_IP” accept’

    How can I do it? Thank you.

  10. [[email protected] ~]# iptables -nL
    Chain INPUT (policy ACCEPT)
    target     prot opt source               destination
    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
    INPUT_direct  all  --  0.0.0.0/0            0.0.0.0/0
    INPUT_ZONES_SOURCE  all  --  0.0.0.0/0            0.0.0.0/0
    INPUT_ZONES  all  --  0.0.0.0/0            0.0.0.0/0
    DROP       all  --  0.0.0.0/0            0.0.0.0/0            ctstate INVALID
    REJECT     all  --  0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited
    
    Chain FORWARD (policy ACCEPT)
    target     prot opt source               destination
    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
    FORWARD_direct  all  --  0.0.0.0/0            0.0.0.0/0
    FORWARD_IN_ZONES_SOURCE  all  --  0.0.0.0/0            0.0.0.0/0
    FORWARD_IN_ZONES  all  --  0.0.0.0/0            0.0.0.0/0
    FORWARD_OUT_ZONES_SOURCE  all  --  0.0.0.0/0            0.0.0.0/0
    FORWARD_OUT_ZONES  all  --  0.0.0.0/0            0.0.0.0/0
    DROP       all  --  0.0.0.0/0            0.0.0.0/0            ctstate INVALID
    REJECT     all  --  0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited
    
    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination
    OUTPUT_direct  all  --  0.0.0.0/0            0.0.0.0/0
    
    Chain FORWARD_IN_ZONES (1 references)
    target     prot opt source               destination
    FWDI_public  all  --  0.0.0.0/0            0.0.0.0/0
    FWDI_public  all  --  0.0.0.0/0            0.0.0.0/0
    
    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  --  0.0.0.0/0            0.0.0.0/0
    FWDO_public  all  --  0.0.0.0/0            0.0.0.0/0
    
    Chain FORWARD_OUT_ZONES_SOURCE (1 references)
    target     prot opt source               destination
    
    Chain FORWARD_direct (1 references)
    target     prot opt source               destination
    
    Chain FWDI_public (2 references)
    target     prot opt source               destination
    FWDI_public_log  all  --  0.0.0.0/0            0.0.0.0/0
    FWDI_public_deny  all  --  0.0.0.0/0            0.0.0.0/0
    FWDI_public_allow  all  --  0.0.0.0/0            0.0.0.0/0
    DROP       all  --  0.0.0.0/0            0.0.0.0/0
    
    Chain FWDI_public_allow (1 references)
    target     prot opt source               destination
    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate NEW mark match 0x64
    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate NEW mark match 0x65
    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate NEW mark match 0x66
    
    Chain FWDI_public_deny (1 references)
    target     prot opt source               destination
    
    Chain FWDI_public_log (1 references)
    target     prot opt source               destination
    
    Chain FWDO_public (2 references)
    target     prot opt source               destination
    FWDO_public_log  all  --  0.0.0.0/0            0.0.0.0/0
    FWDO_public_deny  all  --  0.0.0.0/0            0.0.0.0/0
    FWDO_public_allow  all  --  0.0.0.0/0            0.0.0.0/0
    DROP       all  --  0.0.0.0/0            0.0.0.0/0
    
    Chain FWDO_public_allow (1 references)
    target     prot opt source               destination
    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
    
    Chain FWDO_public_deny (1 references)
    target     prot opt source               destination
    
    Chain FWDO_public_log (1 references)
    target     prot opt source               destination
    
    Chain INPUT_ZONES (1 references)
    target     prot opt source               destination
    IN_public  all  --  0.0.0.0/0            0.0.0.0/0
    IN_public  all  --  0.0.0.0/0            0.0.0.0/0
    
    Chain INPUT_ZONES_SOURCE (1 references)
    target     prot opt source               destination
    
    Chain INPUT_direct (1 references)
    target     prot opt source               destination
    REJECT     tcp  --  0.0.0.0/0            0.0.0.0/0            multiport dports 22 match-set fail2ban-sshd src reject-with icmp-port-unreachable
    REJECT     tcp  --  0.0.0.0/0            0.0.0.0/0            multiport dports 22 match-set fail2ban-sshd-ddos src reject-with icmp-port-unreachable
    REJECT     tcp  --  0.0.0.0/0            0.0.0.0/0            multiport dports 22 match-set fail2ban-dropbear src reject-with icmp-port-unreachable
    REJECT     tcp  --  0.0.0.0/0            0.0.0.0/0            multiport dports 22 match-set fail2ban-selinux-ssh src reject-with icmp-port-unreachable
    REJECT     tcp  --  0.0.0.0/0            0.0.0.0/0            multiport dports 80,443 match-set fail2ban-nginx-http-auth src reject-with icmp-port-unreachable
    REJECT     tcp  --  0.0.0.0/0            0.0.0.0/0            multiport dports 80,443 match-set fail2ban-nginx-limit-req src reject-with icmp-port-unreachable
    REJECT     tcp  --  0.0.0.0/0            0.0.0.0/0            multiport dports 80,443 match-set fail2ban-nginx-botsearch src reject-with icmp-port-unreachable
    REJECT     tcp  --  0.0.0.0/0            0.0.0.0/0            multiport dports 80,443 match-set fail2ban-php-url-fopen src reject-with icmp-port-unreachable
    
    Chain IN_public (2 references)
    target     prot opt source               destination
    IN_public_log  all  --  0.0.0.0/0            0.0.0.0/0
    IN_public_deny  all  --  0.0.0.0/0            0.0.0.0/0
    IN_public_allow  all  --  0.0.0.0/0            0.0.0.0/0
    DROP       all  --  0.0.0.0/0            0.0.0.0/0
    
    Chain IN_public_allow (1 references)
    target     prot opt source               destination
    ACCEPT     tcp  --  93.Y.184.74         0.0.0.0/0            tcp dpt:444 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 OUTPUT_direct (1 references)
    target     prot opt source               destination
    • Thanks. Even though firewalld uses netfilter under the hood, you sometimes need to get into direct rules to get advanced stuff working.

      Try the following (I use IPs and ports to match your example). Create a destination NAT rule to forward all (source 3.3.3.3/32) traffic from TCP port 444 to 2.2.2.2:444.

      # iptables -t nat -A PREROUTING -s 3.3.3.3/32 -p tcp --dport 444 -j DNAT --to-destination 2.2.2.2:444

      Then create a forwarding rule as well as allow all related and established traffic:

      # iptables -A FORWARD -d 2.2.2.2/32 -p tcp --dport 444 -j ACCEPT
      # iptables -A FORWARD -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT

      Finally, enable IP masquerading:

      # iptables -t nat -A POSTROUTING -p tcp -j MASQUERADE

      The above will do the trick. If you require a firewalld solution then you’ll have to figure it out yourself I’m afraid.

    • I’ve found solution with Firewalld -https://fedoraproject.org/wiki/Features/FirewalldRichLanguage

      firewall-cmd —zone=public —permanent —add-rich-rule=’rule family=”ipv4″ source address=”MY_IP” forward-port to-addr=”95.X.11.15″ to-port=”443″ port=”443″ protocol=”tcp”‘

      And this rule is being deleted -forward-ports: port=444:proto=tcp:toport=444:toaddr=95.X.11.15

  11. [[email protected] ~]# firewall-cmd --list-all --zone=public
    public (active)
      target: DROP
      icmp-block-inversion: no
      interfaces: eth0
      sources:
      services:
      ports:
      protocols:
      masquerade: yes
      forward-ports: port=444:proto=tcp:toport=444:toaddr=95.X.11.15
      sourceports:
      icmp-blocks:
      rich rules:
                rule family="ipv4" source address="93.Y.184.74" service name="PRDP" accept
  12. Hi Tomas, my server ip is 192.168.10.40. I just want forward the local port 22 to 80 on this server for systems in the 192.168.10.0/24 network. I just did: # firewall-cmd –permanent –add-forward-port=port=22:proto=tcp:toport=80 which is successful but I didn’t put any source addresses and destination address.Am I right here? If I need to put,Should I put network address(192.168.10.0) as source addresses or my server ip address 192.168.10.40? Or not needed at all?Please respond to me.

    • The last time I checked firewalld did not allow port redirection from localhost. I would suggest to use iptables to create a NAT rule to achieve port redirection.

    • Can do, but keep in mind that being able to find information is somewhat an exam requirement :)

      # iptables -t nat -A PREROUTING -p tcp -m tcp --dport 22 -j REDIRECT --to-ports 80
  13. Hi Tomas,
    Is your examples almost as the same as the exam? Am i correct, that if i have a 2 vm, they should be able to connect to internet? I am planning to do my testing offline. without connecting to internet. BUt your setup is should be able to coccent to internet..that is based from the exam setup you gave

    • These are examples from my homelab. You do not need internet connection to use the examples, as these are based on two private subnets 10.10.1.0/24 and 10.8.8.0/24 (see the blog post).

    • Firewalld uses iptables under the hood, so I find iptables quite helpful when I have to troubleshoot firewalld configuration. However, you don’t need to learn iptables to configure your server as a router, you can use firewalld.

  14. Ok thank you for your time. Can you please tell me, did you turn off your Netwokrmanager during exam? Is nmcli is really needed? Or modifying the config file is enough? I have mastered the iscsi,smtp mariadb, but im lacking with kerberos and this nmcli as well as the rich rules.. Im trying to squeeze my time, eliminate what i can eliminate. muy exam is in 15 days.. i Hvve 3 days to decide if i will resched it in May or not.

    • I cannot tell you what I did during the exam, but if you don’t feel confident, then it makes sense to reschedule it.

  15. Thomas, good afternoon.

    I am studying for the EX300 exam, but I have doubts about Rich Rules and Port Forwarding

    The Port Forwarding I understood

    to redirect ssh to port 6000
    $ firewall-cmd –add-forward-port=port=6000:proto=tcp:toport=22:toaddr=192.168.122.197

    # ssh -p 6000 192.168.122.197 – it’s ok

    Now to do the same using the rich rules I’m not getting

    $ firewall-cmd –add-rich-rule ‘rule family=ipv4 source address=192.168.122.197 forward-port port=80 protocol=tcp to-port=8080’

    $ elinks http://192.168.122.197:8080

    The “conection refused” error occurs

    # firewall-cmd –list-all
    public (default, active)
    interfaces: eth0 eth1 team0
    sources:
    services: dhcpv6-client http https ssh
    ports: 3260/tcp
    masquerade: yes
    forward-ports:
    icmp-blocks:
    rich rules:
    rule family=”ipv4″ source address=”192.168.122.197″ forward-port port=”80″ protocol=”tcp” to-port=”8080″

    what am I doing wrong?

    thank you

    • In the second example you seem to use IP 192.168.122.197 as the source address, however, in the first example the same IP address is used as the destination address.

    • It was just an example. I meant that with port-forward I was able to redirect ssh.

      But using the rich rules technique I can not redirect

      firewall-cmd –add-rich-rule “rule family=ipv4 source address=192.168.122.197 forward-port port=6000 protocol=tcp to-port=22”

    • Firewalld does not allow port redirection from localhost. If you try from another server, it should work.

  16. Hello Tomas

    Last week i gave RHCSA exam and got 300/300 now I’m preparing for RHCE exam

    I installed IPA server on centos 7.2 using VirtualBoz and on IPA server i have two interfaces enp0s3 and enp0s8. I added enp0s3 (interface facing Internet) part of Public Zone and enp0s8 is part of DMZ zone with IP Addr = 10.8.8.2

    And on Second server i have one interface enp0s3(Host Only Network) with IP Addr = 10.8.8.50 part of DMZ Zone and made 10.8.8.2 gw of this second server

    I enabled masquerading on public zone of IPA Server . But when i try to ping ipa server i get “ping: unknown host ipa” same case if i try to ping http://www.google.com “ping: unknown host http://www.google.com

    If i revert back all changes and make enp0s3 and enp0s8 part of public zone on IPA server it start working but stops working as soon i make enp0s8 part of DMZ zone. Any suggestions

    • The error message suggests that your DNS resolution may not be working properly.

      Try accessing the IPA server on the IP address and see if that works.

  17. From firewall-cmd on IPA server i added following services and ports in both PUBLIC and DMZ Zones
    dmz (active)
    interfaces: enp0s8
    sources:
    services: ssh
    ports: 443/tcp 80/tcp 88/udp 464/udp 88/tcp 123/udp 389/tcp 53/tcp 53/udp 636/tcp
    masquerade: no ——————————————— (and yes on Public Zone)
    forward-ports:
    icmp-blocks:
    rich rules:

    It started working, i was able to ping ipa again using name, but when i added the gw on Serv1(10.8.8.50) IP addr of IPA server 10.8.8.2. it stopped working

    On Serv1(10.8.8.50) default zone is still public ,

    • It seems the issue was on Serv1(10.8.8.50) Firewall Zone. Previously default zone was set to Public then i change the default to DMZ it started working. My guess is both zone on IPA and Client should be same zone depending on port and gateway ,especially gateway because 10.8.8.2 enp0s8 is part of dmz zone and not public

  18. Thanks for the good information. Do you have any experience with configuring this same setup in an AWS cloud environment where only 1 interface is required? I’ve tried to sort it out but most of the rules you created in the final steps refer to passing the protocol from 1 interface to the other.

    • My AWS setup is a bit different thanks to NAT gateways. I used instances with 2 interfaces some years ago, nowadays I create private and public subnets, and use a NAT gateway for instances in the private one.

Leave a Reply to VDV Cancel reply

Your email address will not be published. Required fields are marked *