mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-06 17:18:32 +00:00
Add UDP encapsulation of ESP in IPv6
This patch provides UDP encapsulation of ESP packets over IPv6. Ports the IPv4 code to IPv6 and adds support for IPv6 in udpencap.c As required by the RFC and unlike in IPv4 encapsulation, UDP checksums are calculated. Co-authored-by: Aurelien Cazuc <aurelien.cazuc.external@stormshield.eu> Sponsored-by: Stormshield Sponsored-by: Wiktel Sponsored-by: Klara, Inc.
This commit is contained in:
parent
38f5f2a4af
commit
80044c785c
|
@ -4429,7 +4429,7 @@ netipsec/keysock.c optional ipsec inet | ipsec inet6 | \
|
||||||
ipsec_support inet | ipsec_support inet6
|
ipsec_support inet | ipsec_support inet6
|
||||||
netipsec/subr_ipsec.c optional ipsec inet | ipsec inet6 | \
|
netipsec/subr_ipsec.c optional ipsec inet | ipsec inet6 | \
|
||||||
ipsec_support inet | ipsec_support inet6
|
ipsec_support inet | ipsec_support inet6
|
||||||
netipsec/udpencap.c optional ipsec inet
|
netipsec/udpencap.c optional ipsec inet | ipsec inet6
|
||||||
netipsec/xform_ah.c optional ipsec inet | ipsec inet6
|
netipsec/xform_ah.c optional ipsec inet | ipsec inet6
|
||||||
netipsec/xform_esp.c optional ipsec inet | ipsec inet6
|
netipsec/xform_esp.c optional ipsec inet | ipsec inet6
|
||||||
netipsec/xform_ipcomp.c optional ipsec inet | ipsec inet6
|
netipsec/xform_ipcomp.c optional ipsec inet | ipsec inet6
|
||||||
|
|
|
@ -267,7 +267,7 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off,
|
||||||
}
|
}
|
||||||
if (up->u_flags & UF_ESPINUDP) {/* IPSec UDP encaps. */
|
if (up->u_flags & UF_ESPINUDP) {/* IPSec UDP encaps. */
|
||||||
if (IPSEC_ENABLED(ipv4) &&
|
if (IPSEC_ENABLED(ipv4) &&
|
||||||
UDPENCAP_INPUT(n, off, AF_INET) != 0)
|
UDPENCAP_INPUT(ipv4, n, off, AF_INET) != 0)
|
||||||
return (0); /* Consumed. */
|
return (0); /* Consumed. */
|
||||||
}
|
}
|
||||||
#endif /* IPSEC */
|
#endif /* IPSEC */
|
||||||
|
@ -893,19 +893,32 @@ udp_ctloutput(struct socket *so, struct sockopt *sopt)
|
||||||
case SOPT_SET:
|
case SOPT_SET:
|
||||||
switch (sopt->sopt_name) {
|
switch (sopt->sopt_name) {
|
||||||
#if defined(IPSEC) || defined(IPSEC_SUPPORT)
|
#if defined(IPSEC) || defined(IPSEC_SUPPORT)
|
||||||
#ifdef INET
|
#if defined(INET) || defined(INET6)
|
||||||
case UDP_ENCAP:
|
case UDP_ENCAP:
|
||||||
if (!INP_CHECK_SOCKAF(so, AF_INET)) {
|
#ifdef INET
|
||||||
INP_WUNLOCK(inp);
|
if (INP_SOCKAF(so) == AF_INET) {
|
||||||
return (EINVAL);
|
if (!IPSEC_ENABLED(ipv4)) {
|
||||||
|
INP_WUNLOCK(inp);
|
||||||
|
return (ENOPROTOOPT);
|
||||||
|
}
|
||||||
|
error = UDPENCAP_PCBCTL(ipv4, inp, sopt);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (!IPSEC_ENABLED(ipv4)) {
|
|
||||||
INP_WUNLOCK(inp);
|
|
||||||
return (ENOPROTOOPT);
|
|
||||||
}
|
|
||||||
error = UDPENCAP_PCBCTL(inp, sopt);
|
|
||||||
break;
|
|
||||||
#endif /* INET */
|
#endif /* INET */
|
||||||
|
#ifdef INET6
|
||||||
|
if (INP_SOCKAF(so) == AF_INET6) {
|
||||||
|
if (!IPSEC_ENABLED(ipv6)) {
|
||||||
|
INP_WUNLOCK(inp);
|
||||||
|
return (ENOPROTOOPT);
|
||||||
|
}
|
||||||
|
error = UDPENCAP_PCBCTL(ipv6, inp, sopt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif /* INET6 */
|
||||||
|
INP_WUNLOCK(inp);
|
||||||
|
return (EINVAL);
|
||||||
|
#endif /* INET || INET6 */
|
||||||
|
|
||||||
#endif /* IPSEC */
|
#endif /* IPSEC */
|
||||||
case UDPLITE_SEND_CSCOV:
|
case UDPLITE_SEND_CSCOV:
|
||||||
case UDPLITE_RECV_CSCOV:
|
case UDPLITE_RECV_CSCOV:
|
||||||
|
@ -944,19 +957,32 @@ udp_ctloutput(struct socket *so, struct sockopt *sopt)
|
||||||
case SOPT_GET:
|
case SOPT_GET:
|
||||||
switch (sopt->sopt_name) {
|
switch (sopt->sopt_name) {
|
||||||
#if defined(IPSEC) || defined(IPSEC_SUPPORT)
|
#if defined(IPSEC) || defined(IPSEC_SUPPORT)
|
||||||
#ifdef INET
|
#if defined(INET) || defined(INET6)
|
||||||
case UDP_ENCAP:
|
case UDP_ENCAP:
|
||||||
if (!INP_CHECK_SOCKAF(so, AF_INET)) {
|
#ifdef INET
|
||||||
INP_WUNLOCK(inp);
|
if (INP_SOCKAF(so) == AF_INET) {
|
||||||
return (EINVAL);
|
if (!IPSEC_ENABLED(ipv4)) {
|
||||||
|
INP_WUNLOCK(inp);
|
||||||
|
return (ENOPROTOOPT);
|
||||||
|
}
|
||||||
|
error = UDPENCAP_PCBCTL(ipv4, inp, sopt);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (!IPSEC_ENABLED(ipv4)) {
|
|
||||||
INP_WUNLOCK(inp);
|
|
||||||
return (ENOPROTOOPT);
|
|
||||||
}
|
|
||||||
error = UDPENCAP_PCBCTL(inp, sopt);
|
|
||||||
break;
|
|
||||||
#endif /* INET */
|
#endif /* INET */
|
||||||
|
#ifdef INET6
|
||||||
|
if (INP_SOCKAF(so) == AF_INET6) {
|
||||||
|
if (!IPSEC_ENABLED(ipv6)) {
|
||||||
|
INP_WUNLOCK(inp);
|
||||||
|
return (ENOPROTOOPT);
|
||||||
|
}
|
||||||
|
error = UDPENCAP_PCBCTL(ipv6, inp, sopt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif /* INET6 */
|
||||||
|
INP_WUNLOCK(inp);
|
||||||
|
return (EINVAL);
|
||||||
|
#endif /* INET || INET6 */
|
||||||
|
|
||||||
#endif /* IPSEC */
|
#endif /* IPSEC */
|
||||||
case UDPLITE_SEND_CSCOV:
|
case UDPLITE_SEND_CSCOV:
|
||||||
case UDPLITE_RECV_CSCOV:
|
case UDPLITE_RECV_CSCOV:
|
||||||
|
|
|
@ -75,6 +75,7 @@
|
||||||
#include "opt_rss.h"
|
#include "opt_rss.h"
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
#include <sys/domain.h>
|
||||||
#include <sys/jail.h>
|
#include <sys/jail.h>
|
||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
#include <sys/lock.h>
|
#include <sys/lock.h>
|
||||||
|
@ -158,6 +159,9 @@ udp6_append(struct inpcb *inp, struct mbuf *n, int off,
|
||||||
if (filtered)
|
if (filtered)
|
||||||
return (in_pcbrele_rlocked(inp));
|
return (in_pcbrele_rlocked(inp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
off += sizeof(struct udphdr);
|
||||||
|
|
||||||
#if defined(IPSEC) || defined(IPSEC_SUPPORT)
|
#if defined(IPSEC) || defined(IPSEC_SUPPORT)
|
||||||
/* Check AH/ESP integrity. */
|
/* Check AH/ESP integrity. */
|
||||||
if (IPSEC_ENABLED(ipv6)) {
|
if (IPSEC_ENABLED(ipv6)) {
|
||||||
|
@ -165,6 +169,12 @@ udp6_append(struct inpcb *inp, struct mbuf *n, int off,
|
||||||
m_freem(n);
|
m_freem(n);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* IPSec UDP encaps. */
|
||||||
|
if ((up->u_flags & UF_ESPINUDP) != 0 &&
|
||||||
|
UDPENCAP_INPUT(ipv6, n, off, AF_INET6) != 0) {
|
||||||
|
return (0); /* Consumed. */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* IPSEC */
|
#endif /* IPSEC */
|
||||||
#ifdef MAC
|
#ifdef MAC
|
||||||
|
@ -189,7 +199,7 @@ udp6_append(struct inpcb *inp, struct mbuf *n, int off,
|
||||||
opts = tmp_opts;
|
opts = tmp_opts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_adj(n, off + sizeof(struct udphdr));
|
m_adj(n, off);
|
||||||
|
|
||||||
so = inp->inp_socket;
|
so = inp->inp_socket;
|
||||||
SOCKBUF_LOCK(&so->so_rcv);
|
SOCKBUF_LOCK(&so->so_rcv);
|
||||||
|
|
|
@ -628,6 +628,15 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
|
||||||
m_copydata(m, protoff, 1, &nxt8);
|
m_copydata(m, protoff, 1, &nxt8);
|
||||||
prot = nxt8;
|
prot = nxt8;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check that we have NAT-T enabled and apply transport mode
|
||||||
|
* decapsulation NAT procedure (RFC3948).
|
||||||
|
* Do this before invoking into the PFIL.
|
||||||
|
*/
|
||||||
|
if (sav->natt != NULL &&
|
||||||
|
(prot == IPPROTO_UDP || prot == IPPROTO_TCP))
|
||||||
|
udp_ipsec_adjust_cksum(m, sav, prot, skip);
|
||||||
|
|
||||||
/* IPv6-in-IP encapsulation */
|
/* IPv6-in-IP encapsulation */
|
||||||
if (prot == IPPROTO_IPV6 &&
|
if (prot == IPPROTO_IPV6 &&
|
||||||
saidx->mode != IPSEC_MODE_TRANSPORT) {
|
saidx->mode != IPSEC_MODE_TRANSPORT) {
|
||||||
|
|
|
@ -84,6 +84,8 @@ static const struct ipsec_methods ipv6_methods = {
|
||||||
.check_policy = ipsec6_in_reject,
|
.check_policy = ipsec6_in_reject,
|
||||||
.ctlinput = ipsec6_ctlinput,
|
.ctlinput = ipsec6_ctlinput,
|
||||||
.hdrsize = ipsec_hdrsiz_inpcb,
|
.hdrsize = ipsec_hdrsiz_inpcb,
|
||||||
|
.udp_input = udp_ipsec_input,
|
||||||
|
.udp_pcbctl = udp_ipsec_pcbctl,
|
||||||
};
|
};
|
||||||
#ifndef KLD_MODULE
|
#ifndef KLD_MODULE
|
||||||
static const struct ipsec_support ipv6_ipsec = {
|
static const struct ipsec_support ipv6_ipsec = {
|
||||||
|
|
|
@ -935,7 +935,7 @@ ipsec_process_done(struct mbuf *m, struct secpolicy *sp, struct secasvar *sav,
|
||||||
}
|
}
|
||||||
|
|
||||||
key_freesp(&sp), sp = NULL; /* Release reference to SP */
|
key_freesp(&sp), sp = NULL; /* Release reference to SP */
|
||||||
#ifdef INET
|
#if defined(INET) || defined(INET6)
|
||||||
/*
|
/*
|
||||||
* Do UDP encapsulation if SA requires it.
|
* Do UDP encapsulation if SA requires it.
|
||||||
*/
|
*/
|
||||||
|
@ -944,7 +944,7 @@ ipsec_process_done(struct mbuf *m, struct secpolicy *sp, struct secasvar *sav,
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
#endif /* INET */
|
#endif /* INET || INET6 */
|
||||||
/*
|
/*
|
||||||
* We're done with IPsec processing, transmit the packet using the
|
* We're done with IPsec processing, transmit the packet using the
|
||||||
* appropriate network protocol (IP or IPv6).
|
* appropriate network protocol (IP or IPv6).
|
||||||
|
|
|
@ -164,10 +164,10 @@ extern const struct ipsec_support * const ipv6_ipsec_support;
|
||||||
#define IPSEC_CTLINPUT(proto, param) \
|
#define IPSEC_CTLINPUT(proto, param) \
|
||||||
(*(proto ## _ipsec_support)->methods->ctlinput)(param)
|
(*(proto ## _ipsec_support)->methods->ctlinput)(param)
|
||||||
|
|
||||||
#define UDPENCAP_INPUT(m, ...) \
|
#define UDPENCAP_INPUT(proto, m, ...) \
|
||||||
(*ipv4_ipsec_support->methods->udp_input)(m, __VA_ARGS__)
|
(*(proto ## _ipsec_support)->methods->udp_input)(m, __VA_ARGS__)
|
||||||
#define UDPENCAP_PCBCTL(inp, sopt) \
|
#define UDPENCAP_PCBCTL(proto, inp, sopt) \
|
||||||
(*ipv4_ipsec_support->methods->udp_pcbctl)(inp, sopt)
|
(*(proto ## _ipsec_support)->methods->udp_pcbctl)(inp, sopt)
|
||||||
|
|
||||||
#elif defined(IPSEC_SUPPORT)
|
#elif defined(IPSEC_SUPPORT)
|
||||||
struct ipsec_support {
|
struct ipsec_support {
|
||||||
|
@ -196,10 +196,10 @@ int ipsec_kmod_udp_input(struct ipsec_support * const, struct mbuf *, int, int);
|
||||||
int ipsec_kmod_udp_pcbctl(struct ipsec_support * const, struct inpcb *,
|
int ipsec_kmod_udp_pcbctl(struct ipsec_support * const, struct inpcb *,
|
||||||
struct sockopt *);
|
struct sockopt *);
|
||||||
|
|
||||||
#define UDPENCAP_INPUT(m, ...) \
|
#define UDPENCAP_INPUT(proto, m, ...) \
|
||||||
ipsec_kmod_udp_input(ipv4_ipsec_support, m, __VA_ARGS__)
|
ipsec_kmod_udp_input(proto ## _ipsec_support, m, __VA_ARGS__)
|
||||||
#define UDPENCAP_PCBCTL(inp, sopt) \
|
#define UDPENCAP_PCBCTL(proto, inp, sopt) \
|
||||||
ipsec_kmod_udp_pcbctl(ipv4_ipsec_support, inp, sopt)
|
ipsec_kmod_udp_pcbctl(proto ## _ipsec_support, inp, sopt)
|
||||||
|
|
||||||
#define IPSEC_INPUT(proto, ...) \
|
#define IPSEC_INPUT(proto, ...) \
|
||||||
ipsec_kmod_input(proto ## _ipsec_support, __VA_ARGS__)
|
ipsec_kmod_input(proto ## _ipsec_support, __VA_ARGS__)
|
||||||
|
|
|
@ -5752,6 +5752,7 @@ key_setnatt(struct secasvar *sav, const struct sadb_msghdr *mhp)
|
||||||
struct sockaddr *sa;
|
struct sockaddr *sa;
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
uint16_t cksum;
|
uint16_t cksum;
|
||||||
|
int i;
|
||||||
|
|
||||||
IPSEC_ASSERT(sav->natt == NULL, ("natt is already initialized"));
|
IPSEC_ASSERT(sav->natt == NULL, ("natt is already initialized"));
|
||||||
/*
|
/*
|
||||||
|
@ -5838,52 +5839,117 @@ key_setnatt(struct secasvar *sav, const struct sadb_msghdr *mhp)
|
||||||
if (sav->sah->saidx.mode != IPSEC_MODE_TUNNEL) {
|
if (sav->sah->saidx.mode != IPSEC_MODE_TUNNEL) {
|
||||||
cksum = 0;
|
cksum = 0;
|
||||||
if (oai != NULL) {
|
if (oai != NULL) {
|
||||||
/* Currently we support only AF_INET */
|
|
||||||
sa = (struct sockaddr *)(oai + 1);
|
sa = (struct sockaddr *)(oai + 1);
|
||||||
if (sa->sa_family != AF_INET ||
|
switch (sa->sa_family) {
|
||||||
sa->sa_len != sizeof(struct sockaddr_in)) {
|
#ifdef AF_INET
|
||||||
|
case AF_INET:
|
||||||
|
if (sa->sa_len != sizeof(struct sockaddr_in)) {
|
||||||
|
ipseclog((LOG_DEBUG,
|
||||||
|
"%s: wrong NAT-OAi header.\n",
|
||||||
|
__func__));
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
/* Ignore address if it the same */
|
||||||
|
if (((struct sockaddr_in *)sa)->sin_addr.s_addr !=
|
||||||
|
sav->sah->saidx.src.sin.sin_addr.s_addr) {
|
||||||
|
bcopy(sa, &sav->natt->oai.sa, sa->sa_len);
|
||||||
|
sav->natt->flags |= IPSEC_NATT_F_OAI;
|
||||||
|
/* Calculate checksum delta */
|
||||||
|
addr = sav->sah->saidx.src.sin.sin_addr.s_addr;
|
||||||
|
cksum = in_addword(cksum, ~addr >> 16);
|
||||||
|
cksum = in_addword(cksum, ~addr & 0xffff);
|
||||||
|
addr = sav->natt->oai.sin.sin_addr.s_addr;
|
||||||
|
cksum = in_addword(cksum, addr >> 16);
|
||||||
|
cksum = in_addword(cksum, addr & 0xffff);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef AF_INET6
|
||||||
|
case AF_INET6:
|
||||||
|
if (sa->sa_len != sizeof(struct sockaddr_in6)) {
|
||||||
|
ipseclog((LOG_DEBUG,
|
||||||
|
"%s: wrong NAT-OAi header.\n",
|
||||||
|
__func__));
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
/* Ignore address if it the same */
|
||||||
|
if (memcmp(&((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr,
|
||||||
|
&sav->sah->saidx.src.sin6.sin6_addr.s6_addr,
|
||||||
|
sizeof(struct in6_addr)) != 0) {
|
||||||
|
bcopy(sa, &sav->natt->oai.sa, sa->sa_len);
|
||||||
|
sav->natt->flags |= IPSEC_NATT_F_OAI;
|
||||||
|
/* Calculate checksum delta */
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
cksum = in_addword(cksum,
|
||||||
|
~sav->sah->saidx.src.sin6.sin6_addr.s6_addr16[i]);
|
||||||
|
cksum = in_addword(cksum,
|
||||||
|
sav->natt->oai.sin6.sin6_addr.s6_addr16[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
ipseclog((LOG_DEBUG,
|
ipseclog((LOG_DEBUG,
|
||||||
"%s: wrong NAT-OAi header.\n",
|
"%s: wrong NAT-OAi header.\n",
|
||||||
__func__));
|
__func__));
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
}
|
}
|
||||||
/* Ignore address if it the same */
|
|
||||||
if (((struct sockaddr_in *)sa)->sin_addr.s_addr !=
|
|
||||||
sav->sah->saidx.src.sin.sin_addr.s_addr) {
|
|
||||||
bcopy(sa, &sav->natt->oai.sa, sa->sa_len);
|
|
||||||
sav->natt->flags |= IPSEC_NATT_F_OAI;
|
|
||||||
/* Calculate checksum delta */
|
|
||||||
addr = sav->sah->saidx.src.sin.sin_addr.s_addr;
|
|
||||||
cksum = in_addword(cksum, ~addr >> 16);
|
|
||||||
cksum = in_addword(cksum, ~addr & 0xffff);
|
|
||||||
addr = sav->natt->oai.sin.sin_addr.s_addr;
|
|
||||||
cksum = in_addword(cksum, addr >> 16);
|
|
||||||
cksum = in_addword(cksum, addr & 0xffff);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (oar != NULL) {
|
if (oar != NULL) {
|
||||||
/* Currently we support only AF_INET */
|
|
||||||
sa = (struct sockaddr *)(oar + 1);
|
sa = (struct sockaddr *)(oar + 1);
|
||||||
if (sa->sa_family != AF_INET ||
|
switch (sa->sa_family) {
|
||||||
sa->sa_len != sizeof(struct sockaddr_in)) {
|
#ifdef AF_INET
|
||||||
|
case AF_INET:
|
||||||
|
if (sa->sa_len != sizeof(struct sockaddr_in)) {
|
||||||
|
ipseclog((LOG_DEBUG,
|
||||||
|
"%s: wrong NAT-OAr header.\n",
|
||||||
|
__func__));
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
/* Ignore address if it the same */
|
||||||
|
if (((struct sockaddr_in *)sa)->sin_addr.s_addr !=
|
||||||
|
sav->sah->saidx.dst.sin.sin_addr.s_addr) {
|
||||||
|
bcopy(sa, &sav->natt->oar.sa, sa->sa_len);
|
||||||
|
sav->natt->flags |= IPSEC_NATT_F_OAR;
|
||||||
|
/* Calculate checksum delta */
|
||||||
|
addr = sav->sah->saidx.dst.sin.sin_addr.s_addr;
|
||||||
|
cksum = in_addword(cksum, ~addr >> 16);
|
||||||
|
cksum = in_addword(cksum, ~addr & 0xffff);
|
||||||
|
addr = sav->natt->oar.sin.sin_addr.s_addr;
|
||||||
|
cksum = in_addword(cksum, addr >> 16);
|
||||||
|
cksum = in_addword(cksum, addr & 0xffff);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef AF_INET6
|
||||||
|
case AF_INET6:
|
||||||
|
if (sa->sa_len != sizeof(struct sockaddr_in6)) {
|
||||||
|
ipseclog((LOG_DEBUG,
|
||||||
|
"%s: wrong NAT-OAr header.\n",
|
||||||
|
__func__));
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
/* Ignore address if it the same */
|
||||||
|
if (memcmp(&((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr,
|
||||||
|
&sav->sah->saidx.dst.sin6.sin6_addr.s6_addr, 16) != 0) {
|
||||||
|
bcopy(sa, &sav->natt->oar.sa, sa->sa_len);
|
||||||
|
sav->natt->flags |= IPSEC_NATT_F_OAR;
|
||||||
|
/* Calculate checksum delta */
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
cksum = in_addword(cksum,
|
||||||
|
~sav->sah->saidx.dst.sin6.sin6_addr.s6_addr16[i]);
|
||||||
|
cksum = in_addword(cksum,
|
||||||
|
sav->natt->oar.sin6.sin6_addr.s6_addr16[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
ipseclog((LOG_DEBUG,
|
ipseclog((LOG_DEBUG,
|
||||||
"%s: wrong NAT-OAr header.\n",
|
"%s: wrong NAT-OAr header.\n",
|
||||||
__func__));
|
__func__));
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
}
|
}
|
||||||
/* Ignore address if it the same */
|
|
||||||
if (((struct sockaddr_in *)sa)->sin_addr.s_addr !=
|
|
||||||
sav->sah->saidx.dst.sin.sin_addr.s_addr) {
|
|
||||||
bcopy(sa, &sav->natt->oar.sa, sa->sa_len);
|
|
||||||
sav->natt->flags |= IPSEC_NATT_F_OAR;
|
|
||||||
/* Calculate checksum delta */
|
|
||||||
addr = sav->sah->saidx.dst.sin.sin_addr.s_addr;
|
|
||||||
cksum = in_addword(cksum, ~addr >> 16);
|
|
||||||
cksum = in_addword(cksum, ~addr & 0xffff);
|
|
||||||
addr = sav->natt->oar.sin.sin_addr.s_addr;
|
|
||||||
cksum = in_addword(cksum, addr >> 16);
|
|
||||||
cksum = in_addword(cksum, addr & 0xffff);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
sav->natt->cksum = cksum;
|
sav->natt->cksum = cksum;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
#include "opt_inet.h"
|
#include "opt_inet.h"
|
||||||
|
#include "opt_inet6.h"
|
||||||
#include "opt_ipsec.h"
|
#include "opt_ipsec.h"
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
@ -42,11 +43,14 @@
|
||||||
#include <netinet/in_pcb.h>
|
#include <netinet/in_pcb.h>
|
||||||
#include <netinet/in_systm.h>
|
#include <netinet/in_systm.h>
|
||||||
#include <netinet/ip.h>
|
#include <netinet/ip.h>
|
||||||
|
#include <netinet/ip6.h>
|
||||||
#include <netinet/ip_var.h>
|
#include <netinet/ip_var.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <netinet/udp.h>
|
#include <netinet/udp.h>
|
||||||
#include <netinet/udp_var.h>
|
#include <netinet/udp_var.h>
|
||||||
|
|
||||||
|
#include <netinet6/ip6_var.h>
|
||||||
|
|
||||||
#include <net/vnet.h>
|
#include <net/vnet.h>
|
||||||
|
|
||||||
#include <netipsec/ipsec.h>
|
#include <netipsec/ipsec.h>
|
||||||
|
@ -116,7 +120,6 @@ udp_ipsec_input(struct mbuf *m, int off, int af)
|
||||||
union sockaddr_union dst;
|
union sockaddr_union dst;
|
||||||
struct secasvar *sav;
|
struct secasvar *sav;
|
||||||
struct udphdr *udp;
|
struct udphdr *udp;
|
||||||
struct ip *ip;
|
|
||||||
uint32_t spi;
|
uint32_t spi;
|
||||||
int hlen;
|
int hlen;
|
||||||
|
|
||||||
|
@ -141,7 +144,9 @@ udp_ipsec_input(struct mbuf *m, int off, int af)
|
||||||
dst.sa.sa_family = af;
|
dst.sa.sa_family = af;
|
||||||
switch (af) {
|
switch (af) {
|
||||||
#ifdef INET
|
#ifdef INET
|
||||||
case AF_INET:
|
case AF_INET: {
|
||||||
|
struct ip *ip;
|
||||||
|
|
||||||
dst.sin.sin_len = sizeof(struct sockaddr_in);
|
dst.sin.sin_len = sizeof(struct sockaddr_in);
|
||||||
ip = mtod(m, struct ip *);
|
ip = mtod(m, struct ip *);
|
||||||
ip->ip_p = IPPROTO_ESP;
|
ip->ip_p = IPPROTO_ESP;
|
||||||
|
@ -149,11 +154,20 @@ udp_ipsec_input(struct mbuf *m, int off, int af)
|
||||||
hlen = ip->ip_hl << 2;
|
hlen = ip->ip_hl << 2;
|
||||||
dst.sin.sin_addr = ip->ip_dst;
|
dst.sin.sin_addr = ip->ip_dst;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef INET6
|
#ifdef INET6
|
||||||
case AF_INET6:
|
case AF_INET6: {
|
||||||
/* Not yet */
|
struct ip6_hdr *ip6;
|
||||||
/* FALLTHROUGH */
|
|
||||||
|
dst.sin6.sin6_len = sizeof(struct sockaddr_in6);
|
||||||
|
ip6 = mtod(m, struct ip6_hdr *);
|
||||||
|
ip6->ip6_nxt = IPPROTO_ESP;
|
||||||
|
off = offsetof(struct ip6_hdr, ip6_nxt);
|
||||||
|
hlen = sizeof(struct ip6_hdr);
|
||||||
|
dst.sin6.sin6_addr = ip6->ip6_dst;
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
ESPSTAT_INC(esps_nopf);
|
ESPSTAT_INC(esps_nopf);
|
||||||
|
@ -192,12 +206,30 @@ udp_ipsec_input(struct mbuf *m, int off, int af)
|
||||||
* <-skip->
|
* <-skip->
|
||||||
*/
|
*/
|
||||||
m_striphdr(m, hlen, sizeof(*udp));
|
m_striphdr(m, hlen, sizeof(*udp));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We cannot yet update the cksums so clear any h/w cksum flags
|
* We cannot yet update the cksums so clear any h/w cksum flags
|
||||||
* as they are no longer valid.
|
* as they are no longer valid.
|
||||||
*/
|
*/
|
||||||
if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID)
|
switch (af) {
|
||||||
m->m_pkthdr.csum_flags &= ~(CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
|
#ifdef INET
|
||||||
|
case AF_INET:
|
||||||
|
if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID)
|
||||||
|
m->m_pkthdr.csum_flags &= ~(CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
|
||||||
|
break;
|
||||||
|
#endif /* INET */
|
||||||
|
#ifdef INET6
|
||||||
|
case AF_INET6:
|
||||||
|
if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID_IPV6)
|
||||||
|
m->m_pkthdr.csum_flags &= ~(CSUM_DATA_VALID_IPV6 | CSUM_PSEUDO_HDR);
|
||||||
|
break;
|
||||||
|
#endif /* INET6 */
|
||||||
|
default:
|
||||||
|
ESPSTAT_INC(esps_nopf);
|
||||||
|
m_freem(m);
|
||||||
|
return (EPFNOSUPPORT);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can update ip_len and ip_sum here, but ipsec4_input_cb()
|
* We can update ip_len and ip_sum here, but ipsec4_input_cb()
|
||||||
* will do this anyway, so don't touch them here.
|
* will do this anyway, so don't touch them here.
|
||||||
|
@ -212,16 +244,31 @@ udp_ipsec_output(struct mbuf *m, struct secasvar *sav)
|
||||||
{
|
{
|
||||||
struct udphdr *udp;
|
struct udphdr *udp;
|
||||||
struct mbuf *n;
|
struct mbuf *n;
|
||||||
struct ip *ip;
|
|
||||||
int hlen, off;
|
int hlen, off;
|
||||||
|
|
||||||
IPSEC_ASSERT(sav->natt != NULL, ("UDP encapsulation isn't required."));
|
IPSEC_ASSERT(sav->natt != NULL, ("UDP encapsulation isn't required."));
|
||||||
|
|
||||||
if (sav->sah->saidx.dst.sa.sa_family == AF_INET6)
|
switch (sav->sah->saidx.dst.sa.sa_family) {
|
||||||
|
#ifdef INET
|
||||||
|
case AF_INET: {
|
||||||
|
struct ip *ip;
|
||||||
|
ip = mtod(m, struct ip *);
|
||||||
|
hlen = ip->ip_hl << 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef INET6
|
||||||
|
case AF_INET6:
|
||||||
|
KASSERT(ip6->ip6_nxt == IPPROTO_ESP,
|
||||||
|
("unexpected next header type %d", ip->ip6_nxt));
|
||||||
|
hlen = sizeof(struct ip6_hdr);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
ESPSTAT_INC(esps_nopf);
|
||||||
return (EAFNOSUPPORT);
|
return (EAFNOSUPPORT);
|
||||||
|
}
|
||||||
|
|
||||||
ip = mtod(m, struct ip *);
|
|
||||||
hlen = ip->ip_hl << 2;
|
|
||||||
n = m_makespace(m, hlen, sizeof(*udp), &off);
|
n = m_makespace(m, hlen, sizeof(*udp), &off);
|
||||||
if (n == NULL) {
|
if (n == NULL) {
|
||||||
DPRINTF(("%s: m_makespace for udphdr failed\n", __func__));
|
DPRINTF(("%s: m_makespace for udphdr failed\n", __func__));
|
||||||
|
@ -234,9 +281,36 @@ udp_ipsec_output(struct mbuf *m, struct secasvar *sav)
|
||||||
udp->uh_sum = 0;
|
udp->uh_sum = 0;
|
||||||
udp->uh_ulen = htons(m->m_pkthdr.len - hlen);
|
udp->uh_ulen = htons(m->m_pkthdr.len - hlen);
|
||||||
|
|
||||||
ip = mtod(m, struct ip *);
|
switch (sav->sah->saidx.dst.sa.sa_family) {
|
||||||
ip->ip_len = htons(m->m_pkthdr.len);
|
#ifdef INET
|
||||||
ip->ip_p = IPPROTO_UDP;
|
case AF_INET: {
|
||||||
|
struct ip *ip;
|
||||||
|
|
||||||
|
ip = mtod(m, struct ip *);
|
||||||
|
ip->ip_len = htons(m->m_pkthdr.len);
|
||||||
|
ip->ip_p = IPPROTO_UDP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef INET6
|
||||||
|
case AF_INET6: {
|
||||||
|
struct ip6_hdr *ip6;
|
||||||
|
|
||||||
|
ip6 = mtod(m, struct ip6_hdr *);
|
||||||
|
ip6->ip6_plen = htons(m->m_pkthdr.len);
|
||||||
|
ip6->ip6_nxt = IPPROTO_UDP;
|
||||||
|
udp->uh_sum = in6_cksum_pseudo(ip6,
|
||||||
|
m->m_pkthdr.len - hlen, ip6->ip6_nxt, 0);
|
||||||
|
m->m_pkthdr.csum_flags = CSUM_UDP_IPV6;
|
||||||
|
m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
ESPSTAT_INC(esps_nopf);
|
||||||
|
return (EAFNOSUPPORT);
|
||||||
|
}
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,7 +318,6 @@ void
|
||||||
udp_ipsec_adjust_cksum(struct mbuf *m, struct secasvar *sav, int proto,
|
udp_ipsec_adjust_cksum(struct mbuf *m, struct secasvar *sav, int proto,
|
||||||
int skip)
|
int skip)
|
||||||
{
|
{
|
||||||
struct ip *ip;
|
|
||||||
uint16_t cksum, off;
|
uint16_t cksum, off;
|
||||||
|
|
||||||
IPSEC_ASSERT(sav->natt != NULL, ("NAT-T isn't required"));
|
IPSEC_ASSERT(sav->natt != NULL, ("NAT-T isn't required"));
|
||||||
|
@ -270,22 +343,67 @@ udp_ipsec_adjust_cksum(struct mbuf *m, struct secasvar *sav, int proto,
|
||||||
if (proto == IPPROTO_TCP) {
|
if (proto == IPPROTO_TCP) {
|
||||||
/* Ignore for TCP. */
|
/* Ignore for TCP. */
|
||||||
m->m_pkthdr.csum_data = 0xffff;
|
m->m_pkthdr.csum_data = 0xffff;
|
||||||
m->m_pkthdr.csum_flags |= (CSUM_DATA_VALID |
|
switch (sav->sah->saidx.dst.sa.sa_family) {
|
||||||
CSUM_PSEUDO_HDR);
|
#ifdef INET
|
||||||
|
case AF_INET:
|
||||||
|
m->m_pkthdr.csum_flags |= (CSUM_DATA_VALID |
|
||||||
|
CSUM_PSEUDO_HDR);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef INET6
|
||||||
|
case AF_INET6:
|
||||||
|
m->m_pkthdr.csum_flags |= (CSUM_DATA_VALID_IPV6 |
|
||||||
|
CSUM_PSEUDO_HDR);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cksum = 0; /* Reset for UDP. */
|
cksum = 0; /* Reset for UDP. */
|
||||||
}
|
}
|
||||||
m_copyback(m, skip + off, sizeof(cksum), (caddr_t)&cksum);
|
m_copyback(m, skip + off, sizeof(cksum), (caddr_t)&cksum);
|
||||||
} else { /* Fully recompute */
|
} else { /* Fully recompute */
|
||||||
ip = mtod(m, struct ip *);
|
switch (sav->sah->saidx.dst.sa.sa_family) {
|
||||||
cksum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
|
#ifdef INET
|
||||||
htons(m->m_pkthdr.len - skip + proto));
|
case AF_INET: {
|
||||||
m_copyback(m, skip + off, sizeof(cksum), (caddr_t)&cksum);
|
struct ip *ip;
|
||||||
m->m_pkthdr.csum_flags =
|
|
||||||
(proto == IPPROTO_UDP) ? CSUM_UDP: CSUM_TCP;
|
ip = mtod(m, struct ip *);
|
||||||
m->m_pkthdr.csum_data = off;
|
cksum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
|
||||||
in_delayed_cksum(m);
|
htons(m->m_pkthdr.len - skip + proto));
|
||||||
m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
|
m_copyback(m, skip + off, sizeof(cksum),
|
||||||
|
(caddr_t)&cksum);
|
||||||
|
m->m_pkthdr.csum_flags =
|
||||||
|
(proto == IPPROTO_UDP) ? CSUM_UDP : CSUM_TCP;
|
||||||
|
m->m_pkthdr.csum_data = off;
|
||||||
|
in_delayed_cksum(m);
|
||||||
|
m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef INET6
|
||||||
|
case AF_INET6: {
|
||||||
|
struct ip6_hdr *ip6;
|
||||||
|
|
||||||
|
ip6 = mtod(m, struct ip6_hdr *);
|
||||||
|
cksum = in6_cksum_pseudo(ip6, m->m_pkthdr.len - skip,
|
||||||
|
proto, 0);
|
||||||
|
m_copyback(m, skip + off, sizeof(cksum),
|
||||||
|
(caddr_t)&cksum);
|
||||||
|
m->m_pkthdr.csum_flags =
|
||||||
|
(proto == IPPROTO_UDP) ? CSUM_UDP_IPV6 : CSUM_TCP_IPV6;
|
||||||
|
m->m_pkthdr.csum_data = off;
|
||||||
|
in6_delayed_cksum(m,
|
||||||
|
m->m_pkthdr.len - sizeof(struct ip6_hdr),
|
||||||
|
sizeof(struct ip6_hdr));
|
||||||
|
m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue