Only in /home/zul/tmp/src/sys/netinet: in_selsrc.c Only in /home/zul/tmp/src/sys/netinet: in_selsrc.h Only in /home/zul/tmp/src/sys/netinet: ip_etherip.c Only in /home/zul/tmp/src/sys/netinet: ip_etherip.h diff -ru --exclude=CVS /home/zul/tmp/src/sys/netinet/ip_output.c /home/zul/ipsec6/sys/netinet/ip_output.c --- /home/zul/tmp/src/sys/netinet/ip_output.c 2007-01-05 20:55:44.000000000 +0100 +++ /home/zul/ipsec6/sys/netinet/ip_output.c 2007-01-05 20:52:48.000000000 +0100 @@ -170,6 +170,26 @@ (((csum_flags) & M_CSUM_TCPv4) != 0 && tcp_do_loopback_cksum) || \ (((csum_flags) & M_CSUM_IPv4) != 0 && ip_do_loopback_cksum))) +#ifdef FAST_IPSEC +static int ip_output_cb(struct mbuf *, struct ip_callback *); +#endif + +#ifdef FAST_IPSEC +/* + * XXX Dummy implementation + * We need to split the stack in two and only process the second part + */ +static int +ip_output_cb(struct mbuf * m, struct ip_callback * ip_cb) +{ + int error; + + error = ip_output(m, NULL, NULL,IP_RAWOUTPUT, NULL, NULL); + free(ip_cb,M_TEMP); + return error; +} +#endif /* FAST_IPSEC */ + /* * IP output. The packet in mbuf chain m contains a skeletal IP * header (with len, off, ttl, proto, tos, src, dst). @@ -206,6 +226,7 @@ struct inpcb *inp; struct m_tag *mtag; struct secpolicy *sp = NULL; + struct ip_callback * ip_cb = NULL; struct tdb_ident *tdbi; int s; #endif @@ -762,9 +783,17 @@ ip->ip_len = htons(ip->ip_len); ip->ip_off = htons(ip->ip_off); #endif + + ip_cb = malloc(sizeof(struct ip_callback), M_TEMP, M_WAITOK); + if (ip_cb == NULL){ + error = ENOMEM; + goto bad; + } + + ip_cb->fn = ip_output_cb; /* NB: callee frees mbuf */ - error = ipsec4_process_packet(m, sp->req, flags, 0); + error = ipsec4_process_packet(m, sp->req, flags, 0, ip_cb); /* * Preserve KAME behaviour: ENOENT can be returned * when an SA acquire is in progress. Don't propagate diff -ru --exclude=CVS /home/zul/tmp/src/sys/netinet/tcp_input.c /home/zul/ipsec6/sys/netinet/tcp_input.c --- /home/zul/tmp/src/sys/netinet/tcp_input.c 2007-01-05 20:55:44.000000000 +0100 +++ /home/zul/ipsec6/sys/netinet/tcp_input.c 2007-01-05 20:45:47.000000000 +0100 @@ -1218,7 +1218,7 @@ #ifdef INET6 else if (in6p && (in6p->in6p_socket->so_options & SO_ACCEPTCONN) == 0 && - ipsec4_in_reject_so(m, in6p->in6p_socket)) { + ipsec6_in_reject_so(m, in6p->in6p_socket)) { ipsecstat.in_polvio++; goto drop; } @@ -1526,7 +1526,7 @@ } #endif -#ifdef IPSEC +#if defined(IPSEC) || defined(FAST_IPSEC) switch (af) { #ifdef INET case AF_INET: @@ -1547,7 +1547,7 @@ break; #endif } -#endif +#endif /* IPSEC */ /* * LISTEN socket received a SYN @@ -2761,9 +2761,15 @@ #ifdef FAST_IPSEC /* Extract the destination from the IP header in the mbuf. */ bzero(&dst, sizeof(union sockaddr_union)); - dst.sa.sa_len = sizeof(struct sockaddr_in); - dst.sa.sa_family = AF_INET; - dst.sin.sin_addr = ip->ip_dst; + if (ip) { + dst.sa.sa_len = sizeof(struct sockaddr_in); + dst.sa.sa_family = AF_INET; + dst.sin.sin_addr = ip->ip_dst; + } else { + dst.sa.sa_len = sizeof(struct sockaddr_in6); + dst.sa.sa_family = AF_INET6; + dst.sin6.sin6_addr = ip6->ip6_dst; + } /* * Look up an SADB entry which matches the address of the peer. diff -ru --exclude=CVS /home/zul/tmp/src/sys/netinet/tcp_output.c /home/zul/ipsec6/sys/netinet/tcp_output.c --- /home/zul/tmp/src/sys/netinet/tcp_output.c 2007-01-05 20:55:44.000000000 +0100 +++ /home/zul/ipsec6/sys/netinet/tcp_output.c 2007-01-05 20:45:47.000000000 +0100 @@ -185,6 +185,9 @@ #ifdef FAST_IPSEC #include #include +#ifdef INET6 +#include +#endif /* INET6 */ #endif /* FAST_IPSEC*/ #ifdef IPSEC #include @@ -374,7 +377,7 @@ } else #endif if (in6p && tp->t_family == AF_INET6) { -#ifdef IPSEC +#if defined(IPSEC) || defined(FAST_IPSEC) if (! IPSEC_PCB_SKIP_IPSEC(in6p->in6p_sp, IPSEC_DIR_OUTBOUND)) optlen += ipsec6_hdrsiz_tcp(tp); #endif @@ -1160,9 +1163,6 @@ TCP_REASS_UNLOCK(tp); #ifdef TCP_SIGNATURE -#if defined(INET6) && defined(FAST_IPSEC) - if (tp->t_family == AF_INET) -#endif if (tp->t_flags & TF_SIGNATURE) { u_char *bp; /* @@ -1378,9 +1378,6 @@ tp->snd_up = tp->snd_una; /* drag it along */ #ifdef TCP_SIGNATURE -#if defined(INET6) && defined(FAST_IPSEC) - if (tp->t_family == AF_INET) /* XXX */ -#endif if (sigoff && (tp->t_flags & TF_SIGNATURE)) { struct secasvar *sav; u_int8_t *sigp; diff -ru --exclude=CVS /home/zul/tmp/src/sys/netinet/tcp_subr.c /home/zul/ipsec6/sys/netinet/tcp_subr.c --- /home/zul/tmp/src/sys/netinet/tcp_subr.c 2007-01-05 20:55:44.000000000 +0100 +++ /home/zul/ipsec6/sys/netinet/tcp_subr.c 2007-01-05 20:45:48.000000000 +0100 @@ -2303,9 +2303,6 @@ optlen += TCPOLEN_TSTAMP_APPA; #ifdef TCP_SIGNATURE -#if defined(INET6) && defined(FAST_IPSEC) - if (tp->t_family == AF_INET) -#endif if (tp->t_flags & TF_SIGNATURE) optlen += TCPOLEN_SIGNATURE + 2; #endif /* TCP_SIGNATURE */ diff -ru --exclude=CVS /home/zul/tmp/src/sys/netinet6/icmp6.c /home/zul/ipsec6/sys/netinet6/icmp6.c --- /home/zul/tmp/src/sys/netinet6/icmp6.c 2007-01-05 20:55:47.000000000 +0100 +++ /home/zul/ipsec6/sys/netinet6/icmp6.c 2006-12-17 19:10:00.000000000 +0100 @@ -102,6 +102,11 @@ #include #endif +#ifdef FAST_IPSEC +#include +#include +#endif + #include "faith.h" #if defined(NFAITH) && 0 < NFAITH #include @@ -2330,7 +2334,7 @@ sdst.sin6_len = sizeof(struct sockaddr_in6); bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr)); pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&sdst); -#ifdef IPSEC +#if defined(IPSEC) || defined(FAST_IPSEC) key_sa_routechange((struct sockaddr *)&sdst); #endif } diff -ru --exclude=CVS /home/zul/tmp/src/sys/netinet6/in6_proto.c /home/zul/ipsec6/sys/netinet6/in6_proto.c --- /home/zul/tmp/src/sys/netinet6/in6_proto.c 2007-01-05 20:55:47.000000000 +0100 +++ /home/zul/ipsec6/sys/netinet6/in6_proto.c 2006-12-17 19:10:00.000000000 +0100 @@ -115,6 +115,13 @@ #include #endif /* IPSEC */ + +#ifdef FAST_IPSEC +#include +#include +#include +#endif /* FAST_IPSEC */ + #include "carp.h" #if NCARP > 0 #include @@ -203,6 +210,23 @@ 0, 0, 0, 0, }, #endif /* IPSEC */ +#ifdef FAST_IPSEC +{ SOCK_RAW, &inet6domain, IPPROTO_AH, PR_ATOMIC|PR_ADDR, + ipsec6_common_input, 0, ah6_ctlinput, 0, + 0, + 0, 0, 0, 0, +}, +{ SOCK_RAW, &inet6domain, IPPROTO_ESP, PR_ATOMIC|PR_ADDR, + ipsec6_common_input, 0, esp6_ctlinput, 0, + 0, + 0, 0, 0, 0, +}, +{ SOCK_RAW, &inet6domain, IPPROTO_IPCOMP, PR_ATOMIC|PR_ADDR, + ipsec6_common_input, 0, 0, 0, + 0, + 0, 0, 0, 0, +}, +#endif /* FAST_IPSEC */ #ifdef INET { SOCK_RAW, &inet6domain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR|PR_LASTHDR, encap6_input, rip6_output, encap6_ctlinput, rip6_ctloutput, Only in /home/zul/tmp/src/sys/netinet6: ip6_etherip.c Only in /home/zul/tmp/src/sys/netinet6: ip6_etherip.h diff -ru --exclude=CVS /home/zul/tmp/src/sys/netinet6/ip6_forward.c /home/zul/ipsec6/sys/netinet6/ip6_forward.c --- /home/zul/tmp/src/sys/netinet6/ip6_forward.c 2007-01-05 20:55:47.000000000 +0100 +++ /home/zul/ipsec6/sys/netinet6/ip6_forward.c 2006-12-17 19:10:00.000000000 +0100 @@ -65,6 +65,13 @@ #include #endif /* IPSEC */ +#ifdef FAST_IPSEC +#include +#include +#include +#include +#endif + #ifdef PFIL_HOOKS #include #endif @@ -77,6 +84,20 @@ extern struct pfil_head inet6_pfil_hook; /* XXX */ #endif +#ifdef FAST_IPSEC +static int ip6_forward_cb(struct mbuf *, struct ip_callback *); + +static int +ip6_forward_cb(struct mbuf * m, struct ip_callback * ip_cb) +{ + int error; + error = ip6_output(m, NULL, NULL, IPV6_FORWARDING/*XXX*/, NULL, NULL, + NULL); + free(ip_cb,M_TEMP); + return error; +} +#endif /* FAST_IPSEC */ + /* * Forward a packet. If some error occurs return the sender * an icmp packet. Note we can't always generate a meaningful @@ -107,6 +128,11 @@ struct secpolicy *sp = NULL; int ipsecrt = 0; #endif +#ifdef FAST_IPSEC + struct secpolicy *sp = NULL; + int needipsec = 0; + int s; +#endif #ifdef IPSEC /* @@ -332,6 +358,24 @@ } skip_ipsec: #endif /* IPSEC */ +#ifdef FAST_IPSEC + /* Check the security policy (SP) for the packet */ + + sp = ipsec6_check_policy(m, NULL, 0, &needipsec, &error); + if (error != 0) { + /* + * Hack: -EINVAL is used to signal that a packet + * should be silently discarded. This is typically + * because we asked key management for an SA and + * it was delayed (e.g. kicked up to IKE). + */ + if (error == -EINVAL) + error = 0; + goto freecopy; + } + +#endif /* FAST_IPSEC */ + dst = &ip6_forward_rt.ro_dst; if (!srcrt) { @@ -447,6 +491,36 @@ return; } +#ifdef FAST_IPSEC + /* + * If we need to encapsulate the packet, do it here + * ipsec6_proces_packet will send the packet using ip6_output + */ + if (needipsec) { + + struct ip_callback * ip_cb; + int skip, protoff; + + ip_cb = malloc(sizeof(struct ip_callback), M_TEMP, M_WAITOK); + if (ip_cb == NULL) { + if (m) + m_freem(m); + goto freecopy; + } + + ip_cb->fn = ip6_forward_cb; + + skip = sizeof(struct ip6_hdr); + protoff = offsetof(struct ip6_hdr, ip6_nxt); + + s = splsoftnet(); + error = ipsec6_process_packet(m,sp->req,skip, protoff, ip_cb); + splx(s); + if (mcopy) + goto freecopy; + } +#endif + if (m->m_pkthdr.len > IN6_LINKMTU(rt->rt_ifp)) { in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig); if (mcopy) { diff -ru --exclude=CVS /home/zul/tmp/src/sys/netinet6/ip6_input.c /home/zul/ipsec6/sys/netinet6/ip6_input.c --- /home/zul/tmp/src/sys/netinet6/ip6_input.c 2007-01-05 20:55:47.000000000 +0100 +++ /home/zul/ipsec6/sys/netinet6/ip6_input.c 2006-12-17 19:10:00.000000000 +0100 @@ -112,6 +112,13 @@ #include #endif +#ifdef FAST_IPSEC +#include +#include +#include +#endif /* FAST_IPSEC */ + + #include #include "faith.h" @@ -241,6 +248,13 @@ int nxt, ours = 0; struct ifnet *deliverifp = NULL; int srcrt = 0; +#ifdef FAST_IPSEC + struct m_tag *mtag; + struct tdb_ident *tdbi; + struct secpolicy *sp; + int s, error; +#endif + #ifdef IPSEC /* @@ -327,6 +341,8 @@ */ #ifdef IPSEC if (!ipsec_getnhist(m)) +#elif defined(FAST_IPSEC) + if (!ipsec_indone(m)) #else if (1) #endif @@ -753,6 +769,45 @@ goto bad; } #endif +#ifdef FAST_IPSEC + /* + * enforce IPsec policy checking if we are seeing last header. + * note that we do not visit this with protocols with pcb layer + * code - like udp/tcp/raw ip. + */ + if ((inet6sw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0) { + /* + * Check if the packet has already had IPsec processing + * done. If so, then just pass it along. This tag gets + * set during AH, ESP, etc. input handling, before the + * packet is returned to the ip input queue for delivery. + */ + mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); + s = splsoftnet(); + if (mtag != NULL) { + tdbi = (struct tdb_ident *)(mtag + 1); + sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND); + } else { + sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, + IP_FORWARDING, &error); + } + if (sp != NULL) { + /* + * Check security policy against packet attributes. + */ + error = ipsec_in_reject(sp, m); + KEY_FREESP(&sp); + } else { + /* XXX error stat??? */ + error = EINVAL; + DPRINTF(("ip6_input: no SP, packet discarded\n"));/*XXX*/ + goto bad; + } + splx(s); + if (error) + goto bad; + } +#endif /* FAST_IPSEC */ nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); } diff -ru --exclude=CVS /home/zul/tmp/src/sys/netinet6/ip6_output.c /home/zul/ipsec6/sys/netinet6/ip6_output.c --- /home/zul/tmp/src/sys/netinet6/ip6_output.c 2007-01-05 20:55:47.000000000 +0100 +++ /home/zul/ipsec6/sys/netinet6/ip6_output.c 2007-01-05 20:53:35.000000000 +0100 @@ -103,6 +103,13 @@ #include #endif /* IPSEC */ +#ifdef FAST_IPSEC +#include +#include +#include +#include +#endif + #include #ifdef PFIL_HOOKS @@ -138,11 +145,91 @@ struct socket *)); #endif +static int ip6_output2 (struct mbuf *, struct ip6_pktopts *, + struct route_in6 *, int, struct ip6_moptions*, struct socket *, + struct ifnet **, int, void *, struct ip6_exthdrs *, struct in6_addr *); + +#ifdef FAST_IPSEC +struct ip6_output_cb_args { + struct ip6_pktopts * opt; + struct route_in6 * ro; + int flags; + struct ip6_moptions * im6o; + struct socket * so; + struct ifnet ** ifpp; + struct in6_addr finaldst; +}; + +static int ip6_output_cb(struct mbuf*, struct ip_callback *); +static void get_exthdrs_from_mbuf(struct mbuf*, struct ip6_exthdrs*); +#endif + #define IN6_NEED_CHECKSUM(ifp, csum_flags) \ (__predict_true(((ifp)->if_flags & IFF_LOOPBACK) == 0 || \ (((csum_flags) & M_CSUM_UDPv6) != 0 && udp_do_loopback_cksum) || \ (((csum_flags) & M_CSUM_TCPv6) != 0 && tcp_do_loopback_cksum))) + +#ifdef FAST_IPSEC +static void +get_exthdrs_from_mbuf(struct mbuf * m, struct ip6_exthdrs * exthdrs) +{ + struct ip6_hdr * ip6; + struct ip6_ext * ip6e; + struct mbuf * mnext; + u_int8_t nxt; + + KASSERT(exthdrs != NULL); + KASSERT(m != NULL); + + exthdrs->ip6e_ip6 = m; + ip6 = mtod(m, struct ip6_hdr *); + nxt = ip6->ip6_nxt; + mnext = m->m_next; + + while (nxt) { + switch(nxt) { + case IPPROTO_HOPOPTS: + exthdrs->ip6e_hbh = mnext; + break; + case IPPROTO_ROUTING: + exthdrs->ip6e_rthdr = mnext; + break; + case IPPROTO_DSTOPTS: + exthdrs->ip6e_dest1 = mnext; + break; + default: + return; + } + + ip6e = mtod(mnext, struct ip6_ext *); + nxt = ip6e->ip6e_nxt; + mnext = mnext->m_next; + } + + return; +} + + +static int +ip6_output_cb(struct mbuf * m, struct ip_callback * ip_cb) +{ + struct ip6_exthdrs exthdrs; + struct ip6_output_cb_args * args; + int error; + + memset(&exthdrs, 0, sizeof(exthdrs)); + get_exthdrs_from_mbuf(m, &exthdrs); + args = (struct ip6_output_cb_args *)&ip_cb->ip_callback_args[0]; + error = ip6_output2(m, args->opt, args->ro, args->flags, args->im6o, + args->so, args->ifpp, 1, NULL, &exthdrs, + &args->finaldst); + + free(ip_cb, M_TEMP); + return error; +} +#endif + /* * IP6 output. The packet in mbuf chain m contains a skeletal IP6 * header (with pri, len, nxt, hlim, src, dst). @@ -165,23 +252,12 @@ struct ifnet **ifpp /* XXX: just for statistics */ ) { - struct ip6_hdr *ip6, *mhip6; - struct ifnet *ifp, *origifp; + struct ip6_hdr *ip6; struct mbuf *m = m0; - int hlen, tlen, len, off; - boolean_t tso; - struct route_in6 ip6route; - struct rtentry *rt = NULL; - struct sockaddr_in6 *dst, src_sa, dst_sa; int error = 0; - struct in6_ifaddr *ia = NULL; - u_long mtu; - int alwaysfrag, dontfrag; - u_int32_t optlen = 0, plen = 0, unfragpartlen = 0; + u_int32_t optlen = 0, plen = 0; struct ip6_exthdrs exthdrs; - struct in6_addr finaldst, src0, dst0; - u_int32_t zone; - struct route_in6 *ro_pmtu = NULL; + struct in6_addr finaldst; int hdrsplit = 0; int needipsec = 0; #ifdef IPSEC @@ -190,6 +266,10 @@ ip6 = mtod(m, struct ip6_hdr *); #endif /* IPSEC */ +#ifdef FAST_IPSEC + struct secpolicy *sp = NULL; + int s; +#endif #ifdef DIAGNOSTIC if ((m->m_flags & M_PKTHDR) == 0) @@ -290,6 +370,24 @@ skippolicycheck:; #endif /* IPSEC */ +#ifdef FAST_IPSEC + /* Check the security policy (SP) for the packet */ + + sp = ipsec6_check_policy(m, so, flags, &needipsec, &error); + if (error != 0) { + /* + * Hack: -EINVAL is used to signal that a packet + * should be silently discarded. This is typically + * because we asked key management for an SA and + * it was delayed (e.g. kicked up to IKE). + */ + if (error == -EINVAL) + error = 0; + goto freehdrs; + } + +#endif /* FAST_IPSEC */ + if (needipsec && (m->m_pkthdr.csum_flags & (M_CSUM_UDPv6|M_CSUM_TCPv6)) != 0) { @@ -305,9 +403,11 @@ 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 we need IPsec, or there is at least one extension header, @@ -527,18 +627,6 @@ ip6stat.ip6s_localout++; - /* - * Route packet. - */ - /* initialize cached route */ - if (ro == 0) { - ro = &ip6route; - bzero((caddr_t)ro, sizeof(*ro)); - } - ro_pmtu = ro; - if (opt && opt->ip6po_rthdr) - ro = &opt->ip6po_route; - dst = (struct sockaddr_in6 *)&ro->ro_dst; /* * if specified, try to fill in the traffic class field. @@ -566,6 +654,158 @@ ip6->ip6_hlim = ip6_defmcasthlim; } +#ifdef FAST_IPSEC + if (needipsec) { + + struct ip_callback * ip_cb; + struct ip6_output_cb_args * ip_cb_args; + int skip, protoff; + + ip_cb = malloc(sizeof(struct ip_callback) + + sizeof(struct ip6_output_cb_args), + M_TEMP, M_WAITOK); + + if (ip_cb == NULL) { + error = ENOMEM; + goto bad; + } + + ip_cb->fn = ip6_output_cb; + ip_cb_args = (struct ip6_output_cb_args*)&ip_cb->ip_callback_args; + + ip_cb_args->opt = opt; + ip_cb_args->ro = ro; + ip_cb_args->flags = flags; + ip_cb_args->im6o = im6o; + ip_cb_args->so = so; + ip_cb_args->ifpp = ifpp; + ip_cb_args->finaldst = finaldst; + + if (!optlen) { /* no extension header */ + skip = sizeof(struct ip6_hdr); + protoff = offsetof(struct ip6_hdr, ip6_nxt); + } else { + skip = sizeof(struct ip6_hdr); + protoff = offsetof(struct ip6_hdr, ip6_nxt); + + if (exthdrs.ip6e_hbh) { + protoff = skip + offsetof(struct ip6_ext, ip6e_nxt); + skip += exthdrs.ip6e_hbh->m_len; + } + + if (exthdrs.ip6e_dest1) { + protoff = skip + offsetof(struct ip6_ext, ip6e_nxt); + skip += exthdrs.ip6e_dest1->m_len; + } + + if (exthdrs.ip6e_rthdr) { + protoff = skip + offsetof(struct ip6_ext, ip6e_nxt); + skip += exthdrs.ip6e_rthdr->m_len; + } + } + + s = splsoftnet(); + error = ipsec6_process_packet(m, sp->req, skip, protoff, ip_cb); + + /* + * Preserve KAME behaviour: ENOENT can be returned + * when an SA acquire is in progress. Don't propagate + * this to user-level; it confuses applications. + * XXX this will go away when the SADB is redone. + */ + if (error == ENOENT) + error = 0; + splx(s); + goto done; + } +#endif /* FAST_IPSEC */ +#ifdef IPSEC + if (needipsectun){ + error = ip6_output2(m, opt, ro, flags, im6o, so, ifpp, + needipsec, sp, &exthdrs, &finaldst); + goto done; + } + +#endif /* IPSEC */ + error = ip6_output2(m, opt, ro, flags, im6o, so, ifpp, needipsec, NULL, + &exthdrs, &finaldst); + +done: + +#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: + m_freem(exthdrs.ip6e_hbh); /* m_freem will check if mbuf is 0 */ + m_freem(exthdrs.ip6e_dest1); + m_freem(exthdrs.ip6e_rthdr); + m_freem(exthdrs.ip6e_dest2); + /* FALLTHROUGH */ +bad: + m_freem(m); + goto done; +} + +int +ip6_output2(m0, opt, ro, flags, im6o, so, ifpp, needipsec, spp, + exthdrs,finaldst) + struct mbuf *m0; + struct ip6_pktopts *opt; + struct route_in6 *ro; + int flags; + struct ip6_moptions *im6o; + struct socket *so; + struct ifnet **ifpp; /* XXX: just for statistics */ + int needipsec; + void * spp; + struct ip6_exthdrs * exthdrs; + struct in6_addr * finaldst; +{ + struct ip6_hdr *ip6, *mhip6; + struct ifnet *ifp, *origifp; + struct mbuf *m = m0; + int hlen, tlen, len, off; + boolean_t tso; + struct route_in6 ip6route; + struct rtentry *rt = NULL; + struct sockaddr_in6 *dst, src_sa, dst_sa; + int error = 0; + struct in6_ifaddr *ia = NULL; + u_long mtu; + int alwaysfrag, dontfrag; + u_int32_t unfragpartlen = 0; + struct in6_addr src0, dst0; + u_int32_t zone; + struct route_in6 *ro_pmtu = NULL; +#ifdef IPSEC + int needipsectun = needipsec && (spp != NULL); + struct secpolicy * sp = spp; +#endif + + KASSERT(exthdrs != NULL); + + /* + * Route packet. + */ + /* initialize cached route */ + if (ro == NULL) { + ro = &ip6route; + bzero((caddr_t)ro, sizeof(*ro)); + } + ro_pmtu = ro; + if (opt && opt->ip6po_rthdr) + ro = &opt->ip6po_route; + dst = (struct sockaddr_in6 *)&ro->ro_dst; + #ifdef IPSEC if (needipsec && needipsectun) { struct ipsec_output_state state; @@ -578,8 +818,8 @@ * * IPv6 [ESP|AH] IPv6 [extension headers] payload */ - bzero(&exthdrs, sizeof(exthdrs)); - exthdrs.ip6e_ip6 = m; + bzero(exthdrs, sizeof(*exthdrs)); + exthdrs->ip6e_ip6 = m; bzero(&state, sizeof(state)); state.m = m; @@ -613,10 +853,9 @@ goto bad; } - exthdrs.ip6e_ip6 = m; + exthdrs->ip6e_ip6 = m; } #endif /* IPSEC */ - /* adjust pointer */ ip6 = mtod(m, struct ip6_hdr *); @@ -786,7 +1025,7 @@ *ifpp = ifp; /* Determine path MTU. */ - if ((error = ip6_getpmtu(ro_pmtu, ro, ifp, &finaldst, &mtu, + if ((error = ip6_getpmtu(ro_pmtu, ro, ifp, finaldst, &mtu, &alwaysfrag)) != 0) goto bad; #ifdef IPSEC @@ -830,8 +1069,8 @@ * it must be examined and processed even by the source node. * (RFC 2460, section 4.) */ - if (exthdrs.ip6e_hbh) { - struct ip6_hbh *hbh = mtod(exthdrs.ip6e_hbh, struct ip6_hbh *); + if (exthdrs->ip6e_hbh) { + struct ip6_hbh *hbh = mtod(exthdrs->ip6e_hbh, struct ip6_hbh *); u_int32_t dummy1; /* XXX unused */ u_int32_t dummy2; /* XXX unused */ @@ -987,6 +1226,14 @@ * fragment if possible. * Must be able to put at least 8 bytes per fragment. */ + + unfragpartlen = sizeof(struct ip6_hdr); + if (exthdrs->ip6e_hbh) unfragpartlen += exthdrs->ip6e_hbh->m_len; + if (exthdrs->ip6e_dest1) unfragpartlen += + exthdrs->ip6e_dest1->m_len; + if (exthdrs->ip6e_rthdr) unfragpartlen += + exthdrs->ip6e_rthdr->m_len; + hlen = unfragpartlen; if (mtu > IPV6_MAXPACKET) mtu = IPV6_MAXPACKET; @@ -1023,15 +1270,15 @@ * Change the next header field of the last header in the * unfragmentable part. */ - if (exthdrs.ip6e_rthdr) { - nextproto = *mtod(exthdrs.ip6e_rthdr, u_char *); - *mtod(exthdrs.ip6e_rthdr, u_char *) = IPPROTO_FRAGMENT; - } else if (exthdrs.ip6e_dest1) { - nextproto = *mtod(exthdrs.ip6e_dest1, u_char *); - *mtod(exthdrs.ip6e_dest1, u_char *) = IPPROTO_FRAGMENT; - } else if (exthdrs.ip6e_hbh) { - nextproto = *mtod(exthdrs.ip6e_hbh, u_char *); - *mtod(exthdrs.ip6e_hbh, u_char *) = IPPROTO_FRAGMENT; + if (exthdrs->ip6e_rthdr) { + nextproto = *mtod(exthdrs->ip6e_rthdr, u_char *); + *mtod(exthdrs->ip6e_rthdr, u_char *) = IPPROTO_FRAGMENT; + } else if (exthdrs->ip6e_dest1) { + nextproto = *mtod(exthdrs->ip6e_dest1, u_char *); + *mtod(exthdrs->ip6e_dest1, u_char *) = IPPROTO_FRAGMENT; + } else if (exthdrs->ip6e_hbh) { + nextproto = *mtod(exthdrs->ip6e_hbh, u_char *); + *mtod(exthdrs->ip6e_hbh, u_char *) = IPPROTO_FRAGMENT; } else { nextproto = ip6->ip6_nxt; ip6->ip6_nxt = IPPROTO_FRAGMENT; @@ -1137,28 +1384,17 @@ ip6stat.ip6s_fragmented++; done: - /* XXX Second if is invariant? */ - if (ro == &ip6route) - rtcache_free((struct route *)ro); - else if (ro_pmtu == &ip6route) - rtcache_free((struct route *)ro_pmtu); - -#ifdef IPSEC - if (sp != NULL) - key_freesp(sp); -#endif /* IPSEC */ - - return (error); + /* XXX Second if is invariant? */ + if (ro == &ip6route) + rtcache_free((struct route *)ro); + else if (ro_pmtu == &ip6route) + rtcache_free((struct route *)ro_pmtu); + + return (error); -freehdrs: - m_freem(exthdrs.ip6e_hbh); /* m_freem will check if mbuf is 0 */ - m_freem(exthdrs.ip6e_dest1); - m_freem(exthdrs.ip6e_rthdr); - m_freem(exthdrs.ip6e_dest2); - /* FALLTHROUGH */ bad: - m_freem(m); - goto done; + m_freem(m); + goto done; } static int @@ -1822,7 +2058,7 @@ } break; -#ifdef IPSEC +#if defined(IPSEC) || defined(FAST_IPSEC) case IPV6_IPSEC_POLICY: { caddr_t req = NULL; @@ -2028,7 +2264,7 @@ in6p->in6p_moptions, mp); break; -#ifdef IPSEC +#if defined(IPSEC) || defined(FAST_IPSEC) case IPV6_IPSEC_POLICY: { caddr_t req = NULL; diff -ru --exclude=CVS /home/zul/tmp/src/sys/netinet6/raw_ip6.c /home/zul/ipsec6/sys/netinet6/raw_ip6.c --- /home/zul/tmp/src/sys/netinet6/raw_ip6.c 2007-01-05 20:55:47.000000000 +0100 +++ /home/zul/ipsec6/sys/netinet6/raw_ip6.c 2007-01-05 20:53:35.000000000 +0100 @@ -98,6 +98,12 @@ #include #endif /* IPSEC */ +#ifdef FAST_IPSEC +#include +#include /* XXX ipsecstat namespace */ +#include +#endif + #include #include "faith.h" @@ -204,6 +210,12 @@ /* do not inject data into pcb */ } else #endif /* IPSEC */ +#ifdef FAST_IPSEC + /* + * Check AH/ESP integrity + */ + if (!ipsec6_in_reject(m,last)) +#endif /* FAST_IPSEC */ if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { if (last->in6p_flags & IN6P_CONTROLOPTS) ip6_savecontrol(last, &opts, ip6, n); @@ -234,6 +246,20 @@ /* do not inject data into pcb */ } else #endif /* IPSEC */ +#ifdef FAST_IPSEC + if (last && ipsec6_in_reject(m, last)) { + m_freem(m); + /* + * XXX ipsec6_in_reject update stat if there is an error + * so we just need to update stats by hand in the case of last is + * NULL + */ + if (!last) + ipsec6stat.in_polvio++; + ip6stat.ip6s_delivered--; + /* do not inject data into pcb */ + } else +#endif /* FAST_IPSEC */ if (last) { if (last->in6p_flags & IN6P_CONTROLOPTS) ip6_savecontrol(last, &opts, ip6, m); diff -ru --exclude=CVS /home/zul/tmp/src/sys/netipsec/ipcomp_var.h /home/zul/ipsec6/sys/netipsec/ipcomp_var.h --- /home/zul/tmp/src/sys/netipsec/ipcomp_var.h 2007-01-05 20:55:51.000000000 +0100 +++ /home/zul/ipsec6/sys/netipsec/ipcomp_var.h 2006-07-19 17:44:43.000000000 +0200 @@ -56,6 +56,7 @@ u_int64_t ipcomps_ibytes; /* Input bytes */ u_int64_t ipcomps_obytes; /* Output bytes */ u_int64_t ipcomps_toobig; /* Packet got > IP_MAXPACKET */ + u_int64_t ipcomps_minlen; /* Packet too short for compress */ u_int64_t ipcomps_pdrops; /* Packet blocked due to policy */ u_int64_t ipcomps_crypto; /* "Crypto" processing failure */ u_int64_t ipcomps_hist[IPCOMP_ALG_MAX];/* Per-algorithm op count */ diff -ru --exclude=CVS /home/zul/tmp/src/sys/netipsec/ipsec.c /home/zul/ipsec6/sys/netipsec/ipsec.c --- /home/zul/tmp/src/sys/netipsec/ipsec.c 2007-01-05 20:55:51.000000000 +0100 +++ /home/zul/ipsec6/sys/netipsec/ipsec.c 2006-12-17 19:10:00.000000000 +0100 @@ -722,6 +722,60 @@ return sp; } +#ifdef INET6 +struct secpolicy * +ipsec6_checkpolicy(m, dir, flag, error, in6p) + struct mbuf *m; + u_int dir, flag; + int *error; + struct in6pcb *in6p; +{ + struct secpolicy *sp; + + *error = 0; + + + /* XXX KAME IPv6 calls us with non-null inp but bogus inp_socket? */ + if (in6p == NULL || in6p->in6p_socket == NULL) { + sp = ipsec_getpolicybyaddr(m, dir, flag, error); + } else + sp = ipsec_getpolicybysock(m, dir, IN6PCB_TO_PCB(in6p), error); + if (sp == NULL) { + IPSEC_ASSERT(*error != 0, + ("ipsec6_checkpolicy: getpolicy failed w/o error")); + newipsecstat.ips_out_inval++; + return NULL; + } + IPSEC_ASSERT(*error == 0, + ("ipsec6_checkpolicy: sp w/ error set to %u", *error)); + switch (sp->policy) { + case IPSEC_POLICY_ENTRUST: + default: + printf("ipsec6_checkpolicy: invalid policy %u\n", sp->policy); + /* fall thru... */ + case IPSEC_POLICY_DISCARD: + newipsecstat.ips_out_polvio++; + *error = -EINVAL; /* packet is discarded by caller */ + break; + case IPSEC_POLICY_BYPASS: + case IPSEC_POLICY_NONE: + KEY_FREESP(&sp); + sp = NULL; /* NB: force NULL result */ + break; + case IPSEC_POLICY_IPSEC: + if (sp->req == NULL) /* acquire an SA */ + *error = key_spdacquire(sp); + break; + } + if (*error != 0) { + KEY_FREESP(&sp); + sp = NULL; + } + DPRINTF(("ipsecpol: done, sp %p error %d, \n", sp, *error)); + return sp; +} +#endif /* INET6 */ + static int ipsec4_setspidx_inpcb(m, pcb) struct mbuf *m; @@ -2165,6 +2219,106 @@ printf("---\n"); } +#ifdef INET6 +struct secpolicy * +ipsec6_check_policy(m,so,flags,needipsecp,errorp) + struct mbuf * m; + const struct socket * so; + int flags; + int * needipsecp; + int * errorp; +{ + struct in6pcb *in6p = NULL; + struct m_tag *mtag; + struct secpolicy *sp = NULL; + struct tdb_ident *tdbi; + int s; + int error = 0; + int needipsec = 0; + + if (so != NULL && so->so_proto->pr_domain->dom_family == AF_INET6) + in6p = sotoin6pcb(so); + + mtag = m_tag_find(m, PACKET_TAG_IPSEC_PENDING_TDB, NULL); + s = splsoftnet(); + if (mtag != NULL) { + tdbi = (struct tdb_ident *)(mtag + 1); + sp = ipsec_getpolicy(tdbi, IPSEC_DIR_OUTBOUND); + if (sp == NULL) + error = -EINVAL; /* force silent drop */ + m_tag_delete(m, mtag); + } else { + if ( in6p != NULL && + IPSEC_PCB_SKIP_IPSEC(in6p->in6p_sp, IPSEC_DIR_OUTBOUND)) + goto skippolicycheck; + sp = ipsec6_checkpolicy(m, IPSEC_DIR_OUTBOUND, flags, &error, in6p); + } + + /* + * There are four return cases: + * sp != NULL apply IPsec policy + * sp == NULL, error == 0 no IPsec handling needed + * sp == NULL, error == -EINVAL discard packet w/o error + * sp == NULL, error != 0 discard packet, report error + */ + if (sp == NULL) { + splx(s); + + if (error != 0) { + needipsec = 0; + } else { + /* No IPsec processing for this packet. */ + needipsec = 0; + } + } else { + /* Loop detection, check if ipsec processing already done */ + IPSEC_ASSERT(sp->req != NULL, ("ip6_output: no ipsec request")); + for (mtag = m_tag_first(m); mtag != NULL; + mtag = m_tag_next(m, mtag)) { +#ifdef MTAG_ABI_COMPAT + if (mtag->m_tag_cookie != MTAG_ABI_COMPAT) + continue; +#endif + if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE && + mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED) + continue; + /* + * Check if policy has an SA associated with it. + * This can happen when an SP has yet to acquire + * an SA; e.g. on first reference. If it occurs, + * then we let ipsec4_process_packet do its thing. + */ + if (sp->req->sav == NULL) + break; + tdbi = (struct tdb_ident *)(mtag + 1); + if (tdbi->spi == sp->req->sav->spi && + tdbi->proto == sp->req->sav->sah->saidx.proto && + bcmp(&tdbi->dst, &sp->req->sav->sah->saidx.dst, + sizeof (union sockaddr_union)) == 0) { + /* + * No IPsec processing is needed, free + * reference to SP. + * + * NB: null pointer to avoid free at + * done: below. + */ + KEY_FREESP(&sp), sp = NULL; + needipsec = 0; + splx(s); + goto skippolicycheck; + } + } + splx(s); + needipsec = 1; + } +skippolicycheck:; + + *errorp = error; + *needipsecp = needipsec; + return sp; +} +#endif + /* XXX this stuff doesn't belong here... */ static struct xformsw* xforms = NULL; diff -ru --exclude=CVS /home/zul/tmp/src/sys/netipsec/ipsec.h /home/zul/ipsec6/sys/netipsec/ipsec.h --- /home/zul/tmp/src/sys/netipsec/ipsec.h 2007-01-05 20:55:51.000000000 +0100 +++ /home/zul/ipsec6/sys/netipsec/ipsec.h 2006-12-17 19:10:00.000000000 +0100 @@ -150,6 +150,18 @@ int count; /* for lifetime */ /* XXX: here is mbuf place holder to be sent ? */ }; + + +/* + * structure used to callback into the ip stack when ipsec processing was + * done + * arg is an opaque type which must not be accessed by ipsec processing + */ +struct ip_callback { + int (*fn)(struct mbuf *, struct ip_callback *); + char ip_callback_args[1]; +}; + #endif /* _KERNEL */ /* according to IANA assignment, port 0x0000 and proto 0xff are reserved. */ @@ -328,8 +340,9 @@ extern int ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int protoff, struct m_tag *mt); extern int ipsec4_process_packet __P((struct mbuf *, struct ipsecrequest *, - int, int)); -extern int ipsec_process_done __P((struct mbuf *, struct ipsecrequest *)); + int, int, struct ip_callback *)); +extern int ipsec_process_done __P((struct mbuf *, struct ipsecrequest *, + int, int, struct ip_callback *)); #define ipsec_indone(m) \ (m_tag_find((m), PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL) diff -ru --exclude=CVS /home/zul/tmp/src/sys/netipsec/ipsec6.h /home/zul/ipsec6/sys/netipsec/ipsec6.h --- /home/zul/tmp/src/sys/netipsec/ipsec6.h 2007-01-05 20:55:51.000000000 +0100 +++ /home/zul/ipsec6/sys/netipsec/ipsec6.h 2006-11-05 17:13:19.000000000 +0100 @@ -70,6 +70,13 @@ caddr_t request, size_t len, int priv)); extern int ipsec6_get_policy __P((struct in6pcb *inp, caddr_t request, size_t len, struct mbuf **mp)); + +extern struct secpolicy *ipsec6_checkpolicy __P((struct mbuf *, u_int, + u_int, int *, struct in6pcb *)); + +struct secpolicy * ipsec6_check_policy(struct mbuf *, + const struct socket *, int, int*,int*); + extern int ipsec6_in_reject __P((struct mbuf *, struct in6pcb *)); /* * KAME ipsec6_in_reject_so(struct mbuf*, struct so) compatibility shim @@ -102,6 +109,9 @@ struct mbuf *, struct secpolicy *, int, int *)); extern int ipsec6_output_tunnel __P((struct ipsec_output_state *, struct secpolicy *, int)); + +int ipsec6_process_packet __P((struct mbuf*,struct ipsecrequest *, + int, int, struct ip_callback *)); #endif /*_KERNEL*/ #endif /* !_NETIPSEC_IPSEC6_H_ */ diff -ru --exclude=CVS /home/zul/tmp/src/sys/netipsec/ipsec_input.c /home/zul/ipsec6/sys/netipsec/ipsec_input.c --- /home/zul/tmp/src/sys/netipsec/ipsec_input.c 2007-01-05 20:55:51.000000000 +0100 +++ /home/zul/ipsec6/sys/netipsec/ipsec_input.c 2006-12-17 19:10:00.000000000 +0100 @@ -413,8 +413,9 @@ m_tag_prepend(m, mtag); } else { - mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE; - /* XXX do we need to mark m_flags??? */ + if (mt != NULL) + mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE; + /* XXX do we need to mark m_flags??? */ } key_sa_recordxfer(sav, m); /* record data transfer */ @@ -603,7 +604,7 @@ /* Sanity check */ if (m == NULL) { - DPRINTF(("ipsec4_common_input_cb: null mbuf")); + DPRINTF(("ipsec6_common_input_cb: null mbuf")); IPSEC_ISTAT(sproto, espstat.esps_badkcr, ahstat.ahs_badkcr, ipcompstat.ipcomps_badkcr); error = EINVAL; @@ -614,7 +615,7 @@ if (m->m_len < sizeof(struct ip6_hdr) && (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { - DPRINTF(("ipsec_common_input_cb: processing failed " + DPRINTF(("ipsec6_common_input_cb: processing failed " "for SA %s/%08lx\n", ipsec_address(&sav->sah->saidx.dst), (u_long) ntohl(sav->spi))); @@ -649,7 +650,7 @@ (saidx->proxy.sa.sa_family != AF_INET && saidx->proxy.sa.sa_family != 0)) { - DPRINTF(("ipsec_common_input_cb: inner " + DPRINTF(("ipsec6_common_input_cb: inner " "source address %s doesn't correspond to " "expected proxy source %s, SA %s/%08lx\n", inet_ntoa4(ipn.ip_src), @@ -686,7 +687,7 @@ (saidx->proxy.sa.sa_family != AF_INET6 && saidx->proxy.sa.sa_family != 0)) { - DPRINTF(("ipsec_common_input_cb: inner " + DPRINTF(("ipsec6_common_input_cb: inner " "source address %s doesn't correspond to " "expected proxy source %s, SA %s/%08lx\n", ip6_sprintf(&ip6n.ip6_src), @@ -714,7 +715,7 @@ mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE, sizeof(struct tdb_ident), M_NOWAIT); if (mtag == NULL) { - DPRINTF(("ipsec_common_input_cb: failed to " + DPRINTF(("ipsec6_common_input_cb: failed to " "get tag\n")); IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops, ipcompstat.ipcomps_hdrops); @@ -729,8 +730,9 @@ m_tag_prepend(m, mtag); } else { - mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE; - /* XXX do we need to mark m_flags??? */ + if (mt != NULL) + mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE; + /* XXX do we need to mark m_flags??? */ } key_sa_recordxfer(sav, m); diff -ru --exclude=CVS /home/zul/tmp/src/sys/netipsec/ipsec_netbsd.c /home/zul/ipsec6/sys/netipsec/ipsec_netbsd.c --- /home/zul/tmp/src/sys/netipsec/ipsec_netbsd.c 2007-01-05 20:55:51.000000000 +0100 +++ /home/zul/ipsec6/sys/netipsec/ipsec_netbsd.c 2006-06-08 11:13:33.000000000 +0200 @@ -68,6 +68,7 @@ #include #include #include +#include #include #include #include @@ -206,6 +207,93 @@ #ifdef INET6 void +ah6_ctlinput(cmd, sa, d) + int cmd; + struct sockaddr *sa; + void *d; +{ + const struct newah *ahp; + struct newah ah; + struct secasvar *sav; + struct ip6_hdr *ip6; + struct mbuf *m; + struct ip6ctlparam *ip6cp = NULL; + int off; + + if (sa->sa_family != AF_INET6 || + sa->sa_len != sizeof(struct sockaddr_in6)) + return; + if ((unsigned)cmd >= PRC_NCMDS) + return; + + /* if the parameter is from icmp6, decode it. */ + if (d != NULL) { + ip6cp = (struct ip6ctlparam *)d; + m = ip6cp->ip6c_m; + ip6 = ip6cp->ip6c_ip6; + off = ip6cp->ip6c_off; + } else { + m = NULL; + ip6 = NULL; + off = 0; + } + + if (ip6) { + /* + * XXX: We assume that when ip6 is non NULL, + * M and OFF are valid. + */ + + /* check if we can safely examine src and dst ports */ + if (m->m_pkthdr.len < off + sizeof(ah)) + return; + + if (m->m_len < off + sizeof(ah)) { + /* + * this should be rare case, + * so we compromise on this copy... + */ + m_copydata(m, off, sizeof(ah), (caddr_t)&ah); + ahp = &ah; + } else + ahp = (struct newah *)(mtod(m, caddr_t) + off); + + if (cmd == PRC_MSGSIZE) { + int valid = 0; + + /* + * Check to see if we have a valid SA corresponding to + * the address in the ICMP message payload. + */ + sav = KEY_ALLOCSA((union sockaddr_union*)sa, + IPPROTO_AH, ahp->ah_spi); + + if (sav) { + if (sav->state == SADB_SASTATE_MATURE || + sav->state == SADB_SASTATE_DYING) + valid++; + KEY_FREESAV(&sav); + } + + /* XXX Further validation? */ + + /* + * Depending on the value of "valid" and routing table + * size (mtudisc_{hi,lo}wat), we will: + * - recalcurate the new MTU and create the + * corresponding routing entry, or + * - ignore the MTU change notification. + */ + icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); + } + + /* we normally notify single pcb here */ + } else { + /* we normally notify any pcb here */ + } +} + +void esp6_ctlinput(cmd, sa, d) int cmd; struct sockaddr *sa; diff -ru --exclude=CVS /home/zul/tmp/src/sys/netipsec/ipsec_output.c /home/zul/ipsec6/sys/netipsec/ipsec_output.c --- /home/zul/tmp/src/sys/netipsec/ipsec_output.c 2007-01-05 20:55:51.000000000 +0100 +++ /home/zul/ipsec6/sys/netipsec/ipsec_output.c 2006-12-17 19:10:00.000000000 +0100 @@ -92,7 +92,8 @@ #include /* ovbcopy() in ipsec6_encapsulate() */ int -ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr) +ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr, + int skip, int protoff, struct ip_callback * ip_cb) { struct tdb_ident *tdbi; struct m_tag *mtag; @@ -166,7 +167,22 @@ */ if (isr->next) { newipsecstat.ips_out_bundlesa++; - return ipsec4_process_packet(m, isr->next, 0, 0); + switch ( saidx->dst.sa.sa_family ) { +#ifdef INET + case AF_INET: + return ipsec4_process_packet(m, isr->next, 0, 0,ip_cb); +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + return ipsec6_process_packet(m, isr->next, skip, protoff, + ip_cb); +#endif /* INET6 */ + default : + DPRINTF(("ipsec_process_done: unknown protocol family %u\n" + , saidx->dst.sa.sa_family)); + error = ENXIO; + goto bad; + } } /* @@ -184,22 +200,21 @@ ip->ip_len = ntohs(ip->ip_len); ip->ip_off = ntohs(ip->ip_off); #endif /* __FreeBSD_ */ - return ip_output(m, NULL, NULL, IP_RAWOUTPUT, - (struct ip_moptions *)NULL, (struct socket *)NULL); - -#endif /* INET */ + return ip_cb->fn(m, ip_cb); +#endif /* INET */ #ifdef INET6 case AF_INET6: /* * We don't need massage, IPv6 header fields are always in * net endian. */ - return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); + return ip_cb->fn(m, ip_cb); #endif /* INET6 */ } panic("ipsec_process_done"); bad: m_freem(m); + free(ip_cb, M_TEMP); KEY_FREESAV(&sav); return (error); } @@ -347,11 +362,11 @@ */ int ipsec4_process_packet( - struct mbuf *m, - struct ipsecrequest *isr, - int flags, - int tunalready -) + struct mbuf *m, + struct ipsecrequest *isr, + int flags, + int tunalready, + struct ip_callback * ip_cb) { struct secasindex saidx; struct secasvar *sav; @@ -433,7 +448,7 @@ #endif /* Encapsulate the packet */ - error = ipip_output(m, isr, &mp, 0, 0); + error = ipip_output(m, isr, &mp, 0, 0, ip_cb); if (mp == NULL && !error) { /* Should never happen. */ DPRINTF(("ipsec4_process_packet: ipip_output " @@ -484,9 +499,10 @@ ip = mtod(m, struct ip *); i = ip->ip_hl << 2; off = offsetof(struct ip, ip_p); - error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off); + error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off,ip_cb); } else { - error = ipsec_process_done(m, isr); + /* skip and protoff are unused for v4 case */ + error = ipsec_process_done(m, isr, 0, 0, ip_cb); } splx(s); return error; @@ -494,292 +510,110 @@ splx(s); if (m) m_freem(m); + if (ip_cb) + free(ip_cb, M_TEMP); return error; } #endif #ifdef INET6 -/* - * Chop IP6 header from the payload. - */ -static struct mbuf * -ipsec6_splithdr(struct mbuf *m) -{ - struct mbuf *mh; - struct ip6_hdr *ip6; - int hlen; - - IPSEC_ASSERT(m->m_len >= sizeof (struct ip6_hdr), - ("ipsec6_splithdr: first mbuf too short, len %u", m->m_len)); - ip6 = mtod(m, struct ip6_hdr *); - hlen = sizeof(struct ip6_hdr); - if (m->m_len > hlen) { - MGETHDR(mh, M_DONTWAIT, MT_HEADER); - if (!mh) { - m_freem(m); - return NULL; - } - M_MOVE_PKTHDR(mh, m); - MH_ALIGN(mh, hlen); - m->m_len -= hlen; - m->m_data += hlen; - mh->m_next = m; - m = mh; - m->m_len = hlen; - bcopy((caddr_t)ip6, mtod(m, caddr_t), hlen); - } else if (m->m_len < hlen) { - m = m_pullup(m, hlen); - if (!m) - return NULL; - } - return m; -} - -/* - * IPsec output logic for IPv6, transport mode. - */ int -ipsec6_output_trans( - struct ipsec_output_state *state, - u_char *nexthdrp, - struct mbuf *mprev, - struct secpolicy *sp, - int flags, - int *tun -) +ipsec6_process_packet( + struct mbuf *m, + struct ipsecrequest *isr, + int skip, + int protoff, + struct ip_callback * ip_cb + ) { - struct ipsecrequest *isr; struct secasindex saidx; - int error = 0; - struct mbuf *m; + struct secasvar *sav; + struct ip6_hdr *ip6; + int s, error; - IPSEC_ASSERT(state != NULL, ("ipsec6_output: null state")); - IPSEC_ASSERT(state->m != NULL, ("ipsec6_output: null m")); - IPSEC_ASSERT(nexthdrp != NULL, ("ipsec6_output: null nexthdrp")); - IPSEC_ASSERT(mprev != NULL, ("ipsec6_output: null mprev")); - IPSEC_ASSERT(sp != NULL, ("ipsec6_output: null sp")); - IPSEC_ASSERT(tun != NULL, ("ipsec6_output: null tun")); - - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("ipsec6_output_trans: applyed SP\n"); - kdebug_secpolicy(sp)); - - isr = sp->req; - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { - /* the rest will be handled by ipsec6_output_tunnel() */ - *tun = 1; /* need tunnel-mode processing */ - return 0; - } + IPSEC_ASSERT(m != NULL, ("ipsec6_process_packet: null mbuf")); + IPSEC_ASSERT(isr != NULL, ("ipsec6_process_packet: null isr")); - *tun = 0; - m = state->m; + s = splsoftnet(); /* insure SA contents don't change */ isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error); if (isr == NULL) { -#ifdef notdef - /* XXX should notification be done for all errors ? */ - /* - * Notify the fact that the packet is discarded - * to ourselves. I believe this is better than - * just silently discarding. (jinmei@kame.net) - * XXX: should we restrict the error to TCP packets? - * XXX: should we directly notify sockets via - * pfctlinputs? - */ - icmp6_error(m, ICMP6_DST_UNREACH, - ICMP6_DST_UNREACH_ADMIN, 0); - m = NULL; /* NB: icmp6_error frees mbuf */ -#endif + // XXX Should we send a notification ? goto bad; - } - - return (*isr->sav->tdb_xform->xf_output)(m, isr, NULL, - sizeof (struct ip6_hdr), - offsetof(struct ip6_hdr, ip6_nxt)); -bad: - if (m) - m_freem(m); - state->m = NULL; - return error; -} + } -static int -ipsec6_encapsulate(struct mbuf *m, struct secasvar *sav) -{ - struct ip6_hdr *oip6; - struct ip6_hdr *ip6; - size_t plen; - - /* can't tunnel between different AFs */ - if (sav->sah->saidx.src.sa.sa_family != AF_INET6 || - sav->sah->saidx.dst.sa.sa_family != AF_INET6) { - m_freem(m); - return EINVAL; - } - IPSEC_ASSERT(m->m_len != sizeof (struct ip6_hdr), - ("ipsec6_encapsulate: mbuf wrong size; len %u", m->m_len)); - - - /* - * grow the mbuf to accommodate the new IPv6 header. - */ - plen = m->m_pkthdr.len; - if (M_LEADINGSPACE(m->m_next) < sizeof(struct ip6_hdr)) { - struct mbuf *n; - MGET(n, M_DONTWAIT, MT_DATA); - if (!n) { - m_freem(m); - return ENOBUFS; - } - n->m_len = sizeof(struct ip6_hdr); - n->m_next = m->m_next; - m->m_next = n; - m->m_pkthdr.len += sizeof(struct ip6_hdr); - oip6 = mtod(n, struct ip6_hdr *); + sav = isr->sav; + if (sav->tdb_xform->xf_type != XF_IP4) { + error = (*sav->tdb_xform->xf_output)(m, isr, NULL, skip, + protoff, ip_cb); } else { - m->m_next->m_len += sizeof(struct ip6_hdr); - m->m_next->m_data -= sizeof(struct ip6_hdr); - m->m_pkthdr.len += sizeof(struct ip6_hdr); - oip6 = mtod(m->m_next, struct ip6_hdr *); - } - ip6 = mtod(m, struct ip6_hdr *); - ovbcopy((caddr_t)ip6, (caddr_t)oip6, sizeof(struct ip6_hdr)); - - /* Fake link-local scope-class addresses */ - if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_src)) - oip6->ip6_src.s6_addr16[1] = 0; - if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_dst)) - oip6->ip6_dst.s6_addr16[1] = 0; - - /* construct new IPv6 header. see RFC 2401 5.1.2.2 */ - /* ECN consideration. */ - ip6_ecn_ingress(ip6_ipsec_ecn, &ip6->ip6_flow, &oip6->ip6_flow); - if (plen < IPV6_MAXPACKET - sizeof(struct ip6_hdr)) - ip6->ip6_plen = htons(plen); - else { - /* 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_hlim = IPV6_DEFHLIM; - - /* XXX Should ip6_src be updated later ? */ - - return 0; -} - -/* - * IPsec output logic for IPv6, tunnel mode. - */ -int -ipsec6_output_tunnel( - struct ipsec_output_state *state, - struct secpolicy *sp, - int flags -) -{ - struct ip6_hdr *ip6; - struct ipsecrequest *isr; - struct secasindex saidx; - int error; - struct sockaddr_in6* dst6; - struct mbuf *m; - - IPSEC_ASSERT(state != NULL, ("ipsec6_output: null state")); - IPSEC_ASSERT(state->m != NULL, ("ipsec6_output: null m")); - IPSEC_ASSERT(sp != NULL, ("ipsec6_output: null sp")); - - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("ipsec6_output_tunnel: applyed SP\n"); - kdebug_secpolicy(sp)); - - m = state->m; - /* - * transport mode ipsec (before the 1st tunnel mode) is already - * processed by ipsec6_output_trans(). - */ - for (isr = sp->req; isr; isr = isr->next) { - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) - break; - } - isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error); - if (isr == NULL) - goto bad; - - /* - * There may be the case that SA status will be changed when - * we are refering to one. So calling splsoftnet(). - */ - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { - /* - * build IPsec tunnel. - */ - /* XXX should be processed with other familiy */ - if (isr->sav->sah->saidx.src.sa.sa_family != AF_INET6) { - ipseclog((LOG_ERR, "ipsec6_output_tunnel: " - "family mismatched between inner and outer, spi=%lu\n", - (u_long)ntohl(isr->sav->spi))); - newipsecstat.ips_out_inval++; - error = EAFNOSUPPORT; - goto bad; - } - - m = ipsec6_splithdr(m); - if (!m) { - newipsecstat.ips_out_nomem++; - error = ENOMEM; - goto bad; - } - error = ipsec6_encapsulate(m, isr->sav); - if (error) { - m = NULL; - goto bad; - } - ip6 = mtod(m, struct ip6_hdr *); + union sockaddr_union *dst = &sav->sah->saidx.dst; - state->ro = &isr->sav->sah->sa_route; - state->dst = (struct sockaddr *)&state->ro->ro_dst; - dst6 = (struct sockaddr_in6 *)state->dst; - if (!IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, &ip6->ip6_dst)) - rtcache_free(state->ro); - else - rtcache_check(state->ro); - if (state->ro->ro_rt == NULL) { - bzero(dst6, sizeof(*dst6)); - dst6->sin6_family = AF_INET6; - dst6->sin6_len = sizeof(*dst6); - dst6->sin6_addr = ip6->ip6_dst; - rtcache_init(state->ro); - if (state->ro->ro_rt == NULL) { - ip6stat.ip6s_noroute++; - newipsecstat.ips_out_noroute++; - error = EHOSTUNREACH; - goto bad; - } - } + ip6 = mtod(m, struct ip6_hdr *); - /* adjust state->dst if tunnel endpoint is offlink */ - if (state->ro->ro_rt->rt_flags & RTF_GATEWAY) { - state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway; - dst6 = (struct sockaddr_in6 *)state->dst; - } - } + /* Do the appropriate encapsulation, if necessary */ + if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ + dst->sa.sa_family != AF_INET6 || /* PF mismatch */ + + ((dst->sa.sa_family == AF_INET6) && + (!IN6_IS_ADDR_UNSPECIFIED(&dst->sin6.sin6_addr)) && + (!IN6_ARE_ADDR_EQUAL(&dst->sin6.sin6_addr, + &ip6->ip6_dst))) + ) + { + struct mbuf *mp; - m = ipsec6_splithdr(m); - if (!m) { - newipsecstat.ips_out_nomem++; - error = ENOMEM; - goto bad; + /* Fix IPv6 header payload length. */ + if (m->m_len < sizeof(struct ip6_hdr)) + if ((m = m_pullup(m,sizeof(struct ip6_hdr))) == NULL) + return ENOBUFS; + + if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) { + /* No jumbogram support. */ + m_freem(m); + return ENXIO; /*XXX*/ + } + ip6 = mtod(m, struct ip6_hdr *); + ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6)); + + /* Encapsulate the packet */ + error = ipip_output(m, isr, &mp, 0, 0, ip_cb); + if (mp == NULL && !error) { + /* Should never happen. */ + DPRINTF(("ipsec6_process_packet: ipip_output " + "returns no mbuf and no error!")); + error = EFAULT; + } + if (error) { + if (mp) { + /* XXX: Should never happen! */ + m_freem(mp); + } + m = NULL; /* ipip_output() already freed it */ + goto bad; + } + + m = mp; + mp = NULL; + + /* + * here paquet is tunnelled. Compute the new values of skip and + * protoff + */ + + skip = sizeof(struct ip6_hdr); + protoff = offsetof(struct ip6_hdr, ip6_nxt); + } + error = ipsec_process_done(m, isr,skip,protoff,ip_cb); } - ip6 = mtod(m, struct ip6_hdr *); - return (*isr->sav->tdb_xform->xf_output)(m, isr, NULL, - sizeof (struct ip6_hdr), - offsetof(struct ip6_hdr, ip6_nxt)); + splx(s); + return error; bad: + splx(s); if (m) m_freem(m); - state->m = NULL; + if (ip_cb) + free(ip_cb, M_TEMP); return error; } #endif /*INET6*/ diff -ru --exclude=CVS /home/zul/tmp/src/sys/netipsec/key.c /home/zul/ipsec6/sys/netipsec/key.c --- /home/zul/tmp/src/sys/netipsec/key.c 2007-01-05 20:55:51.000000000 +0100 +++ /home/zul/ipsec6/sys/netipsec/key.c 2006-12-17 19:10:01.000000000 +0100 @@ -102,6 +102,7 @@ #include #include +#include #include @@ -1047,12 +1048,35 @@ struct secasvar *sav; u_int stateidx, state; int s; + int must_check_spi = 1; + int must_check_alg = 0; + u_int16_t cpi = 0; + u_int8_t algo = 0; IPSEC_ASSERT(dst != NULL, ("key_allocsa: null dst address")); KEYDEBUG(KEYDEBUG_IPSEC_STAMP, printf("DP key_allocsa from %s:%u\n", where, tag)); + /* + * XXX IPCOMP case + * We use cpi to define spi here. In the case where cpi <= + * IPCOMP_CPI_NEGOTIATE_MIN, cpi just define the algorithm used, not + * the real spi. In this case, don't check the spi but check the + * algorithm + */ + + if (proto == IPPROTO_IPCOMP) { + u_int32_t tmp; + tmp = ntohl(spi); + cpi = (u_int16_t) tmp; + if (cpi < IPCOMP_CPI_NEGOTIATE_MIN) { + algo = (u_int8_t) cpi; + must_check_spi = 0; + must_check_alg = 1; + } + } + /* * searching SAD. * XXX: to be checked internal IP header somewhere. Also when @@ -1075,8 +1099,12 @@ continue; if (proto != sav->sah->saidx.proto) continue; - if (spi != sav->spi) + if (must_check_spi && spi != sav->spi) continue; + + /* XXX only on the ipcomp case */ + if (must_check_alg && algo != sav->alg_comp) + continue; #if 0 /* don't check src */ /* check src address */ if (key_sockaddrcmp(&src->sa, &sav->sah->saidx.src.sa, 0) != 0) @@ -1767,32 +1795,6 @@ dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST]; xpl0 = (struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY]; -#if defined(__NetBSD__) && defined(INET6) - /* - * On NetBSD, FAST_IPSEC and INET6 can be configured together, - * but FAST_IPSEC does not protect IPv6 traffic. - * Rather than silently leaking IPv6 traffic for which IPsec - * is configured, forbid specifying IPsec for IPv6 traffic. - * - * (On FreeBSD, both FAST_IPSEC and INET6 gives a compile-time error.) - */ - if (((const struct sockaddr *)(src0 + 1))->sa_family == AF_INET6 || - ((const struct sockaddr *)(dst0 + 1))->sa_family == AF_INET6) { - static int v6_warned = 0; - - if (v6_warned == 0) { - printf("key_spdadd: FAST_IPSEC does not support IPv6."); - printf("Check syslog for more per-SPD warnings.\n"); - v6_warned++; - } - log(LOG_WARNING, - "FAST_IPSEC does not support PF_INET6 SPDs. " - "Request refused.\n"); - - return EOPNOTSUPP; /* EPROTOTYPE? EAFNOSUPPORT? */ - } -#endif /* __NetBSD__ && INET6 */ - /* make secindex */ /* XXX boundary check against sa_len */ KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir, @@ -2404,9 +2406,10 @@ return key_sendup_mbuf(so, m, KEY_SENDUP_ALL); } + static struct sockaddr key_src = { - .sa_len = 2, - .sa_family = PF_KEY, + .sa_len = 2, + .sa_family = PF_KEY, }; static struct mbuf * @@ -3368,7 +3371,7 @@ switch (sav->sah->saidx.proto) { case IPPROTO_ESP: case IPPROTO_AH: - if (ntohl(sav->spi) <= 255) { + if (ntohl(sav->spi) <= 255) { /* spi is always positive */ ipseclog((LOG_DEBUG, "key_mature: illegal range of SPI %u.\n", (u_int32_t)ntohl(sav->spi))); diff -ru --exclude=CVS /home/zul/tmp/src/sys/netipsec/keysock.c /home/zul/ipsec6/sys/netipsec/keysock.c --- /home/zul/tmp/src/sys/netipsec/keysock.c 2007-01-05 20:55:51.000000000 +0100 +++ /home/zul/ipsec6/sys/netipsec/keysock.c 2006-11-13 21:57:30.000000000 +0100 @@ -72,6 +72,7 @@ }; static struct key_cb key_cb; + static struct sockaddr key_dst = { .sa_len = 2, .sa_family = PF_KEY, @@ -81,7 +82,6 @@ .sa_family = PF_KEY, }; - static int key_sendup0 __P((struct rawcb *, struct mbuf *, int, int)); struct pfkeystat pfkeystat; diff -ru --exclude=CVS /home/zul/tmp/src/sys/netipsec/xform.h /home/zul/ipsec6/sys/netipsec/xform.h --- /home/zul/tmp/src/sys/netipsec/xform.h 2007-01-05 20:55:51.000000000 +0100 +++ /home/zul/ipsec6/sys/netipsec/xform.h 2006-10-22 23:29:16.000000000 +0200 @@ -94,7 +94,8 @@ int (*xf_input)(struct mbuf*, struct secasvar*, /* input */ int, int); int (*xf_output)(struct mbuf*, /* output */ - struct ipsecrequest *, struct mbuf **, int, int); + struct ipsecrequest *, struct mbuf **, int, int, + struct ip_callback *); struct xformsw *xf_next; /* list of registered xforms */ }; @@ -108,7 +109,7 @@ extern int ip4_input6(struct mbuf **m, int *offp, int proto); extern void ip4_input(struct mbuf *m, ...); extern int ipip_output(struct mbuf *, struct ipsecrequest *, - struct mbuf **, int, int); + struct mbuf **, int, int, struct ip_callback*); /* XF_AH */ extern int ah_init0(struct secasvar *, struct xformsw *, struct cryptoini *); diff -ru --exclude=CVS /home/zul/tmp/src/sys/netipsec/xform_ah.c /home/zul/ipsec6/sys/netipsec/xform_ah.c --- /home/zul/tmp/src/sys/netipsec/xform_ah.c 2007-01-05 20:55:51.000000000 +0100 +++ /home/zul/ipsec6/sys/netipsec/xform_ah.c 2006-12-17 19:10:01.000000000 +0100 @@ -955,12 +955,12 @@ */ static int ah_output( - struct mbuf *m, - struct ipsecrequest *isr, - struct mbuf **mp, - int skip, - int protoff -) + struct mbuf *m, + struct ipsecrequest *isr, + struct mbuf **mp, + int skip, + int protoff, + struct ip_callback * ip_cb) { struct secasvar *sav; struct auth_hash *ahx; @@ -1175,11 +1175,14 @@ tc->tc_proto = sav->sah->saidx.proto; tc->tc_skip = skip; tc->tc_protoff = protoff; + tc->tc_ptr = (caddr_t)ip_cb; return crypto_dispatch(crp); bad: if (m) m_freem(m); + if (ip_cb) + free(ip_cb, M_TEMP); return (error); } @@ -1193,6 +1196,7 @@ struct tdb_crypto *tc; struct ipsecrequest *isr; struct secasvar *sav; + struct ip_callback * ip_cb; struct mbuf *m; caddr_t ptr; int s, err; @@ -1201,6 +1205,7 @@ IPSEC_ASSERT(tc != NULL, ("ah_output_cb: null opaque data area!")); skip = tc->tc_skip; protoff = tc->tc_protoff; + ip_cb = (struct ip_callback *)tc->tc_ptr; ptr = (caddr_t) (tc + 1); m = (struct mbuf *) crp->crp_buf; @@ -1267,7 +1272,7 @@ #endif /* NB: m is reclaimed by ipsec_process_done. */ - err = ipsec_process_done(m, isr); + err = ipsec_process_done(m, isr, skip, protoff,ip_cb); KEY_FREESAV(&sav); splx(s); return err; @@ -1277,6 +1282,8 @@ splx(s); if (m) m_freem(m); + if (ip_cb) + free(ip_cb, M_TEMP); free(tc, M_XDATA); crypto_freereq(crp); return error; @@ -1284,8 +1291,8 @@ static struct xformsw ah_xformsw = { XF_AH, XFT_AUTH, "IPsec AH", - ah_init, ah_zeroize, ah_input, ah_output, - NULL, + ah_init, ah_zeroize, ah_input, ah_output, + NULL, }; INITFN void diff -ru --exclude=CVS /home/zul/tmp/src/sys/netipsec/xform_esp.c /home/zul/ipsec6/sys/netipsec/xform_esp.c --- /home/zul/tmp/src/sys/netipsec/xform_esp.c 2007-01-05 20:55:51.000000000 +0100 +++ /home/zul/ipsec6/sys/netipsec/xform_esp.c 2006-12-17 19:10:01.000000000 +0100 @@ -667,11 +667,12 @@ */ static int esp_output( - struct mbuf *m, - struct ipsecrequest *isr, - struct mbuf **mp, - int skip, - int protoff + struct mbuf *m, + struct ipsecrequest *isr, + struct mbuf **mp, + int skip, + int protoff, + struct ip_callback * ip_cb ) { struct enc_xform *espx; @@ -873,6 +874,9 @@ tc->tc_spi = sav->spi; tc->tc_dst = saidx->dst; tc->tc_proto = saidx->proto; + tc->tc_skip = skip; + tc->tc_protoff = protoff; + tc->tc_ptr = (caddr_t)ip_cb; /* Crypto operation descriptor. */ crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */ @@ -898,6 +902,8 @@ bad: if (m) m_freem(m); + if (ip_cb) + free(ip_cb, M_TEMP); return (error); } @@ -910,8 +916,9 @@ struct tdb_crypto *tc; struct ipsecrequest *isr; struct secasvar *sav; + struct ip_callback * ip_cb; struct mbuf *m; - int s, err, error; + int s, err, error , skip, protoff; tc = (struct tdb_crypto *) crp->crp_opaque; IPSEC_ASSERT(tc != NULL, ("esp_output_cb: null opaque data area!")); @@ -920,6 +927,9 @@ s = splsoftnet(); isr = tc->tc_isr; + ip_cb = (struct ip_callback *)tc->tc_ptr; + skip = tc->tc_skip; + protoff = tc->tc_protoff; sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi); if (sav == NULL) { espstat.esps_notdb++; @@ -984,7 +994,7 @@ #endif /* NB: m is reclaimed by ipsec_process_done. */ - err = ipsec_process_done(m, isr); + err = ipsec_process_done(m, isr, skip, protoff, ip_cb); KEY_FREESAV(&sav); splx(s); return err; @@ -994,6 +1004,8 @@ splx(s); if (m) m_freem(m); + if (ip_cb) + free(ip_cb, M_TEMP); free(tc, M_XDATA); crypto_freereq(crp); return error; @@ -1002,8 +1014,8 @@ static struct xformsw esp_xformsw = { XF_ESP, XFT_CONF|XFT_AUTH, "IPsec ESP", esp_init, esp_zeroize, esp_input, - esp_output, - NULL, + esp_output, + NULL, }; INITFN void diff -ru --exclude=CVS /home/zul/tmp/src/sys/netipsec/xform_ipcomp.c /home/zul/ipsec6/sys/netipsec/xform_ipcomp.c --- /home/zul/tmp/src/sys/netipsec/xform_ipcomp.c 2007-01-05 20:55:51.000000000 +0100 +++ /home/zul/ipsec6/sys/netipsec/xform_ipcomp.c 2006-12-17 19:10:01.000000000 +0100 @@ -72,7 +72,7 @@ #include #include -int ipcomp_enable = 0; +int ipcomp_enable = 1; struct ipcompstat ipcompstat; #ifdef __FreeBSD__ @@ -334,22 +334,20 @@ */ static int ipcomp_output( - struct mbuf *m, - struct ipsecrequest *isr, - struct mbuf **mp, - int skip, - int protoff + struct mbuf *m, + struct ipsecrequest *isr, + struct mbuf **mp, + int skip, + int protoff, + struct ip_callback * ip_cb ) { struct secasvar *sav; struct comp_algo *ipcompx; - int error, ralen, hlen, maxpacketsize, roff; - u_int8_t prot; + int error, ralen, hlen, maxpacketsize; struct cryptodesc *crdc; struct cryptop *crp; struct tdb_crypto *tc; - struct mbuf *mo; - struct ipcomp *ipcomp; IPSEC_SPLASSERT_SOFTNET("ipcomp_output"); sav = isr->sav; @@ -358,6 +356,13 @@ IPSEC_ASSERT(ipcompx != NULL, ("ipcomp_output: null compression xform")); ralen = m->m_pkthdr.len - skip; /* Raw payload length before comp. */ + + /* Don't process the packet if it is too short */ + if ( ralen < ipcompx->minlen ){ + ipcompstat.ipcomps_minlen++; + return ipsec_process_done(m,isr,skip, protoff, ip_cb); + } + hlen = IPCOMP_HLENGTH; ipcompstat.ipcomps_output++; @@ -408,40 +413,6 @@ goto bad; } - /* Inject IPCOMP header */ - mo = m_makespace(m, skip, hlen, &roff); - if (mo == NULL) { - ipcompstat.ipcomps_wrap++; - DPRINTF(("ipcomp_output: failed to inject IPCOMP header for " - "IPCA %s/%08lx\n", - ipsec_address(&sav->sah->saidx.dst), - (u_long) ntohl(sav->spi))); - error = ENOBUFS; - goto bad; - } - ipcomp = (struct ipcomp *)(mtod(mo, caddr_t) + roff); - - /* Initialize the IPCOMP header */ - /* XXX alignment always correct? */ - switch (sav->sah->saidx.dst.sa.sa_family) { -#ifdef INET - case AF_INET: - ipcomp->comp_nxt = mtod(m, struct ip *)->ip_p; - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - ipcomp->comp_nxt = mtod(m, struct ip6_hdr *)->ip6_nxt; - break; -#endif - } - ipcomp->comp_flags = 0; - ipcomp->comp_cpi = htons((u_int16_t) ntohl(sav->spi)); - - /* Fix Next Protocol in IPv4/IPv6 header */ - prot = IPPROTO_IPCOMP; - m_copyback(m, protoff, sizeof(u_int8_t), (u_char *) &prot); - /* Ok now, we can pass to the crypto processing */ /* Get crypto descriptors */ @@ -455,10 +426,10 @@ crdc = crp->crp_desc; /* Compression descriptor */ - crdc->crd_skip = skip + hlen; - crdc->crd_len = m->m_pkthdr.len - (skip + hlen); + crdc->crd_skip = skip; + crdc->crd_len = m->m_pkthdr.len - skip; crdc->crd_flags = CRD_F_COMP; - crdc->crd_inject = skip + hlen; + crdc->crd_inject = skip; /* Compression operation */ crdc->crd_alg = ipcompx->type; @@ -478,7 +449,9 @@ tc->tc_spi = sav->spi; tc->tc_dst = sav->sah->saidx.dst; tc->tc_proto = sav->sah->saidx.proto; - tc->tc_skip = skip + hlen; + tc->tc_protoff = protoff; + tc->tc_skip = skip; + tc->tc_ptr = (caddr_t)ip_cb; /* Crypto operation descriptor */ crp->crp_ilen = m->m_pkthdr.len; /* Total input length */ @@ -492,6 +465,8 @@ bad: if (m) m_freem(m); + if (ip_cb) + free(ip_cb, M_TEMP); return (error); } @@ -504,13 +479,19 @@ struct tdb_crypto *tc; struct ipsecrequest *isr; struct secasvar *sav; - struct mbuf *m; - int s, error, skip, rlen; + struct ip_callback * ip_cb; + struct mbuf *m, *mo; + int s, error, skip, rlen, roff, protoff; + u_int8_t prot; + u_int16_t cpi; + struct ipcomp * ipcomp; tc = (struct tdb_crypto *) crp->crp_opaque; IPSEC_ASSERT(tc != NULL, ("ipcomp_output_cb: null opaque data area!")); m = (struct mbuf *) crp->crp_buf; skip = tc->tc_skip; + protoff = tc->tc_protoff; + ip_cb = (struct ip_callback *)tc->tc_ptr; rlen = crp->crp_ilen - skip; s = splsoftnet(); @@ -551,6 +532,45 @@ ipcompstat.ipcomps_hist[sav->alg_comp]++; if (rlen > crp->crp_olen) { + /* Inject IPCOMP header */ + mo = m_makespace(m, skip, IPCOMP_HLENGTH, &roff); + if (mo == NULL) { + ipcompstat.ipcomps_wrap++; + DPRINTF(("ipcomp_output: failed to inject IPCOMP header for " + "IPCA %s/%08lx\n", + ipsec_address(&sav->sah->saidx.dst), + (u_long) ntohl(sav->spi))); + error = ENOBUFS; + goto bad; + } + ipcomp = (struct ipcomp *)(mtod(mo, caddr_t) + roff); + + /* Initialize the IPCOMP header */ + /* XXX alignment always correct? */ + switch (sav->sah->saidx.dst.sa.sa_family) { + #ifdef INET + case AF_INET: + ipcomp->comp_nxt = mtod(m, struct ip *)->ip_p; + break; + #endif /* INET */ + #ifdef INET6 + case AF_INET6: + ipcomp->comp_nxt = mtod(m, struct ip6_hdr *)->ip6_nxt; + break; + #endif + } + ipcomp->comp_flags = 0; + + if ((sav->flags & SADB_X_EXT_RAWCPI) == 0) + cpi = sav->alg_enc; + else + cpi = ntohl(sav->spi) & 0xffff; + ipcomp->comp_cpi = htons(cpi); + + /* Fix Next Protocol in IPv4/IPv6 header */ + prot = IPPROTO_IPCOMP; + m_copyback(m, tc->tc_protoff, sizeof(u_int8_t), (u_char *) &prot); + /* Adjust the length in the IP header */ switch (sav->sah->saidx.dst.sa.sa_family) { #ifdef INET @@ -584,7 +604,7 @@ crypto_freereq(crp); /* NB: m is reclaimed by ipsec_process_done. */ - error = ipsec_process_done(m, isr); + error = ipsec_process_done(m, isr, skip, protoff, ip_cb); KEY_FREESAV(&sav); splx(s); return error; @@ -594,6 +614,8 @@ splx(s); if (m) m_freem(m); + if (ip_cb) + free(ip_cb, M_TEMP); free(tc, M_XDATA); crypto_freereq(crp); return error; @@ -602,8 +624,8 @@ static struct xformsw ipcomp_xformsw = { XF_IPCOMP, XFT_COMP, "IPcomp", ipcomp_init, ipcomp_zeroize, ipcomp_input, - ipcomp_output, - NULL, + ipcomp_output, + NULL, }; INITFN void diff -ru --exclude=CVS /home/zul/tmp/src/sys/netipsec/xform_ipip.c /home/zul/ipsec6/sys/netipsec/xform_ipip.c --- /home/zul/tmp/src/sys/netipsec/xform_ipip.c 2007-01-05 20:55:51.000000000 +0100 +++ /home/zul/ipsec6/sys/netipsec/xform_ipip.c 2006-12-17 20:33:31.000000000 +0100 @@ -422,11 +422,12 @@ int ipip_output( - struct mbuf *m, - struct ipsecrequest *isr, - struct mbuf **mp, - int skip, - int protoff + struct mbuf *m, + struct ipsecrequest *isr, + struct mbuf **mp, + int skip, + int protoff, + struct ip_callback * ip_cb ) { struct secasvar *sav; @@ -682,25 +683,30 @@ static struct xformsw ipe4_xformsw = { XF_IP4, 0, "IPv4 Simple Encapsulation", - ipe4_init, ipe4_zeroize, ipe4_input, ipip_output, - NULL, + ipe4_init, ipe4_zeroize, ipe4_input, ipip_output, + NULL, }; + +#ifdef INET extern struct domain inetdomain; -static struct ipprotosw ipe4_protosw[] = { -{ SOCK_RAW, &inetdomain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR|PR_LASTHDR, +static struct ipprotosw ipe4_protosw = { + SOCK_RAW, &inetdomain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR|PR_LASTHDR, ip4_input, 0, 0, rip_ctloutput, rip_usrreq, 0, 0, 0, 0, -}, +}; +#endif + #ifdef INET6 -{ SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR|PR_LASTHDR, - ip4_input, 0, 0, rip_ctloutput, - rip_usrreq, +extern struct domain inet6domain; +static struct ip6protosw ipe4_protosw6 = { + SOCK_RAW, &inet6domain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR|PR_LASTHDR, + ip4_input6, 0, 0, rip6_ctloutput, + rip6_usrreq, 0, 0, 0, 0, -}, -#endif }; +#endif /* * Check the encapsulated packet to see if we want it @@ -727,11 +733,13 @@ xform_register(&ipe4_xformsw); /* attach to encapsulation framework */ /* XXX save return cookie for detach on module remove */ +#ifdef INET (void) encap_attach_func(AF_INET, -1, - ipe4_encapcheck, (struct protosw*) &ipe4_protosw[0], NULL); + ipe4_encapcheck, (struct protosw*) &ipe4_protosw, NULL); +#endif #ifdef INET6 (void) encap_attach_func(AF_INET6, -1, - ipe4_encapcheck, (struct protosw*) &ipe4_protosw[1], NULL); + ipe4_encapcheck, (struct protosw*)(void*) &ipe4_protosw6, NULL); #endif } diff -ru --exclude=CVS /home/zul/tmp/src/sys/netipsec/xform_tcp.c /home/zul/ipsec6/sys/netipsec/xform_tcp.c --- /home/zul/tmp/src/sys/netipsec/xform_tcp.c 2007-01-05 20:55:51.000000000 +0100 +++ /home/zul/ipsec6/sys/netipsec/xform_tcp.c 2006-10-22 23:29:16.000000000 +0200 @@ -147,7 +147,7 @@ */ static int tcpsignature_output(struct mbuf *m, struct ipsecrequest *isr, - struct mbuf **mp, int skip, int protoff) + struct mbuf **mp, int skip, int protoff, struct ip_callback*) { return (EINVAL); @@ -156,7 +156,7 @@ static struct xformsw tcpsignature_xformsw = { XF_TCPSIGNATURE, XFT_AUTH, "TCPMD5", tcpsignature_init, tcpsignature_zeroize, - tcpsignature_input, tcpsignature_output + tcpsignature_input, tcpsignature_output, NULL }; INITFN void