send all http/https traffic through squid using firewalld

Issues related to configuring your network
xbucaneer
Posts: 13
Joined: 2022/10/28 05:09:32

send all http/https traffic through squid using firewalld

Post by xbucaneer » 2022/11/12 21:43:34

I have a CentOS 7 box running squid/squidGuard, dnsmasq and firewalld.

The CentOS box has 2 NIC's; enp2s0 (192.168.0.40) connects to a sagemcom modem and the internet, enp6s0 (192.168.1.100) connects to a TP-link wifi modem set as an access point and is meant to offer filtered internet access to its clients.

Squid and squidGuard are both working on the server and the server is sharing its internet connection, but the clients connected on the TP-link are receiving unfiltered internet access.

Here are details about firewalld

firewall-cmd --get-active-zones
internal
interfaces: enp6s0
external
interfaces: enp2s0

# firewall-cmd --zone=external --list-all
external (active)
target: default
icmp-block-inversion: no
interfaces: enp2s0
sources:
services: ssh
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: enp6s0
sources:
services: dhcp dhcpv6 dhcpv6-client dns ftp http https mdns squid ssh
ports: 53/tcp 53/udp 3126/tcp 3127/tcp 3128/tcp
protocols:
masquerade: yes
forward-ports:
source-ports:
icmp-blocks:
rich rules:

here is direct.xml which I believe is supposed to do the port forwarding required to route traffic through squid but I note there are no forward ports in the internal zone.

<?xml version="1.0" encoding="utf-8"?>
<direct>
<rule ipv="ipv4" table="nat" chain="PREROUTING" priority="0">-i enp6s0 -p tcp --dport 80 -j REDIRECT --to-ports 3126</rule>
<rule ipv="ipv4" table="nat" chain="PREROUTING" priority="0">-i enp6s0 -p tcp --dport 443 -j REDIRECT --to-ports 3127</rule>
</direct>

and
# firewall-cmd --direct --get-all-rules

gave no output so i issued the commands

# firewall-cmd --permanent --direct -add-rule ipv4 nat PREROUTING 0 -p tcp -m -dort 80 -j REDIRECT -TO-PORTS 3126 --to-destination 192.168.1.100

# firewall-cmd --permanent --direct -add-rule ipv4 nat PREROUTING 0 -p tcp -m -dort 443 -j REDIRECT -TO-PORTS 3127 --to-destination 192.168.1.100

# firewall-cmd --reload

now...
firewall-cmd --direct --get-all-rules
ipv4 nat PREROUTING 0 -i enp6s0 -p tcp --dport 80 -j REDIRECT --to-ports 3126
ipv4 nat PREROUTING 0 -i enp6s0 -p tcp --dport 443 -j REDIRECT --to-ports 3127

now I am seeing acitivity in the squid logs but the clients on the TP-Link wifi still have unfiltered internet
I am lost, please help TIA!

User avatar
jlehtone
Posts: 4523
Joined: 2007/12/11 08:17:33
Location: Finland

Re: send all http/https traffic through squid using firewalld

Post by jlehtone » 2022/11/12 22:26:36

Does that dNAT rule mean that if a client tries to access https://forums.centos.org/ it will be redirected to contact https://forums.centos.org:3127/ ?
I'd guess that it should rather connect https://192.168.1.100:3127/

xbucaneer
Posts: 13
Joined: 2022/10/28 05:09:32

Re: send all http/https traffic through squid using firewalld

Post by xbucaneer » 2022/11/13 01:24:39

jlehtone wrote:
2022/11/12 22:26:36
Does that dNAT rule mean that if a client tries to access https://forums.centos.org/ it will be redirected to contact https://forums.centos.org:3127/ ?
I'd guess that it should rather connect https://192.168.1.100:3127/
where does the dnat rule mention centos.org or any of its IPs?

it says

# firewall-cmd --permanent --direct -add-rule ipv4 nat PREROUTING 0 -p tcp -m -dort 443 -j REDIRECT -TO-PORTS 3127 --to-destination 192.168.1.100

