Use Dynamic Firewall Manager to configure a basic zone-based firewall.

From my point of view, this is the best possible solution as you can use it to reliably configure multiple Linux operating systems regardless of the family and automate it using Ansible or any other configuration management utilities.

Installation

Install Dynamic Firewall Manager.

$ sudo apt install firewalld

It will use the nftables framework by default.

$ update-alternatives --query iptables
Name: iptables
Link: /usr/sbin/iptables
Slaves:
 iptables-restore /usr/sbin/iptables-restore
 iptables-save /usr/sbin/iptables-save
Status: auto
Best: /usr/sbin/iptables-nft
Value: /usr/sbin/iptables-nft

Alternative: /usr/sbin/iptables-legacy
Priority: 10
Slaves:
 iptables-restore /usr/sbin/iptables-legacy-restore
 iptables-save /usr/sbin/iptables-legacy-save

Alternative: /usr/sbin/iptables-nft
Priority: 20
Slaves:
 iptables-restore /usr/sbin/iptables-nft-restore
 iptables-save /usr/sbin/iptables-nft-save

Server services

There are two interfaces eth0 (external) and eth1 (internal).

$ ip --brief address show scope global 
eth0             UP             10.10.1.29/16 
eth1             UP             172.16.0.1/16 

Services running on this server.

$ sudo ss -l4pn
Netid      State       Recv-Q       Send-Q             Local Address:Port             Peer Address:Port      Process                                
udp        UNCONN      0            0                     172.16.0.1:53                    0.0.0.0:*          users:(("named",pid=485,fd=21))       
udp        UNCONN      0            0                     10.10.1.29:53                    0.0.0.0:*          users:(("named",pid=485,fd=18))       
udp        UNCONN      0            0                      127.0.0.1:53                    0.0.0.0:*          users:(("named",pid=485,fd=15))       
udp        UNCONN      0            0                     172.16.0.1:123                   0.0.0.0:*          users:(("chronyd",pid=512,fd=5))      
tcp        LISTEN      0            10                    172.16.0.1:53                    0.0.0.0:*          users:(("named",pid=485,fd=22))       
tcp        LISTEN      0            10                    10.10.1.29:53                    0.0.0.0:*          users:(("named",pid=485,fd=19))       
tcp        LISTEN      0            10                     127.0.0.1:53                    0.0.0.0:*          users:(("named",pid=485,fd=16))       
tcp        LISTEN      0            128                      0.0.0.0:22                    0.0.0.0:*          users:(("sshd",pid=508,fd=3))         
tcp        LISTEN      0            4096                   127.0.0.1:953                   0.0.0.0:*          users:(("named",pid=485,fd=23))       
tcp        LISTEN      0            511                      0.0.0.0:80                    0.0.0.0:*          users:(("nginx",pid=519,fd=6),("nginx",pid=518,fd=6))

We want to allow ssh on external and internal interface. Limit DNS (BIND), NTP (chrony), and HTTP server (nginx) to the internal interface.

Check firewall state

Check permanent configuration.

$ sudo firewall-cmd --check-config
success

Check service state.

$ sudo firewall-cmd --state
running

Inspect predefined zones

There is a list of already predefined zones.

$ firewall-cmd --get-zones
block dmz drop external home internal public trusted work

Zone definitions according to the trust level from the least to most trusted.

$ cat /usr/lib/firewalld/zones/drop.xml
<?xml version="1.0" encoding="utf-8"?>
<zone target="DROP">
  <short>Drop</short>
  <description>Unsolicited incoming network packets are dropped. Incoming packets that are related to outgoing network connections are accepte
d. Outgoing network connections are allowed.</description>
</zone>
$ cat /usr/lib/firewalld/zones/block.xml
<?xml version="1.0" encoding="utf-8"?>                                                                                                        
<zone target="%%REJECT%%">                                          
  <short>Block</short>
  <description>Unsolicited incoming network packets are rejected. Incoming packets that are related to outgoing network connections are accepted. Outgoing network connections are allowed.</description>
</zone>                                                             
$ cat /usr/lib/firewalld/zones/public.xml
<?xml version="1.0" encoding="utf-8"?>
<zone>
  <short>Public</short>
  <description>For use in public areas. You do not trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted.</description>
  <service name="ssh"/>
  <service name="dhcpv6-client"/>
