summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorAngelos D. Keromytis <angelos@cvs.openbsd.org>1999-12-25 04:48:17 +0000
committerAngelos D. Keromytis <angelos@cvs.openbsd.org>1999-12-25 04:48:17 +0000
commit19d8f442cc18028e750d8eccc0e9b51a134b4193 (patch)
tree4131d7e40c265102a2f6f5d29e45f75bdfbf4dc1 /sys
parent4a6ef205c38d6e48720b261c61dd09049cba0f65 (diff)
Move the IPsec packet-processing loop to a separate routine, so we can
reuse it in ip6_output and the bridge. The policy-lookup code will probably follow suit in a separate routine sometime soon.
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet/ip_ipsp.c247
-rw-r--r--sys/netinet/ip_ipsp.h6
-rw-r--r--sys/netinet/ip_output.c159
3 files changed, 268 insertions, 144 deletions
diff --git a/sys/netinet/ip_ipsp.c b/sys/netinet/ip_ipsp.c
index 9ba1f87556e..8f6b4a6bcc7 100644
--- a/sys/netinet/ip_ipsp.c
+++ b/sys/netinet/ip_ipsp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ipsp.c,v 1.59 1999/12/08 06:06:43 itojun Exp $ */
+/* $OpenBSD: ip_ipsp.c,v 1.60 1999/12/25 04:48:16 angelos Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
@@ -45,27 +45,28 @@
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
-#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/errno.h>
-#include <sys/time.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <net/if.h>
#include <net/route.h>
+#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
-#include <netinet/in_var.h>
-#include <netinet/ip_var.h>
-#include <netinet/ip_icmp.h>
+#endif /* INET */
+
+#ifdef INET6
+#include <netinet6/in6.h>
+#include <netinet6/ip6.h>
+#endif /* INET6 */
-#include <net/raw_cb.h>
#include <net/pfkeyv2.h>
#include <netinet/ip_ipsp.h>
@@ -85,6 +86,10 @@ void tdb_hashstats(void);
#define DPRINTF(x)
#endif
+#ifndef offsetof
+#define offsetof(s, e) ((int)&((s *)0)->e)
+#endif
+
#ifdef __GNUC__
#define INLINE static __inline
#endif
@@ -1495,3 +1500,231 @@ ipsp_address(union sockaddr_union sa)
return "(unknown address family)";
}
}
+
+/*
+ * Loop over a tdb chain, taking into consideration protocol tunneling. The
+ * fourth argument is set if the first encapsulation header is already in
+ * place.
+ */
+int
+ipsp_process_packet(struct mbuf *m, struct mbuf **mp, struct tdb *tdb, int *af,
+ int tunalready)
+{
+ int i, error, off;
+ struct tdb *t;
+
+#ifdef INET
+ struct ip *ip;
+#endif /* INET */
+
+#ifdef INET6
+ struct ip6_hdr *ip6;
+#endif /* INET6 */
+
+ for (t = tdb; t != NULL; t = t->tdb_onext)
+ if ((t->tdb_sproto == IPPROTO_ESP && !esp_enable) ||
+ (t->tdb_sproto == IPPROTO_AH && !ah_enable))
+ {
+ DPRINTF(("ipsp_process_packet(): IPSec outbound packet dropped due to policy\n"));
+ m_freem(m);
+ return EHOSTUNREACH;
+ }
+
+ while (tdb && tdb->tdb_xform)
+ {
+ /* Check if the SPI is invalid */
+ if (tdb->tdb_flags & TDBF_INVALID)
+ {
+ DPRINTF(("ipsp_process_packet(): attempt to use invalid SA %s/%08x/%u\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto));
+ m_freem(m);
+ return ENXIO;
+ }
+
+#ifndef INET6
+ /* Sanity check */
+ if (tdb->tdb_dst.sa.sa_family != AF_INET)
+ {
+ DPRINTF(("ipsp_process_packet(): attempt to use SA %s/%08x/%u for protocol family %d\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto, tdb->tdb_dst.sa.sa_family));
+ m_freem(m);
+ return ENXIO;
+ }
+#endif /* INET6 */
+
+#ifndef INET
+ /* Sanity check */
+ if (tdb->tdb_dst.sa.sa_family != AF_INET6)
+ {
+ DPRINTF(("ipsp_process_packet(): attempt to use SA %s/%08x/%u for protocol family %d\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto, tdb->tdb_dst.sa.sa_family));
+ m_freem(m);
+ return ENXIO;
+ }
+#endif /* INET */
+
+ /* Register first use, setup expiration timer */
+ if (tdb->tdb_first_use == 0)
+ {
+ tdb->tdb_first_use = time.tv_sec;
+ tdb_expiration(tdb, TDBEXP_TIMEOUT);
+ }
+
+ /* Check for tunneling if we don't have the first header in place */
+ if (tunalready == 0)
+ {
+ if ((*af) == tdb->tdb_dst.sa.sa_family)
+ {
+#ifdef INET
+ if ((*af) == AF_INET)
+ i = sizeof(struct ip);
+#endif /* INET */
+
+#ifdef INET6
+ if ((*af) == AF_INET6)
+ i = sizeof(struct ip6_hdr);
+#endif /* INET6 */
+
+ if (m->m_len < i)
+ {
+ if ((m = m_pullup(m, i)) == 0)
+ return ENOBUFS;
+ }
+
+#ifdef INET
+ ip = mtod(m, struct ip *);
+#endif /* INET */
+
+#ifdef INET6
+ ip6 = mtod(m, struct ip6_hdr *);
+#endif /* INET6 */
+ }
+
+ if ((tdb->tdb_dst.sa.sa_family != (*af)) ||
+ ((tdb->tdb_flags & TDBF_TUNNELING) &&
+ (tdb->tdb_xform->xf_type != XF_IP4)) ||
+#ifdef INET
+ ((tdb->tdb_dst.sa.sa_family == AF_INET) &&
+ (tdb->tdb_dst.sin.sin_addr.s_addr != INADDR_ANY) &&
+ (tdb->tdb_dst.sin.sin_addr.s_addr != ip->ip_dst.s_addr)) ||
+#endif /* INET */
+#ifdef INET6
+ ((tdb->tdb_dst.sa.sa_family == AF_INET6) &&
+ (!IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_dst.sin6.sin6_addr)) &&
+ (!IN6_ARE_ADDR_EQUAL(&tdb->tdb_dst.sin6.sin6_addr,
+ &ip6->ip6_dst))) ||
+#endif /* INET6 */
+ 0)
+ {
+#ifdef INET
+ /* Fix IPv4 header checksum and length */
+ if ((*af) == AF_INET)
+ {
+ ip->ip_len = htons(m->m_pkthdr.len);
+ ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
+ i = ip->ip_hl << 2;
+ off = offsetof(struct ip, ip_p);
+ }
+#endif /* INET */
+
+#ifdef INET6
+ /* Fix IPv6 header payload length */
+ if ((*af) == AF_INET6)
+ {
+ ip6->ip6_plen = htons(m->m_pkthdr.len);
+ i = sizeof(struct ip6_hdr);
+ off = offsetof(struct ip6_hdr, ip6_nxt);
+ }
+#endif /* INET6 */
+
+ /* Encapsulate */
+ error = ipe4_output(m, tdb, mp, i, off);
+ if ((*mp) == NULL)
+ error = EFAULT;
+ if (error)
+ {
+ if (*mp)
+ m_freem(*mp);
+ return error;
+ }
+
+ *af = tdb->tdb_dst.sa.sa_family;
+ m = *mp;
+ *mp = NULL;
+ }
+ }
+ else
+ {
+ tunalready = 0;
+
+ if (tdb->tdb_xform->xf_type == XF_IP4)
+ continue;
+ }
+
+#ifdef INET
+ if (tdb->tdb_dst.sa.sa_family == AF_INET)
+ {
+ ip = mtod(m, struct ip *);
+ i = ip->ip_hl << 2;
+ off = offsetof(struct ip, ip_p);
+
+ if (tdb->tdb_xform->xf_type == XF_IP4)
+ {
+ ip->ip_len = htons(m->m_pkthdr.len);
+ ip->ip_sum = in_cksum(m, i);
+ }
+ }
+#endif /* INET */
+
+#ifdef INET6
+ if (tdb->tdb_dst.sa.sa_family == AF_INET6)
+ {
+ ip6 = mtod(m, struct ip6_hdr *);
+ i = sizeof(struct ip6_hdr);
+ off = offsetof(struct ip6_hdr, ip6_nxt);
+ ip6->ip6_plen = htons(m->m_pkthdr.len);
+ }
+#endif /* INET6 */
+
+ error = (*(tdb->tdb_xform->xf_output))(m, tdb, mp, i, off);
+ if ((*mp) == NULL)
+ error = EFAULT;
+ if (error)
+ {
+ if (*mp)
+ m_freem(*mp);
+ return error;
+ }
+
+ m = *mp;
+ *mp = NULL;
+ tdb = tdb->tdb_onext;
+
+#ifdef INET
+ /* Fix the header length, for AH processing */
+ if ((*af) == AF_INET)
+ {
+ ip = mtod(m, struct ip *);
+ ip->ip_len = htons(m->m_pkthdr.len);
+ }
+#endif /* INET */
+
+#ifdef INET6
+ /* Fix the header length, for AH processing */
+ if ((*af) == AF_INET6)
+ {
+ ip6 = mtod(m, struct ip6_hdr *);
+ ip6->ip6_plen = htons(m->m_pkthdr.len);
+ }
+#endif /* INET6 */
+ }
+
+#ifdef INET
+ /* Fix checksum */
+ if ((*af) == AF_INET)
+ {
+ ip = mtod(m, struct ip *);
+ ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
+ }
+#endif /* INET */
+
+ *mp = m;
+ return 0;
+}
diff --git a/sys/netinet/ip_ipsp.h b/sys/netinet/ip_ipsp.h
index 0f2a2d8ee19..cf204a90083 100644
--- a/sys/netinet/ip_ipsp.h
+++ b/sys/netinet/ip_ipsp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ipsp.h,v 1.50 1999/12/08 12:10:25 angelos Exp $ */
+/* $OpenBSD: ip_ipsp.h,v 1.51 1999/12/25 04:48:16 angelos Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
@@ -563,5 +563,9 @@ extern int checkreplaywindow32(u_int32_t, u_int32_t, u_int32_t *, u_int32_t,
u_int32_t *);
extern unsigned char ipseczeroes[];
+
+/* Packet processing */
+int ipsp_process_packet(struct mbuf *, struct mbuf **, struct tdb *,
+ int *, int);
#endif /* _KERNEL */
#endif /* _NETINET_IPSP_H_ */
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 678a6ca1c04..691128fe25a 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_output.c,v 1.59 1999/12/21 08:23:06 angelos Exp $ */
+/* $OpenBSD: ip_output.c,v 1.60 1999/12/25 04:48:16 angelos Exp $ */
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
/*
@@ -140,8 +140,8 @@ ip_output(m0, va_alist)
struct route_enc re0, *re = &re0;
struct sockaddr_encap *ddst, *gw;
u_int8_t sa_require, sa_have = 0;
- struct tdb *tdb, *t;
- int s, ip6flag = 0;
+ int s, protoflag = AF_INET;
+ struct tdb *tdb;
#ifdef INET6
struct ip6_hdr *ip6;
@@ -392,6 +392,7 @@ sendit:
goto no_encap;
}
+ /* Do an SPD lookup */
ddst = (struct sockaddr_encap *) &re->re_dst;
ddst->sen_family = PF_KEY;
ddst->sen_len = SENT_IP4_LEN;
@@ -516,8 +517,7 @@ sendit:
*/
splx(s);
goto no_encap;
- }
- else {
+ } else {
if (tdb->tdb_authalgxform)
sa_require = NOTIFY_SATYPE_AUTH;
if (tdb->tdb_encalgxform)
@@ -552,16 +552,19 @@ sendit:
*/
SPI_CHAIN_ATTRIB(sa_have, tdb_onext, tdb);
- if (sa_require & ~sa_have)
+ if (sa_require & ~sa_have) {
+ splx(s);
goto no_encap;
+ }
if (tdb == NULL) {
splx(s);
if (gw->sen_type == SENT_IPSP)
- DPRINTF(("ip_output(): non-existant TDB for SA %s/%08x/%u\n", inet_ntoa4(gw->sen_ipsp_dst), ntohl(gw->sen_ipsp_spi), gw->sen_ipsp_sproto));
+ DPRINTF(("ip_output(): non-existant TDB for SA %s/%08x/%u\n", inet_ntoa4(gw->sen_ipsp_dst), ntohl(gw->sen_ipsp_spi), gw->sen_ipsp_sproto));
+
#ifdef INET6
- else
- DPRINTF(("ip_output(): non-existant TDB for SA %s/%08x/%u\n", inet6_ntoa4(gw->sen_ipsp6_dst), ntohl(gw->sen_ipsp6_spi), gw->sen_ipsp6_sproto));
+ if (gw->sen_type == SENT_IPSP6)
+ DPRINTF(("ip_output(): non-existant TDB for SA %s/%08x/%u\n", inet6_ntoa4(gw->sen_ipsp6_dst), ntohl(gw->sen_ipsp6_spi), gw->sen_ipsp6_sproto));
#endif /* INET6 */
if (re->re_rt)
@@ -571,138 +574,22 @@ sendit:
goto done;
}
- for (t = tdb; t != NULL; t = t->tdb_onext)
- if ((t->tdb_sproto == IPPROTO_ESP && !esp_enable) ||
- (t->tdb_sproto == IPPROTO_AH && !ah_enable)) {
- DPRINTF(("ip_output(): IPSec outbound packet dropped due to policy\n"));
-
+ error = ipsp_process_packet(m, &mp, tdb, &protoflag, 0);
+ if ((mp == NULL) && (!error))
+ error = ENOBUFS;
+ if (error) {
if (re->re_rt)
RTFREE(re->re_rt);
- error = EHOSTUNREACH;
- m_freem(m);
+ if (mp)
+ m_freem(mp);
goto done;
- }
-
- while (tdb && tdb->tdb_xform) {
- /* Check if the SPI is invalid */
- if (tdb->tdb_flags & TDBF_INVALID) {
- splx(s);
- DPRINTF(("ip_output(): attempt to use invalid SA %s/%08x/%u\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto));
- m_freem(m);
- if (re->re_rt)
- RTFREE(re->re_rt);
- return ENXIO;
- }
-
-#ifndef INET6
- /* Sanity check */
- if (tdb->tdb_dst.sa.sa_family != AF_INET) {
- splx(s);
- DPRINTF(("ip_output(): attempt to use SA %s/%08x/%u for protocol family %d\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto, tdb->tdb_dst.sa.sa_family));
- m_freem(m);
- if (re->re_rt)
- RTFREE(re->re_rt);
- return ENXIO;
- }
-#endif /* INET6 */
-
- /* Register first use, setup expiration timer */
- if (tdb->tdb_first_use == 0) {
- tdb->tdb_first_use = time.tv_sec;
- tdb_expiration(tdb, TDBEXP_TIMEOUT);
- }
-
- /* Check for tunneling */
- if (((tdb->tdb_dst.sa.sa_family == AF_INET) &&
- (tdb->tdb_dst.sin.sin_addr.s_addr !=
- INADDR_ANY) &&
- (tdb->tdb_dst.sin.sin_addr.s_addr !=
- ip->ip_dst.s_addr)) ||
- (tdb->tdb_dst.sa.sa_family == AF_INET6) ||
- ((tdb->tdb_flags & TDBF_TUNNELING) &&
- (tdb->tdb_xform->xf_type != XF_IP4))) {
- /* Fix length and checksum */
- ip->ip_len = htons(m->m_pkthdr.len);
- ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
- error = ipe4_output(m, tdb, &mp,
- ip->ip_hl << 2,
- offsetof(struct ip, ip_p));
- if (mp == NULL)
- error = EFAULT;
- if (error) {
- splx(s);
- if (re->re_rt)
- RTFREE(re->re_rt);
- return error;
- }
- if (tdb->tdb_dst.sa.sa_family == AF_INET)
- ip6flag = 0;
-#ifdef INET6
- if (tdb->tdb_dst.sa.sa_family == AF_INET6)
- ip6flag = 1;
-#endif /* INET6 */
- m = mp;
- mp = NULL;
- }
-
- if ((tdb->tdb_xform->xf_type == XF_IP4) &&
- (tdb->tdb_dst.sa.sa_family == AF_INET)) {
- ip = mtod(m, struct ip *);
- ip->ip_len = htons(m->m_pkthdr.len);
- ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
- }
-
-#ifdef INET6
- if ((tdb->tdb_xform->xf_type == XF_IP4) &&
- (tdb->tdb_dst.sa.sa_family == AF_INET6)) {
- ip6 = mtod(m, struct ip6_hdr *);
- ip6->ip6_plen = htons(m->m_pkthdr.len);
- }
-#endif /* INET6 */
-
-#ifdef INET6
- /*
- * This assumes that there is only just an IPv6
- * header prepended.
- */
- if (ip6flag)
- error = (*(tdb->tdb_xform->xf_output))(m, tdb, &mp, sizeof(struct ip6_hdr), offsetof(struct ip6_hdr, ip6_nxt));
-#endif /* INET6 */
-
- if (!ip6flag)
- error = (*(tdb->tdb_xform->xf_output))(m, tdb, &mp, ip->ip_hl << 2, offsetof(struct ip, ip_p));
- if (!error && mp == NULL)
- error = EFAULT;
- if (error) {
- splx(s);
- if (mp != NULL)
- m_freem(mp);
- if (re->re_rt)
- RTFREE(re->re_rt);
- return error;
- }
-
- m = mp;
- mp = NULL;
+ }
- if (!ip6flag) {
- ip = mtod(m, struct ip *);
- ip->ip_len = htons(m->m_pkthdr.len);
- }
+ m = mp;
+ mp = NULL;
-#ifdef INET6
- if (ip6flag) {
- ip6 = mtod(m, struct ip6_hdr *);
- ip6->ip6_plen = htons(m->m_pkthdr.len);
- }
-#endif /* INET6 */
- tdb = tdb->tdb_onext;
- }
splx(s);
- if (!ip6flag)
- ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
-
/*
* At this point, m is pointing to an mbuf chain with the
* processed packet. Call ourselves recursively, but
@@ -711,7 +598,7 @@ sendit:
if (re->re_rt)
RTFREE(re->re_rt);
- if (!ip6flag) {
+ if (protoflag == AF_INET) {
ip = mtod(m, struct ip *);
NTOHS(ip->ip_len);
NTOHS(ip->ip_off);
@@ -722,7 +609,7 @@ sendit:
}
#ifdef INET6
- if (ip6flag) {
+ if (protoflag == AF_INET6) {
ip6 = mtod(m, struct ip6_hdr *);
NTOHS(ip6->ip6_plen);