From 0cd74db89b7c7ca5bface8b05ae8263c0a54217b Mon Sep 17 00:00:00 2001 From: gnn Date: Sun, 1 Jul 2007 11:41:27 +0000 Subject: Commit IPv6 support for FAST_IPSEC to the tree. This commit includes only the kernel files, the rest of the files will follow in a second commit. Reviewed by: bz Approved by: re Supported by: Secure Computing --- sys/netipsec/ipsec.c | 18 +++++---- sys/netipsec/ipsec.h | 11 +----- sys/netipsec/ipsec6.h | 10 +---- sys/netipsec/ipsec_mbuf.c | 10 ++--- sys/netipsec/ipsec_output.c | 31 +++++++++------- sys/netipsec/key.c | 5 --- sys/netipsec/key_debug.c | 2 +- sys/netipsec/keysock.c | 89 +++++++++++++-------------------------------- sys/netipsec/xform_ah.c | 2 +- 9 files changed, 64 insertions(+), 114 deletions(-) (limited to 'sys/netipsec') diff --git a/sys/netipsec/ipsec.c b/sys/netipsec/ipsec.c index 101c284..1f8e6ab 100644 --- a/sys/netipsec/ipsec.c +++ b/sys/netipsec/ipsec.c @@ -76,6 +76,7 @@ #include #endif +#include #include #ifdef INET6 #include @@ -102,7 +103,7 @@ int ipsec_debug = 0; #endif /* NB: name changed so netstat doesn't use it */ -struct newipsecstat newipsecstat; +struct ipsecstat ipsec4stat; int ip4_ah_offsetmask = 0; /* maybe IP_DF? */ int ip4_ipsec_dfbit = 0; /* DF bit on encap. 0: clear 1: set 2: copy */ int ip4_esp_trans_deflev = IPSEC_LEVEL_USE; @@ -149,7 +150,7 @@ SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ESP_RANDPAD, SYSCTL_INT(_net_inet_ipsec, OID_AUTO, crypto_support, CTLFLAG_RW, &crypto_support,0, ""); SYSCTL_STRUCT(_net_inet_ipsec, OID_AUTO, - ipsecstats, CTLFLAG_RD, &newipsecstat, newipsecstat, ""); + ipsecstats, CTLFLAG_RD, &ipsec4stat, ipsecstat, ""); #ifdef REGRESSION /* @@ -168,7 +169,8 @@ SYSCTL_INT(_net_inet_ipsec, OID_AUTO, test_integrity, CTLFLAG_RW, &ipsec_integrity, 0, "Emulate man-in-the-middle attack"); #endif -#ifdef INET6 +#ifdef INET6 +struct ipsecstat ipsec6stat; int ip6_esp_trans_deflev = IPSEC_LEVEL_USE; int ip6_esp_net_deflev = IPSEC_LEVEL_USE; int ip6_ah_trans_deflev = IPSEC_LEVEL_USE; @@ -199,6 +201,8 @@ SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEBUG, debug, CTLFLAG_RW, &ipsec_debug, 0, ""); SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ESP_RANDPAD, esp_randpad, CTLFLAG_RW, &ip6_esp_randpad, 0, ""); +SYSCTL_STRUCT(_net_inet6_ipsec6, IPSECCTL_STATS, + ipsecstats, CTLFLAG_RD, &ipsec6stat, ipsecstat, ""); #endif /* INET6 */ static int ipsec4_setspidx_inpcb __P((struct mbuf *, struct inpcb *pcb)); @@ -451,7 +455,7 @@ ipsec4_checkpolicy(m, dir, flag, error, inp) sp = ipsec_getpolicybysock(m, dir, inp, error); if (sp == NULL) { IPSEC_ASSERT(*error != 0, ("getpolicy failed w/o error")); - newipsecstat.ips_out_inval++; + ipsec4stat.ips_out_inval++; return NULL; } IPSEC_ASSERT(*error == 0, ("sp w/ error set to %u", *error)); @@ -461,7 +465,7 @@ ipsec4_checkpolicy(m, dir, flag, error, inp) printf("%s: invalid policy %u\n", __func__, sp->policy); /* fall thru... */ case IPSEC_POLICY_DISCARD: - newipsecstat.ips_out_polvio++; + ipsec4stat.ips_out_polvio++; *error = -EINVAL; /* packet is discarded by caller */ break; case IPSEC_POLICY_BYPASS: @@ -1462,7 +1466,7 @@ ipsec4_in_reject(m, inp) if (sp != NULL) { result = ipsec_in_reject(sp, m); if (result) - newipsecstat.ips_in_polvio++; + ipsec4stat.ips_in_polvio++; KEY_FREESP(&sp); } else { result = 0; /* XXX should be panic ? @@ -1502,7 +1506,7 @@ ipsec6_in_reject(m, inp) if (sp != NULL) { result = ipsec_in_reject(sp, m); if (result) - newipsecstat.ips_in_polvio++; + ipsec6stat.ips_in_polvio++; KEY_FREESP(&sp); } else { result = 0; diff --git a/sys/netipsec/ipsec.h b/sys/netipsec/ipsec.h index e514ce5..1464014 100644 --- a/sys/netipsec/ipsec.h +++ b/sys/netipsec/ipsec.h @@ -205,7 +205,7 @@ struct secspacq { */ #define IPSEC_REPLAYWSIZE 32 -/* old statistics for ipsec processing */ +/* statistics for ipsec processing */ struct ipsecstat { u_quad_t in_success; /* succeeded inbound process */ u_quad_t in_polvio; @@ -236,10 +236,7 @@ struct ipsecstat { u_quad_t spdcachelookup; u_quad_t spdcachemiss; -}; -/* statistics for ipsec processing */ -struct newipsecstat { u_int32_t ips_in_polvio; /* input: sec policy violation */ u_int32_t ips_out_polvio; /* output: sec policy violation */ u_int32_t ips_out_nosa; /* output: SA unavailable */ @@ -335,7 +332,7 @@ extern int ipsec_replay; extern int ipsec_integrity; #endif -extern struct newipsecstat newipsecstat; +extern struct ipsecstat ipsec4stat; extern struct secpolicy ip4_def_policy; extern int ip4_esp_trans_deflev; extern int ip4_esp_net_deflev; @@ -352,10 +349,6 @@ extern int crypto_support; /* for openbsd compatibility */ #define DPRINTF(x) do { if (ipsec_debug) printf x; } while (0) -/* XXX for KAME code compatibility */ -#define ipsec_pcbconn(_x) -#define ipsec_pcbdisconn(_x) - extern struct ipsecrequest *ipsec_newisr(void); extern void ipsec_delisr(struct ipsecrequest *); diff --git a/sys/netipsec/ipsec6.h b/sys/netipsec/ipsec6.h index 84c3c8a..32b2b83 100644 --- a/sys/netipsec/ipsec6.h +++ b/sys/netipsec/ipsec6.h @@ -41,6 +41,7 @@ #include #ifdef _KERNEL +extern struct ipsecstat ipsec6stat; extern int ip6_esp_trans_deflev; extern int ip6_esp_net_deflev; extern int ip6_ah_trans_deflev; @@ -50,15 +51,6 @@ extern int ip6_esp_randpad; struct inpcb; -/* KAME compatibility shims */ -#define ipsec6_getpolicybyaddr ipsec_getpolicybyaddr -#define ipsec6_getpolicybysock ipsec_getpolicybysock -#define ipsec6stat newipsecstat -#define out_inval ips_out_inval -#define in_polvio ips_in_polvio -#define out_polvio ips_out_polvio -#define key_freesp(_x) KEY_FREESP(&_x) - extern int ipsec6_delete_pcbpolicy __P((struct inpcb *)); extern int ipsec6_set_policy __P((struct inpcb *inp, int optname, caddr_t request, size_t len, int priv)); diff --git a/sys/netipsec/ipsec_mbuf.c b/sys/netipsec/ipsec_mbuf.c index b63a5af..d4ec42a 100644 --- a/sys/netipsec/ipsec_mbuf.c +++ b/sys/netipsec/ipsec_mbuf.c @@ -88,7 +88,7 @@ m_makespace(struct mbuf *m0, int skip, int hlen, int *off) return (NULL); n->m_next = m->m_next; /* splice new mbuf */ m->m_next = n; - newipsecstat.ips_mbinserted++; + ipsec4stat.ips_mbinserted++; if (hlen <= M_TRAILINGSPACE(m) + remain) { /* * New header fits in the old mbuf if we copy @@ -122,7 +122,7 @@ m_makespace(struct mbuf *m0, int skip, int hlen, int *off) /* splice in second mbuf */ n2->m_next = n->m_next; n->m_next = n2; - newipsecstat.ips_mbinserted++; + ipsec4stat.ips_mbinserted++; } else { memcpy(mtod(n, caddr_t) + hlen, mtod(m, caddr_t) + skip, remain); @@ -238,7 +238,7 @@ m_striphdr(struct mbuf *m, int skip, int hlen) /* Remove the header and associated data from the mbuf. */ if (roff == 0) { /* The header was at the beginning of the mbuf */ - newipsecstat.ips_input_front++; + ipsec4stat.ips_input_front++; m_adj(m1, hlen); if ((m1->m_flags & M_PKTHDR) == 0) m->m_pkthdr.len -= hlen; @@ -250,7 +250,7 @@ m_striphdr(struct mbuf *m, int skip, int hlen) * so first let's remove the remainder of the header from * the beginning of the remainder of the mbuf chain, if any. */ - newipsecstat.ips_input_end++; + ipsec4stat.ips_input_end++; if (roff + hlen > m1->m_len) { /* Adjust the next mbuf by the remainder */ m_adj(m1->m_next, roff + hlen - m1->m_len); @@ -275,7 +275,7 @@ m_striphdr(struct mbuf *m, int skip, int hlen) * The header lies in the "middle" of the mbuf; copy * the remainder of the mbuf down over the header. */ - newipsecstat.ips_input_middle++; + ipsec4stat.ips_input_middle++; bcopy(mtod(m1, u_char *) + roff + hlen, mtod(m1, u_char *) + roff, m1->m_len - (roff + hlen)); diff --git a/sys/netipsec/ipsec_output.c b/sys/netipsec/ipsec_output.c index 4f9b8c59..7a1ec83 100644 --- a/sys/netipsec/ipsec_output.c +++ b/sys/netipsec/ipsec_output.c @@ -155,7 +155,7 @@ ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr) * doing further processing. */ if (isr->next) { - newipsecstat.ips_out_bundlesa++; + ipsec4stat.ips_out_bundlesa++; return ipsec4_process_packet(m, isr->next, 0, 0); } key_sa_recordxfer(sav, m); /* record data transfer */ @@ -281,7 +281,7 @@ again: * this packet because it is responsibility for * upper layer to retransmit the packet. */ - newipsecstat.ips_out_nosa++; + ipsec4stat.ips_out_nosa++; goto bad; } sav = isr->sav; @@ -572,6 +572,7 @@ ipsec6_output_trans( *tun = 0; m = state->m; + IPSECREQUEST_LOCK(isr); /* insure SA contents don't change */ isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error); if (isr == NULL) { #ifdef notdef @@ -591,10 +592,15 @@ ipsec6_output_trans( goto bad; } - return (*isr->sav->tdb_xform->xf_output)(m, isr, NULL, - sizeof (struct ip6_hdr), - offsetof(struct ip6_hdr, ip6_nxt)); + error = (*isr->sav->tdb_xform->xf_output)(m, isr, NULL, + sizeof (struct ip6_hdr), + offsetof(struct ip6_hdr, + ip6_nxt)); + IPSECREQUEST_UNLOCK(isr); + return error; bad: + if (isr) + IPSECREQUEST_UNLOCK(isr); if (m) m_freem(m); state->m = NULL; @@ -614,7 +620,7 @@ ipsec6_encapsulate(struct mbuf *m, struct secasvar *sav) m_freem(m); return EINVAL; } - IPSEC_ASSERT(m->m_len != sizeof (struct ip6_hdr), + IPSEC_ASSERT(m->m_len == sizeof (struct ip6_hdr), ("mbuf wrong size; len %u", m->m_len)); @@ -658,8 +664,8 @@ ipsec6_encapsulate(struct mbuf *m, struct secasvar *sav) /* ip6->ip6_plen will be updated in ip6_output() */ } ip6->ip6_nxt = IPPROTO_IPV6; - sav->sah->saidx.src.sin6.sin6_addr = ip6->ip6_src; - sav->sah->saidx.dst.sin6.sin6_addr = ip6->ip6_dst; + ip6->ip6_src = sav->sah->saidx.src.sin6.sin6_addr; + ip6->ip6_dst = sav->sah->saidx.dst.sin6.sin6_addr; ip6->ip6_hlim = IPV6_DEFHLIM; /* XXX Should ip6_src be updated later ? */ @@ -699,7 +705,6 @@ ipsec6_output_tunnel(struct ipsec_output_state *state, struct secpolicy *sp, int } IPSECREQUEST_LOCK(isr); /* insure SA contents don't change */ - isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error); if (isr == NULL) goto bad; @@ -717,14 +722,14 @@ ipsec6_output_tunnel(struct ipsec_output_state *state, struct secpolicy *sp, int ipseclog((LOG_ERR, "%s: family mismatched between " "inner and outer, spi=%u\n", __func__, ntohl(isr->sav->spi))); - newipsecstat.ips_out_inval++; + ipsec6stat.ips_out_inval++; error = EAFNOSUPPORT; goto bad; } m = ipsec6_splithdr(m); if (!m) { - newipsecstat.ips_out_nomem++; + ipsec6stat.ips_out_nomem++; error = ENOMEM; goto bad; } @@ -753,7 +758,7 @@ ipsec6_output_tunnel(struct ipsec_output_state *state, struct secpolicy *sp, int } if (state->ro->ro_rt == 0) { ip6stat.ip6s_noroute++; - newipsecstat.ips_out_noroute++; + ipsec6stat.ips_out_noroute++; error = EHOSTUNREACH; goto bad; } @@ -767,7 +772,7 @@ ipsec6_output_tunnel(struct ipsec_output_state *state, struct secpolicy *sp, int m = ipsec6_splithdr(m); if (!m) { - newipsecstat.ips_out_nomem++; + ipsec6stat.ips_out_nomem++; error = ENOMEM; goto bad; } diff --git a/sys/netipsec/key.c b/sys/netipsec/key.c index cb0284c..5dfc32f 100644 --- a/sys/netipsec/key.c +++ b/sys/netipsec/key.c @@ -2145,8 +2145,6 @@ key_spddelete2(so, m, mhp) /* create new sadb_msg to reply. */ len = PFKEY_ALIGN8(sizeof(struct sadb_msg)); - if (len > MCLBYTES) - return key_senderror(so, m, ENOBUFS); MGETHDR(n, M_DONTWAIT, MT_DATA); if (n && len > MHLEN) { MCLGET(n, M_DONTWAIT); @@ -4518,8 +4516,6 @@ key_getspi(so, m, mhp) /* create new sadb_msg to reply. */ len = PFKEY_ALIGN8(sizeof(struct sadb_msg)) + PFKEY_ALIGN8(sizeof(struct sadb_sa)); - if (len > MCLBYTES) - return key_senderror(so, m, ENOBUFS); MGETHDR(n, M_DONTWAIT, MT_DATA); if (len > MHLEN) { @@ -7299,7 +7295,6 @@ key_setkey(struct seckey *src, u_int16_t exttype) return NULL; len = PFKEY_ALIGN8(sizeof(struct sadb_key) + _KEYLEN(src)); - m = key_alloc_mbuf(len); if (m == NULL) return NULL; diff --git a/sys/netipsec/key_debug.c b/sys/netipsec/key_debug.c index 97294f3..7252ea0 100644 --- a/sys/netipsec/key_debug.c +++ b/sys/netipsec/key_debug.c @@ -73,7 +73,7 @@ static void kdebug_secreplay __P((struct secreplay *)); #endif #ifndef _KERNEL -#define panic(param) { printf(param); exit(-1); } +#define panic(fmt, ...) { printf(fmt, ## __VA_ARGS__); exit(-1); } #endif /* NOTE: host byte order */ diff --git a/sys/netipsec/keysock.c b/sys/netipsec/keysock.c index ee3495e..21539f12 100644 --- a/sys/netipsec/keysock.c +++ b/sys/netipsec/keysock.c @@ -81,7 +81,6 @@ key_output(struct mbuf *m, struct socket *so) { struct sadb_msg *msg; int len, error = 0; - int s; if (m == 0) panic("%s: NULL pointer was passed.\n", __func__); @@ -116,11 +115,8 @@ key_output(struct mbuf *m, struct socket *so) goto end; } - /*XXX giant lock*/ - s = splnet(); error = key_parse(m, so); m = NULL; - splx(s); end: if (m) m_freem(m); @@ -213,15 +209,19 @@ key_sendup(so, msg, len, target) while (tlen > 0) { if (tlen == len) { MGETHDR(n, M_DONTWAIT, MT_DATA); + if (n == NULL) { + pfkeystat.in_nomem++; + return ENOBUFS; + } n->m_len = MHLEN; } else { MGET(n, M_DONTWAIT, MT_DATA); + if (n == NULL) { + pfkeystat.in_nomem++; + return ENOBUFS; + } n->m_len = MLEN; } - if (!n) { - pfkeystat.in_nomem++; - return ENOBUFS; - } if (tlen >= MCLBYTES) { /*XXX better threshold? */ MCLGET(n, M_DONTWAIT); if ((n->m_flags & M_EXT) == 0) { @@ -278,22 +278,18 @@ key_sendup_mbuf(so, m, target) pfkeystat.in_total++; pfkeystat.in_bytes += m->m_pkthdr.len; if (m->m_len < sizeof(struct sadb_msg)) { -#if 1 m = m_pullup(m, sizeof(struct sadb_msg)); if (m == NULL) { pfkeystat.in_nomem++; return ENOBUFS; } -#else - /* don't bother pulling it up just for stats */ -#endif } if (m->m_len >= sizeof(struct sadb_msg)) { struct sadb_msg *msg; msg = mtod(m, struct sadb_msg *); pfkeystat.in_msgtype[msg->sadb_msg_type]++; } - + mtx_lock(&rawcb_mtx); LIST_FOREACH(rp, &rawcb_list, list) { if (rp->rcb_proto.sp_family != PF_KEY) @@ -344,11 +340,13 @@ key_sendup_mbuf(so, m, target) if ((n = m_copy(m, 0, (int)M_COPYALL)) == NULL) { m_freem(m); pfkeystat.in_nomem++; + mtx_unlock(&rawcb_mtx); return ENOBUFS; } if ((error = key_sendup0(rp, n, 0)) != 0) { m_freem(m); + mtx_unlock(&rawcb_mtx); return error; } @@ -362,6 +360,7 @@ key_sendup_mbuf(so, m, target) error = 0; m_freem(m); } + mtx_unlock(&rawcb_mtx); return error; } @@ -372,7 +371,6 @@ key_sendup_mbuf(so, m, target) static void key_abort(struct socket *so) { - raw_usrreqs.pru_abort(so); } @@ -384,29 +382,21 @@ static int key_attach(struct socket *so, int proto, struct thread *td) { struct keycb *kp; - int s, error; + int error; + + KASSERT(so->so_pcb == NULL, ("key_attach: so_pcb != NULL")); - if (sotorawcb(so) != 0) - return EISCONN; /* XXX panic? */ - kp = (struct keycb *)malloc(sizeof *kp, M_PCB, M_WAITOK|M_ZERO); /* XXX */ + /* XXX */ + MALLOC(kp, struct keycb *, sizeof *kp, M_PCB, M_WAITOK | M_ZERO); if (kp == 0) return ENOBUFS; - /* - * The splnet() is necessary to block protocols from sending - * error notifications (like RTM_REDIRECT or RTM_LOSING) while - * this PCB is extant but incompletely initialized. - * Probably we should try to do more of this work beforehand and - * eliminate the spl. - */ - s = splnet(); so->so_pcb = (caddr_t)kp; - error = raw_usrreqs.pru_attach(so, proto, td); + error = raw_attach(so, proto); kp = (struct keycb *)sotorawcb(so); if (error) { free(kp, M_PCB); so->so_pcb = (caddr_t) 0; - splx(s); return error; } @@ -420,7 +410,6 @@ key_attach(struct socket *so, int proto, struct thread *td) soisconnected(so); so->so_options |= SO_USELOOPBACK; - splx(s); return 0; } @@ -431,11 +420,7 @@ key_attach(struct socket *so, int proto, struct thread *td) static int key_bind(struct socket *so, struct sockaddr *nam, struct thread *td) { - int s, error; - s = splnet(); - error = raw_usrreqs.pru_bind(so, nam, td); /* xxx just EINVAL */ - splx(s); - return error; + return EINVAL; } /* @@ -456,11 +441,7 @@ key_close(struct socket *so) static int key_connect(struct socket *so, struct sockaddr *nam, struct thread *td) { - int s, error; - s = splnet(); - error = raw_usrreqs.pru_connect(so, nam, td); /* XXX just EINVAL */ - splx(s); - return error; + return EINVAL; } /* @@ -489,11 +470,7 @@ key_detach(struct socket *so) static int key_disconnect(struct socket *so) { - int s, error; - s = splnet(); - error = raw_usrreqs.pru_disconnect(so); - splx(s); - return error; + return(raw_usrreqs.pru_disconnect(so)); } /* @@ -503,11 +480,7 @@ key_disconnect(struct socket *so) static int key_peeraddr(struct socket *so, struct sockaddr **nam) { - int s, error; - s = splnet(); - error = raw_usrreqs.pru_peeraddr(so, nam); - splx(s); - return error; + return(raw_usrreqs.pru_peeraddr(so, nam)); } /* @@ -518,11 +491,7 @@ static int key_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct mbuf *control, struct thread *td) { - int s, error; - s = splnet(); - error = raw_usrreqs.pru_send(so, flags, m, nam, control, td); - splx(s); - return error; + return(raw_usrreqs.pru_send(so, flags, m, nam, control, td)); } /* @@ -532,11 +501,7 @@ key_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, static int key_shutdown(struct socket *so) { - int s, error; - s = splnet(); - error = raw_usrreqs.pru_shutdown(so); - splx(s); - return error; + return(raw_usrreqs.pru_shutdown(so)); } /* @@ -546,11 +511,7 @@ key_shutdown(struct socket *so) static int key_sockaddr(struct socket *so, struct sockaddr **nam) { - int s, error; - s = splnet(); - error = raw_usrreqs.pru_sockaddr(so, nam); - splx(s); - return error; + return(raw_usrreqs.pru_sockaddr(so, nam)); } struct pr_usrreqs key_usrreqs = { diff --git a/sys/netipsec/xform_ah.c b/sys/netipsec/xform_ah.c index 6114908..da8f666 100644 --- a/sys/netipsec/xform_ah.c +++ b/sys/netipsec/xform_ah.c @@ -110,7 +110,7 @@ static int ah_output_cb(struct cryptop*); struct auth_hash * ah_algorithm_lookup(int alg) { - if (alg >= AH_ALG_MAX) + if (alg > SADB_AALG_MAX) return NULL; switch (alg) { case SADB_X_AALG_NULL: -- cgit v1.1