diff options
author | gnn <gnn@FreeBSD.org> | 2007-07-01 11:41:27 +0000 |
---|---|---|
committer | gnn <gnn@FreeBSD.org> | 2007-07-01 11:41:27 +0000 |
commit | 0cd74db89b7c7ca5bface8b05ae8263c0a54217b (patch) | |
tree | 2bcfb09751e29be8d172ae9e835bab3e5c5699f2 /sys/netinet6/ip6_output.c | |
parent | 384e40af76655727c82190f4d5dc6c857583206e (diff) | |
download | FreeBSD-src-0cd74db89b7c7ca5bface8b05ae8263c0a54217b.zip FreeBSD-src-0cd74db89b7c7ca5bface8b05ae8263c0a54217b.tar.gz |
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
Diffstat (limited to 'sys/netinet6/ip6_output.c')
-rw-r--r-- | sys/netinet6/ip6_output.c | 435 |
1 files changed, 181 insertions, 254 deletions
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index 9175e10..b08862a 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -91,18 +91,11 @@ #include <netinet/tcp_var.h> #include <netinet6/nd6.h> -#ifdef IPSEC -#include <netinet6/ipsec.h> -#ifdef INET6 -#include <netinet6/ipsec6.h> -#endif -#include <netkey/key.h> -#endif /* IPSEC */ - #ifdef FAST_IPSEC #include <netipsec/ipsec.h> #include <netipsec/ipsec6.h> #include <netipsec/key.h> +#include <netinet6/ip6_ipsec.h> #endif /* FAST_IPSEC */ #include <netinet6/ip6protosw.h> @@ -139,6 +132,42 @@ static int copypktopts __P((struct ip6_pktopts *, struct ip6_pktopts *, int)); /* + * Make an extension header from option data. hp is the source, and + * mp is the destination. + */ +#define MAKE_EXTHDR(hp, mp) \ + do { \ + if (hp) { \ + struct ip6_ext *eh = (struct ip6_ext *)(hp); \ + error = ip6_copyexthdr((mp), (caddr_t)(hp), \ + ((eh)->ip6e_len + 1) << 3); \ + if (error) \ + goto freehdrs; \ + } \ + } while (/*CONSTCOND*/ 0) + +/* + * Form a chain of extension headers. + * m is the extension header mbuf + * mp is the previous mbuf in the chain + * p is the next header + * i is the type of option. + */ +#define MAKE_CHAIN(m, mp, p, i)\ + do {\ + if (m) {\ + if (!hdrsplit) \ + panic("assumption failed: hdr not split"); \ + *mtod((m), u_char *) = *(p);\ + *(p) = (i);\ + p = mtod((m), u_char *);\ + (m)->m_next = (mp)->m_next;\ + (mp)->m_next = (m);\ + (mp) = (m);\ + }\ + } while (/*CONSTCOND*/ 0) + +/* * IP6 output. The packet in mbuf chain m contains a skeletal IP6 * header (with pri, len, nxt, hlim, src, dst). * This function may modify ver and hlim only. @@ -162,6 +191,7 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp, inp) struct ip6_hdr *ip6, *mhip6; struct ifnet *ifp, *origifp; struct mbuf *m = m0; + struct mbuf *mprev = NULL; int hlen, tlen, len, off; struct route_in6 ip6route; struct rtentry *rt = NULL; @@ -178,25 +208,22 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp, inp) struct route_in6 *ro_pmtu = NULL; int hdrsplit = 0; int needipsec = 0; -#if defined(IPSEC) || defined(FAST_IPSEC) +#ifdef FAST_IPSEC + struct ipsec_output_state state; + struct ip6_rthdr *rh = NULL; int needipsectun = 0; + int segleft_org = 0; struct secpolicy *sp = NULL; -#endif /*IPSEC || FAST_IPSEC*/ +#endif /* FAST_IPSEC */ ip6 = mtod(m, struct ip6_hdr *); + if (ip6 == NULL) { + printf ("ip6 is NULL"); + goto bad; + } + finaldst = ip6->ip6_dst; -#define MAKE_EXTHDR(hp, mp) \ - do { \ - if (hp) { \ - struct ip6_ext *eh = (struct ip6_ext *)(hp); \ - error = ip6_copyexthdr((mp), (caddr_t)(hp), \ - ((eh)->ip6e_len + 1) << 3); \ - if (error) \ - goto freehdrs; \ - } \ - } while (/*CONSTCOND*/ 0) - bzero(&exthdrs, sizeof(exthdrs)); if (opt) { @@ -206,7 +233,7 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp, inp) if (opt->ip6po_rthdr) { /* * Destination options header(1st part) - * This only makes sence with a routing header. + * This only makes sense with a routing header. * See Section 9.2 of RFC 3542. * Disabling this part just for MIP6 convenience is * a bad idea. We need to think carefully about a @@ -222,90 +249,20 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp, inp) MAKE_EXTHDR(opt->ip6po_dest2, &exthdrs.ip6e_dest2); } -#ifdef IPSEC - /* get a security policy for this packet */ - if (inp == NULL) - sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error); - else - sp = ipsec6_getpolicybypcb(m, IPSEC_DIR_OUTBOUND, inp, &error); - - if (sp == NULL) { - ipsec6stat.out_inval++; - goto freehdrs; - } - - error = 0; - - /* check policy */ - switch (sp->policy) { - case IPSEC_POLICY_DISCARD: - /* - * This packet is just discarded. - */ - ipsec6stat.out_polvio++; - goto freehdrs; - - case IPSEC_POLICY_BYPASS: - case IPSEC_POLICY_NONE: - /* no need to do IPsec. */ - needipsec = 0; - break; - - case IPSEC_POLICY_IPSEC: - if (sp->req == NULL) { - /* acquire a policy */ - error = key_spdacquire(sp); - goto freehdrs; - } - needipsec = 1; - break; - - case IPSEC_POLICY_ENTRUST: - default: - printf("ip6_output: Invalid policy found. %d\n", sp->policy); - } -#endif /* IPSEC */ + /* + * IPSec checking which handles several cases. + * FAST IPSEC: We re-injected the packet. + */ #ifdef FAST_IPSEC - /* get a security policy for this packet */ - if (inp == NULL) - sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error); - else - sp = ipsec_getpolicybysock(m, IPSEC_DIR_OUTBOUND, inp, &error); - - if (sp == NULL) { - newipsecstat.ips_out_inval++; - goto freehdrs; - } - - error = 0; - - /* check policy */ - switch (sp->policy) { - case IPSEC_POLICY_DISCARD: - /* - * This packet is just discarded. - */ - newipsecstat.ips_out_polvio++; + switch(ip6_ipsec_output(&m, inp, &flags, &error, &ifp, &sp)) + { + case 1: /* Bad packet */ goto freehdrs; - - case IPSEC_POLICY_BYPASS: - case IPSEC_POLICY_NONE: - /* no need to do IPsec. */ - needipsec = 0; - break; - - case IPSEC_POLICY_IPSEC: - if (sp->req == NULL) { - /* acquire a policy */ - error = key_spdacquire(sp); - goto freehdrs; - } - needipsec = 1; - break; - - case IPSEC_POLICY_ENTRUST: + case -1: /* Do IPSec */ + needipsec = 1; + case 0: /* No IPSec */ default: - printf("ip6_output: Invalid policy found. %d\n", sp->policy); + break; } #endif /* FAST_IPSEC */ @@ -314,12 +271,17 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp, inp) * Keep the length of the unfragmentable part for fragmentation. */ optlen = 0; - if (exthdrs.ip6e_hbh) optlen += exthdrs.ip6e_hbh->m_len; - if (exthdrs.ip6e_dest1) optlen += exthdrs.ip6e_dest1->m_len; - if (exthdrs.ip6e_rthdr) optlen += exthdrs.ip6e_rthdr->m_len; + if (exthdrs.ip6e_hbh) + optlen += exthdrs.ip6e_hbh->m_len; + if (exthdrs.ip6e_dest1) + optlen += exthdrs.ip6e_dest1->m_len; + if (exthdrs.ip6e_rthdr) + optlen += exthdrs.ip6e_rthdr->m_len; unfragpartlen = optlen + sizeof(struct ip6_hdr); + /* NOTE: we don't add AH/ESP length here. do that later. */ - if (exthdrs.ip6e_dest2) optlen += exthdrs.ip6e_dest2->m_len; + if (exthdrs.ip6e_dest2) + optlen += exthdrs.ip6e_dest2->m_len; /* * If we need IPsec, or there is at least one extension header, @@ -369,106 +331,94 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp, inp) * during the header composing process, "m" points to IPv6 header. * "mprev" points to an extension header prior to esp. */ - { - u_char *nexthdrp = &ip6->ip6_nxt; - struct mbuf *mprev = m; - - /* - * we treat dest2 specially. this makes IPsec processing - * much easier. the goal here is to make mprev point the - * mbuf prior to dest2. - * - * result: IPv6 dest2 payload - * m and mprev will point to IPv6 header. - */ - if (exthdrs.ip6e_dest2) { - if (!hdrsplit) - panic("assumption failed: hdr not split"); - exthdrs.ip6e_dest2->m_next = m->m_next; - m->m_next = exthdrs.ip6e_dest2; - *mtod(exthdrs.ip6e_dest2, u_char *) = ip6->ip6_nxt; - ip6->ip6_nxt = IPPROTO_DSTOPTS; - } - -#define MAKE_CHAIN(m, mp, p, i)\ - do {\ - if (m) {\ - if (!hdrsplit) \ - panic("assumption failed: hdr not split"); \ - *mtod((m), u_char *) = *(p);\ - *(p) = (i);\ - p = mtod((m), u_char *);\ - (m)->m_next = (mp)->m_next;\ - (mp)->m_next = (m);\ - (mp) = (m);\ - }\ - } while (/*CONSTCOND*/ 0) - /* - * result: IPv6 hbh dest1 rthdr dest2 payload - * m will point to IPv6 header. mprev will point to the - * extension header prior to dest2 (rthdr in the above case). - */ - MAKE_CHAIN(exthdrs.ip6e_hbh, mprev, nexthdrp, IPPROTO_HOPOPTS); - MAKE_CHAIN(exthdrs.ip6e_dest1, mprev, nexthdrp, - IPPROTO_DSTOPTS); - MAKE_CHAIN(exthdrs.ip6e_rthdr, mprev, nexthdrp, - IPPROTO_ROUTING); - -#if defined(IPSEC) || defined(FAST_IPSEC) - if (!needipsec) - goto skip_ipsec2; - - /* - * pointers after IPsec headers are not valid any more. - * other pointers need a great care too. - * (IPsec routines should not mangle mbufs prior to AH/ESP) - */ - exthdrs.ip6e_dest2 = NULL; - - { - struct ip6_rthdr *rh = NULL; - int segleft_org = 0; - struct ipsec_output_state state; - - if (exthdrs.ip6e_rthdr) { - rh = mtod(exthdrs.ip6e_rthdr, struct ip6_rthdr *); - segleft_org = rh->ip6r_segleft; - rh->ip6r_segleft = 0; - } - - bzero(&state, sizeof(state)); - state.m = m; - error = ipsec6_output_trans(&state, nexthdrp, mprev, sp, flags, - &needipsectun); - m = state.m; - if (error) { - /* mbuf is already reclaimed in ipsec6_output_trans. */ - m = NULL; - switch (error) { - case EHOSTUNREACH: - case ENETUNREACH: - case EMSGSIZE: - case ENOBUFS: - case ENOMEM: - break; - default: - printf("ip6_output (ipsec): error code %d\n", error); - /* FALLTHROUGH */ - case ENOENT: - /* don't show these error codes to the user */ - error = 0; - break; - } - goto bad; - } - if (exthdrs.ip6e_rthdr) { - /* ah6_output doesn't modify mbuf chain */ - rh->ip6r_segleft = segleft_org; + u_char *nexthdrp = &ip6->ip6_nxt; + mprev = m; + + /* + * we treat dest2 specially. this makes IPsec processing + * much easier. the goal here is to make mprev point the + * mbuf prior to dest2. + * + * result: IPv6 dest2 payload + * m and mprev will point to IPv6 header. + */ + if (exthdrs.ip6e_dest2) { + if (!hdrsplit) + panic("assumption failed: hdr not split"); + exthdrs.ip6e_dest2->m_next = m->m_next; + m->m_next = exthdrs.ip6e_dest2; + *mtod(exthdrs.ip6e_dest2, u_char *) = ip6->ip6_nxt; + ip6->ip6_nxt = IPPROTO_DSTOPTS; + } + + /* + * result: IPv6 hbh dest1 rthdr dest2 payload + * m will point to IPv6 header. mprev will point to the + * extension header prior to dest2 (rthdr in the above case). + */ + MAKE_CHAIN(exthdrs.ip6e_hbh, mprev, nexthdrp, IPPROTO_HOPOPTS); + MAKE_CHAIN(exthdrs.ip6e_dest1, mprev, nexthdrp, + IPPROTO_DSTOPTS); + MAKE_CHAIN(exthdrs.ip6e_rthdr, mprev, nexthdrp, + IPPROTO_ROUTING); + +#ifdef FAST_IPSEC + if (!needipsec) + goto skip_ipsec2; + + /* + * pointers after IPsec headers are not valid any more. + * other pointers need a great care too. + * (IPsec routines should not mangle mbufs prior to AH/ESP) + */ + exthdrs.ip6e_dest2 = NULL; + + if (exthdrs.ip6e_rthdr) { + rh = mtod(exthdrs.ip6e_rthdr, struct ip6_rthdr *); + segleft_org = rh->ip6r_segleft; + rh->ip6r_segleft = 0; + } + + bzero(&state, sizeof(state)); + state.m = m; + error = ipsec6_output_trans(&state, nexthdrp, mprev, sp, flags, + &needipsectun); + m = state.m; + if (error) { + /* mbuf is already reclaimed in ipsec6_output_trans. */ + m = NULL; + switch (error) { + case EHOSTUNREACH: + case ENETUNREACH: + case EMSGSIZE: + case ENOBUFS: + case ENOMEM: + break; + default: + printf("ip6_output (ipsec): error code %d\n", error); + /* FALLTHROUGH */ + case ENOENT: + /* don't show these error codes to the user */ + error = 0; + break; } - } -skip_ipsec2:; -#endif + goto bad; + } else if (!needipsectun) { + /* + * In the FAST IPSec case we have already + * re-injected the packet and it has been freed + * by the ipsec_done() function. So, just clean + * up after ourselves. + */ + m = NULL; + goto done; + } + if (exthdrs.ip6e_rthdr) { + /* ah6_output doesn't modify mbuf chain */ + rh->ip6r_segleft = segleft_org; } +skip_ipsec2:; +#endif /* FAST_IPSEC */ /* * If there is a routing header, replace the destination address field @@ -572,7 +522,13 @@ again: ip6->ip6_hlim = ip6_defmcasthlim; } -#if defined(IPSEC) || defined(FAST_IPSEC) +#ifdef FAST_IPSEC + /* + * Same as similar comment above. + * We only want to do regular IPSEC here and leave this pure + * in the case that we're using FAST_IPSEC which uses + * this code to re-inject packets. + */ if (needipsec && needipsectun) { struct ipsec_output_state state; @@ -617,11 +573,20 @@ again: break; } goto bad; + } else { + /* + * In the FAST IPSec case we have already + * re-injected the packet and it has been freed + * by the ipsec_done() function. So, just clean + * up after ourselves. + */ + m = NULL; + goto done; } exthdrs.ip6e_ip6 = m; } -#endif /* IPSEC */ +#endif /* FAST_IPSEC */ /* adjust pointer */ ip6 = mtod(m, struct ip6_hdr *); @@ -965,10 +930,6 @@ passout: ia6->ia_ifa.if_opackets++; ia6->ia_ifa.if_obytes += m->m_pkthdr.len; } -#ifdef IPSEC - /* clean ipsec history once it goes out of the node */ - ipsec_delaux(m); -#endif error = nd6_output(ifp, origifp, m, dst, ro->ro_rt); goto done; } @@ -991,10 +952,7 @@ passout: struct ip6_frag *ip6f; u_int32_t id = htonl(ip6_randomid()); u_char nextproto; -#if 0 - struct ip6ctlparam ip6cp; - u_int32_t mtu32; -#endif + int qslots = ifp->if_snd.ifq_maxlen - ifp->if_snd.ifq_len; /* @@ -1006,25 +964,6 @@ passout: if (mtu > IPV6_MAXPACKET) mtu = IPV6_MAXPACKET; -#if 0 - /* - * It is believed this code is a leftover from the - * development of the IPV6_RECVPATHMTU sockopt and - * associated work to implement RFC3542. - * It's not entirely clear what the intent of the API - * is at this point, so disable this code for now. - * The IPV6_RECVPATHMTU sockopt and/or IPV6_DONTFRAG - * will send notifications if the application requests. - */ - - /* Notify a proper path MTU to applications. */ - mtu32 = (u_int32_t)mtu; - bzero(&ip6cp, sizeof(ip6cp)); - ip6cp.ip6c_cmdarg = (void *)&mtu32; - pfctlinput2(PRC_MSGSIZE, (struct sockaddr *)&ro_pmtu->ro_dst, - (void *)&ip6cp); -#endif - len = (mtu - hlen - sizeof(struct ip6_frag)) & ~7; if (len < 8) { error = EMSGSIZE; @@ -1130,10 +1069,6 @@ sendorfree: ia->ia_ifa.if_opackets++; ia->ia_ifa.if_obytes += m->m_pkthdr.len; } -#ifdef IPSEC - /* clean ipsec history once it goes out of the node */ - ipsec_delaux(m); -#endif error = nd6_output(ifp, origifp, m, dst, ro->ro_rt); } else m_freem(m); @@ -1149,15 +1084,6 @@ done: RTFREE(ro_pmtu->ro_rt); } -#ifdef IPSEC - if (sp != NULL) - key_freesp(sp); -#endif /* IPSEC */ -#ifdef FAST_IPSEC - if (sp != NULL) - KEY_FREESP(&sp); -#endif /* FAST_IPSEC */ - return (error); freehdrs: @@ -1167,7 +1093,8 @@ freehdrs: m_freem(exthdrs.ip6e_dest2); /* FALLTHROUGH */ bad: - m_freem(m); + if (m) + m_freem(m); goto done; } @@ -1847,7 +1774,7 @@ do { \ } break; -#if defined(IPSEC) || defined(FAST_IPSEC) +#ifdef FAST_IPSEC case IPV6_IPSEC_POLICY: { caddr_t req = NULL; @@ -1867,7 +1794,7 @@ do { \ m_freem(m); } break; -#endif /* KAME IPSEC */ +#endif /* FAST_IPSEC */ default: error = ENOPROTOOPT; @@ -2064,7 +1991,7 @@ do { \ } break; -#if defined(IPSEC) || defined(FAST_IPSEC) +#ifdef FAST_IPSEC case IPV6_IPSEC_POLICY: { caddr_t req = NULL; @@ -2093,7 +2020,7 @@ do { \ m_freem(m); break; } -#endif /* KAME IPSEC */ +#endif /* FAST_IPSEC */ default: error = ENOPROTOOPT; @@ -2449,7 +2376,7 @@ copypktopts(dst, src, canwait) if (src->ip6po_pktinfo) { dst->ip6po_pktinfo = malloc(sizeof(*dst->ip6po_pktinfo), M_IP6OPT, canwait); - if (dst->ip6po_pktinfo == NULL && canwait == M_NOWAIT) + if (dst->ip6po_pktinfo == NULL) goto bad; *dst->ip6po_pktinfo = *src->ip6po_pktinfo; } @@ -2487,7 +2414,7 @@ ip6_copypktopts(src, canwait) struct ip6_pktopts *dst; dst = malloc(sizeof(*dst), M_IP6OPT, canwait); - if (dst == NULL && canwait == M_NOWAIT) + if (dst == NULL) return (NULL); ip6_initpktopts(dst); |