Bug 127920 - [pf] ipv6 and synproxy don't play well together
Summary: [pf] ipv6 and synproxy don't play well together
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 7.1-PRERELEASE
Hardware: Any Any
: Normal Affects Only Me
Assignee: Gleb Smirnoff
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-10-07 14:00 UTC by hlh
Modified: 2014-08-25 15:53 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description hlh 2008-10-07 14:00:09 UTC
My pf.conf:

---begin---
net_if="em0"

set block-policy drop
set debug misc
set loginterface $net_if
set state-policy if-bound

scrub in all

block in  log all
block out log all

set skip on lo0

antispoof quick for $net_if inet

pass out quick on $net_if proto { tcp, udp, icmp, icmp6 } all keep state
pass  in quick on $net_if proto udp from any to ($net_if) port domain
pass     quick inet proto icmp all icmp-type echoreq keep state
pass  in quick inet proto icmp all icmp-type unreach code needfrag
pass  in quick inet6 proto icmp6 all

pass  in quick on $net_if       proto tcp from any to ($net_if) port ssh\
 flags S/SA synproxy state (source-track rule, max-src-conn-rate 1/5,\
 overload <bad_hosts> flush)

pass     quick on $net_if    proto ipv6
pass     quick on $net_if    inet6
--- end ---

Note the last rule which allow any IPv6 traffic!

If I `ssh -4` to this box, the connection succeed.
If I `ssh -6` to this box, I get a timeout and the last rule is of no use.

If I comment out the rule with synproxy, `ssh -6` succeed - the last rule allow it.

If I replace `synproxy state` with `keep state` everything is as expected.

Henri

How-To-Repeat: see above.
Comment 1 Mark Linimon freebsd_committer freebsd_triage 2008-10-07 17:10:55 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-pf

Over to maintainer(s).
Comment 2 bordjukov 2009-01-18 19:29:56 UTC
I am having the same problem.

FreeBSD router.supranet.eu 7.1-RELEASE-p2 FreeBSD 7.1-RELEASE-p2 #2: Wed 
Jan 14 15:58:07 EET 2009 
root@router.xxx.yyy:/var/src/sys/i386/compile/H5A8S  i386

pf.conf:
> ...
> 
> # Settings
> 
> set block-policy drop
> set skip on lo0
> 
> ## TRAFFIC NORMALIZATION
> scrub in on $ext_if all fragment reassemble
> scrub out on $ext_if all fragment reassemble random-id no-df
> scrub in on $tunnel_if all fragment reassemble
> scrub out on $tunnel_if all fragment reassemble random-id no-df
> 
> # Queueing
> 
> # Translation
> <NAT settings here>
> 
> # Filtering
> 
> # activate spoofing protection for all interfaces
> # block in log quick from urpf-failed
> antispoof log quick for $loopback_if                                                            label "Antispoof for $if interface."
> antispoof log quick for $int_if                                                                 label "Antispoof for $if interface."
> 
> # default rule
> block    log all                                                                                label "Block all."
> block in on $ext_if proto { tcp udp } from any to any port { 137, 138, 139, 445 }               label "Block netbios broadcasts and don't log."
> 
> pass out from self to any modulate state                                                        label "Permit outgoing traffic from the firewall."
> pass out on !$int_if from $localnet6 to any modulate state                                      label "Permit outgoing traffic from the local v6 net."
> pass    inet proto icmp all icmp-type { 0, 3, 4, 11 } keep state                                label "Permit safe ICMP."
> # http://www.freebsd.org/cgi/man.cgi?query=icmp6
> pass     inet6 proto icmp6 all icmp6-type { 1,2,3,4 } keep state                                label "Permit safe ICMPv6."
> pass in  on $tunnel_if inet6 proto icmp6 from $tun_endpoint icmp6-type {128,135,136} keep state label "Permit IPv6 ping, neighbor solic., advert. from endpoint."
> 
> 
> # Allow access to services
> pass in  inet proto tcp from any to $pub_ips port $tcp_services synproxy state                  label "Access to $dstaddr $proto/$dstport."
> 
> 
> 
> #### Trouble comes from this rule
> pass in  inet6 proto tcp from any to $pub_ips port $tcp_services synproxy state                 label "Access to $dstaddr $proto/$dstport."
> 
> 
> 
> 
> pass in  proto udp from any to $pub_ips port $udp_services keep state                           label "Access to $dstaddr $proto/$dstport."
> pass in  on $ext_if inet proto {tcp udp} from any to $localnet port $connectable synproxy state label "Allow incoming connections -> mapped $proto ports on $if."
> 
> # trusted IPs
> pass from <trusted_ips> to any keep state                                                       label "Grant access to trusted IPs."
> 
> # trust local network
> pass in  on $int_if all modulate state                                                          label "Permit incoming traffic from the Local network."
> pass out on $int_if proto {tcp, udp} from any to $localnet4 port $connectable modulate state    label "Allow connections to mapped ports to reach LAN destinations."
> pass     proto tcp from any to $localnet6 port $client_tcp_services modulate state              label "Allow IPv6 access to/from the ($proto) client services."
> pass     proto { tcp, udp } from any to $localnet6 port $connectable modulate state             label "Allow IPv6 access to/from the connectable ($proto) ports."



