Subject: Re: more IPsec NAT-T problems
To: None <tech-net@netbsd.org>
From: Emmanuel Dreyfus <manu@netbsd.org>
List: tech-net
Date: 11/27/2004 19:57:21
Emmanuel Dreyfus <manu@netbsd.org> wrote:

> And here is the problem: most DSL routers are broken and block
> fragmented UDP packets. The goal is therefore to not send two
> frag(UDP:ESP:ICMP), but to send two UDP:ESP:frag(ICMP) instead.

Here is the patch to fix that behavior. 

That depends on the other NAT-T patch. Briefly, sp->req->sav->natt_type holds
the NAT-Traversal method. UDP_ENCAP_ESPINUDP_MAXFRAGLEN is defined as 552: the
maximum length of a DNS request.

It seems to work, does it looks reasonable? 

Index: sys/netinet/ip_output.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_output.c,v
retrieving revision 1.136
diff -U4 -r1.136 ip_output.c
--- sys/netinet/ip_output.c     6 Oct 2004 05:42:24 -0000       1.136
+++ sys/netinet/ip_output.c     27 Nov 2004 18:29:02 -0000
@@ -138,8 +138,9 @@
 #ifdef IPSEC
 #include <netinet6/ipsec.h>
 #include <netkey/key.h>
 #include <netkey/key_debug.h>
+#include <netinet/udp.h> /* For NAT-T */
 #endif /*IPSEC*/
 
 #ifdef FAST_IPSEC
 #include <netipsec/ipsec.h>
@@ -182,8 +183,9 @@
        struct socket *so;
        va_list ap;
 #ifdef IPSEC
        struct secpolicy *sp = NULL;
+       int natt_frag = 0;
 #endif /*IPSEC*/
 #ifdef FAST_IPSEC
        struct inpcb *inp;
        struct m_tag *mtag;
@@ -505,8 +507,22 @@
                printf("ip_output: Invalid policy found. %d\n", sp->policy);
        }
 
        /*
+        * NAT-T fragmentation: don't do IPSec processing now, 
+        * we'll do it on each fragmented packet. 
+        */
+       if (sp->req->sav &&
+           ((sp->req->sav->natt_type & UDP_ENCAP_ESPINUDP) ||
+            (sp->req->sav->natt_type & UDP_ENCAP_ESPINUDP_NON_IKE))) {
+               if (ntohs(ip->ip_len) > UDP_ENCAP_ESPINUDP_MAXFRAGLEN) {
+                       natt_frag = 1;
+                       mtu = UDP_ENCAP_ESPINUDP_MAXFRAGLEN;
+                       goto skip_ipsec;
+               }
+       }
+
+       /*
         * ipsec4_output() expects ip_len and ip_off in network
         * order.  They have been set to network order above.
         */
 @@ -825,13 +841,26 @@
 #endif
 #ifdef IPSEC
                        /* clean ipsec history once it goes out of the node */
                        ipsec_delaux(m);
+
+                       /* 
+                        * If we get there, the packet has not been handeld by
+                        * IPSec whereas it should have. Now that it has been 
+                        * fragmented, re-inject it in ip_output so that IPsec
+                        * processing can occur.
+                        */
+                       if (natt_frag) {
+                               error = ip_output(m, opt, 
+                                   ro, flags, imo, so, mtu_p);
+                       } else 
 #endif
-                       KASSERT((m->m_pkthdr.csum_flags &
-                           (M_CSUM_UDPv4 | M_CSUM_TCPv4)) == 0);
-                       error = (*ifp->if_output)(ifp, m, sintosa(dst),
-                           ro->ro_rt);
+                       {
+                               KASSERT((m->m_pkthdr.csum_flags &
+                                   (M_CSUM_UDPv4 | M_CSUM_TCPv4)) == 0);
+                               error = (*ifp->if_output)(ifp, m, sintosa(dst),
+                                   ro->ro_rt);
+                       }
                } else
                        m_freem(m);
        }

-- 
Emmanuel Dreyfus
Il y a 10 sortes de personnes dans le monde: ceux qui comprennent 
le binaire et ceux qui ne le comprennent pas.
manu@netbsd.org