</zone>
$ cat /usr/lib/firewalld/zones/external.xml
<?xml version="1.0" encoding="utf-8"?>
<zone>
  <short>External</short> 
  <description>For use on external networks. You do not trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted.</description>
  <service name="ssh"/>
  <masquerade/>
</zone>
$ cat /usr/lib/firewalld/zones/dmz.xml
<?xml version="1.0" encoding="utf-8"?>
<zone>
  <short>DMZ</short>
  <description>For computers in your demilitarized zone that are publicly-accessible with limited access to your internal network. Only selected incoming connections are accepted.</description>
  <service name="ssh"/>
</zone>
$ cat /usr/lib/firewalld/zones/work.xml
<?xml version="1.0" encoding="utf-8"?>
<zone>
  <short>Work</short>
  <description>For use in work areas. You mostly trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted.</description>
  <service name="ssh"/>
  <service name="dhcpv6-client"/>
</zone>
$ cat /usr/lib/firewalld/zones/home.xml
<?xml version="1.0" encoding="utf-8"?>
<zone>
  <short>Home</short>
  <description>For use in home areas. You mostly trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted.</description>
  <service name="ssh"/>
  <service name="mdns"/>
  <service name="samba-client"/>
  <service name="dhcpv6-client"/>
</zone>
$ cat /usr/lib/firewalld/zones/internal.xml
<?xml version="1.0" encoding="utf-8"?>
<zone>
  <short>Internal</short> 
  <description>For use on internal networks. You mostly trust the other computers on the networks to not harm your computer. Only selected incoming connections are accepted.</description>
  <service name="ssh"/>
  <service name="mdns"/>
  <service name="samba-client"/>
  <service name="dhcpv6-client"/>
</zone>
$ cat /usr/lib/firewalld/zones/trusted.xml
<?xml version="1.0" encoding="utf-8"?>
<zone target="ACCEPT">
  <short>Trusted</short>
  <description>All network connections are accepted.</description>
</zone>

Each zone definition contains basic configuration. Please read firewalld.zones and firewalld.zone manual pages. You can create your own zones or use the existing ones.

Assign interfaces to zones

Assign eth0 interface to the external zone.

$ sudo firewall-cmd --zone=external --add-interface=eth0
success

Assign eth1 interface to the internal zone.

$ sudo firewall-cmd --zone=internal --add-interface=eth1
success

Set the default zone for any other interface.

$ sudo firewall-cmd --set-default-zone=drop
success

Display active zones.

$ sudo firewall-cmd --get-active-zones 
external
  interfaces: eth0
internal
  interfaces: eth1

Display current external zone.

