Add support for IPsec Network Address Translator traversal (NAT-T), as

described by RFC 3947 and 3948.
This commit is contained in:
manu 2005-02-12 12:31:07 +00:00
parent a8f0ad3c37
commit 5c217c1a67
14 changed files with 675 additions and 30 deletions

View File

@ -1,4 +1,4 @@
LIST OF CHANGES FROM LAST RELEASE: <$Revision: 1.423 $>
LIST OF CHANGES FROM LAST RELEASE: <$Revision: 1.424 $>
[Note: This file does not mention every change made to the NetBSD source tree.
@ -214,3 +214,4 @@ Changes from NetBSD 2.0 to NetBSD 3.0:
groupadd(8): Add the -r option, used to specify a gid range in which
groups can be created. [jmmv 20050205]
ipf(8): updated to version 4.1.5. [martti 20050208]
ipsec(4): Add support for IPsec NAT-T [manu 20050212]

View File

@ -1,4 +1,4 @@
.\" $NetBSD: ipsec.4,v 1.25 2003/10/21 08:44:04 itojun Exp $
.\" $NetBSD: ipsec.4,v 1.26 2005/02/12 12:31:07 manu Exp $
.\" $KAME: ipsec.4,v 1.17 2001/06/27 15:25:10 itojun Exp $
.\"
.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -41,6 +41,7 @@
.Pp
.Cd options IPSEC
.Cd options IPSEC_ESP
.Cd options IPSEC_NAT_T
.Cd options IPSEC_DEBUG
.Sh DESCRIPTION
.Nm
@ -112,6 +113,15 @@ will enable source code that is subject to export control in some countries
and compiled kernel binary will be subject to certain restriction.
This option assumes
.Em IPSEC .
.It Cd options IPSEC_NAT_T
Includes support for
.Tn IPsec
Network Address Translator traversal (NAT-T), as described in RFC 3947
and 3948. This feature might be patent-encumbered in some countries.
This option assumes
.Em IPSEC
and
.Em IPSEC_ESP .
.El
.\"
.Ss Kernel interface

View File

@ -1,4 +1,4 @@
.\" $NetBSD: options.4,v 1.265 2005/01/25 01:59:07 wiz Exp $
.\" $NetBSD: options.4,v 1.266 2005/02/12 12:31:07 manu Exp $
.\"
.\" Copyright (c) 1996
.\" Perry E. Metzger. All rights reserved.
@ -1517,6 +1517,12 @@ protocol.
See
.Xr ipsec 4
for details.
.It Cd options IPSEC_NAT_T
Includes support for
.Tn IPsec
Network Address Translator traversal (NAT-T), as described in RFC 3947
and 3948. This feature might be
patent-encumbered in some countries.
.It Cd options ALTQ
Enabled ALTQ (Alternate Queueing).
For simple rate-limiting, use

View File

@ -1,4 +1,4 @@
/* $NetBSD: pfkeyv2.h,v 1.18 2005/01/14 04:11:55 itojun Exp $ */
/* $NetBSD: pfkeyv2.h,v 1.19 2005/02/12 12:31:07 manu Exp $ */
/* $KAME: pfkeyv2.h,v 1.36 2003/07/25 09:33:37 itojun Exp $ */
/*
@ -75,7 +75,8 @@ you leave this credit intact on any copies of this file.
#define SADB_X_SPDSETIDX 20
#define SADB_X_SPDEXPIRE 21 /* not yet */
#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 @@ struct sadb_x_ipsecrequest {
*/
};
/* NAT traversal type, see draft-ietf-ipsec-udp-encaps-06 */
/* 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 @@ struct sadb_x_ipsecrequest {
#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

View File

@ -1,4 +1,4 @@
/* $NetBSD: in_pcb.h,v 1.38 2004/04/21 17:49:46 itojun Exp $ */
/* $NetBSD: in_pcb.h,v 1.39 2005/02/12 12:31:07 manu Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -105,8 +105,12 @@ struct inpcb {
#define INP_LOWPORT 0x20 /* user wants "low" port binding */
#define INP_ANONPORT 0x40 /* port chosen for user */
#define INP_RECVIF 0x80 /* receive incoming interface */
/* XXX should move to an UDP control block */
#define INP_ESPINUDP 0x100 /* ESP over UDP for NAT-T */
#define INP_ESPINUDP_NON_IKE 0x200 /* ESP over UDP for NAT-T */
#define INP_CONTROLOPTS (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\
INP_RECVIF)
#define INP_ESPINUDP_ALL (INP_ESPINUDP|INP_ESPINUDP_NON_IKE)
#define sotoinpcb(so) ((struct inpcb *)(so)->so_pcb)

