Date: Wed, 05 Sep 2012 15:02:20 +0200 From: Andreas Longwitz <longwitz@incore.de> To: freebsd-net@freebsd.org Subject: Support for IPSec VPN's: some patches for netipsec/key.c Message-ID: <50474D5C.4020003@incore.de>
next in thread | raw e-mail | index | archive | help
Hi, as continuation of http://lists.freebsd.org/pipermail/freebsd-stable/2012-April/067307.html I like to describe what I have done to get smartphones with IPSec VPN's working with a FreeBSD 8.3 server. The clients are IPhones with Cisco IPSec (authentication_method xauth_rsa_server in tunnel mode) and Androids with L2TP over IPSec (authentication_method rsasig in transport mode). On the server I have FreeBSD 8.3 with NAT-T support and the ports ipsec-tools-0.8.0_2 and mpd-5.5. To filter all packets in transport and tunnel mode on the enc0 interface, I use net.enc.out.ipsec_filter_mask=1 and net.enc.in.ipsec_filter_mask=3. Further my server has included the patches given in kern/146190 to ignore checksums and kern/169620 to avoid packet bypass on ngX. The following patches are all for netipsec/key.c: I use parameter "generate_policy on" in racoon.conf. This works for clients with NAT-T, but direct connected clients need the following patch (likewise in ipsec-tools/roadwarrior/client/phase1-up.sh): @@ -1927,19 +1930,27 @@ #if 1 if (newsp->req && newsp->req->saidx.src.sa.sa_family) { struct sockaddr *sa; + uint16_t *pport; sa = (struct sockaddr *)(src0 + 1); if (sa->sa_family != newsp->req->saidx.src.sa.sa_family) { _key_delsp(newsp); return key_senderror(so, m, EINVAL); } + pport = (uint16_t *)newsp->req->saidx.src.sa.sa_data; + if ( *pport == htons(500) ) /* UDP_ENCAP_ESPINUDP_PORT */ + *pport = 0; } if (newsp->req && newsp->req->saidx.dst.sa.sa_family) { struct sockaddr *sa; + uint16_t *pport; sa = (struct sockaddr *)(dst0 + 1); if (sa->sa_family != newsp->req->saidx.dst.sa.sa_family) { _key_delsp(newsp); return key_senderror(so, m, EINVAL); } + pport = (uint16_t *)newsp->req->saidx.dst.sa.sa_data; + if ( *pport == htons(500) ) /* UDP_ENCAP_ESPINUDP_PORT */ + *pport = 0; } #endif The next patch eliminates a (probably not important) mistake in loop handling and an important change in calling key_cmpsaidx() from key_getsah(). With this patch mixed transport and tunnel modes behind the same router work correct. @@ -1312,11 +1312,14 @@ continue; if (key_cmpspidx_exactly(spidx, &sp->spidx)) { SP_ADDREF(sp); - break; + SPTREE_UNLOCK(); + goto found; } } SPTREE_UNLOCK(); + return NULL; + found: return sp; } @@ -2968,11 +2983,15 @@ LIST_FOREACH(sah, &V_sahtree, chain) { if (sah->state == SADB_SASTATE_DEAD) continue; - if (key_cmpsaidx(&sah->saidx, saidx, CMP_REQID)) - break; + if (key_cmpsaidx(&sah->saidx, saidx, CMP_MODE_REQID)) { + SAHTREE_UNLOCK(); + goto found; + } } SAHTREE_UNLOCK(); + return NULL; + found: return sah; } The last patch makes it possible for a transport mode client to open a new connection to the server immediately after closing an old connection. Without this patch the client must wait for the routers to forget all there NAT entries. @@ -4065,10 +4084,12 @@ /* * If NAT-T is enabled, check ports for tunnel mode. * Do not check ports if they are set to zero in the SPD. - * Also do not do it for transport mode, as there is no + * Also do not do it for native transport mode, as there is no * port information available in the SP. */ - if (saidx1->mode == IPSEC_MODE_TUNNEL && + if ((saidx1->mode == IPSEC_MODE_TUNNEL || + (saidx1->mode == IPSEC_MODE_TRANSPORT && + saidx1->proto == IPPROTO_ESP)) && saidx1->src.sa.sa_family == AF_INET && saidx1->dst.sa.sa_family == AF_INET && ((const struct sockaddr_in *)(&saidx1->src))->sin_port && One case is left: At the moment it is not possible for the kernel to handle more than one IPSEC/L2TP (transport mode) connection from clients behind the same NAT router. To get rid of this limitation the kernel must do some housekeeping for the clients inner and outer udp src ports (the corresponding dst ports are 1701 and 4500) to find the correct SA for outgoing packets. I do not know what would be the best place to store these informations. Any suggestions ? At the end a question: At the beginning of ip_ipsec_output() in ip_ipsec.c the flag PACKET_TAG_IPSEC_PENDING_TDB is used, but I can not find the place where this flag is set in the kernel. Can somebody enlighten me ? -- Dr. Andreas Longwitz Data Service GmbH Beethovenstr. 2A 23617 Stockelsdorf Amtsgericht Lübeck, HRB 318 BS Geschäftsführer: Wilfried Paepcke, Dr. Andreas Longwitz, Josef Flatau
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?50474D5C.4020003>