$ sudo firewall-cmd --list-all --zone=external 
external (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources: 
  services: ssh
  ports: 
  protocols: 
  forward: no
  masquerade: yes
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

Display current internal zone.

$ sudo firewall-cmd --list-all --zone=internal 
internal (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth1
  sources: 
  services: dhcpv6-client mdns samba-client ssh
  ports: 
  protocols: 
  forward: no
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

Make configuration permanent.

$ sudo firewall-cmd --runtime-to-permanent
success

Services

List predefined services.

$ sudo firewall-cmd --get-services
RH-Satellite-6 RH-Satellite-6-capsule amanda-client amanda-k5-client amqp amqps apcupsd audit bacula bacula-client bb bgp bitcoin bitcoin-rpc bitcoin-testnet bitcoin-testnet-rpc bittorrent-lsd ceph ceph-mon cfengine cockpit collectd condor-collector ctdb dhcp dhcpv6 dhcpv6-client distcc dns dns-over-tls docker-registry docker-swarm dropbox-lansync elasticsearch etcd-client etcd-server finger foreman foreman-proxy freeipa-4 freeipa-ldap freeipa-ldaps freeipa-replication freeipa-trust ftp ganglia-client ganglia-master git grafana gre high-availability http https imap imaps ipp ipp-client ipsec irc ircs iscsi-target isns jenkins kadmin kdeconnect kerberos kibana klogin kpasswd kprop kshell kube-apiserver ldap ldaps libvirt libvirt-tls lightning-network llmnr managesieve matrix mdns memcache minidlna mongodb mosh mountd mqtt mqtt-tls ms-wbt mssql murmur mysql nbd nfs nfs3 nmea-0183 nrpe ntp nut openvpn ovirt-imageio ovirt-storageconsole ovirt-vmconsole plex pmcd pmproxy pmwebapi pmwebapis pop3 pop3s postgresql privoxy prometheus proxy-dhcp ptp pulseaudio puppetmaster quassel radius rdp redis redis-sentinel rpc-bind rquotad rsh rsyncd rtsp salt-master samba samba-client samba-dc sane sip sips slp smtp smtp-submission smtps snmp snmptrap spideroak-lansync spotify-sync squid ssdp ssh steam-streaming svdrp svn syncthing syncthing-gui synergy syslog syslog-tls telnet tentacle tftp tftp-client tile38 tinc tor-socks transmission-client upnp-client vdsm vnc-server wbem-http wbem-https wsman wsmans xdmcp xmpp-bosh xmpp-client xmpp-local xmpp-server zabbix-agent zabbix-server

Inspect sample ssh service definition.

$ cat /usr/lib/firewalld/services/ssh.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>SSH</short>
  <description>Secure Shell (SSH) is a protocol for logging into and executing commands on remote machines. It provides secure encrypted communications. If you plan on accessing your machine remotely via SSH over a firewalled interface, enable this option. You need the openssh-server package installed for this option to be useful.</description>
  <port protocol="tcp" port="22"/>
</service>

Read firewalld.service manual page to define custom firewalld service configuration file.

Configure services for each zone

List services enabled in the external zone.

$ sudo firewall-cmd --list-services --zone=external
ssh

List services enabled in the internal zone.

$ sudo firewall-cmd --list-services --zone=internal
dhcpv6-client mdns samba-client ssh

Disable not used services.

$ sudo firewall-cmd --zone=internal --remove-service=dhcpv6-client 
success
$ sudo firewall-cmd --zone=internal --remove-service=mdns
success
$ sudo firewall-cmd --zone=internal --remove-service=samba-client 
success

Enable DNS (BIND) service.

$ sudo firewall-cmd --zone=internal --add-service=dns
success

Enable HTTP (nginx) service.

$ sudo firewall-cmd --zone=internal --add-service=http
success

Enable NTP (chrony) service.

$ sudo firewall-cmd --zone=internal --add-service=ntp
success

List enabled services in the internal zone.

$ sudo firewall-cmd --list-services --zone=internal
dns http ntp ssh

Make configuration permanent.

$ sudo firewall-cmd --runtime-to-permanent
success

Reload permanent configuration

Reload permanent configuration to drop any runtime changes.

$ sudo firewall-cmd --zone=internal --add-service=dhcpv6-client 
success
$ sudo firewall-cmd --zone=internal --list-services
dhcpv6-client dns http ntp ssh
$ sudo firewall-cmd --reload
success
$ sudo firewall-cmd --zone=internal --list-services
dns http ntp ssh

Additional notes

This is a basic introduction to show you how easy is to use Dynamic Firewall Manager. Play with it to learn some more advanced concepts.

You can define any other zone as default (like public) to ease configuration process, especially when there is only one interface.

Some services like docker will create it own zone.

$ firewall-cmd --get-active-zones 
docker
  interfaces: docker0
external
  interfaces: eth0
internal
  interfaces: eth1
$ sudo cat /etc/firewalld/zones/docker.xml
<?xml version="1.0" encoding="utf-8"?>
<zone version="1.0" target="ACCEPT">
  <short>docker</short>
  <description>zone for docker bridge network interfaces</description>
</zone>

Sample nftables ruleset.

$ nft list ruleset
table inet firewalld {
	chain raw_PREROUTING {
		type filter hook prerouting priority raw + 10; policy accept;
		icmpv6 type { nd-router-advert, nd-neighbor-solicit } accept
		meta nfproto ipv6 fib saddr . iif oif missing drop
	}

	chain mangle_PREROUTING {
		type filter hook prerouting priority mangle + 10; policy accept;
		jump mangle_PREROUTING_POLICIES_pre
		jump mangle_PREROUTING_ZONES
		jump mangle_PREROUTING_POLICIES_post
	}

	chain mangle_PREROUTING_POLICIES_pre {
		jump mangle_PRE_policy_allow-host-ipv6
	}

	chain mangle_PREROUTING_ZONES {
		iifname "eth1" goto mangle_PRE_internal
		iifname "eth0" goto mangle_PRE_external
		goto mangle_PRE_drop
	}

	chain mangle_PREROUTING_POLICIES_post {
	}

	chain filter_INPUT {
		type filter hook input priority filter + 10; policy accept;
		ct state { established, related } accept
		ct status dnat accept
		iifname "lo" accept
		jump filter_INPUT_POLICIES_pre
		jump filter_INPUT_ZONES
		jump filter_INPUT_POLICIES_post
		ct state { invalid } drop
		reject with icmpx type admin-prohibited
	}

	chain filter_FORWARD {
		type filter hook forward priority filter + 10; policy accept;
		ct state { established, related } accept
		ct status dnat accept
		iifname "lo" accept
		ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } reject with icmpv6 type addr-unreachable
		jump filter_FORWARD_POLICIES_pre
		jump filter_FORWARD_IN_ZONES
		jump filter_FORWARD_OUT_ZONES
		jump filter_FORWARD_POLICIES_post
		ct state { invalid } drop
		reject with icmpx type admin-prohibited
	}

	chain filter_OUTPUT {
		type filter hook output priority filter + 10; policy accept;
		oifname "lo" accept
		ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } reject with icmpv6 type addr-unreachable
		jump filter_OUTPUT_POLICIES_pre
		jump filter_OUTPUT_POLICIES_post
	}

	chain filter_INPUT_POLICIES_pre {
		jump filter_IN_policy_allow-host-ipv6
	}

	chain filter_INPUT_ZONES {
		iifname "eth1" goto filter_IN_internal
		iifname "eth0" goto filter_IN_external
		goto filter_IN_drop
	}

	chain filter_INPUT_POLICIES_post {
	}

	chain filter_FORWARD_POLICIES_pre {
	}

	chain filter_FORWARD_IN_ZONES {
		iifname "eth1" goto filter_FWDI_internal
		iifname "eth0" goto filter_FWDI_external
		goto filter_FWDI_drop
	}

	chain filter_FORWARD_OUT_ZONES {
		oifname "eth1" goto filter_FWDO_internal
		oifname "eth0" goto filter_FWDO_external
		goto filter_FWDO_drop
	}

	chain filter_FORWARD_POLICIES_post {
	}

	chain filter_OUTPUT_POLICIES_pre {
	}

	chain filter_OUTPUT_POLICIES_post {
	}

	chain filter_IN_external {
		jump filter_IN_external_pre
		jump filter_IN_external_log
		jump filter_IN_external_deny
		jump filter_IN_external_allow
		jump filter_IN_external_post
		meta l4proto { icmp, ipv6-icmp } accept
	}

	chain filter_IN_external_pre {
	}

	chain filter_IN_external_log {
	}

	chain filter_IN_external_deny {
	}

	chain filter_IN_external_allow {
		tcp dport 22 ct state { new, untracked } accept
	}

	chain filter_IN_external_post {
	}

	chain filter_FWDO_external {
		jump filter_FWDO_external_pre
		jump filter_FWDO_external_log
		jump filter_FWDO_external_deny
		jump filter_FWDO_external_allow
		jump filter_FWDO_external_post
	}

	chain filter_FWDO_external_pre {
	}

	chain filter_FWDO_external_log {
	}

	chain filter_FWDO_external_deny {
	}

	chain filter_FWDO_external_allow {
		ct state { new, untracked } accept
	}

	chain filter_FWDO_external_post {
	}

	chain filter_FWDI_external {
		jump filter_FWDI_external_pre
		jump filter_FWDI_external_log
		jump filter_FWDI_external_deny
		jump filter_FWDI_external_allow
		jump filter_FWDI_external_post
		meta l4proto { icmp, ipv6-icmp } accept
	}

	chain filter_FWDI_external_pre {
	}

	chain filter_FWDI_external_log {
	}

	chain filter_FWDI_external_deny {
	}

	chain filter_FWDI_external_allow {
	}

	chain filter_FWDI_external_post {
	}

	chain mangle_PRE_external {
		jump mangle_PRE_external_pre
		jump mangle_PRE_external_log
		jump mangle_PRE_external_deny
		jump mangle_PRE_external_allow
		jump mangle_PRE_external_post
	}

	chain mangle_PRE_external_pre {
	}

	chain mangle_PRE_external_log {
	}

	chain mangle_PRE_external_deny {
	}

	chain mangle_PRE_external_allow {
	}

	chain mangle_PRE_external_post {
	}

	chain filter_IN_internal {
		jump filter_IN_internal_pre
		jump filter_IN_internal_log
		jump filter_IN_internal_deny
		jump filter_IN_internal_allow
		jump filter_IN_internal_post
		meta l4proto { icmp, ipv6-icmp } accept
	}

	chain filter_IN_internal_pre {
	}

	chain filter_IN_internal_log {
	}

	chain filter_IN_internal_deny {
	}

	chain filter_IN_internal_allow {
		tcp dport 22 ct state { new, untracked } accept
		tcp dport 53 ct state { new, untracked } accept
		udp dport 53 ct state { new, untracked } accept
		tcp dport 80 ct state { new, untracked } accept
		udp dport 123 ct state { new, untracked } accept
	}

	chain filter_IN_internal_post {
	}

	chain filter_FWDO_internal {
		jump filter_FWDO_internal_pre
		jump filter_FWDO_internal_log
		jump filter_FWDO_internal_deny
		jump filter_FWDO_internal_allow
		jump filter_FWDO_internal_post
	}

	chain filter_FWDO_internal_pre {
	}

	chain filter_FWDO_internal_log {
	}

	chain filter_FWDO_internal_deny {
	}

	chain filter_FWDO_internal_allow {
	}

	chain filter_FWDO_internal_post {
	}

	chain filter_FWDI_internal {
		jump filter_FWDI_internal_pre
		jump filter_FWDI_internal_log
		jump filter_FWDI_internal_deny
		jump filter_FWDI_internal_allow
		jump filter_FWDI_internal_post
		meta l4proto { icmp, ipv6-icmp } accept
	}

	chain filter_FWDI_internal_pre {
	}

	chain filter_FWDI_internal_log {
	}

	chain filter_FWDI_internal_deny {
	}

	chain filter_FWDI_internal_allow {
	}

	chain filter_FWDI_internal_post {
	}

	chain mangle_PRE_internal {
		jump mangle_PRE_internal_pre
		jump mangle_PRE_internal_log
		jump mangle_PRE_internal_deny
		jump mangle_PRE_internal_allow
		jump mangle_PRE_internal_post
	}

	chain mangle_PRE_internal_pre {
	}

	chain mangle_PRE_internal_log {
	}

	chain mangle_PRE_internal_deny {
	}

	chain mangle_PRE_internal_allow {
	}

	chain mangle_PRE_internal_post {
	}

	chain filter_IN_drop {
		jump filter_IN_drop_pre
		jump filter_IN_drop_log
		jump filter_IN_drop_deny
		jump filter_IN_drop_allow
		jump filter_IN_drop_post
		drop
	}

	chain filter_IN_drop_pre {
	}

	chain filter_IN_drop_log {
	}

	chain filter_IN_drop_deny {
	}

	chain filter_IN_drop_allow {
	}

	chain filter_IN_drop_post {
	}

	chain filter_FWDO_drop {
		jump filter_FWDO_drop_pre
		jump filter_FWDO_drop_log
		jump filter_FWDO_drop_deny
		jump filter_FWDO_drop_allow
		jump filter_FWDO_drop_post
		drop
	}

	chain filter_FWDO_drop_pre {
	}

	chain filter_FWDO_drop_log {
	}

	chain filter_FWDO_drop_deny {
	}

	chain filter_FWDO_drop_allow {
	}

	chain filter_FWDO_drop_post {
	}

	chain filter_FWDI_drop {
		jump filter_FWDI_drop_pre
		jump filter_FWDI_drop_log
		jump filter_FWDI_drop_deny
		jump filter_FWDI_drop_allow
		jump filter_FWDI_drop_post
		drop
	}

	chain filter_FWDI_drop_pre {
	}

	chain filter_FWDI_drop_log {
	}

	chain filter_FWDI_drop_deny {
	}

	chain filter_FWDI_drop_allow {
	}

	chain filter_FWDI_drop_post {
	}

	chain mangle_PRE_drop {
		jump mangle_PRE_drop_pre
		jump mangle_PRE_drop_log
		jump mangle_PRE_drop_deny
		jump mangle_PRE_drop_allow
		jump mangle_PRE_drop_post
	}

	chain mangle_PRE_drop_pre {
	}

	chain mangle_PRE_drop_log {
	}

	chain mangle_PRE_drop_deny {
	}

	chain mangle_PRE_drop_allow {
	}

	chain mangle_PRE_drop_post {
	}

	chain filter_IN_policy_allow-host-ipv6 {
		jump filter_IN_policy_allow-host-ipv6_pre
		jump filter_IN_policy_allow-host-ipv6_log
		jump filter_IN_policy_allow-host-ipv6_deny
		jump filter_IN_policy_allow-host-ipv6_allow
		jump filter_IN_policy_allow-host-ipv6_post
	}

	chain filter_IN_policy_allow-host-ipv6_pre {
	}

	chain filter_IN_policy_allow-host-ipv6_log {
	}

	chain filter_IN_policy_allow-host-ipv6_deny {
	}

	chain filter_IN_policy_allow-host-ipv6_allow {
		icmpv6 type nd-neighbor-advert accept
		icmpv6 type nd-neighbor-solicit accept
		icmpv6 type nd-router-advert accept
		icmpv6 type nd-redirect accept
	}

	chain filter_IN_policy_allow-host-ipv6_post {
	}

	chain mangle_PRE_policy_allow-host-ipv6 {
		jump mangle_PRE_policy_allow-host-ipv6_pre
		jump mangle_PRE_policy_allow-host-ipv6_log
		jump mangle_PRE_policy_allow-host-ipv6_deny
		jump mangle_PRE_policy_allow-host-ipv6_allow
		jump mangle_PRE_policy_allow-host-ipv6_post
	}

	chain mangle_PRE_policy_allow-host-ipv6_pre {
	}

	chain mangle_PRE_policy_allow-host-ipv6_log {
	}

	chain mangle_PRE_policy_allow-host-ipv6_deny {
	}

	chain mangle_PRE_policy_allow-host-ipv6_allow {
	}

	chain mangle_PRE_policy_allow-host-ipv6_post {
	}
}
table ip firewalld {
	chain nat_PREROUTING {
		type nat hook prerouting priority dstnat + 10; policy accept;
		jump nat_PREROUTING_POLICIES_pre
		jump nat_PREROUTING_ZONES
		jump nat_PREROUTING_POLICIES_post
	}

	chain nat_PREROUTING_POLICIES_pre {
		jump nat_PRE_policy_allow-host-ipv6
	}

	chain nat_PREROUTING_ZONES {
		iifname "eth1" goto nat_PRE_internal
		iifname "eth0" goto nat_PRE_external
		goto nat_PRE_drop
	}

	chain nat_PREROUTING_POLICIES_post {
	}

	chain nat_POSTROUTING {
		type nat hook postrouting priority srcnat + 10; policy accept;
		jump nat_POSTROUTING_POLICIES_pre
		jump nat_POSTROUTING_ZONES
		jump nat_POSTROUTING_POLICIES_post
	}

	chain nat_POSTROUTING_POLICIES_pre {
	}

	chain nat_POSTROUTING_ZONES {
		oifname "eth1" goto nat_POST_internal
		oifname "eth0" goto nat_POST_external
		goto nat_POST_drop
	}

	chain nat_POSTROUTING_POLICIES_post {
	}

	chain nat_POST_external {
		jump nat_POST_external_pre
		jump nat_POST_external_log
		jump nat_POST_external_deny
		jump nat_POST_external_allow
		jump nat_POST_external_post
	}

	chain nat_POST_external_pre {
	}

	chain nat_POST_external_log {
	}

	chain nat_POST_external_deny {
	}

	chain nat_POST_external_allow {
		oifname != "lo" masquerade
	}

	chain nat_POST_external_post {
	}

	chain nat_PRE_external {
		jump nat_PRE_external_pre
		jump nat_PRE_external_log
		jump nat_PRE_external_deny
		jump nat_PRE_external_allow
		jump nat_PRE_external_post
	}

	chain nat_PRE_external_pre {
	}

	chain nat_PRE_external_log {
	}

	chain nat_PRE_external_deny {
	}

	chain nat_PRE_external_allow {
	}

	chain nat_PRE_external_post {
	}

	chain nat_POST_internal {
		jump nat_POST_internal_pre
		jump nat_POST_internal_log
		jump nat_POST_internal_deny
		jump nat_POST_internal_allow
		jump nat_POST_internal_post
	}

	chain nat_POST_internal_pre {
	}

	chain nat_POST_internal_log {
	}

	chain nat_POST_internal_deny {
	}

	chain nat_POST_internal_allow {
	}

	chain nat_POST_internal_post {
	}

	chain nat_PRE_internal {
		jump nat_PRE_internal_pre
		jump nat_PRE_internal_log
		jump nat_PRE_internal_deny
		jump nat_PRE_internal_allow
		jump nat_PRE_internal_post
	}

	chain nat_PRE_internal_pre {
	}

	chain nat_PRE_internal_log {
	}

	chain nat_PRE_internal_deny {
	}

	chain nat_PRE_internal_allow {
	}

	chain nat_PRE_internal_post {
	}

	chain nat_POST_drop {
		jump nat_POST_drop_pre
		jump nat_POST_drop_log
		jump nat_POST_drop_deny
		jump nat_POST_drop_allow
		jump nat_POST_drop_post
	}

	chain nat_POST_drop_pre {
	}

	chain nat_POST_drop_log {
	}

	chain nat_POST_drop_deny {
	}

	chain nat_POST_drop_allow {
	}

	chain nat_POST_drop_post {
	}

	chain nat_PRE_drop {
		jump nat_PRE_drop_pre
		jump nat_PRE_drop_log
		jump nat_PRE_drop_deny
		jump nat_PRE_drop_allow
		jump nat_PRE_drop_post
	}

	chain nat_PRE_drop_pre {
	}

	chain nat_PRE_drop_log {
	}

	chain nat_PRE_drop_deny {
	}

	chain nat_PRE_drop_allow {
	}

	chain nat_PRE_drop_post {
	}

	chain nat_PRE_policy_allow-host-ipv6 {
		jump nat_PRE_policy_allow-host-ipv6_pre
		jump nat_PRE_policy_allow-host-ipv6_log
		jump nat_PRE_policy_allow-host-ipv6_deny
		jump nat_PRE_policy_allow-host-ipv6_allow
		jump nat_PRE_policy_allow-host-ipv6_post
	}

	chain nat_PRE_policy_allow-host-ipv6_pre {
	}

	chain nat_PRE_policy_allow-host-ipv6_log {
	}

	chain nat_PRE_policy_allow-host-ipv6_deny {
	}

	chain nat_PRE_policy_allow-host-ipv6_allow {
	}

	chain nat_PRE_policy_allow-host-ipv6_post {
	}
}
table ip6 firewalld {
	chain nat_PREROUTING {
		type nat hook prerouting priority dstnat + 10; policy accept;
		jump nat_PREROUTING_POLICIES_pre
		jump nat_PREROUTING_ZONES
		jump nat_PREROUTING_POLICIES_post
	}

	chain nat_PREROUTING_POLICIES_pre {
		jump nat_PRE_policy_allow-host-ipv6
	}

	chain nat_PREROUTING_ZONES {
		iifname "eth1" goto nat_PRE_internal
		iifname "eth0" goto nat_PRE_external
		goto nat_PRE_drop
	}

	chain nat_PREROUTING_POLICIES_post {
	}

	chain nat_POSTROUTING {
		type nat hook postrouting priority srcnat + 10; policy accept;
		jump nat_POSTROUTING_POLICIES_pre
		jump nat_POSTROUTING_ZONES
		jump nat_POSTROUTING_POLICIES_post
	}

	chain nat_POSTROUTING_POLICIES_pre {
	}

	chain nat_POSTROUTING_ZONES {
		oifname "eth1" goto nat_POST_internal
		oifname "eth0" goto nat_POST_external
		goto nat_POST_drop
	}

	chain nat_POSTROUTING_POLICIES_post {
	}

	chain nat_POST_external {
		jump nat_POST_external_pre
		jump nat_POST_external_log
		jump nat_POST_external_deny
		jump nat_POST_external_allow
		jump nat_POST_external_post
	}

	chain nat_POST_external_pre {
	}

	chain nat_POST_external_log {
	}

	chain nat_POST_external_deny {
	}

	chain nat_POST_external_allow {
	}

	chain nat_POST_external_post {
	}

	chain nat_PRE_external {
		jump nat_PRE_external_pre
		jump nat_PRE_external_log
		jump nat_PRE_external_deny
		jump nat_PRE_external_allow
		jump nat_PRE_external_post
	}

	chain nat_PRE_external_pre {
	}

	chain nat_PRE_external_log {
	}

	chain nat_PRE_external_deny {
	}

	chain nat_PRE_external_allow {
	}

	chain nat_PRE_external_post {
	}

	chain nat_POST_internal {
		jump nat_POST_internal_pre
		jump nat_POST_internal_log
		jump nat_POST_internal_deny
		jump nat_POST_internal_allow
		jump nat_POST_internal_post
	}

	chain nat_POST_internal_pre {
	}

	chain nat_POST_internal_log {
	}

	chain nat_POST_internal_deny {
	}

	chain nat_POST_internal_allow {
	}

	chain nat_POST_internal_post {
	}

	chain nat_PRE_internal {
		jump nat_PRE_internal_pre
		jump nat_PRE_internal_log
		jump nat_PRE_internal_deny
		jump nat_PRE_internal_allow
		jump nat_PRE_internal_post
	}

	chain nat_PRE_internal_pre {
	}

	chain nat_PRE_internal_log {
	}

	chain nat_PRE_internal_deny {
	}

	chain nat_PRE_internal_allow {
	}

	chain nat_PRE_internal_post {
	}

	chain nat_POST_drop {
		jump nat_POST_drop_pre
		jump nat_POST_drop_log
		jump nat_POST_drop_deny
		jump nat_POST_drop_allow
		jump nat_POST_drop_post
	}

	chain nat_POST_drop_pre {
	}

	chain nat_POST_drop_log {
	}

	chain nat_POST_drop_deny {
	}

	chain nat_POST_drop_allow {
	}

	chain nat_POST_drop_post {
	}

	chain nat_PRE_drop {
		jump nat_PRE_drop_pre
		jump nat_PRE_drop_log
		jump nat_PRE_drop_deny
		jump nat_PRE_drop_allow
		jump nat_PRE_drop_post
	}

	chain nat_PRE_drop_pre {
	}

	chain nat_PRE_drop_log {
	}

	chain nat_PRE_drop_deny {
	}

	chain nat_PRE_drop_allow {
	}

	chain nat_PRE_drop_post {
	}

	chain nat_PRE_policy_allow-host-ipv6 {
		jump nat_PRE_policy_allow-host-ipv6_pre
		jump nat_PRE_policy_allow-host-ipv6_log
		jump nat_PRE_policy_allow-host-ipv6_deny
		jump nat_PRE_policy_allow-host-ipv6_allow
		jump nat_PRE_policy_allow-host-ipv6_post
	}

	chain nat_PRE_policy_allow-host-ipv6_pre {
	}

	chain nat_PRE_policy_allow-host-ipv6_log {
	}

	chain nat_PRE_policy_allow-host-ipv6_deny {
	}

	chain nat_PRE_policy_allow-host-ipv6_allow {
	}

	chain nat_PRE_policy_allow-host-ipv6_post {
	}
}

Read manual pages to get better understanding as everything here is well-thought.

$ man -k firewalld
firewall-cmd (1)     - firewalld command line client
firewall-offline-cmd (1) - firewalld offline command line client
firewalld (1)        - Dynamic Firewall Manager
firewalld.conf (5)   - firewalld configuration file
firewalld.dbus (5)   - firewalld D-Bus interface description
firewalld.direct (5) - firewalld direct configuration file
firewalld.helper (5) - firewalld helper configuration files
firewalld.icmptype (5) - firewalld icmptype configuration files
firewalld.ipset (5)  - firewalld ipset configuration files
firewalld.lockdown-whitelist (5) - firewalld lockdown whitelist configuration file
firewalld.policies (5) - firewalld policies
firewalld.policy (5) - firewalld policy configuration files
firewalld.richlanguage (5) - Rich Language Documentation
firewalld.service (5) - firewalld service configuration files
firewalld.zone (5)   - firewalld zone configuration files
firewalld.zones (5)  - firewalld zones