diff -u head/sys/conf/options nat_t/src/sys/conf/options --- head/sys/conf/options 2008-05-31 14:51:53.000000000 -0700 +++ nat_t/src/sys/conf/options 2008-07-04 08:55:32.000000000 -0700 @@ -1,4 +1,4 @@ -# $FreeBSD: head/sys/conf/options 179315 2008-05-26 10:40:09Z bz $ +# $FreeBSD: src/sys/conf/options,v 1.632 2008/05/26 10:39:52 bz Exp $ # # On the handling of kernel options # @@ -372,6 +372,7 @@ INET opt_inet.h INET6 opt_inet6.h IPSEC opt_ipsec.h +IPSEC_NAT_T opt_ipsec.h IPSEC_DEBUG opt_ipsec.h IPSEC_FILTERTUNNEL opt_ipsec.h IPDIVERT diff -u head/sys/conf/NOTES nat_t/src/sys/conf/NOTES --- head/sys/conf/NOTES 2008-07-05 09:44:52.000000000 -0700 +++ nat_t/src/sys/conf/NOTES 2008-07-05 12:15:46.000000000 -0700 @@ -1,4 +1,4 @@ -# $FreeBSD: head/sys/conf/NOTES 180267 2008-07-04 21:24:35Z jhb $ +# $FreeBSD: src/sys/conf/NOTES,v 1.1498 2008/07/04 21:24:35 jhb Exp $ # # NOTES -- Lines that can be cut/pasted into kernel and hints configs. # @@ -531,6 +531,11 @@ # using ipfw(8)'s 'ipsec' keyword, when this option is enabled. # #options IPSEC_FILTERTUNNEL #filter ipsec packets from a tunnel +# +# Set IPSEC_NAT_T to enable NAT-Traversal support. This enables +# optional UDP encapsulation of ESP packets. +# +options IPSEC_NAT_T #NAT-T support, UDP encap of ESP options IPX #IPX/SPX communications protocols diff -u head/sys/net/pfkeyv2.h nat_t/src/sys/net/pfkeyv2.h --- head/sys/net/pfkeyv2.h 2008-05-31 14:55:14.000000000 -0700 +++ nat_t/src/sys/net/pfkeyv2.h 2008-07-04 08:55:32.000000000 -0700 @@ -1,4 +1,4 @@ -/* $FreeBSD: head/sys/net/pfkeyv2.h 171167 2007-07-03 12:13:45Z gnn $ */ +/* $FreeBSD: src/sys/net/pfkeyv2.h,v 1.16 2007/07/03 12:13:43 gnn Exp $ */ /* $KAME: pfkeyv2.h,v 1.37 2003/09/06 05:15:43 itojun Exp $ */ /*- @@ -75,7 +75,8 @@ #define SADB_X_SPDSETIDX 20 #define SADB_X_SPDEXPIRE 21 #define SADB_X_SPDDELETE2 22 /* by policy id */ -#define SADB_MAX 22 +#define SADB_X_NAT_T_NEW_MAPPING 23 +#define SADB_MAX 23 struct sadb_msg { u_int8_t sadb_msg_version; @@ -255,6 +256,34 @@ */ }; +/* NAT traversal type, see RFC 3948 */ +/* sizeof(struct sadb_x_nat_t_type) == 8 */ +struct sadb_x_nat_t_type { + u_int16_t sadb_x_nat_t_type_len; + u_int16_t sadb_x_nat_t_type_exttype; + u_int8_t sadb_x_nat_t_type_type; + u_int8_t sadb_x_nat_t_type_reserved[3]; +}; + +/* NAT traversal source or destination port */ +/* sizeof(struct sadb_x_nat_t_port) == 8 */ +struct sadb_x_nat_t_port { + u_int16_t sadb_x_nat_t_port_len; + u_int16_t sadb_x_nat_t_port_exttype; + u_int16_t sadb_x_nat_t_port_port; + u_int16_t sadb_x_nat_t_port_reserved; +}; + +/* ESP fragmentation size */ +/* sizeof(struct sadb_x_nat_t_frag) == 8 */ +struct sadb_x_nat_t_frag { + u_int16_t sadb_x_nat_t_frag_len; + u_int16_t sadb_x_nat_t_frag_exttype; + u_int16_t sadb_x_nat_t_frag_fraglen; + u_int16_t sadb_x_nat_t_frag_reserved; +}; + + #define SADB_EXT_RESERVED 0 #define SADB_EXT_SA 1 #define SADB_EXT_LIFETIME_CURRENT 2 @@ -275,7 +304,12 @@ #define SADB_X_EXT_KMPRIVATE 17 #define SADB_X_EXT_POLICY 18 #define SADB_X_EXT_SA2 19 -#define SADB_EXT_MAX 19 +#define SADB_X_EXT_NAT_T_TYPE 20 +#define SADB_X_EXT_NAT_T_SPORT 21 +#define SADB_X_EXT_NAT_T_DPORT 22 +#define SADB_X_EXT_NAT_T_OA 23 +#define SADB_X_EXT_NAT_T_FRAG 24 +#define SADB_EXT_MAX 24 #define SADB_SATYPE_UNSPEC 0 #define SADB_SATYPE_AH 2 diff -u head/sys/netinet/in_pcb.h nat_t/src/sys/netinet/in_pcb.h --- head/sys/netinet/in_pcb.h 2008-05-31 14:52:39.000000000 -0700 +++ nat_t/src/sys/netinet/in_pcb.h 2008-07-04 14:42:44.000000000 -0700 @@ -27,7 +27,7 @@ * SUCH DAMAGE. * * @(#)in_pcb.h 8.1 (Berkeley) 6/10/93 - * $FreeBSD: head/sys/netinet/in_pcb.h 178888 2008-05-09 23:03:00Z julian $ + * $FreeBSD: src/sys/netinet/in_pcb.h,v 1.106 2008/05/09 23:02:57 julian Exp $ */ #ifndef _NETINET_IN_PCB_H_ @@ -349,6 +349,9 @@ #define INP_FAITH 0x200 /* accept FAITH'ed connections */ #define INP_RECVTTL 0x400 /* receive incoming IP TTL */ #define INP_DONTFRAG 0x800 /* don't fragment packet */ +/* XXX UDP-specific, move to a UDP control block? */ +#define INP_ESPINUDP 0x1000 /* ESP in UDP */ +#define INP_ESPINUDP_NON_IKE 0x2000 /* ESP in UDP w/ non-IKE marker */ #define IN6P_IPV6_V6ONLY 0x008000 /* restrict AF_INET6 socket for v6 */ diff -u head/sys/netinet/in_proto.c nat_t/src/sys/netinet/in_proto.c --- head/sys/netinet/in_proto.c 2008-05-31 14:52:39.000000000 -0700 +++ nat_t/src/sys/netinet/in_proto.c 2008-07-04 08:55:32.000000000 -0700 @@ -30,7 +30,7 @@ */ #include -__FBSDID("$FreeBSD: head/sys/netinet/in_proto.c 178167 2008-04-13 05:45:14Z qingli $"); +__FBSDID("$FreeBSD: src/sys/netinet/in_proto.c,v 1.88 2008/04/13 05:45:14 qingli Exp $"); #include "opt_ipx.h" #include "opt_mrouting.h" @@ -122,7 +122,7 @@ .pr_flags = PR_ATOMIC|PR_ADDR, .pr_input = udp_input, .pr_ctlinput = udp_ctlinput, - .pr_ctloutput = ip_ctloutput, + .pr_ctloutput = udp_ctloutput, .pr_init = udp_init, .pr_usrreqs = &udp_usrreqs }, diff -u head/sys/netinet/udp.h nat_t/src/sys/netinet/udp.h --- head/sys/netinet/udp.h 2008-05-31 14:52:39.000000000 -0700 +++ nat_t/src/sys/netinet/udp.h 2008-07-06 16:25:41.000000000 -0700 @@ -28,7 +28,7 @@ * SUCH DAMAGE. * * @(#)udp.h 8.1 (Berkeley) 6/10/93 - * $FreeBSD: head/sys/netinet/udp.h 166841 2007-02-20 10:13:11Z rwatson $ + * $FreeBSD: src/sys/netinet/udp.h,v 1.10 2007/02/20 10:13:11 rwatson Exp $ */ #ifndef _NETINET_UDP_H_ @@ -45,4 +45,17 @@ u_short uh_sum; /* udp checksum */ }; +/* socket options for UDP */ +#define UDP_ENCAP 100 + +/* Encapsulation types */ +#define UDP_ENCAP_ESPINUDP_NON_IKE 1 /* draft-ietf-ipsec-nat-t-ike-00/01 */ +#define UDP_ENCAP_ESPINUDP 2 /* draft-ietf-ipsec-udp-encaps-02+ */ + +/* Default encapsulation port */ +#define UDP_ENCAP_ESPINUDP_PORT 500 + +/* Maximum UDP fragment size for ESP over UDP */ +#define UDP_ENCAP_ESPINUDP_MAXFRAGLEN 552 + #endif diff -u head/sys/netinet/udp_var.h nat_t/src/sys/netinet/udp_var.h --- head/sys/netinet/udp_var.h 2008-05-31 14:52:39.000000000 -0700 +++ nat_t/src/sys/netinet/udp_var.h 2008-07-06 16:25:41.000000000 -0700 @@ -28,7 +28,7 @@ * SUCH DAMAGE. * * @(#)udp_var.h 8.1 (Berkeley) 6/10/93 - * $FreeBSD: head/sys/netinet/udp_var.h 171339 2007-07-10 09:30:46Z rwatson $ + * $FreeBSD: src/sys/netinet/udp_var.h,v 1.33 2007/07/10 09:30:46 rwatson Exp $ */ #ifndef _NETINET_UDP_VAR_H_ @@ -103,6 +103,7 @@ extern int udp_log_in_vain; void udp_ctlinput(int, struct sockaddr *, void *); +int udp_ctloutput(struct socket *, struct sockopt *); void udp_init(void); void udp_input(struct mbuf *, int); struct inpcb *udp_notify(struct inpcb *inp, int errno); diff -u head/sys/netinet/udp_usrreq.c nat_t/src/sys/netinet/udp_usrreq.c --- head/sys/netinet/udp_usrreq.c 2008-07-05 09:44:56.000000000 -0700 +++ nat_t/src/sys/netinet/udp_usrreq.c 2008-07-16 15:13:17.000000000 -0700 @@ -31,7 +31,7 @@ */ #include -__FBSDID("$FreeBSD: head/sys/netinet/udp_usrreq.c 180198 2008-07-02 23:23:27Z rwatson $"); +__FBSDID("$FreeBSD: src/sys/netinet/udp_usrreq.c,v 1.224 2008/07/02 23:23:27 rwatson Exp $"); #include "opt_ipfw.h" #include "opt_inet6.h" @@ -82,6 +82,7 @@ #ifdef IPSEC #include +#include #endif #include @@ -141,6 +142,14 @@ static void udp_detach(struct socket *so); static int udp_output(struct inpcb *, struct mbuf *, struct sockaddr *, struct mbuf *, struct thread *); +#ifdef IPSEC +#ifdef IPSEC_NAT_T +#define INP_ESPINUDP_ALL (INP_ESPINUDP|INP_ESPINUDP_NON_IKE) +#ifdef INET +static struct mbuf *udp4_espdecap(struct socket *, struct mbuf *, int); +#endif +#endif /* IPSEC_NAT_T */ +#endif /* IPSEC */ static void udp_zone_change(void *tag) @@ -204,6 +213,13 @@ ipsec4stat.in_polvio++; return; } +#ifdef IPSEC_NAT_T + if (inp->inp_flags & INP_ESPINUDP_ALL) { /* UDP encap */ + n = udp4_espdecap(inp->inp_socket, n, off); + if (n == NULL) /* consumed */ + return; + } +#endif /* IPSEC_NAT_T */ #endif /* IPSEC */ #ifdef MAC if (mac_inpcb_check_deliver(inp, n) != 0) { @@ -758,6 +774,83 @@ CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_PRISON, 0, 0, udp_getcred, "S,xucred", "Get the xucred of a UDP connection"); +int +udp_ctloutput(struct socket *so, struct sockopt *sopt) +{ + int error = 0, optval; + struct inpcb *inp; + + inp = sotoinpcb(so); + KASSERT(inp != NULL, ("udp_ctloutput: inp == NULL")); + INP_WLOCK(inp); + if (sopt->sopt_level != IPPROTO_UDP) { +#ifdef INET6 + if (INP_CHECK_SOCKAF(so, AF_INET6)) { + INP_WUNLOCK(inp); + error = ip6_ctloutput(so, sopt); +#endif + } else { + INP_WUNLOCK(inp); + error = ip_ctloutput(so, sopt); +#ifdef INET6 + } +#endif + return (error); + } + + switch (sopt->sopt_dir) { + case SOPT_SET: + switch (sopt->sopt_name) { + case UDP_ENCAP: + INP_WUNLOCK(inp); + error = sooptcopyin(sopt, &optval, sizeof optval, + sizeof optval); + if (error) + break; + inp = sotoinpcb(so); + KASSERT(inp != NULL, ("udp_ctloutput: inp == NULL")); + INP_WLOCK(inp); + switch (optval) { +#ifdef IPSEC_NAT_T + case UDP_ENCAP_ESPINUDP: + case UDP_ENCAP_ESPINUDP_NON_IKE: + case 0: + inp->inp_flags &= ~INP_ESPINUDP_ALL; + if (optval == UDP_ENCAP_ESPINUDP) + inp->inp_flags |= INP_ESPINUDP; + else if (optval == UDP_ENCAP_ESPINUDP_NON_IKE) + inp->inp_flags |= INP_ESPINUDP_NON_IKE; + break; +#endif + default: + error = EINVAL; + break; + } + INP_WUNLOCK(inp); + break; + default: + INP_WUNLOCK(inp); + error = ENOPROTOOPT; + break; + } + break; + case SOPT_GET: + switch (sopt->sopt_name) { + case UDP_ENCAP: + optval = inp->inp_flags & INP_ESPINUDP_ALL; + INP_WUNLOCK(inp); + error = sooptcopyout(sopt, &optval, sizeof optval); + break; + default: + INP_WUNLOCK(inp); + error = ENOPROTOOPT; + break; + } + break; + } + return (error); +} + static int udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr, struct mbuf *control, struct thread *td) @@ -984,6 +1077,139 @@ return (error); } + +#if defined(IPSEC) && defined(IPSEC_NAT_T) +#ifdef INET +/* + * Potentially decap ESP in UDP frame. Check for an ESP header + * and optional marker; if present, strip the UDP header and + * push the result through IPSEC. + * + * Returns mbuf to be processed (potentially re-allocated) or + * NULL if consumed and/or processed. + */ +static struct mbuf * +udp4_espdecap(struct socket *so, struct mbuf *m, int off) +{ + size_t minlen, payload, skip, iphlen; + caddr_t data; + struct inpcb *inp; + struct m_tag *tag; + struct udphdr *udphdr; + struct ip *ip; + + /* + * Pull up data so the longest case is contiguous: + * IP/UDP hdr + non ESP marker + ESP hdr. + */ + minlen = off + sizeof(uint64_t) + sizeof(struct esp); + if (minlen > m->m_pkthdr.len) + minlen = m->m_pkthdr.len; + if ((m = m_pullup(m, minlen)) == NULL) { + udpstat.udps_hdrops++; /* XXX? */ + printf("%s: m_pullup failed\n", __func__);/* XXX */ + return NULL; /* bypass caller processing */ + } + data = mtod(m, caddr_t); /* points to ip header */ + payload = m->m_len - off; /* size of payload */ + + if (payload == 1 && data[off] == '\xff') + return m; /* NB: keepalive packet, no decap */ + + inp = sotoinpcb(so); + KASSERT((inp->inp_flags & INP_ESPINUDP_ALL) != 0, + ("inp_flags 0x%x", inp->inp_flags)); + + /* + * Check that the payload is large enough to hold an + * ESP header and compute the amount of data to remove. + * + * NB: the caller has already done a pullup for us. + * XXX can we assume alignment and eliminate bcopy's? + */ + if (inp->inp_flags & INP_ESPINUDP) { + uint32_t spi; + + if (payload <= sizeof(struct esp)) { + udpstat.udps_hdrops++; /* XXX? */ + m_freem(m); + return NULL; /* discard */ + } + bcopy(data + off, &spi, sizeof(uint32_t)); + if (spi == 0) /* non-ESP marker */ + return m; /* NB: no decap */ + skip = sizeof(struct udphdr); + } else { + uint64_t marker; + + if (payload <= sizeof(uint64_t) + sizeof(struct esp)) { + udpstat.udps_hdrops++; /* XXX? */ + m_freem(m); + return NULL; /* discard */ + } + bcopy(data + off, &marker, sizeof(uint64_t)); + if (marker != 0) /* non-IKE marker */ + return m; /* NB: no decap */ + skip = sizeof(uint64_t) + sizeof(struct udphdr); + } + + /* + * Setup a PACKET_TAG_IPSEC_NAT_T_PORT tag to remember + * the UDP ports. This is required if we want to select + * the right SPD for multiple hosts behind same NAT. + * + * NB: ports are maintained in network order everywhere + * in the NAT-T code. + */ + tag = m_tag_get(PACKET_TAG_IPSEC_NAT_T_PORTS, + 2*sizeof(uint16_t), M_NOWAIT); + if (tag == NULL) { + /* XXX stat */ + printf("%s: m_tag_get failed\n", __func__); /* XXX */ + m_freem(m); + return NULL; /* discard */ + } + iphlen = off - sizeof(struct udphdr); + udphdr = (struct udphdr *)(data + iphlen); + ((uint16_t *)(tag + 1))[0] = udphdr->uh_sport; + ((uint16_t *)(tag + 1))[1] = udphdr->uh_dport; + m_tag_prepend(m, tag); + + /* + * Remove the UDP header (and possibly the non ESP marker) + * IP header length is iphlen + * Before: + * <--- off ---> + * +----+------+-----+ + * | IP | UDP | ESP | + * +----+------+-----+ + * <-skip-> + * After: + * +----+-----+ + * | IP | ESP | + * +----+-----+ + * <-skip-> + */ + ovbcopy(data, data + skip, iphlen); + m_adj(m, skip); + + ip = mtod(m, struct ip *); + ip->ip_len -= skip; + ip->ip_p = IPPROTO_ESP; + + /* + * Clear h/w cksum flags as they are no longer valid. + */ + if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) + m->m_pkthdr.csum_flags &= ~(CSUM_DATA_VALID|CSUM_PSEUDO_HDR); + + /* XXX stat */ + ipsec4_common_input(m, iphlen, ip->ip_p); + return NULL; /* NB: consumed, bypass processing */ +} +#endif /* INET */ +#endif /* defined(IPSEC) && defined(IPSEC_NAT_T) */ + static void udp_abort(struct socket *so) { diff -u head/sys/netipsec/ipsec.c nat_t/src/sys/netipsec/ipsec.c --- head/sys/netipsec/ipsec.c 2008-05-31 14:56:35.000000000 -0700 +++ nat_t/src/sys/netipsec/ipsec.c 2008-07-04 08:53:26.000000000 -0700 @@ -1,4 +1,4 @@ -/* $FreeBSD: head/sys/netipsec/ipsec.c 179290 2008-05-24 15:32:46Z bz $ */ +/* $FreeBSD: src/sys/netipsec/ipsec.c,v 1.28 2008/05/24 15:32:46 bz Exp $ */ /* $KAME: ipsec.c,v 1.103 2001/05/24 07:14:18 sakane Exp $ */ /*- @@ -1843,16 +1843,16 @@ /* Return a printable string for the IPv4 address. */ static char * -inet_ntoa4(struct in_addr ina) +inet_ntoa4(const struct sockaddr_in *sin) { - static char buf[4][4 * sizeof "123" + 4]; - unsigned char *ucp = (unsigned char *) &ina; + static char buf[4][4 * sizeof "123" + 4 + 10]; + const unsigned char *ucp = (const unsigned char *)&sin->sin_addr; static int i = 3; /* XXX-BZ returns static buffer. */ i = (i + 1) % 4; - sprintf(buf[i], "%d.%d.%d.%d", ucp[0] & 0xff, ucp[1] & 0xff, - ucp[2] & 0xff, ucp[3] & 0xff); + sprintf(buf[i], "%d.%d.%d.%d[%u]", ucp[0] & 0xff, ucp[1] & 0xff, + ucp[2] & 0xff, ucp[3] & 0xff, ntohs(sin->sin_port)); return (buf[i]); } @@ -1866,7 +1866,7 @@ switch (sa->sa.sa_family) { #ifdef INET case AF_INET: - return inet_ntoa4(sa->sin.sin_addr); + return inet_ntoa4(&sa->sin); #endif /* INET */ #ifdef INET6 diff -u head/sys/netipsec/ipsec_input.c nat_t/src/sys/netipsec/ipsec_input.c --- head/sys/netipsec/ipsec_input.c 2008-05-31 14:56:35.000000000 -0700 +++ nat_t/src/sys/netipsec/ipsec_input.c 2008-07-04 15:09:26.000000000 -0700 @@ -1,4 +1,4 @@ -/* $FreeBSD: head/sys/netipsec/ipsec_input.c 179290 2008-05-24 15:32:46Z bz $ */ +/* $FreeBSD: src/sys/netipsec/ipsec_input.c,v 1.21 2008/05/24 15:32:46 bz Exp $ */ /* $OpenBSD: ipsec_input.c,v 1.63 2003/02/20 18:35:43 deraadt Exp $ */ /*- * The authors of this code are John Ioannidis (ji@tla.org), @@ -111,6 +111,9 @@ struct secasvar *sav; u_int32_t spi; int error; +#ifdef IPSEC_NAT_T + struct m_tag *tag; +#endif IPSEC_ISTAT(sproto, espstat.esps_input, ahstat.ahs_input, ipcompstat.ipcomps_input); @@ -165,6 +168,12 @@ m_copydata(m, offsetof(struct ip, ip_dst), sizeof(struct in_addr), (caddr_t) &dst_address.sin.sin_addr); +#ifdef IPSEC_NAT_T + /* find the source port for NAT_T; see udp*_espdecap */ + tag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL); + if (tag != NULL) + dst_address.sin.sin_port = ((u_int16_t *)(tag + 1))[1]; +#endif /* IPSEC_NAT_T */ break; #endif /* INET */ #ifdef INET6 diff -u head/sys/netipsec/ipsec_output.c nat_t/src/sys/netipsec/ipsec_output.c --- head/sys/netipsec/ipsec_output.c 2008-05-31 14:56:35.000000000 -0700 +++ nat_t/src/sys/netipsec/ipsec_output.c 2008-07-06 16:25:41.000000000 -0700 @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: head/sys/netipsec/ipsec_output.c 179290 2008-05-24 15:32:46Z bz $ + * $FreeBSD: src/sys/netipsec/ipsec_output.c,v 1.19 2008/05/24 15:32:46 bz Exp $ */ /* @@ -82,6 +82,10 @@ #include +#ifdef IPSEC_NAT_T +#include +#endif + int ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr) { @@ -172,6 +176,47 @@ ip->ip_len = ntohs(ip->ip_len); ip->ip_off = ntohs(ip->ip_off); +#ifdef IPSEC_NAT_T + /* + * If NAT-T is enabled, now that all IPSEC processing is done + * insert UDP encapsulation header after IP header. + */ + if (sav->natt_type != 0) { +#ifdef _IP_VHL + const int hlen = IP_VHL_HL(ip->ip_vhl); +#else + const int hlen = (ip->ip_hl << 2); +#endif + int size, off; + struct mbuf *mi; + struct udphdr *udp; + + size = sizeof(struct udphdr); + if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) + size += sizeof(u_int64_t); + mi = m_makespace(m, hlen, size, &off); + if (mi == NULL) { + error = ENOBUFS; + goto bad; + } + + udp = (struct udphdr *)(mtod(mi, caddr_t) + off); + if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) + udp->uh_sport = htons(UDP_ENCAP_ESPINUDP_PORT); + else + udp->uh_sport = + KEY_PORTFROMSADDR(&sav->sah->saidx.src); + udp->uh_dport = KEY_PORTFROMSADDR(&sav->sah->saidx.dst); + udp->uh_sum = 0; + udp->uh_ulen = htons(m->m_pkthdr.len - hlen); + ip->ip_len = m->m_pkthdr.len; + ip->ip_p = IPPROTO_UDP; + + if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) + *(u_int64_t *)(udp + 1) = 0; + } +#endif /* IPSEC_NAT_T */ + return ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL); #endif /* INET */ #ifdef INET6 diff -u head/sys/netipsec/key.c nat_t/src/sys/netipsec/key.c --- head/sys/netipsec/key.c 2008-07-01 11:39:52.000000000 -0700 +++ nat_t/src/sys/netipsec/key.c 2008-07-05 09:13:07.000000000 -0700 @@ -1,4 +1,4 @@ -/* $FreeBSD: head/sys/netipsec/key.c 180086 2008-06-29 00:49:50Z julian $ */ +/* $FreeBSD: src/sys/netipsec/key.c,v 1.33 2008/06/29 00:49:50 julian Exp $ */ /* $KAME: key.c,v 1.191 2001/06/27 10:46:49 sakane Exp $ */ /*- @@ -210,6 +210,11 @@ 0, /* SADB_X_EXT_KMPRIVATE */ sizeof(struct sadb_x_policy), /* SADB_X_EXT_POLICY */ sizeof(struct sadb_x_sa2), /* SADB_X_SA2 */ + sizeof(struct sadb_x_nat_t_type),/* SADB_X_EXT_NAT_T_TYPE */ + sizeof(struct sadb_x_nat_t_port),/* SADB_X_EXT_NAT_T_SPORT */ + sizeof(struct sadb_x_nat_t_port),/* SADB_X_EXT_NAT_T_DPORT */ + sizeof(struct sadb_address), /* SADB_X_EXT_NAT_T_OA */ + sizeof(struct sadb_x_nat_t_frag),/* SADB_X_EXT_NAT_T_FRAG */ }; static const int maxsize[] = { sizeof(struct sadb_msg), /* SADB_EXT_RESERVED */ @@ -232,6 +237,11 @@ 0, /* SADB_X_EXT_KMPRIVATE */ 0, /* SADB_X_EXT_POLICY */ sizeof(struct sadb_x_sa2), /* SADB_X_SA2 */ + sizeof(struct sadb_x_nat_t_type),/* SADB_X_EXT_NAT_T_TYPE */ + sizeof(struct sadb_x_nat_t_port),/* SADB_X_EXT_NAT_T_SPORT */ + sizeof(struct sadb_x_nat_t_port),/* SADB_X_EXT_NAT_T_DPORT */ + 0, /* SADB_X_EXT_NAT_T_OA */ + sizeof(struct sadb_x_nat_t_frag),/* SADB_X_EXT_NAT_T_FRAG */ }; static int ipsec_esp_keymin = 256; @@ -393,6 +403,10 @@ const struct sadb_msghdr *)); static int key_spddump __P((struct socket *, struct mbuf *, const struct sadb_msghdr *)); +#ifdef IPSEC_NAT_T +static int key_nat_map(struct socket *, struct mbuf *, + const struct sadb_msghdr *); +#endif static struct mbuf *key_setdumpsp __P((struct secpolicy *, u_int8_t, u_int32_t, u_int32_t)); static u_int key_getspreqmsglen __P((struct secpolicy *)); @@ -418,6 +432,13 @@ static struct mbuf *key_setsadbsa __P((struct secasvar *)); static struct mbuf *key_setsadbaddr __P((u_int16_t, const struct sockaddr *, u_int8_t, u_int16_t)); +#ifdef IPSEC_NAT_T +static struct mbuf *key_setsadbxport __P((u_int16_t, u_int16_t)); +static struct mbuf *key_setsadbxtype __P((u_int16_t)); +#endif +static void key_porttosaddr __P((struct sockaddr *, u_int16_t)); +#define KEY_PORTTOSADDR(saddr, port) \ + key_porttosaddr((struct sockaddr *)(saddr), (port)) static struct mbuf *key_setsadbxsa2 __P((u_int8_t, u_int32_t, u_int32_t)); static struct mbuf *key_setsadbxpolicy __P((u_int16_t, u_int8_t, u_int32_t)); @@ -1049,12 +1070,21 @@ struct secasvar *sav; u_int stateidx, arraysize, state; const u_int *saorder_state_valid; + int chkport; IPSEC_ASSERT(dst != NULL, ("null dst address")); KEYDEBUG(KEYDEBUG_IPSEC_STAMP, printf("DP %s from %s:%u\n", __func__, where, tag)); +#ifdef IPSEC_NAT_T + chkport = (dst->sa.sa_family == AF_INET && + dst->sa.sa_len == sizeof(struct sockaddr_in) && + dst->sin.sin_port != 0); +#else + chkport = 0; +#endif + /* * searching SAD. * XXX: to be checked internal IP header somewhere. Also when @@ -1086,11 +1116,11 @@ continue; #if 0 /* don't check src */ /* check src address */ - if (key_sockaddrcmp(&src->sa, &sav->sah->saidx.src.sa, 0) != 0) + if (key_sockaddrcmp(&src->sa, &sav->sah->saidx.src.sa, chkport) != 0) continue; #endif /* check dst address */ - if (key_sockaddrcmp(&dst->sa, &sav->sah->saidx.dst.sa, 0) != 0) + if (key_sockaddrcmp(&dst->sa, &sav->sah->saidx.dst.sa, chkport) != 0) continue; sa_addref(sav); goto done; @@ -2352,6 +2382,71 @@ return key_sendup_mbuf(so, m, KEY_SENDUP_ALL); } +#ifdef IPSEC_NAT_T +/* + * SADB_X_NAT_T_NEW_MAPPING + */ +static int +key_nat_map(so, m, mhp) + struct socket *so; + struct mbuf *m; + const struct sadb_msghdr *mhp; +{ + struct sadb_x_nat_t_type *type; + struct sadb_x_nat_t_port *sport; + struct sadb_x_nat_t_port *dport; + struct sadb_address *addr; + struct sadb_x_nat_t_frag *frag; + + IPSEC_ASSERT(so != NULL, ("null socket")); + IPSEC_ASSERT(m != NULL, ("null mbuf")); + IPSEC_ASSERT(mhp != NULL, ("null msghdr")); + IPSEC_ASSERT(mhp->msg != NULL, ("null msg")); + + if (mhp->ext[SADB_X_EXT_NAT_T_TYPE] == NULL || + mhp->ext[SADB_X_EXT_NAT_T_SPORT] == NULL || + mhp->ext[SADB_X_EXT_NAT_T_DPORT] == NULL) { + ipseclog((LOG_DEBUG, "%s: invalid message.\n", __func__)); + return key_senderror(so, m, EINVAL); + } + if (mhp->extlen[SADB_X_EXT_NAT_T_TYPE] < sizeof(*type) || + mhp->extlen[SADB_X_EXT_NAT_T_SPORT] < sizeof(*sport) || + mhp->extlen[SADB_X_EXT_NAT_T_DPORT] < sizeof(*dport)) { + ipseclog((LOG_DEBUG, "%s: invalid message.\n", __func__)); + return key_senderror(so, m, EINVAL); + } + + if (mhp->ext[SADB_X_EXT_NAT_T_OA] != NULL && + mhp->extlen[SADB_X_EXT_NAT_T_OA] < sizeof(*addr)) { + ipseclog((LOG_DEBUG, "%s: invalid message\n", __func__)); + return key_senderror(so, m, EINVAL); + } + + if (mhp->ext[SADB_X_EXT_NAT_T_FRAG] != NULL && + mhp->extlen[SADB_X_EXT_NAT_T_FRAG] < sizeof(*frag)) { + ipseclog((LOG_DEBUG, "%s: invalid message\n", __func__)); + return key_senderror(so, m, EINVAL); + } + + type = (struct sadb_x_nat_t_type *)mhp->ext[SADB_X_EXT_NAT_T_TYPE]; + sport = (struct sadb_x_nat_t_port *)mhp->ext[SADB_X_EXT_NAT_T_SPORT]; + dport = (struct sadb_x_nat_t_port *)mhp->ext[SADB_X_EXT_NAT_T_DPORT]; + addr = (struct sadb_address *)mhp->ext[SADB_X_EXT_NAT_T_OA]; + frag = (struct sadb_x_nat_t_frag *) mhp->ext[SADB_X_EXT_NAT_T_FRAG]; + + ipseclog((LOG_DEBUG, "%s: type %d, sport = %d, dport = %d\n", + __func__, type->sadb_x_nat_t_type_type, + sport->sadb_x_nat_t_port_port, dport->sadb_x_nat_t_port_port)); + + /* + * XXX handle that, it should also contain a SA, or anything + * that enable to update the SA information. + */ + + return 0; +} +#endif /* IPSEC_NAT_T */ + /* * SADB_SPDDUMP processing * receive @@ -2985,6 +3080,10 @@ sav->lft_c = NULL; sav->lft_h = NULL; sav->lft_s = NULL; +#ifdef IPSEC_NAT_T + sav->natt_type = 0; + sav->esp_frag = 0; +#endif sav->tdb_xform = NULL; /* transform */ sav->tdb_encalgxform = NULL; /* encoding algorithm */ sav->tdb_authalgxform = NULL; /* authentication algorithm */ @@ -3299,6 +3398,11 @@ SADB_EXT_ADDRESS_DST, SADB_EXT_ADDRESS_PROXY, SADB_EXT_KEY_AUTH, SADB_EXT_KEY_ENCRYPT, SADB_EXT_IDENTITY_SRC, SADB_EXT_IDENTITY_DST, SADB_EXT_SENSITIVITY, +#ifdef IPSEC_NAT_T + SADB_X_EXT_NAT_T_TYPE, SADB_X_EXT_NAT_T_SPORT, + SADB_X_EXT_NAT_T_DPORT, SADB_X_EXT_NAT_T_OA, + SADB_X_EXT_NAT_T_FRAG, +#endif }; m = key_setsadbmsg(type, 0, satype, seq, pid, sav->refcnt); @@ -3383,6 +3487,34 @@ goto fail; break; +#ifdef IPSEC_NAT_T + case SADB_X_EXT_NAT_T_TYPE: + m = key_setsadbxtype(sav->natt_type); + if (!m) + goto fail; + break; + + case SADB_X_EXT_NAT_T_DPORT: + m = key_setsadbxport( + KEY_PORTFROMSADDR(&sav->sah->saidx.dst), + SADB_X_EXT_NAT_T_DPORT); + if (!m) + goto fail; + break; + + case SADB_X_EXT_NAT_T_SPORT: + m = key_setsadbxport( + KEY_PORTFROMSADDR(&sav->sah->saidx.src), + SADB_X_EXT_NAT_T_SPORT); + if (!m) + goto fail; + break; + + case SADB_X_EXT_NAT_T_OA: + case SADB_X_EXT_NAT_T_FRAG: + continue; +#endif + case SADB_EXT_ADDRESS_PROXY: case SADB_EXT_IDENTITY_SRC: case SADB_EXT_IDENTITY_DST: @@ -3587,6 +3719,112 @@ return m; } +#ifdef IPSEC_NAT_T +/* + * set a type in sadb_x_nat_t_type + */ +static struct mbuf * +key_setsadbxtype(type) + u_int16_t type; +{ + struct mbuf *m; + size_t len; + struct sadb_x_nat_t_type *p; + + len = PFKEY_ALIGN8(sizeof(struct sadb_x_nat_t_type)); + + m = key_alloc_mbuf(len); + if (!m || m->m_next) { /*XXX*/ + if (m) + m_freem(m); + return NULL; + } + + p = mtod(m, struct sadb_x_nat_t_type *); + + bzero(p, len); + p->sadb_x_nat_t_type_len = PFKEY_UNIT64(len); + p->sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE; + p->sadb_x_nat_t_type_type = type; + + return m; +} +/* + * set a port in sadb_x_nat_t_port. port is in network order + */ +static struct mbuf * +key_setsadbxport(port, type) + u_int16_t port; + u_int16_t type; +{ + struct mbuf *m; + size_t len; + struct sadb_x_nat_t_port *p; + + len = PFKEY_ALIGN8(sizeof(struct sadb_x_nat_t_port)); + + m = key_alloc_mbuf(len); + if (!m || m->m_next) { /*XXX*/ + if (m) + m_freem(m); + return NULL; + } + + p = mtod(m, struct sadb_x_nat_t_port *); + + bzero(p, len); + p->sadb_x_nat_t_port_len = PFKEY_UNIT64(len); + p->sadb_x_nat_t_port_exttype = type; + p->sadb_x_nat_t_port_port = port; + + return m; +} + +/* + * Get port from sockaddr, port is in network order + */ +u_int16_t +key_portfromsaddr(saddr) + struct sockaddr *saddr; +{ + switch (saddr->sa_family) { + case AF_INET: + return ((struct sockaddr_in *)saddr)->sin_port; +#ifdef INET6 + case AF_INET6: + return ((struct sockaddr_in6 *)saddr)->sin6_port; +#endif + } + printf("%s: unexpected address family %d\n", + __func__, saddr->sa_family); + return 0; +} +#endif /* IPSEC_NAT_T */ + +/* + * Set port is struct sockaddr. port is in network order + */ +static void +key_porttosaddr(saddr, port) + struct sockaddr *saddr; + u_int16_t port; +{ + switch (saddr->sa_family) { + case AF_INET: + ((struct sockaddr_in *)saddr)->sin_port = port; + break; +#ifdef INET6 + case AF_INET6: + ((struct sockaddr_in6 *)saddr)->sin6_port = port; + break; +#endif + default: + printf("%s: unexpected address family %d\n", + __func__, saddr->sa_family); + break; + } +} + /* * set data into sadb_x_policy */ @@ -3779,6 +4017,8 @@ const struct secasindex *saidx1, int flag) { + int chkport = 0; + /* sanity */ if (saidx0 == NULL && saidx1 == NULL) return 1; @@ -3802,6 +4042,20 @@ /* CMP_MODE_REQID, CMP_REQID, CMP_HEAD */ if (flag == CMP_MODE_REQID ||flag == CMP_REQID) { +#ifdef IPSEC_NAT_T + /* + * If NAT-T is enabled, check ports for tunnel mode. + * Don't do it for transport mode, as there is no + * port information available in the SP. + * XXX also don't check ports if they are set to zero + * XXX in the SPD: This means we bave a non-generated + * XXX SPD which can't know UDP ports. + */ + if (saidx1->mode == IPSEC_MODE_TUNNEL && + ((const struct sockaddr_in *)(&saidx1->src))->sin_port && + ((const struct sockaddr_in *)(&saidx1->dst))->sin_port ) + chkport = 1; +#endif /* IPSEC_NAT_T */ /* * If reqid of SPD is non-zero, unique SA is required. * The result must be of same reqid in this case. @@ -3809,6 +4063,10 @@ if (saidx1->reqid != 0 && saidx0->reqid != saidx1->reqid) return 0; } +#ifdef IPSEC_NAT_T + else + chkport = 1; +#endif if (flag == CMP_MODE_REQID) { if (saidx0->mode != IPSEC_MODE_ANY @@ -3816,10 +4074,10 @@ return 0; } - if (key_sockaddrcmp(&saidx0->src.sa, &saidx1->src.sa, 0) != 0) { + if (key_sockaddrcmp(&saidx0->src.sa, &saidx1->src.sa, chkport) != 0) { return 0; } - if (key_sockaddrcmp(&saidx0->dst.sa, &saidx1->dst.sa, 0) != 0) { + if (key_sockaddrcmp(&saidx0->dst.sa, &saidx1->dst.sa, chkport) != 0) { return 0; } } @@ -4440,13 +4698,17 @@ if (((struct sockaddr *)(src0 + 1))->sa_len != sizeof(struct sockaddr_in)) return key_senderror(so, m, EINVAL); +#ifndef IPSEC_NAT_T ((struct sockaddr_in *)(src0 + 1))->sin_port = 0; +#endif break; case AF_INET6: if (((struct sockaddr *)(src0 + 1))->sa_len != sizeof(struct sockaddr_in6)) return key_senderror(so, m, EINVAL); +#ifndef IPSEC_NAT_T ((struct sockaddr_in6 *)(src0 + 1))->sin6_port = 0; +#endif break; default: ; /*???*/ @@ -4456,13 +4718,17 @@ if (((struct sockaddr *)(dst0 + 1))->sa_len != sizeof(struct sockaddr_in)) return key_senderror(so, m, EINVAL); +#ifndef IPSEC_NAT_T ((struct sockaddr_in *)(dst0 + 1))->sin_port = 0; +#endif break; case AF_INET6: if (((struct sockaddr *)(dst0 + 1))->sa_len != sizeof(struct sockaddr_in6)) return key_senderror(so, m, EINVAL); +#ifndef IPSEC_NAT_T ((struct sockaddr_in6 *)(dst0 + 1))->sin6_port = 0; +#endif break; default: ; /*???*/ @@ -4471,6 +4737,12 @@ /* XXX boundary check against sa_len */ KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx); +#ifndef IPSEC_NAT_T + /* If not using NAT-T, make sure port numbers are set to zero. */ + KEY_PORTTOSADDR(&saidx.src, 0); + KEY_PORTTOSADDR(&saidx.dst, 0); +#endif + /* SPI allocation */ spi = key_do_getnewspi((struct sadb_spirange *)mhp->ext[SADB_EXT_SPIRANGE], &saidx); @@ -4724,6 +4996,12 @@ /* XXX boundary check against sa_len */ KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx); +#ifndef IPSEC_NAT_T + /* If not using NAT-T, make sure if port number is zero. */ + KEY_PORTTOSADDR(&saidx.src, 0); + KEY_PORTTOSADDR(&saidx.dst, 0); +#endif + /* get a SA header */ if ((sah = key_getsah(&saidx)) == NULL) { ipseclog((LOG_DEBUG, "%s: no SA index found.\n", __func__)); @@ -4790,6 +5068,70 @@ return key_senderror(so, m, 0); } +#ifdef IPSEC_NAT_T + /* + * Handle NAT-T info if present + */ + if (mhp->ext[SADB_X_EXT_NAT_T_OA] != NULL) + printf("update: NAT-T OA present\n"); + + if (mhp->ext[SADB_X_EXT_NAT_T_TYPE] != NULL && + mhp->ext[SADB_X_EXT_NAT_T_SPORT] != NULL && + mhp->ext[SADB_X_EXT_NAT_T_DPORT] != NULL) { + struct sadb_x_nat_t_type *type; + struct sadb_x_nat_t_port *sport; + struct sadb_x_nat_t_port *dport; + struct sadb_address *addr; + struct sadb_x_nat_t_frag *frag; + + if (mhp->extlen[SADB_X_EXT_NAT_T_TYPE] < sizeof(*type) || + mhp->extlen[SADB_X_EXT_NAT_T_SPORT] < sizeof(*sport) || + mhp->extlen[SADB_X_EXT_NAT_T_DPORT] < sizeof(*dport)) { + ipseclog((LOG_DEBUG, "%s: invalid message.\n", + __func__)); + return key_senderror(so, m, EINVAL); + } + + if (mhp->ext[SADB_X_EXT_NAT_T_OA] != NULL && + mhp->extlen[SADB_X_EXT_NAT_T_OA] < sizeof(*addr)) { + ipseclog((LOG_DEBUG, "%s: invalid message\n", + __func__)); + return key_senderror(so, m, EINVAL); + } + + if (mhp->ext[SADB_X_EXT_NAT_T_FRAG] != NULL && + mhp->extlen[SADB_X_EXT_NAT_T_FRAG] < sizeof(*frag)) { + ipseclog((LOG_DEBUG, "%s: invalid message\n", + __func__)); + return key_senderror(so, m, EINVAL); + } + + type = (struct sadb_x_nat_t_type *) + mhp->ext[SADB_X_EXT_NAT_T_TYPE]; + sport = (struct sadb_x_nat_t_port *) + mhp->ext[SADB_X_EXT_NAT_T_SPORT]; + dport = (struct sadb_x_nat_t_port *) + mhp->ext[SADB_X_EXT_NAT_T_DPORT]; + addr = (struct sadb_address *) + mhp->ext[SADB_X_EXT_NAT_T_OA]; + frag = (struct sadb_x_nat_t_frag *) + mhp->ext[SADB_X_EXT_NAT_T_FRAG]; + + if (type) + sav->natt_type = type->sadb_x_nat_t_type_type; + if (sport) + KEY_PORTTOSADDR(&sav->sah->saidx.src, + sport->sadb_x_nat_t_port_port); + if (dport) + KEY_PORTTOSADDR(&sav->sah->saidx.dst, + dport->sadb_x_nat_t_port_port); + if (frag) + sav->esp_frag = frag->sadb_x_nat_t_frag_fraglen; + else + sav->esp_frag = IP_MAXPACKET; + } +#endif /* IPSEC_NAT_T */ + { struct mbuf *n; @@ -4922,6 +5264,11 @@ /* XXX boundary check against sa_len */ KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx); +#ifndef IPSEC_NAT_T + KEY_PORTTOSADDR(&saidx.src, 0); + KEY_PORTTOSADDR(&saidx.dst, 0); +#endif + /* get a SA header */ if ((newsah = key_getsah(&saidx)) == NULL) { /* create a new SA header */ @@ -4958,6 +5305,70 @@ return key_senderror(so, m, error); } +#ifdef IPSEC_NAT_T + /* + * Handle NAT-T info if present + */ + if (mhp->ext[SADB_X_EXT_NAT_T_OA] != NULL) + printf("add: NAT-T OA present\n"); + + if (mhp->ext[SADB_X_EXT_NAT_T_TYPE] != NULL && + mhp->ext[SADB_X_EXT_NAT_T_SPORT] != NULL && + mhp->ext[SADB_X_EXT_NAT_T_DPORT] != NULL) { + struct sadb_x_nat_t_type *type; + struct sadb_x_nat_t_port *sport; + struct sadb_x_nat_t_port *dport; + struct sadb_address *addr; + struct sadb_x_nat_t_frag *frag; + + if (mhp->extlen[SADB_X_EXT_NAT_T_TYPE] < sizeof(*type) || + mhp->extlen[SADB_X_EXT_NAT_T_SPORT] < sizeof(*sport) || + mhp->extlen[SADB_X_EXT_NAT_T_DPORT] < sizeof(*dport)) { + ipseclog((LOG_DEBUG, "%s: invalid message.\n", + __func__)); + return key_senderror(so, m, EINVAL); + } + + if (mhp->ext[SADB_X_EXT_NAT_T_OA] != NULL && + mhp->extlen[SADB_X_EXT_NAT_T_OA] < sizeof(*addr)) { + ipseclog((LOG_DEBUG, "%s: invalid message\n", + __func__)); + return key_senderror(so, m, EINVAL); + } + + if (mhp->ext[SADB_X_EXT_NAT_T_FRAG] != NULL && + mhp->extlen[SADB_X_EXT_NAT_T_FRAG] < sizeof(*frag)) { + ipseclog((LOG_DEBUG, "%s: invalid message\n", + __func__)); + return key_senderror(so, m, EINVAL); + } + + type = (struct sadb_x_nat_t_type *) + mhp->ext[SADB_X_EXT_NAT_T_TYPE]; + sport = (struct sadb_x_nat_t_port *) + mhp->ext[SADB_X_EXT_NAT_T_SPORT]; + dport = (struct sadb_x_nat_t_port *) + mhp->ext[SADB_X_EXT_NAT_T_DPORT]; + addr = (struct sadb_address *) + mhp->ext[SADB_X_EXT_NAT_T_OA]; + frag = (struct sadb_x_nat_t_frag *) + mhp->ext[SADB_X_EXT_NAT_T_FRAG]; + + if (type) + newsav->natt_type = type->sadb_x_nat_t_type_type; + if (sport) + KEY_PORTTOSADDR(&newsav->sah->saidx.src, + sport->sadb_x_nat_t_port_port); + if (dport) + KEY_PORTTOSADDR(&newsav->sah->saidx.dst, + dport->sadb_x_nat_t_port_port); + if (frag) + newsav->esp_frag = frag->sadb_x_nat_t_frag_fraglen; + else + newsav->esp_frag = IP_MAXPACKET; + } +#endif + /* * don't call key_freesav() here, as we would like to keep the SA * in the database on success. @@ -5161,6 +5572,11 @@ /* XXX boundary check against sa_len */ KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx); +#ifndef IPSEC_NAT_T + KEY_PORTTOSADDR(&saidx.src, 0); + KEY_PORTTOSADDR(&saidx.dst, 0); +#endif + /* get a SA header */ SAHTREE_LOCK(); LIST_FOREACH(sah, &sahtree, chain) { @@ -5230,6 +5646,11 @@ /* XXX boundary check against sa_len */ KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx); +#ifndef IPSEC_NAT_T + KEY_PORTTOSADDR(&saidx.src, 0); + KEY_PORTTOSADDR(&saidx.dst, 0); +#endif + SAHTREE_LOCK(); LIST_FOREACH(sah, &sahtree, chain) { if (sah->state == SADB_SASTATE_DEAD) @@ -5344,6 +5765,11 @@ /* XXX boundary check against sa_len */ KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx); +#ifndef IPSEC_NAT_T + KEY_PORTTOSADDR(&saidx.src, 0); + KEY_PORTTOSADDR(&saidx.dst, 0); +#endif + /* get a SA header */ SAHTREE_LOCK(); LIST_FOREACH(sah, &sahtree, chain) { @@ -6031,6 +6457,11 @@ /* XXX boundary check against sa_len */ KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx); +#ifndef IPSEC_NAT_T + KEY_PORTTOSADDR(&saidx.src, 0); + KEY_PORTTOSADDR(&saidx.dst, 0); +#endif + /* get a SA index */ SAHTREE_LOCK(); LIST_FOREACH(sah, &sahtree, chain) { @@ -6644,6 +7075,11 @@ key_spdadd, /* SADB_X_SPDSETIDX */ NULL, /* SADB_X_SPDEXPIRE */ key_spddelete2, /* SADB_X_SPDDELETE2 */ +#ifdef IPSEC_NAT_T + key_nat_map, /* SADB_X_NAT_T_NEW_MAPPING */ +#else + NULL, /* SADB_X_NAT_T_NEW_MAPPING */ +#endif }; /* @@ -6980,6 +7416,13 @@ case SADB_EXT_SPIRANGE: case SADB_X_EXT_POLICY: case SADB_X_EXT_SA2: +#ifdef IPSEC_NAT_T + case SADB_X_EXT_NAT_T_TYPE: + case SADB_X_EXT_NAT_T_SPORT: + case SADB_X_EXT_NAT_T_DPORT: + case SADB_X_EXT_NAT_T_OA: + case SADB_X_EXT_NAT_T_FRAG: +#endif /* duplicate check */ /* * XXX Are there duplication payloads of either diff -u head/sys/netipsec/key.h nat_t/src/sys/netipsec/key.h --- head/sys/netipsec/key.h 2008-05-31 14:56:35.000000000 -0700 +++ nat_t/src/sys/netipsec/key.h 2008-07-04 08:55:32.000000000 -0700 @@ -1,4 +1,4 @@ -/* $FreeBSD: head/sys/netipsec/key.h 139823 2005-01-07 01:45:51Z imp $ */ +/* $FreeBSD: src/sys/netipsec/key.h,v 1.4 2005/01/07 01:45:46 imp Exp $ */ /* $KAME: key.h,v 1.21 2001/07/27 03:51:30 itojun Exp $ */ /*- @@ -99,6 +99,10 @@ extern void key_sa_recordxfer __P((struct secasvar *, struct mbuf *)); extern void key_sa_routechange __P((struct sockaddr *)); extern void key_sa_stir_iv __P((struct secasvar *)); +#ifdef IPSEC_NAT_T +u_int16_t key_portfromsaddr __P((struct sockaddr *)); +#define KEY_PORTFROMSADDR(saddr) key_portfromsaddr((struct sockaddr *)(saddr)) +#endif #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_IPSEC_SA); diff -u head/sys/netipsec/keydb.h nat_t/src/sys/netipsec/keydb.h --- head/sys/netipsec/keydb.h 2008-05-31 14:56:35.000000000 -0700 +++ nat_t/src/sys/netipsec/keydb.h 2008-07-04 08:55:32.000000000 -0700 @@ -1,4 +1,4 @@ -/* $FreeBSD: head/sys/netipsec/keydb.h 157123 2006-03-25 13:38:52Z gnn $ */ +/* $FreeBSD: src/sys/netipsec/keydb.h,v 1.6 2006/03/25 13:38:52 gnn Exp $ */ /* $KAME: keydb.h,v 1.14 2000/08/02 17:58:26 sakane Exp $ */ /*- @@ -142,6 +142,12 @@ struct secashead *sah; /* back pointer to the secashead */ /* + * NAT-Traversal + */ + u_int16_t natt_type; + u_int16_t esp_frag; + + /* * NB: Fields with a tdb_ prefix are part of the "glue" used * to interface to the OpenBSD crypto support. This was done * to distinguish this code from the mainline KAME code. diff -u head/sys/sys/mbuf.h nat_t/src/sys/sys/mbuf.h --- head/sys/sys/mbuf.h 2008-05-31 14:56:45.000000000 -0700 +++ nat_t/src/sys/sys/mbuf.h 2008-07-04 08:55:32.000000000 -0700 @@ -28,7 +28,7 @@ * SUCH DAMAGE. * * @(#)mbuf.h 8.5 (Berkeley) 2/19/95 - * $FreeBSD: head/sys/sys/mbuf.h 178888 2008-05-09 23:03:00Z julian $ + * $FreeBSD: src/sys/sys/mbuf.h,v 1.226 2008/05/09 23:02:59 julian Exp $ */ #ifndef _SYS_MBUF_H_ @@ -858,6 +858,7 @@ #define PACKET_TAG_RTSOCKFAM 25 /* rtsock sa family */ #define PACKET_TAG_IPOPTIONS 27 /* Saved IP options */ #define PACKET_TAG_CARP 28 /* CARP info */ +#define PACKET_TAG_IPSEC_NAT_T_PORTS 29 /* two uint16_t */ /* Specific cookies and tags. */