User avatar
jlehtone
Posts: 4523
Joined: 2007/12/11 08:17:33
Location: Finland

Re: send all http/https traffic through squid using firewalld

Post by jlehtone » 2022/11/13 12:17:17

I save the:
xbucaneer wrote:
2022/11/12 21:43:34
<rule ipv="ipv4" table="nat" chain="PREROUTING" priority="0">-i enp6s0 -p tcp --dport 443 -j REDIRECT --to-ports 3127</rule>

ipv4 nat PREROUTING 0 -i enp6s0 -p tcp --dport 443 -j REDIRECT --to-ports 3127
that lack "-to-destination". The centos.org was just a random URL that a user in 192.168.1.0/24 could type.

How are the actual NAT rules in kernel? You can see them with:

Code: Select all

iptables -t nat -S
Do they redirect to 192.168.1.100?


Another part is that you obviously don't want to route tcp/80 and tcp/443 traffic.
That is, FORWARD should block that outgoing traffic.
The irony is that FirewallD in el7 does not really support that kind of filters. The rich and direct rules are crude workarounds.

[EDIT]
Initially, Red Hat did include two (mutually exclusive) services for el7: (default) firewalld.service and iptables.service. RHEL 7 documentation implied that the first is for toy problems and the second for real work.
On about RHEL 7.4 nftables was backported into kernel, corresponding nftables.service was added, and eventually documentation retconned to offer that instead of iptables.service.

You might be able to set up FirewallD to do the job, but when you have to abandon CentOS 7 (June 2024 the latest), you do have to change your FirewallD config.
Alternatively, you could create solid ruleset with iptables or nftables, particularly the latter.

xbucaneer
Posts: 13
Joined: 2022/10/28 05:09:32

Re: send all http/https traffic through squid using firewalld

Post by xbucaneer » 2022/11/14 06:29:13

thank you for your most informative reply :) ;)
here is the output from the command you suggested
# iptables -t nat -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N OUTPUT_direct
-N POSTROUTING_ZONES
-N POSTROUTING_direct
-N POST_external
-N POST_external_allow
-N POST_external_deny
-N POST_external_log
-N POST_internal
-N POST_internal_allow
-N POST_internal_deny
-N POST_internal_log
-N PREROUTING_ZONES
-N PREROUTING_direct
-N PRE_external
-N PRE_external_allow
-N PRE_external_deny
-N PRE_external_log
-N PRE_internal
-N PRE_internal_allow
-N PRE_internal_deny
-N PRE_internal_log
-A PREROUTING -j PREROUTING_direct
-A PREROUTING -j PREROUTING_ZONES
-A OUTPUT -j OUTPUT_direct
-A POSTROUTING -s 192.168.122.0/24 -d 224.0.0.0/24 -j RETURN
-A POSTROUTING -s 192.168.122.0/24 -d 255.255.255.255/32 -j RETURN
-A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p tcp -j MASQUERADE --to-ports 1024-65535
-A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p udp -j MASQUERADE --to-ports 1024-65535
-A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE
-A POSTROUTING -j POSTROUTING_direct
-A POSTROUTING -j POSTROUTING_ZONES
-A POSTROUTING_ZONES -o enp6s0 -g POST_internal
-A POSTROUTING_ZONES -o enp2s0 -g POST_external
-A POSTROUTING_ZONES -g POST_internal
-A POST_external -j POST_external_log
-A POST_external -j POST_external_deny
-A POST_external -j POST_external_allow
-A POST_external_allow ! -o lo -j MASQUERADE
-A POST_external_allow ! -o lo -j MASQUERADE
-A POST_internal -j POST_internal_log
-A POST_internal -j POST_internal_deny
-A POST_internal -j POST_internal_allow
-A POST_internal_allow ! -o lo -j MASQUERADE
-A POST_internal_allow ! -o lo -j MASQUERADE
-A PREROUTING_ZONES -i enp6s0 -g PRE_internal
-A PREROUTING_ZONES -i enp2s0 -g PRE_external
-A PREROUTING_ZONES -g PRE_internal
-A PREROUTING_direct -i enp6s0 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 3126
-A PREROUTING_direct -i enp6s0 -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 3127
-A PRE_external -j PRE_external_log
-A PRE_external -j PRE_external_deny
-A PRE_external -j PRE_external_allow
-A PRE_internal -j PRE_internal_log
-A PRE_internal -j PRE_internal_deny
-A PRE_internal -j PRE_internal_allow
-A PRE_internal_allow -p tcp -m mark --mark 0x64 -j DNAT --to-destination 192.168.1.100:3126
-A PRE_internal_allow -p tcp -m mark --mark 0x65 -j DNAT --to-destination 192.168.1.100:3127

