06 October 2022

pfSense transparent proxy for selected hosts only

While setting up the pfSense to serve as a transparent proxy, whether with SSL filtering or not, you probably noticed, that although it is possible to define which hosts should be excluded from proxying, the contrary is not that obviuos, nor intuitive.

In my case I needed only one or two hosts to be redirected via the squid proxy, leaving all other hosts untouched. That turned out to be a little tricky and undocumented scenario.

The thing is, that when you configure Squid for transparenty proxying, the squid.conf slightly differs from the one generated for regular proxying, yet there are some rules inserted to pf, which are not visible nor editable from the UI Firewall->NAT level.

Digging a bit deeper you might have noticed, that the scripts, that came along with the Squid package, insert the following rules into pf tables:

[2.6.0-RELEASE]/root: pfctl -sa | grep rdr
(...)
rdr pass on vtnet1 inet proto tcp from any to ! (vtnet1) port = http -> 127.0.0.1 port 8080
rdr pass on vtnet1 inet proto tcp from any to ! (vtnet1) port = https -> 127.0.0.1 port 8443
(...)

Note, that the ports tcp/8080 and tcp/8443, that I use here, are not the default ports for Squid on pfSense, and you will have to adjust either the rules or the squid in your configuration.

The part from any is hard-coded in the script, and may not be altered at the configuration level. That is why we cannot easily choose which source hosts will match the rule on a given interface.

Knowing this, we can however insert own rules into Firewall/NAT, which would take precedence over the default rules, so that the default rules would never be applied.

We do it in a few steps:

  1. Define Firewall/Alias groups for hosts or networks, that should be proxied
  2. Create rules, that will do what the default rules do, but selectively for those aliases only
  3. Create rules, that will disable redirection for all others

The default squid rules will still be there, but since our new rules exhaust all matching possibilites before, those default rules will not be applied.

Ad. 1. Go to Firewall->Aliases, click Add at the bottom and create an alias named HttpProxyHosts. Those will be hosts we want to redirect to the transparent proxy.

pfSense add HttpProxyHosts alias

Do the same for HttpsProxyHosts, if you want to proxy SSL traffic as well.

pfSense add HttpsProxyHosts alias

Ad. 2. Go to Firewall->NAT and add the rules, that will redirect traffic from those aliases to the squid proxy. Note, that you will have to click Display Advanced button.

pfSense add HttpProxyHosts rule

And for HTTPS redirection.

pfSense add HttpsProxyHosts rule

Ad. 3. Go to Firewall->NAT and add the rules, that will disable redirection for the rest of the network.

pfSense add HttpProxyHosts proxy skip rule

And for HTTPS.

pfSense add HttpsProxyHosts proxy skip rule

Now in the pfSense UI you should see:

pfSense rules

And the pf table contains:

[2.6.0-RELEASE]/root: pfctl -sa | grep rdr
(...)
rdr on vtnet1 inet proto tcp from <HttpProxyHosts> to ! 10.12.12.0/24 port = http -> 127.0.0.1 port 8080
rdr on vtnet1 inet proto tcp from <HttpsProxyHosts> to ! 10.12.12.0/24 port = https -> 127.0.0.1 port 8443
no rdr on vtnet1 inet proto tcp from any to any port = http
no rdr on vtnet1 inet proto tcp from any to any port = https
rdr pass on vtnet1 inet proto tcp from any to ! (vtnet1) port = http -> 127.0.0.1 port 8080
rdr pass on vtnet1 inet proto tcp from any to ! (vtnet1) port = https -> 127.0.0.1 port 8443
(...)

The top four rules are those, that we have just created. The bottom two rules are the default squid rules. Now all HTTP traffic from the HttpProxyHosts pool will be redirected to the Squid on tcp/8080, and all HTTPS traffic from the HttpsProxyHosts pool will be redirected to the Squid on tcp/8443. Any other host trying to connect to a http (tcp/80) or https (tcp/443) service will pass through without redirection. The last two rules will have no effect, just like we expected.