-
Notifications
You must be signed in to change notification settings - Fork 603
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Squid - firewall rules sanitization #289
Conversation
$PPTP_ALIAS = "\$pptp"; | ||
} else { | ||
$PPTP_ALIAS = "\$PPTP"; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed some unused PPTP leftovers.
if (strstr($fw_aliases, "PPPoE =")) { | ||
$PPPOE_ALIAS = "\$PPPoE"; | ||
} else { | ||
$PPPOE_ALIAS = "\$pppoe"; | ||
} | ||
|
||
// define ports based on transparent options and ssl filtering | ||
$pf_rule_port = ($squid_conf['ssl_proxy'] == "on" ? "{80,443}" : "80"); | ||
$pf_nat_ports = ($squid_conf['ssl_proxy'] == "on" ? "{80,443}" : "80"); | ||
$pf_rule_ports = "{{$port},{$ssl_port}}"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$pf_nat_ports
is for transparent proxy$pf_rule_ports
is for the defined proxy interfaces (nontransparent) - 3128/3129 by default
(with, or without HTTPS/SSL Interception)
$pf_transparent_rule_port
- always 80, plus 443 if the interface is selected under SSL Intercept Interface(s)
if (in_array($t_iface, $ssl_ifaces)) { | ||
$rules .= "rdr on $t_iface proto tcp from any to !($t_iface) port 443 -> 127.0.0.1 port {$ssl_port}\n"; | ||
$rules .= "rdr pass on $t_iface proto tcp from any to !($t_iface) port 443 -> 127.0.0.1 port {$ssl_port}\n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use rdr pass
to pass traffic destined to 443 to the transparent proxy
} | ||
} | ||
foreach ($transparent_ifaces as $t_iface) { | ||
$pf_transparent_rule_port = (in_array($t_iface, $ssl_ifaces) ? "{80,443}" : "80"); | ||
$rules .= "rdr on $t_iface proto tcp from any to !($t_iface) port 80 -> 127.0.0.1 port {$port}\n"; | ||
$rules .= "rdr pass on $t_iface proto tcp from any to !($t_iface) port 80 -> 127.0.0.1 port {$port}\n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use rdr pass
to pass traffic destined to 80 to the transparent proxy
} | ||
} | ||
/* Handle PPPOE case */ | ||
if (($config['pppoe']['mode'] == "server" && $config['pppoe']['localip']) || (function_exists("is_pppoe_server_enabled") && is_pppoe_server_enabled())) { | ||
$rules .= "rdr on $PPPOE_ALIAS proto tcp from any to !127.0.0.1 port {$pf_rule_port} -> 127.0.0.1 port {$port}\n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, this is really WTF. No idea what it was supposed to do, plus why limited to the HTTP proxy port only?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's for local clients that connected using the PPPoE server. Not sure why it's HTTP only but it's necessary so they could be proxied. The way mpd works it uses a bunch of different local interfaces in a group. There is some code higher up that sets PPPOE_ALIAS
conditionally that is no longer needed. It's only $pppoe
now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, re-added that (below) with the !127.0.0.1
destination, it also does HTTPS now when SSL proxy is enabled, not just HTTP.
$rules .= "# Setup squid pass rules for proxy\n"; | ||
$rules .= "pass in quick on $iface proto tcp from any to !($iface) port {$pf_transparent_rule_port} flags S/SA keep state\n"; | ||
// $rules .= "pass in quick on $iface proto tcp from any to !($iface) port {$port} flags S/SA keep state\n"; | ||
$rules .= "pass in quick on $iface proto tcp from any to !127.0.0.1 port {$pf_rule_ports} flags S/SA keep state\n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pass traffic for the proxy ports (3128/3129 by default on each proxy interface)
$rules .= "\n"; | ||
} | ||
if ($config['pppoe']['mode'] == "server" && $config['pppoe']['localip']) { | ||
$rules .= "pass in quick on $PPPOE_ALIAS proto tcp from any to !127.0.0.1 port {$port} flags S/SA keep state\n"; | ||
$rules .= "pass in quick on $PPPOE_ALIAS proto tcp from any to !127.0.0.1 port {$pf_rule_ports} flags S/SA keep state\n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto for PPPoE.
@@ -2095,7 +2091,7 @@ function squid_generate_rules($type) { | |||
} | |||
/* Handle PPPOE case */ | |||
if (($config['pppoe']['mode'] == "server" && $config['pppoe']['localip']) || (function_exists("is_pppoe_server_enabled") && is_pppoe_server_enabled())) { | |||
$rules .= "no rdr on $PPPOE_ALIAS proto tcp from any to { 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 } port {$pf_rule_port}\n"; | |||
$rules .= "no rdr on $PPPOE_ALIAS proto tcp from any to { 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 } port {$pf_nat_ports}\n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not redirect these if 'Bypass Proxy for Private Address Destination' is checked.
@@ -2117,7 +2113,7 @@ function squid_generate_rules($type) { | |||
} | |||
/* Handle PPPOE case */ | |||
if (($config['pppoe']['mode'] == "server" && $config['pppoe']['localip']) || (function_exists("is_pppoe_server_enabled") && is_pppoe_server_enabled())) { | |||
$rules .= "no rdr on $PPPOE_ALIAS proto tcp from { $exempt_ip } to any port {$pf_rule_port}\n"; | |||
$rules .= "no rdr on $PPPOE_ALIAS proto tcp from { $exempt_ip } to any port {$pf_nat_ports}\n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not redirect 'Bypass Proxy for These Source IPs'
@@ -2139,33 +2135,33 @@ function squid_generate_rules($type) { | |||
} | |||
/* Handle PPPOE case */ | |||
if (($config['pppoe']['mode'] == "server" && $config['pppoe']['localip']) || (function_exists("is_pppoe_server_enabled") && is_pppoe_server_enabled())) { | |||
$rules .= "no rdr on $PPPOE_ALIAS proto tcp from any to { $exempt_dest } port {$pf_rule_port}\n"; | |||
$rules .= "no rdr on $PPPOE_ALIAS proto tcp from any to { $exempt_dest } port {$pf_nat_ports}\n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not redirect 'Bypass Proxy for These Destination IPs'
} | ||
} | ||
foreach ($transparent_ifaces as $t_iface) { | ||
$pf_transparent_rule_port = (in_array($t_iface, $ssl_ifaces) ? "{80,443}" : "80"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed, was not used for anything here.
} | ||
$rules .= "\n"; | ||
break; | ||
case 'filter': | ||
case 'rule': | ||
foreach ($transparent_ifaces as $iface) { | ||
$pf_transparent_rule_port = (in_array($iface, $ssl_ifaces) ? "{80,443,{$port},{$ssl_port}}" : "{80,{$port}}"); | ||
foreach ($proxy_ifaces as $iface) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This really is not about transparent proxy interfaces; rdr pass
does the job there.
$rules .= "# Setup squid pass rules for proxy\n"; | ||
$rules .= "pass in quick on $iface proto tcp from any to !($iface) port {$pf_transparent_rule_port} flags S/SA keep state\n"; | ||
// $rules .= "pass in quick on $iface proto tcp from any to !($iface) port {$port} flags S/SA keep state\n"; | ||
$rules .= "pass in quick on $iface proto tcp from any to ($iface) port {$pf_rule_ports} flags S/SA keep state\n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pass traffic to the interface IP only
$rules .= "\n"; | ||
} | ||
if ($config['pppoe']['mode'] == "server" && $config['pppoe']['localip']) { | ||
$rules .= "pass in quick on $PPPOE_ALIAS proto tcp from any to !127.0.0.1 port {$port} flags S/SA keep state\n"; | ||
$rules .= "pass in quick on $PPPOE_ALIAS proto tcp from any to ($PPPOE_ALIAS) port {$pf_rule_ports} flags S/SA keep state\n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pass traffic to the interface IP only. I guess this should really be
$rules .= "pass in quick on $PPPOE_ALIAS proto tcp from any to {$config['pppoe']['localip']} port {$pf_rule_ports} flags S/SA keep state\n";
for PPPoE???
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that it's a group I'm not certain how pf treats using that as a destination. Using the configured local IP address would be safer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, you mean something like
pass in quick on $pppoe proto tcp from any to ($pppoe) port {$pf_rule_ports} ...
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say this is safer:
pass in quick on $pppoe proto tcp from any to {$config['pppoe']['localip']} port {$pf_rule_ports}
But I'd have to try it out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I really need someone with a working PPPoE setup to test whatever is figured out here. So, to summarize so far:
- nuke the weird $PPPOE_ALIAS everywhere and use $pppoe instead
- use
{$config['pppoe']['localip']}
as destination
Right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That looks right.
I have two VMs with PPPoE server setup but they're acting as "WAN" connections for other pfSense VMs so I can test PPPoE WANs, it's easy to setup and test, there's not much to it. Should work just as easy for clients as those.
$rules .= "rdr pass on $PPPOE_ALIAS proto tcp from any to !($PPPOE_ALIAS) port 80 -> 127.0.0.1 port {$port}\n"; | ||
if ($squid_conf['ssl_proxy'] == "on") { | ||
$rules .= "rdr pass on $t_iface proto tcp from any to !($PPPOE_ALIAS) port 443 -> 127.0.0.1 port {$ssl_port}\n"; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this should really be
$rules .= "rdr pass on $PPPOE_ALIAS proto tcp from any to !{$config['pppoe']['localip']} port ...
for both PPPoE lines above???
Is the "old rules" example above right? You show |
Kinda unsure what's the question. No, there's no rdr pass currently in Squid. |
In the initial comment on the PR you put two boxes of rules "comparison of rules generated by the old and new code", the one labeled "Old rules" has |
Eh... probably pasted something wrong there. The new ones is correct, cannot check any old ones at the moment. There's no rdr pass anywhere there, though. |
That's what I figured, but I wanted to be certain. |
Yeah, I'll fix that part as soon as I can revert the file somewhere and re-check, but the main point of why I started investigating this was that the pass rules created are way too permissive, they just basically let HTTP/HTTPS pass through altogether except if the proxy interface is the destination, and that's impossible to override by normal firewall rules since it's a |
@jim-p - Fixed the "old rules" in the first comment after reverting to
|
@@ -2095,7 +2084,7 @@ function squid_generate_rules($type) { | |||
} | |||
/* Handle PPPOE case */ | |||
if (($config['pppoe']['mode'] == "server" && $config['pppoe']['localip']) || (function_exists("is_pppoe_server_enabled") && is_pppoe_server_enabled())) { | |||
$rules .= "no rdr on $PPPOE_ALIAS proto tcp from any to { 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 } port {$pf_rule_port}\n"; | |||
$rules .= "no rdr on $pppoe proto tcp from any to { 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 } port {$pf_nat_ports}\n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't see where $pppoe is being defined
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rbgarga - the changes here were done as suggested by @jim-p (#289 (comment)) - as I've noted, I don't have any such setup to test, and generally this is something completely outside of my knowledge. Perhaps this should be \$pppoe
instead, NFC.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not a PHP variable but a pf macro that will be in the ruleset already if the pppoe server is enabled (which the if
condition above tests for).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So you want that escaped?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it needs to be escaped
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, done... I guess we are slowly getting there.
(I'd prefer to do a new PR when we are done here, there's bunch of typo fixes to be done in the package as well, plus no need to have this kind of messing in git history).
Closing in favor of #305 - all review comments are included there, plus additional fixes. |
[ Robert Edmonds ] * Release 1.3.1. * Restore protobuf-2.x compatibility (#284, #285). * Use xenial and protobuf 3.6.1 in the Travis-CI environment (#332). * Convert uses of protobuf's scoped_ptr.h to C++11 std::unique_ptr, needed to compile against protobuf 3.6.1 (#320, #333). * Use AX_CXX_COMPILE_STDCXX macro to enable C++11 support in old compilers (#312, #317, #327, #334). [ Fredrik Gustafsson ] * Add std:: to some types (#294, #305, #309). [ Sam Collinson ] * Check the return value of int_range_lookup before using as an array index; it can return -1 (#315). [ Matthias Dittrich ] * Fix compilation on mingw by using explicit protoc --plugin=NAME=PATH syntax in Makefile.am (#289, #290). Sponsored by: Farsight Security, Inc.
Do NOT merge now, this is for discussion ATM.
OK, guys... so, reading the code, it appears to me the current firewall rules generated by Squid do not make particularly good sense. So I've come up with this:
rdr pass
to pass traffic when we have transparent proxy enabled and are doing NATcase 'rule':
) we should pass the traffic to the configured proxy ports only, and the transparent proxy ports/interfaces really have nothing to do with those rules, so no idea why's the code referencing them at allFor a quick idea, here's a comparison of rules generated by the old and new code. with a really simple setup
LAN = igb0_vlan10
being a non-transparent interfaceWLAN = igb0_vlan88
being set up as transparent interface with SSL/MITMOld rules
New rules
Also added some comments to the individual changes below.