I note that the REDIRECTs go to ports and DNATs go to IPs:ports.
can you suggest an appropriate command for firewalld to REDIRECT to IP:port?

User avatar
jlehtone
Posts: 4523
Joined: 2007/12/11 08:17:33
Location: Finland

Re: send all http/https traffic through squid using firewalld

Post by jlehtone » 2022/11/14 08:41:43

Lets trim that. First, do you run virtual machines on this host?
The 192.168.122.0/24 is usually created by libvirt (by default).
If you won't need that virtual subnet, then you can disable from being defined on boot.
Easiest is to disable its autostart by removing symlink /etc/libvirt/qemu/networks/autostart/default.xml and reboot.
The less there are firewall rules (and unused stuff), the better.

Now, the PRE:
xbucaneer wrote:
2022/11/14 06:29:13

Code: Select all

-N PREROUTING_direct
#2  -A PREROUTING_direct -i enp6s0 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 3126
#3  -A PREROUTING_direct -i enp6s0 -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 3127

-N PRE_internal_allow
#6  -A PRE_internal_allow -p tcp -m mark --mark 0x64 -j DNAT --to-destination 192.168.1.100:3126
#7  -A PRE_internal_allow -p tcp -m mark --mark 0x65 -j DNAT --to-destination 192.168.1.100:3127

-N PRE_internal
#5  -A PRE_internal -j PRE_internal_allow