-- 
- Petko
Comment 3 Janne Snabb 2010-07-08 03:35:04 UTC
Hi,

I can confirm that this problem still exists on 8.0p2:

FreeBSD xxx.example.com 8.0-RELEASE-p2 FreeBSD 8.0-RELEASE-p2 #3: Thu May 27 06:52:37 UTC 2010     snabb@xxx.example.com:/usr/obj/usr/src/sys/GENERIC  i386

I was hitting my head against the wall for a while until I found
out that synproxy is just broken and should not be used.

--
Janne Snabb / EPIPE Communications
snabb@epipe.com - http://epipe.com/
Comment 4 Hien 2012-03-09 12:13:10 UTC
Hello,
I confirm this problem still exists on 9.0-RELEASE

FreeBSD web1.deploy.xxxxx 9.0-RELEASE FreeBSD 9.0-RELEASE #0: Tue Jan  3
07:15:25 UTC 2012    
root@obrian.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  i386
Comment 5 Kajetan Staszkiewicz 2014-08-01 13:52:13 UTC
The issue is also present in FreeBSD 10. What happens is that when synproxy code sents a SYN+ACK reply to client's SYN packet, it gets dropped here:

sys/netpfil/pf/pf.c:
4153 	if ((*state)->src.state == PF_TCPS_PROXY_SRC) {
4154 	    if (direction != (*state)->direction) {
4155 	        REASON_SET(reason, PFRES_SYNPROXY);
4156 	    return (PF_SYNPROXY_DROP);
4157 	}

I'm a bit surprised why it does not happen for IPv4 though, unless direction is wrong or the IPv4 packet does not match existing state.
Comment 6 Kajetan Staszkiewicz 2014-08-01 19:57:23 UTC
pf_test6() is missing a check for M_SKIP_FIREWALL flags on mbuf, this flag is present on packets sent via pf_send_tcp(), like SYN+ACK reply to client.

Following patch fixes the issue (line numbers will not match, I have a lot of other patches on pf):

@@ -6068,6 +6211,9 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
        if (kif->pfik_flags & PFI_IFLAG_SKIP)
                return (PF_PASS);
 
+       if (m->m_flags & M_SKIP_FIREWALL)
+               return (PF_PASS);
+
        PF_RULES_RLOCK();
 
        /* We do IP header normalization and packet reassembly here */
Comment 7 commit-hook freebsd_committer 2014-08-15 04:36:28 UTC
A commit references this bug:

Author: glebius
Date: Fri Aug 15 04:35:35 UTC 2014
New revision: 270010
URL: http://svnweb.freebsd.org/changeset/base/270010

Log:
  Fix synproxy with IPv6. pf_test6() was missing a check for M_SKIP_FIREWALL.

  PR:		127920
  Submitted by:	Kajetan Staszkiewicz <vegeta tuxpowered.net>
  Sponsored by:	InnoGames GmbH

Changes:
  head/sys/netpfil/pf/pf.c
Comment 8 commit-hook freebsd_committer 2014-08-25 15:49:25 UTC
A commit references this bug:

Author: glebius
Date: Mon Aug 25 15:48:28 UTC 2014
New revision: 270575
URL: http://svnweb.freebsd.org/changeset/base/270575

Log:
  Merge 270010 from head:
    Fix synproxy with IPv6. pf_test6() was missing a check for M_SKIP_FIREWALL.

    PR:           127920
    Submitted by: Kajetan Staszkiewicz <vegeta tuxpowered.net>
    Sponsored by: InnoGames GmbH

Changes:
_U  stable/10/
  stable/10/sys/netpfil/pf/pf.c