summaryrefslogtreecommitdiffstats
path: root/sys/netipsec/ipsec_output.c
diff options
context:
space:
mode:
authorae <ae@FreeBSD.org>2015-04-18 16:38:45 +0000
committerae <ae@FreeBSD.org>2015-04-18 16:38:45 +0000
commit76eadbeca7623488eb5425c74644ec3e01a5ae50 (patch)
tree3525db1af45e3b26c1da356acb61b98db77790d6 /sys/netipsec/ipsec_output.c
parent7ba042082b083de7e31762c9a6b4ab4975bb2a2f (diff)
downloadFreeBSD-src-76eadbeca7623488eb5425c74644ec3e01a5ae50.zip
FreeBSD-src-76eadbeca7623488eb5425c74644ec3e01a5ae50.tar.gz
Remove xform_ipip.c and code related to XF_IP4.
The only thing is used from this code is ipip_output() function, that does IPIP encapsulation. Other parts of XF_IP4 code were removed in r275133. Also it isn't possible to configure the use of XF_IP4, nor from userland via setkey(8), nor from the kernel. Simplify the ipip_output() function and rename it to ipsec_encap(). * move IP_DF handling from ipsec4_process_packet() into ipsec_encap(); * since ipsec_encap() called from ipsec[64]_process_packet(), it is safe to assume that mbuf is contiguous at least to IP header for used IP version. Remove all unneeded m_pullup(), m_copydata and related checks. * use V_ip_defttl and V_ip6_defhlim for outer headers; * use V_ip4_ipsec_ecn and V_ip6_ipsec_ecn for outer headers; * move all diagnostic messages to the ipsec_encap() callers; * simplify handling of ipsec_encap() results: if it returns non zero value, print diagnostic message and free mbuf. * some style(9) fixes. Differential Revision: https://reviews.freebsd.org/D2303 Reviewed by: glebius Sponsored by: Yandex LLC
Diffstat (limited to 'sys/netipsec/ipsec_output.c')
-rw-r--r--sys/netipsec/ipsec_output.c220
1 files changed, 128 insertions, 92 deletions
diff --git a/sys/netipsec/ipsec_output.c b/sys/netipsec/ipsec_output.c
index 8e65005..2c06c86 100644
--- a/sys/netipsec/ipsec_output.c
+++ b/sys/netipsec/ipsec_output.c
@@ -61,6 +61,7 @@
#include <netinet/ip6.h>
#ifdef INET6
#include <netinet6/ip6_var.h>
+#include <netinet6/scope6_var.h>
#endif
#include <netinet/in_pcb.h>
#ifdef INET6
@@ -419,6 +420,101 @@ bad:
#undef IPSEC_OSTAT
}
+static int
+ipsec_encap(struct mbuf **mp, struct secasindex *saidx)
+{
+#ifdef INET6
+ struct ip6_hdr *ip6;
+#endif
+ struct ip *ip;
+ int setdf;
+ uint8_t itos, proto;
+
+ ip = mtod(*mp, struct ip *);
+ switch (ip->ip_v) {
+#ifdef INET
+ case IPVERSION:
+ proto = IPPROTO_IPIP;
+ /*
+ * Collect IP_DF state from the inner header
+ * and honor system-wide control of how to handle it.
+ */
+ switch (V_ip4_ipsec_dfbit) {
+ case 0: /* clear in outer header */
+ case 1: /* set in outer header */
+ setdf = V_ip4_ipsec_dfbit;
+ break;
+ default:/* propagate to outer header */
+ setdf = (ip->ip_off & ntohs(IP_DF)) != 0;
+ }
+ itos = ip->ip_tos;
+ break;
+#endif
+#ifdef INET6
+ case (IPV6_VERSION >> 4):
+ proto = IPPROTO_IPV6;
+ ip6 = mtod(*mp, struct ip6_hdr *);
+ itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
+ setdf = V_ip4_ipsec_dfbit ? 1: 0;
+ /* scoped address handling */
+ in6_clearscope(&ip6->ip6_src);
+ in6_clearscope(&ip6->ip6_dst);
+ break;
+#endif
+ default:
+ return (EAFNOSUPPORT);
+ }
+ switch (saidx->dst.sa.sa_family) {
+#ifdef INET
+ case AF_INET:
+ if (saidx->src.sa.sa_family != AF_INET ||
+ saidx->src.sin.sin_addr.s_addr == INADDR_ANY ||
+ saidx->dst.sin.sin_addr.s_addr == INADDR_ANY)
+ return (EINVAL);
+ M_PREPEND(*mp, sizeof(struct ip), M_NOWAIT);
+ if (*mp == NULL)
+ return (ENOBUFS);
+ ip = mtod(*mp, struct ip *);
+ ip->ip_v = IPVERSION;
+ ip->ip_hl = sizeof(struct ip) >> 2;
+ ip->ip_p = proto;
+ ip->ip_len = htons((*mp)->m_pkthdr.len);
+ ip->ip_ttl = V_ip_defttl;
+ ip->ip_sum = 0;
+ ip->ip_off = setdf ? htons(IP_DF): 0;
+ ip->ip_src = saidx->src.sin.sin_addr;
+ ip->ip_dst = saidx->dst.sin.sin_addr;
+ ip_ecn_ingress(V_ip4_ipsec_ecn, &ip->ip_tos, &itos);
+ ip_fillid(ip);
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ if (saidx->src.sa.sa_family != AF_INET6 ||
+ IN6_IS_ADDR_UNSPECIFIED(&saidx->src.sin6.sin6_addr) ||
+ IN6_IS_ADDR_UNSPECIFIED(&saidx->dst.sin6.sin6_addr))
+ return (EINVAL);
+ M_PREPEND(*mp, sizeof(struct ip6_hdr), M_NOWAIT);
+ if (*mp == NULL)
+ return (ENOBUFS);
+ ip6 = mtod(*mp, struct ip6_hdr *);
+ ip6->ip6_flow = 0;
+ ip6->ip6_vfc = IPV6_VERSION;
+ ip6->ip6_hlim = V_ip6_defhlim;
+ ip6->ip6_nxt = proto;
+ ip6->ip6_dst = saidx->dst.sin6.sin6_addr;
+ ip6->ip6_src = saidx->src.sin6.sin6_addr;
+ ip6->ip6_plen = htons((*mp)->m_pkthdr.len - sizeof(*ip6));
+ ip_ecn_ingress(V_ip6_ipsec_ecn, &proto, &itos);
+ ip6->ip6_flow |= htonl((uint32_t)proto << 20);
+ break;
+#endif /* INET6 */
+ default:
+ return (EAFNOSUPPORT);
+ }
+ return (0);
+}
+
#ifdef INET
/*
* IPsec output logic for IPv4.
@@ -430,7 +526,7 @@ ipsec4_process_packet(struct mbuf *m, struct ipsecrequest *isr)
struct secasindex saidx;
struct secasvar *sav;
struct ip *ip;
- int error, i, off, setdf;
+ int error, i, off;
IPSEC_ASSERT(m != NULL, ("null mbuf"));
IPSEC_ASSERT(isr != NULL, ("null isr"));
@@ -465,53 +561,23 @@ ipsec4_process_packet(struct mbuf *m, struct ipsecrequest *isr)
/* Do the appropriate encapsulation, if necessary */
if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
dst->sa.sa_family != AF_INET || /* PF mismatch */
-#if 0
- (sav->flags & SADB_X_SAFLAGS_TUNNEL) || /* Tunnel requ'd */
- sav->tdb_xform->xf_type == XF_IP4 || /* ditto */
-#endif
(dst->sa.sa_family == AF_INET && /* Proxy */
dst->sin.sin_addr.s_addr != INADDR_ANY &&
dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) {
- struct mbuf *mp;
-
/* Fix IPv4 header checksum and length */
ip->ip_len = htons(m->m_pkthdr.len);
ip->ip_sum = 0;
ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
- /*
- * Collect IP_DF state from the outer header
- * and honor system-wide control of how to handle it.
- */
- switch (V_ip4_ipsec_dfbit) {
- case 0: /* clear in outer header */
- case 1: /* set in outer header */
- setdf = V_ip4_ipsec_dfbit;
- break;
- default: /* propagate to outer header */
- setdf = ntohs(ip->ip_off & IP_DF);
- }
- /* Encapsulate the packet */
- error = ipip_output(m, isr, &mp, 0, 0);
+ error = ipsec_encap(&m, &sav->sah->saidx);
if (error != 0) {
- m = NULL; /* ipip_output() already freed it */
+ DPRINTF(("%s: encapsulation for SA %s->%s "
+ "SPI 0x%08x failed with error %d\n", __func__,
+ ipsec_address(&sav->sah->saidx.src),
+ ipsec_address(&sav->sah->saidx.dst),
+ ntohl(sav->spi), error));
goto bad;
}
- m = mp;
- /*
- * ipip_output clears IP_DF in the new header. If
- * we need to propagate IP_DF from the outer header,
- * then we have to do it here.
- *
- * XXX shouldn't assume what ipip_output does.
- */
- if (dst->sa.sa_family == AF_INET && setdf) {
- ip = mtod(m, struct ip *);
- ip->ip_off = ntohs(ip->ip_off);
- ip->ip_off |= IP_DF;
- ip->ip_off = htons(ip->ip_off);
- }
}
-
#ifdef DEV_ENC
/* pass the mbuf to enc0 for bpf processing */
ipsec_bpf(m, sav, sav->sah->saidx.dst.sa.sa_family, ENC_OUT|ENC_AFTER);
@@ -523,40 +589,33 @@ ipsec4_process_packet(struct mbuf *m, struct ipsecrequest *isr)
/*
* Dispatch to the appropriate IPsec transform logic. The
* packet will be returned for transmission after crypto
- * processing, etc. are completed. For encapsulation we
- * bypass this call because of the explicit call done above
- * (necessary to deal with IP_DF handling for IPv4).
+ * processing, etc. are completed.
*
* NB: m & sav are ``passed to caller'' who's reponsible for
* for reclaiming their resources.
*/
- if (sav->tdb_xform->xf_type != XF_IP4) {
- union sockaddr_union *dst = &sav->sah->saidx.dst;
- switch(dst->sa.sa_family) {
- case AF_INET:
- ip = mtod(m, struct ip *);
- i = ip->ip_hl << 2;
- off = offsetof(struct ip, ip_p);
- break;
+ switch(dst->sa.sa_family) {
+ case AF_INET:
+ ip = mtod(m, struct ip *);
+ i = ip->ip_hl << 2;
+ off = offsetof(struct ip, ip_p);
+ break;
#ifdef INET6
- case AF_INET6:
- i = sizeof(struct ip6_hdr);
- off = offsetof(struct ip6_hdr, ip6_nxt);
- break;
+ case AF_INET6:
+ i = sizeof(struct ip6_hdr);
+ off = offsetof(struct ip6_hdr, ip6_nxt);
+ break;
#endif /* INET6 */
- default:
+ default:
DPRINTF(("%s: unsupported protocol family %u\n",
- __func__, dst->sa.sa_family));
- error = EPFNOSUPPORT;
- IPSECSTAT_INC(ips_out_inval);
- goto bad;
- }
- error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
- } else {
- error = ipsec_process_done(m, isr);
+ __func__, dst->sa.sa_family));
+ error = EPFNOSUPPORT;
+ IPSECSTAT_INC(ips_out_inval);
+ goto bad;
}
+ error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
IPSECREQUEST_UNLOCK(isr);
- return error;
+ return (error);
bad:
if (isr)
IPSECREQUEST_UNLOCK(isr);
@@ -606,7 +665,6 @@ ipsec6_process_packet(
goto bad;
return EJUSTRETURN;
}
-
sav = isr->sav;
dst = &sav->sah->saidx.dst;
@@ -630,42 +688,20 @@ ipsec6_process_packet(
(!IN6_IS_ADDR_UNSPECIFIED(&dst->sin6.sin6_addr)) &&
(!in6_sa_equal_addrwithscope(&dst->sin6,
&ip6->ip6_dst)))) {
- struct mbuf *mp;
-
- /* Fix IPv6 header payload length. */
- if (m->m_len < sizeof(struct ip6_hdr))
- if ((m = m_pullup(m,sizeof(struct ip6_hdr))) == NULL) {
- error = ENOBUFS;
- goto bad;
- }
-
if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
/* No jumbogram support. */
error = ENXIO; /*XXX*/
goto bad;
}
-
- /* Encapsulate the packet */
- error = ipip_output(m, isr, &mp, 0, 0);
- if (mp == NULL && !error) {
- /* Should never happen. */
- DPRINTF(("ipsec6_process_packet: ipip_output "
- "returns no mbuf and no error!"));
- error = EFAULT;
- goto bad;
- }
-
- if (error) {
- if (mp) {
- /* XXX: Should never happen! */
- m_freem(mp);
- }
- m = NULL; /* ipip_output() already freed it */
+ error = ipsec_encap(&m, &sav->sah->saidx);
+ if (error != 0) {
+ DPRINTF(("%s: encapsulation for SA %s->%s "
+ "SPI 0x%08x failed with error %d\n", __func__,
+ ipsec_address(&sav->sah->saidx.src),
+ ipsec_address(&sav->sah->saidx.dst),
+ ntohl(sav->spi), error));
goto bad;
}
-
- m = mp;
- mp = NULL;
}
#ifdef DEV_ENC
OpenPOWER on IntegriCloud