-P PREROUTING ACCEPT
#1  -A PREROUTING -j PREROUTING_direct
#4  -A PREROUTING_ZONES -i enp6s0 -g PRE_internal
I note that the REDIRECTs go to ports and DNATs go to IPs:ports.
can you suggest an appropriate command for firewalld to REDIRECT to IP:port?
I did number the rules how they are traversed.
Note that direct rules (#2, #3) are before the PRE_internal_allow rules (#6, #7).

You can find description of REDIRECT from man iptables-extensions -- it can change only the port.

Note how (#6, #7) are applied only to marked packets. We do not mark here. It happens in table mangle,
which you can see with iptables -t mangle -S

I'd say that you should remove the two direct rules, because you have "better" rules already in PRE_internal_allow.


The other part is that you don't want to allow http/https in FORWARD. That is in table filter, which one can see
with both iptables -t filter -S and iptables -S

xbucaneer
Posts: 13
Joined: 2022/10/28 05:09:32

Re: send all http/https traffic through squid using firewalld

Post by xbucaneer » 2022/11/15 05:40:15

Thank you again for your informative reply.
Firstly regarding the virtual host...
Currently it is unused but I intend to use it in the future to host an Apache Web Server for the LAN so I will leave it active for now.

I tried following this tutorial
https://www.digitalocean.com/community/ ... n-centos-7
to convert to iptables but upon completion internet sharing did not work and clients connected via the tp-link subnet could not access the internet.
I had hoped to then convert the iptables commands into nftables but discovered that iptables-restore-translate is not available in CentOS 7.

At this stage I feel I have 3 options.
1. Continue trying to get firewalld to work to my satisfaction using the direct rules
2. Convert to iptables and get it working or
3. Do a total re-install with CentOS Stream 9 and use nftables

At the moment I am favouring option1 as I have put months into getting this system working in CentOS 7!
Option 2 is next but means I am still stuck with a depreciated system
Option 3 gives the most up to date system but involves the most work to get up and running!

User avatar
jlehtone
Posts: 4523
Joined: 2007/12/11 08:17:33
Location: Finland

Re: send all http/https traffic through squid using firewalld

Post by jlehtone » 2022/11/15 12:42:40

xbucaneer wrote:
2022/11/15 05:40:15
Firstly regarding the virtual host...
Currently it is unused but I intend to use it in the future to host an Apache Web Server for the LAN so I will leave it active for now.
Virtual host is one thing. Virtual guest an another. Network topology is third.
The libvirt subnet (192.168.122.0/24, named "default") is routed and has NAT.
If you attach VM guest to it, it will have address in 192.168.122.0/24.
If that guest connects to machine in LAN, then the destination will see connection from 192.168.1.100, since the host does masquerade.
If a machine on LAN wants to connect to guest, then it has to connect to 192.168.1.100 and the host has to port-forward to VM guest.

One could disable the NAT on that subnet definition. Then LAN machines could connect to 192.168.122.x
(assuming 192.168.1.100 is their default gateway).
The host would have to allow forwarded traffic to 192.168.122.x and/or ... if you get squid working now, then traffic goes via squid.

Moreover, as long as you have routed networks (with or without NAT), the libvirt will inject rules to firewall.


Third option is to use bridged topology. You would create bridge, for example "br0". Then assign the enp6s0 as port of br0.
The address 192.168.1.100 would be set on br0 and not on enp6s0 any more. The firewall rules that now refer to enp6s0 would
then be about br0.

The VM guest would then be attached to br0. It would have address in LAN (192.168.10/24), directly visible to other LAN machines
and the firewall on the host will not filter any of the guest's traffic that goes to LAN.

However, do you really need an entire second operating system to run the Apache on? You could set it up on the host too.

xbucaneer wrote:
2022/11/15 05:40:15
I tried following this tutorial
https://www.digitalocean.com/community/ ... n-centos-7
They use iptables -S to read current rules from kernel. I did already show that that command does not tell everything.
The netfilter has five tables:

Code: Select all

for T in filter nat mangle raw security ; do echo "#### table: ${T} ####" ; iptables -t ${T} -S ; done
There is another command that lists the whole (IPv4) ruleset:

Code: Select all

iptables-save
If you have 'iptables-services' package, then you can save rulesets to /etc/sysconfig/iptables and /etc/sysconfig/ip6tables with:

Code: Select all

systemctl save iptables
systemctl save ip6tables
One would modify the rules that are in memory and then use those to save so that iptables.service can load them again on boot.

As said, the libvirt can inject rules. Those are not supposed to be saved (if iptables.service is used), because libvirt will re-add them on restart.

xbucaneer wrote:
2022/11/15 05:40:15
At this stage I feel I have 3 options.
1. Continue trying to get firewalld to work to my satisfaction using the direct rules
2. Convert to iptables and get it working or
3. Do a total re-install with CentOS Stream 9 and use nftables
I already said that the two direct rules that you have should not be there
unless they do add the "PRE_internal_allow" rules.

Don't install CentOS Stream 9. If you want "stable" CentOS-like platform, then do use RHEL 9 or a distro based on it.
For example, AlmaLinux 9 or Rocky Linux 9.

xbucaneer
Posts: 13
Joined: 2022/10/28 05:09:32

Re: send all http/https traffic through squid using firewalld

Post by xbucaneer » 2022/11/16 22:39:11

Thank you for your help to date it has been invaluable!

Firstly,
I have deleted the simlink and hence the subnet 192.168.122.0/24

Secondly I have I have deleted the direct rules using
# iptables -F
now the following command returns
# iptables -t nat -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N OUTPUT_direct
-N POSTROUTING_ZONES
-N POSTROUTING_direct
-N POST_external
-N POST_external_allow
-N POST_external_deny
-N POST_external_log
-N POST_internal
-N POST_internal_allow
-N POST_internal_deny
-N POST_internal_log
-N PREROUTING_ZONES
-N PREROUTING_direct
-N PRE_external
-N PRE_external_allow
-N PRE_external_deny
-N PRE_external_log
-N PRE_internal
-N PRE_internal_allow
-N PRE_internal_deny
-N PRE_internal_log
-A PREROUTING -j PREROUTING_direct
-A PREROUTING -j PREROUTING_ZONES
-A OUTPUT -j OUTPUT_direct
-A POSTROUTING -j POSTROUTING_direct
-A POSTROUTING -j POSTROUTING_ZONES
-A POSTROUTING_ZONES -o enp6s0 -g POST_internal
-A POSTROUTING_ZONES -o enp2s0 -g POST_external
-A POSTROUTING_ZONES -g POST_internal
-A POST_external -j POST_external_log
-A POST_external -j POST_external_deny
-A POST_external -j POST_external_allow
-A POST_internal -j POST_internal_log
-A POST_internal -j POST_internal_deny
-A POST_internal -j POST_internal_allow
-A POST_internal_allow ! -o lo -j MASQUERADE
-A POST_internal_allow ! -o lo -j MASQUERADE
-A PREROUTING_ZONES -i enp6s0 -g PRE_internal
-A PREROUTING_ZONES -i enp2s0 -g PRE_external
-A PREROUTING_ZONES -g PRE_internal
-A PRE_external -j PRE_external_log
-A PRE_external -j PRE_external_deny
-A PRE_external -j PRE_external_allow
-A PRE_internal -j PRE_internal_log
-A PRE_internal -j PRE_internal_deny
-A PRE_internal -j PRE_internal_allow


Lastly your suggestion to read "man iptables-extensions" seems to have been most fruitful as the following information came to light...

"TPROXY
This target is only valid in the mangle table, in the PREROUTING chain and user-defined chains which are only called from this chain. It
redirects the packet to a local socket without changing the packet header in any way. It can also change the mark value which can then be
used in advanced routing rules. It takes three options:

--on-port port
This specifies a destination port to use. It is a required option, 0 means the new destination port is the same as the original.
This is only valid if the rule also specifies -p tcp or -p udp.

--on-ip address
This specifies a destination address to use. By default the address is the IP address of the incoming interface. This is only valid
if the rule also specifies -p tcp or -p udp.

--tproxy-mark value[/mask]
Marks packets with the given value/mask. The fwmark value set here can be used by advanced routing. (Required for transparent prox‐
ying to work: otherwise these packets will get forwarded, which is probably not what you want.
)"

clearly I need to incorporate this extension into the firewall as squid is running in transparent mode, however I am unsure of the syntax to apply this to have squid function!

User avatar
jlehtone
Posts: 4523
Joined: 2007/12/11 08:17:33
Location: Finland

Re: send all http/https traffic through squid using firewalld

Post by jlehtone » 2022/11/17 13:36:54

The man iptables-extensions does mention "fwmark" in couple places. The TPROXY can add an "id-tag" to packet.

We saw related example in

Code: Select all

-A PRE_internal_allow -p tcp -m mark --mark 0x64 -j DNAT --to-destination 192.168.1.100:3126
-A PRE_internal_allow -p tcp -m mark --mark 0x65 -j DNAT --to-destination 192.168.1.100:3127
These rules do act on packets that do have id-tag (0x64 and 0x65).

However, there is reference to routing with iproute2. The approriate documentation is in man ip-rule
and the general concept is policy-based routing (aka source-based routing).

The idea is that TPROXY tags some traffic "in the mangle table, in the PREROUTING chain".
Then, routing rules (not the firewall rules) direct traffic to squid.


FirewallD has "zones". A zone can have "services", "ports", "port-forwards", and "rich rules".
The rich rules are for what the first three cannot handle. man firewalld.richlanguage

Then there is "direct interface" for things that firewalld does not support.
man firewalld.direct

For TPROXY, you do need table="mangle" chain="PREROUTING" in direct rule.

Post Reply