View File

@ -1,4 +1,4 @@
/* $NetBSD: in_proto.c,v 1.67 2005/01/31 23:49:36 kim Exp $ */
/* $NetBSD: in_proto.c,v 1.68 2005/02/12 12:31:07 manu Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -61,7 +61,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: in_proto.c,v 1.67 2005/01/31 23:49:36 kim Exp $");
__KERNEL_RCSID(0, "$NetBSD: in_proto.c,v 1.68 2005/02/12 12:31:07 manu Exp $");
#include "opt_mrouting.h"
#include "opt_eon.h" /* ISO CLNL over IP */
@ -157,7 +157,7 @@ const struct protosw inetsw[] = {
ip_init, 0, ip_slowtimo, ip_drain, NULL
},
{ SOCK_DGRAM, &inetdomain, IPPROTO_UDP, PR_ATOMIC|PR_ADDR,
udp_input, 0, udp_ctlinput, ip_ctloutput,
udp_input, 0, udp_ctlinput, udp_ctloutput,
udp_usrreq,
udp_init, 0, 0, 0, NULL
},

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_output.c,v 1.140 2005/02/03 23:13:20 perry Exp $ */
/* $NetBSD: ip_output.c,v 1.141 2005/02/12 12:31:07 manu Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -98,7 +98,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.140 2005/02/03 23:13:20 perry Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.141 2005/02/12 12:31:07 manu Exp $");
#include "opt_pfil_hooks.h"
#include "opt_inet.h"
@ -139,6 +139,9 @@ __KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.140 2005/02/03 23:13:20 perry Exp $"
#include <netinet6/ipsec.h>
#include <netkey/key.h>
#include <netkey/key_debug.h>
#ifdef IPSEC_NAT_T
#include <netinet/udp.h>
#endif
#endif /*IPSEC*/
#ifdef FAST_IPSEC
@ -182,6 +185,9 @@ ip_output(struct mbuf *m0, ...)
va_list ap;
#ifdef IPSEC
struct secpolicy *sp = NULL;
#ifdef IPSEC_NAT_T
int natt_frag = 0;
#endif
#endif /*IPSEC*/
#ifdef FAST_IPSEC
struct inpcb *inp;
@ -504,6 +510,22 @@ sendit:
printf("ip_output: Invalid policy found. %d\n", sp->policy);
}
#ifdef IPSEC_NAT_T
/*
* NAT-T ESP 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) > sp->req->sav->esp_frag) {
natt_frag = 1;
mtu = sp->req->sav->esp_frag;
goto skip_ipsec;
}
}
#endif /* IPSEC_NAT_T */
/*
* ipsec4_output() expects ip_len and ip_off in network
* order. They have been set to network order above.
@ -828,11 +850,26 @@ spd_done:
#ifdef IPSEC
/* clean ipsec history once it goes out of the node */
ipsec_delaux(m);
#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);
#ifdef IPSEC_NAT_T
/*
* 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 /* IPSEC_NAT_T */
#endif /* IPSEC */
{
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);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: udp.h,v 1.10 2003/08/07 16:33:20 agc Exp $ */
/* $NetBSD: udp.h,v 1.11 2005/02/12 12:31:07 manu Exp $ */
/*
* Copyright (c) 1982, 1986, 1993
@ -45,4 +45,17 @@ struct udphdr {
u_int16_t uh_sum; /* udp checksum */
} __attribute__((__packed__));
/* 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-06 */
/* Default encapsulation port */
#define UDP_ENCAP_ESPINUDP_PORT 500
/* Maximum UDP fragment size for ESP over UDP */
#define UDP_ENCAP_ESPINUDP_MAXFRAGLEN 552
#endif /* _NETINET_UDP_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: udp_usrreq.c,v 1.129 2004/12/21 05:51:32 yamt Exp $ */
/* $NetBSD: udp_usrreq.c,v 1.130 2005/02/12 12:31:07 manu Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -61,7 +61,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c,v 1.129 2004/12/21 05:51:32 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c,v 1.130 2005/02/12 12:31:07 manu Exp $");
#include "opt_inet.h"
#include "opt_ipsec.h"
@ -95,6 +95,11 @@ __KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c,v 1.129 2004/12/21 05:51:32 yamt Exp $"
#include <netinet/udp.h>
#include <netinet/udp_var.h>
#ifdef IPSEC_NAT_T
#include <netinet6/ipsec.h>
#include <netinet6/esp.h>
#endif
#ifdef INET6
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
@ -147,6 +152,10 @@ struct inpcbtable udbtable;
struct udpstat udpstat;
#ifdef INET
#ifdef IPSEC_NAT_T
static int udp4_espinudp (struct mbuf *, int, struct sockaddr *,
struct socket *);
#endif
static void udp4_sendup (struct mbuf *, int, struct sockaddr *,
struct socket *);
static int udp4_realinput (struct sockaddr_in *, struct sockaddr_in *,
@ -740,6 +749,20 @@ udp4_realinput(struct sockaddr_in *src, struct sockaddr_in *dst,
return rcvcnt;
}
#ifdef IPSEC_NAT_T
/* Handle ESP over UDP */
if (inp->inp_flags & INP_ESPINUDP_ALL) {
struct sockaddr *sa = (struct sockaddr *)src;
if (udp4_espinudp(m, off, sa, inp->inp_socket) != 0) {
rcvcnt++;
goto bad;
}
/* Normal UDP processing will take place */
}
#endif
udp4_sendup(m, off, (struct sockaddr *)src, inp->inp_socket);
rcvcnt++;
}
@ -908,6 +931,100 @@ udp_ctlinput(int cmd, struct sockaddr *sa, void *v)
return NULL;
}
int
udp_ctloutput(op, so, level, optname, mp)
int op;
struct socket *so;
int level, optname;
struct mbuf **mp;
{
int s;
int error = 0;
struct mbuf *m;
struct inpcb *inp;
int family;
family = so->so_proto->pr_domain->dom_family;
s = splsoftnet();
switch (family) {
#ifdef INET
case PF_INET:
if (level != IPPROTO_UDP) {
error = ip_ctloutput(op, so, level, optname, mp);
goto end;
}
break;
#endif
#ifdef INET6
case PF_INET6:
if (level != IPPROTO_UDP) {
error = ip6_ctloutput(op, so, level, optname, mp);
goto end;
}
break;
#endif
default:
error = EAFNOSUPPORT;
goto end;
break;
}
switch (op) {
case PRCO_SETOPT:
m = *mp;
inp = sotoinpcb(so);
switch (optname) {
case UDP_ENCAP:
if (m == NULL || m->m_len < sizeof (int)) {
error = EINVAL;
goto end;
}
switch(*mtod(m, int *)) {
#ifdef IPSEC_NAT_T
case 0:
inp->inp_flags &= ~INP_ESPINUDP_ALL;
break;
case UDP_ENCAP_ESPINUDP:
inp->inp_flags &= ~INP_ESPINUDP_ALL;
inp->inp_flags |= INP_ESPINUDP;
break;
case UDP_ENCAP_ESPINUDP_NON_IKE:
inp->inp_flags &= ~INP_ESPINUDP_ALL;
inp->inp_flags |= INP_ESPINUDP_NON_IKE;
break;
#endif
default:
error = EINVAL;
goto end;
break;
}
break;
default:
error = ENOPROTOOPT;
goto end;
break;
}
break;
default:
error = EINVAL;
goto end;
break;
}
end:
splx(s);
return error;
}
int
udp_output(struct mbuf *m, ...)
{
@ -1219,3 +1336,113 @@ SYSCTL_SETUP(sysctl_net_inet_udp_setup, "sysctl net.inet.udp subtree setup")
CTL_EOL);
}
#endif
#if (defined INET && defined IPSEC_NAT_T)
/*
* Returns:
* 1 if the packet was processed
* 0 if normal UDP processing should take place
*/
static int
udp4_espinudp(m, off, src, so)
struct mbuf *m;
int off;
struct sockaddr *src;
struct socket *so;
{
size_t len;
caddr_t data;
struct inpcb *inp;
size_t skip = 0;
size_t minlen;
size_t iphdrlen;
struct ip *ip;
struct mbuf *n;
/*
* Collapse the mbuf chain if the first mbuf is too short
* The longest case is: UDP + non ESP marker + ESP
*/
minlen = off + sizeof(u_int64_t) + sizeof(struct esp);
if (minlen > m->m_pkthdr.len)
minlen = m->m_pkthdr.len;
if (m->m_len < minlen) {
if ((m = m_pullup(m, minlen)) == NULL) {
printf("udp4_espinudp: m_pullup failed\n");
return 0;
}
}
len = m->m_len - off;
data = mtod(m, caddr_t) + off;
inp = sotoinpcb(so);
/* Ignore keepalive packets */
if ((len == 1) && (data[0] == '\xff')) {
return 1;
}
/*
* Check that the payload is long enough to hold
* an ESP header and compute the length of encapsulation
* header to remove
*/
if (inp->inp_flags & INP_ESPINUDP) {
u_int32_t *st = (u_int32_t *)data;
if ((len <= sizeof(struct esp)) || (*st == 0))
return 0; /* Normal UDP processing */
skip = sizeof(struct udphdr);
}
if (inp->inp_flags & INP_ESPINUDP_NON_IKE) {
u_int64_t *st = (u_int64_t *)data;
if ((len <= sizeof(u_int64_t) + sizeof(struct esp))
|| (*st != 0))
return 0; /* Normal UDP processing */
skip = sizeof(struct udphdr) + sizeof(u_int64_t);
}
/*
* Remove the UDP header (and possibly the non ESP marker)
* IP header lendth is iphdrlen
* Before:
* <--- off --->
* +----+------+-----+
* | IP | UDP | ESP |
* +----+------+-----+
* <-skip->
* After:
* +----+-----+
* | IP | ESP |
* +----+-----+
* <-skip->
*/
iphdrlen = off - sizeof(struct udphdr);
memmove(mtod(m, caddr_t) + skip, mtod(m, caddr_t), iphdrlen);
m_adj(m, skip);
ip = mtod(m, struct ip *);
ip->ip_len = htons(ntohs(ip->ip_len) - skip);
ip->ip_p = IPPROTO_ESP;
/*
* Copy the mbuf to avoid multiple free, as both
* esp4_input (which we call) and udp_input (which
* called us) free the mbuf.
*/
if ((n = m_dup(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
printf("udp4_espinudp: m_dup failed\n");
return 0;
}
esp4_input(n, iphdrlen);
/* We handled it, it shoudln't be handled by UDP */
return 1;
}
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: udp_var.h,v 1.26 2004/12/21 05:51:33 yamt Exp $ */
/* $NetBSD: udp_var.h,v 1.27 2005/02/12 12:31:08 manu Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@ -94,6 +94,7 @@ extern int udp_do_loopback_cksum;
#endif
void *udp_ctlinput(int, struct sockaddr *, void *);
int udp_ctloutput(int, struct socket *, int, int, struct mbuf **);
void udp_init(void);
void udp_input(struct mbuf *, ...);
int udp_output(struct mbuf *, ...);

View File

@ -1,4 +1,4 @@
/* $NetBSD: esp_output.c,v 1.18 2003/09/07 15:59:36 itojun Exp $ */
/* $NetBSD: esp_output.c,v 1.19 2005/02/12 12:31:08 manu Exp $ */
/* $KAME: esp_output.c,v 1.44 2001/07/26 06:53:15 jinmei Exp $ */
/*
@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: esp_output.c,v 1.18 2003/09/07 15:59:36 itojun Exp $");
__KERNEL_RCSID(0, "$NetBSD: esp_output.c,v 1.19 2005/02/12 12:31:08 manu Exp $");
#include "opt_inet.h"
@ -59,6 +59,9 @@ __KERNEL_RCSID(0, "$NetBSD: esp_output.c,v 1.18 2003/09/07 15:59:36 itojun Exp $
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_var.h>
#ifdef IPSEC_NAT_T
#include <netinet/udp.h>
#endif
#ifdef INET6
#include <netinet/ip6.h>
@ -136,6 +139,17 @@ esp_hdrsiz(isr)
esp_max_padbound() - 1 + 2 + authlen;
}
#ifdef IPSEC_NAT_T
/*
* If NAT-T is enabled, add the space for UDP encapsulation
*/
if (sav->natt_type != 0) {
hdrsiz += sizeof(struct udphdr);
if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
hdrsiz += sizeof(u_int64_t);
}
#endif
return hdrsiz;
estimate:
@ -147,9 +161,15 @@ esp_hdrsiz(isr)
* maximum padding length without random padding length
* 2 = (Pad Length field) + (Next Header field).
* AH_MAXSUMSIZE = maximum ICV we support.
* sizeof(u_int64_t) = non IKE marker (NAT-T)
* sizeof(struct udphdr) = UDP encapsulation (NAT-T)
*/
return sizeof(struct newesp) + esp_max_ivlen() +
esp_max_padbound() - 1 + 2 + AH_MAXSUMSIZE;
esp_max_padbound() - 1 + 2 + AH_MAXSUMSIZE +
#ifdef IPSEC_NAT_T
sizeof(u_int64_t) + sizeof(struct udphdr) +
#endif
0;
}
/*
@ -195,6 +215,9 @@ esp_output(m, nexthdrp, md, isr, af)
size_t extendsiz;
int error = 0;
struct ipsecstat *stat;
#ifdef IPSEC_NAT_T
struct udphdr *udp = NULL;
#endif
switch (af) {
#ifdef INET
@ -329,10 +352,25 @@ esp_output(m, nexthdrp, md, isr, af)
espoff = m->m_pkthdr.len - plen;
#ifdef IPSEC_NAT_T
if (sav->natt_type != 0) {
esphlen += sizeof(struct udphdr);
espoff += sizeof(struct udphdr);
if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) {
/* NON-IKE marker */
esphlen += sizeof(u_int64_t);
espoff += sizeof(u_int64_t);
}
}
#endif
/*
* grow the mbuf to accomodate ESP header.
* before: IP ... payload
* after: IP ... ESP IV payload
* after (without NAT-T): IP ... ESP IV payload
* after (with older NAT-T): IP ... UDP non-IKE-marker ESP IV payload
* after (with newer NAT-T): IP ... UDP ESP IV payload
*/
if (M_LEADINGSPACE(md) < esphlen || (md->m_flags & M_EXT) != 0) {
MGET(n, M_DONTWAIT, MT_DATA);
@ -345,6 +383,7 @@ esp_output(m, nexthdrp, md, isr, af)
mprev->m_next = n;
n->m_next = md;
m->m_pkthdr.len += esphlen;
esp = mtod(n, struct esp *);
} else {
md->m_len += esphlen;
@ -353,6 +392,20 @@ esp_output(m, nexthdrp, md, isr, af)
esp = mtod(md, struct esp *);
}
#ifdef IPSEC_NAT_T
if (sav->natt_type != 0) {
udp = (struct udphdr *)esp;
esp = (struct esp *)(udp + 1);
if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) {
u_int64_t *data = (u_int64_t *)esp;
*data = 0; /* NON-IKE marker */
esp = (struct esp *)(data + 1);
}
}
#endif
nxt = *nexthdrp;
*nexthdrp = IPPROTO_ESP;
switch (af) {
@ -469,6 +522,26 @@ esp_output(m, nexthdrp, md, isr, af)
break;
}
#ifdef IPSEC_NAT_T
if (sav->natt_type != 0) {
*nexthdrp = IPPROTO_UDP;
/*
* Create the UDP encapsulation header for NAT-T
* uh_len is set later, when the size is known.
*/
if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
udp->uh_sport = htons(UDP_ENCAP_ESPINUDP_PORT);
else
udp->uh_sport = htons(sav->local_ike_port);
udp->uh_dport = htons(sav->remote_ike_port);
udp->uh_sum = 0;
} else {
*nexthdrp = IPPROTO_ESP;
}
#endif
/* initialize esp trailer. */
esptail = (struct esptail *)
(mtod(n, u_int8_t *) + n->m_len - sizeof(struct esptail));
@ -612,6 +685,20 @@ esp_output(m, nexthdrp, md, isr, af)
}
}
#ifdef IPSEC_NAT_T
if (sav->natt_type != 0) {
struct ip *ip;
ip = mtod(m, struct ip *);
#ifdef _IP_VHL
udp->uh_ulen =
htons(ntohs(ip->ip_len) - (IP_VHL_HL(ip->ip_vhl) << 2));
#else
udp->uh_ulen = htons(ntohs(ip->ip_len) - (ip->ip_hl << 2));
#endif
}
#endif /* IPSEC_NAT_T */
noantireplay:
if (!m) {
ipseclog((LOG_ERR,

View File

@ -1,4 +1,4 @@
/* $NetBSD: key.c,v 1.20 2004/06/10 01:28:25 jonathan Exp $ */
/* $NetBSD: key.c,v 1.21 2005/02/12 12:31:08 manu Exp $ */
/* $FreeBSD: src/sys/netipsec/key.c,v 1.3.2.3 2004/02/14 22:23:23 bms Exp $ */
/* $KAME: key.c,v 1.191 2001/06/27 10:46:49 sakane Exp $ */
@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.20 2004/06/10 01:28:25 jonathan Exp $");
__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.21 2005/02/12 12:31:08 manu Exp $");
/*
* This code is referd to RFC 2367
@ -183,6 +183,11 @@ static const int minsize[] = {
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_x_nat_t_oa), /* 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 */
@ -205,6 +210,11 @@ static const int maxsize[] = {
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 */
sizeof(struct sadb_x_nat_t_oa), /* 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;
@ -6892,6 +6902,7 @@ static int (*key_typesw[]) __P((struct socket *, struct mbuf *,
key_spdadd, /* SADB_X_SPDSETIDX */
NULL, /* SADB_X_SPDEXPIRE */
key_spddelete2, /* SADB_X_SPDDELETE2 */
NULL, /* SADB_X_NAT_T_NEW_MAPPING */
};
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: key.c,v 1.127 2005/01/11 01:30:17 itojun Exp $ */
/* $NetBSD: key.c,v 1.128 2005/02/12 12:31:08 manu Exp $ */
/* $KAME: key.c,v 1.310 2003/09/08 02:23:44 itojun Exp $ */
/*
@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.127 2005/01/11 01:30:17 itojun Exp $");
__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.128 2005/02/12 12:31:08 manu Exp $");
#include "opt_inet.h"
#include "opt_ipsec.h"
@ -191,6 +191,11 @@ static const int minsize[] = {
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 */
#ifdef SADB_X_EXT_TAG
sizeof(struct sadb_x_tag), /* SADB_X_TAG */
#endif
@ -216,6 +221,11 @@ static const int maxsize[] = {
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 */
#ifdef SADB_X_EXT_TAG
sizeof(struct sadb_x_tag), /* SADB_X_TAG */
#endif
@ -340,6 +350,10 @@ static int key_spdflush __P((struct socket *, struct mbuf *,
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 __P((struct socket *, struct mbuf *,
const struct sadb_msghdr *));
#endif
static struct mbuf *key_setspddump __P((int *));
static u_int key_getspreqmsglen __P((struct secpolicy *));
static int key_spdexpire __P((struct secpolicy *));
@ -2347,6 +2361,71 @@ key_spddump(so, m, mhp)
return 0;
}
#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;
/* sanity check */
if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_nat_map: NULL pointer is passed.");
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, "key_nat_map: invalid message.\n"));
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, "key_nat_map: invalid message.\n"));
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, "key_nat_map: invalid message\n"));
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, "key_nat_map: invalid message\n"));
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];
printf("sadb_nat_map: type %d, sport = %d, dport = %d\n",
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 */
static struct mbuf *
key_setspddump(errorp)
int *errorp;
@ -2961,6 +3040,10 @@ key_setsaval(sav, m, mhp)
sav->lft_c = NULL;
sav->lft_h = NULL;
sav->lft_s = NULL;
#ifdef IPSEC_NAT_T
sav->natt_type = 0;
sav->remote_ike_port = 0;
#endif
/* SA */
if (mhp->ext[SADB_EXT_SA] != NULL) {
@ -5106,6 +5189,63 @@ key_update(so, m, mhp)
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("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, "key_update: "
"invalid message.\n"));
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, "key_update: invalid message\n"));
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, "key_update: invalid message\n"));
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];
sav->natt_type = type->sadb_x_nat_t_type_type;
sav->remote_ike_port = ntohs(dport->sadb_x_nat_t_port_port);
sav->local_ike_port = ntohs(sport->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;
@ -5261,6 +5401,63 @@ key_add(so, m, mhp)
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, "key_add: "
"invalid message.\n"));
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, "key_add: invalid message\n"));
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, "key_update: invalid message\n"));
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];
newsav->natt_type = type->sadb_x_nat_t_type_type;
newsav->local_ike_port = ntohs(sport->sadb_x_nat_t_port_port);
newsav->remote_ike_port = ntohs(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 /* IPSEC_NAT_T */
/*
* don't call key_freesav() here, as we would like to keep the SA
* in the database on success.
@ -7068,6 +7265,11 @@ static int (*key_typesw[]) __P((struct socket *, struct mbuf *,
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,
#endif
};
/*
@ -7404,6 +7606,13 @@ key_align(m, mhp)
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
#ifdef SADB_X_EXT_TAG
case SADB_X_EXT_TAG:
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: keydb.h,v 1.21 2004/12/06 08:05:26 itojun Exp $ */
/* $NetBSD: keydb.h,v 1.22 2005/02/12 12:31:08 manu Exp $ */
/* $KAME: keydb.h,v 1.23 2003/09/07 05:25:20 itojun Exp $ */
/*
@ -107,6 +107,11 @@ struct secasvar {
struct secashead *sah; /* back pointer to the secashead */
u_int32_t id; /* SA id */
/* Nat-Traversal state */
u_int16_t natt_type;
u_int16_t remote_ike_port;
u_int16_t local_ike_port;
u_int16_t esp_frag;
};
/* replay prevention */