X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/d52fe63fc81f7e44faaae711812a211a78434976..9bccf70c0258c7cac2dcb80011b2a964d884c552:/bsd/netinet6/raw_ip6.c diff --git a/bsd/netinet6/raw_ip6.c b/bsd/netinet6/raw_ip6.c index 0baf3af82..f49d75e92 100644 --- a/bsd/netinet6/raw_ip6.c +++ b/bsd/netinet6/raw_ip6.c @@ -1,7 +1,7 @@ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -13,7 +13,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -25,6 +25,8 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $FreeBSD: src/sys/netinet6/raw_ip6.c,v 1.7.2.4 2001/07/29 19:32:40 ume Exp $ */ /* @@ -61,12 +63,6 @@ * * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94 */ -#if BSD310 -#include "opt_inet.h" -#endif - -#include - #include #include #include @@ -88,63 +84,73 @@ #include #include #include -#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) #include -#endif #include #include #include +#if ENABLE_DEFAULT_SCOPE +#include +#endif +#include #if IPSEC #include +#include +extern int ipsec_bypass; #endif /*IPSEC*/ #include "faith.h" +#if defined(NFAITH) && 0 < NFAITH +#include +#endif -#define satosin6(sa) ((struct sockaddr_in6 *)(sa)) -#define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) +#define satosin6(sa) ((struct sockaddr_in6 *)(sa)) +#define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) /* * Raw interface to IP6 protocol. */ -extern struct inpcbhead ripcb; -extern struct inpcbinfo ripcbinfo; +extern struct inpcbhead ripcb; +extern struct inpcbinfo ripcbinfo; extern u_long rip_sendspace; extern u_long rip_recvspace; +struct rip6stat rip6stat; + /* * Setup generic address and protocol structures * for raw_input routine, then pass them along with * mbuf chain. */ int -rip6_input(mp, offp, proto) +rip6_input(mp, offp) struct mbuf **mp; - int *offp, proto; + int *offp; { struct mbuf *m = *mp; register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); register struct inpcb *in6p; struct inpcb *last = 0; - struct ip6_recvpktopts opts; + struct mbuf *opts = NULL; struct sockaddr_in6 rip6src; + int proto = ip6->ip6_nxt; + + rip6stat.rip6s_ipackets++; #if defined(NFAITH) && 0 < NFAITH - if (m->m_pkthdr.rcvif) { - if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) { - /* XXX send icmp6 host/port unreach? */ - m_freem(m); - return IPPROTO_DONE; - } + if (faithprefix(&ip6->ip6_dst)) { + /* XXX send icmp6 host/port unreach? */ + m_freem(m); + return IPPROTO_DONE; } #endif + init_sin6(&rip6src, m); /* general init */ - bzero(&opts, sizeof(opts)); LIST_FOREACH(in6p, &ripcb, inp_list) { - if ((in6p->in6p_vflag & INP_IPV6) == NULL) + if ((in6p->in6p_vflag & INP_IPV6) == 0) continue; if (in6p->in6p_ip6_nxt && in6p->in6p_ip6_nxt != proto) @@ -155,49 +161,76 @@ rip6_input(mp, offp, proto) if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) && !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) continue; - if (in6p->in6p_cksum != -1 - && in6_cksum(m, ip6->ip6_nxt, *offp, - m->m_pkthdr.len - *offp)) { - /* XXX bark something */ - continue; + if (in6p->in6p_cksum != -1) { + rip6stat.rip6s_isum++; + if (in6_cksum(m, ip6->ip6_nxt, *offp, + m->m_pkthdr.len - *offp)) { + rip6stat.rip6s_badsum++; + continue; + } } if (last) { struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); + +#if IPSEC + /* + * Check AH/ESP integrity. + */ + if (ipsec_bypass == 0 && n && ipsec6_in_reject_so(n, last->inp_socket)) { + m_freem(n); + ipsec6stat.in_polvio++; + /* do not inject data into pcb */ + } else +#endif /*IPSEC*/ if (n) { if (last->in6p_flags & IN6P_CONTROLOPTS || last->in6p_socket->so_options & SO_TIMESTAMP) - ip6_savecontrol(last, ip6, n, &opts, - NULL); + ip6_savecontrol(last, &opts, ip6, n); /* strip intermediate headers */ m_adj(n, *offp); if (sbappendaddr(&last->in6p_socket->so_rcv, (struct sockaddr *)&rip6src, - n, opts.head) == 0) { - /* should notify about lost packet */ + n, opts) == 0) { m_freem(n); - if (opts.head) - m_freem(opts.head); + if (opts) + m_freem(opts); + rip6stat.rip6s_fullsock++; } else sorwakeup(last->in6p_socket); - bzero(&opts, sizeof(opts)); + opts = NULL; } } last = in6p; } +#if IPSEC + /* + * Check AH/ESP integrity. + */ + if (ipsec_bypass == 0 && last && ipsec6_in_reject_so(m, last->inp_socket)) { + m_freem(m); + ipsec6stat.in_polvio++; + ip6stat.ip6s_delivered--; + /* do not inject data into pcb */ + } else +#endif /*IPSEC*/ if (last) { if (last->in6p_flags & IN6P_CONTROLOPTS || last->in6p_socket->so_options & SO_TIMESTAMP) - ip6_savecontrol(last, ip6, m, &opts, NULL); + ip6_savecontrol(last, &opts, ip6, m); /* strip intermediate headers */ m_adj(m, *offp); if (sbappendaddr(&last->in6p_socket->so_rcv, - (struct sockaddr *)&rip6src, m, opts.head) == 0) { + (struct sockaddr *)&rip6src, m, opts) == 0) { m_freem(m); - if (opts.head) - m_freem(opts.head); + if (opts) + m_freem(opts); + rip6stat.rip6s_fullsock++; } else sorwakeup(last->in6p_socket); } else { + rip6stat.rip6s_nosock++; + if (m->m_flags & M_MCAST) + rip6stat.rip6s_nosockmcast++; if (proto == IPPROTO_NONE) m_freem(m); else { @@ -217,10 +250,11 @@ rip6_ctlinput(cmd, sa, d) struct sockaddr *sa; void *d; { - struct sockaddr_in6 sa6; struct ip6_hdr *ip6; struct mbuf *m; int off = 0; + struct ip6ctlparam *ip6cp = NULL; + const struct sockaddr_in6 *sa6_src = NULL; void (*notify) __P((struct inpcb *, int)) = in6_rtchange; if (sa->sa_family != AF_INET6 || @@ -238,37 +272,19 @@ rip6_ctlinput(cmd, sa, d) /* if the parameter is from icmp6, decode it. */ if (d != NULL) { - struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; + ip6cp = (struct ip6ctlparam *)d; m = ip6cp->ip6c_m; ip6 = ip6cp->ip6c_ip6; off = ip6cp->ip6c_off; + sa6_src = ip6cp->ip6c_src; } else { m = NULL; ip6 = NULL; + sa6_src = &sa6_any; } - /* translate addresses into internal form */ - sa6 = *(struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif) - sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); - - if (ip6) { - /* - * XXX: We assume that when IPV6 is non NULL, - * M and OFF are valid. - */ - struct in6_addr s; - - /* translate addresses into internal form */ - memcpy(&s, &ip6->ip6_src, sizeof(s)); - if (IN6_IS_ADDR_LINKLOCAL(&s)) - s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); - - (void) in6_pcbnotify(&ripcb, (struct sockaddr *)&sa6, - 0, &s, 0, cmd, notify); - } else - (void) in6_pcbnotify(&ripcb, (struct sockaddr *)&sa6, 0, - &zeroin6_addr, 0, cmd, notify); + (void) in6_pcbnotify(&ripcb, sa, 0, (struct sockaddr *)sa6_src, + 0, cmd, notify); } /* @@ -295,17 +311,8 @@ rip6_output(m, so, dstsock, control) in6p = sotoin6pcb(so); priv = 0; -#if !defined(__APPLE__) - { - struct proc *p = current_proc(); /* XXX */ - - if (p && !suser(p->p_ucred, &p->p_acflag)) - priv = 1; - } -#else - if ((so->so_state & SS_PRIV) != 0) + if (so->so_uid == 0) priv = 1; -#endif dst = &dstsock->sin6_addr; if (control) { if ((error = ip6_setpktoptions(control, &opt, priv, 0)) != 0) @@ -342,7 +349,7 @@ rip6_output(m, so, dstsock, control) * If the scope of the destination is link-local, embed the interface * index in the address. * - * XXX advanced-api value overrides sin6_scope_id + * XXX advanced-api value overrides sin6_scope_id */ if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { struct in6_pktinfo *pi; @@ -354,15 +361,14 @@ rip6_output(m, so, dstsock, control) if (optp && (pi = optp->ip6po_pktinfo) && pi->ipi6_ifindex) { ip6->ip6_dst.s6_addr16[1] = htons(pi->ipi6_ifindex); oifp = ifindex2ifnet[pi->ipi6_ifindex]; - } - else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && + } else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && in6p->in6p_moptions && in6p->in6p_moptions->im6o_multicast_ifp) { oifp = in6p->in6p_moptions->im6o_multicast_ifp; ip6->ip6_dst.s6_addr16[1] = htons(oifp->if_index); } else if (dstsock->sin6_scope_id) { /* boundary check */ - if (dstsock->sin6_scope_id < 0 + if (dstsock->sin6_scope_id < 0 || if_index < dstsock->sin6_scope_id) { error = ENXIO; /* XXX EINVAL? */ goto bad; @@ -391,12 +397,11 @@ rip6_output(m, so, dstsock, control) if (in6p->in6p_route.ro_rt) oifp = ifindex2ifnet[in6p->in6p_route.ro_rt->rt_ifp->if_index]; } - - ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK; - ip6->ip6_vfc |= IPV6_VERSION; -#if 0 /* ip6_plen will be filled in ip6_output. */ - ip6->ip6_plen = htons((u_short)plen); -#endif + ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) | + (in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK); + ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) | + (IPV6_VERSION & IPV6_VERSION_MASK); + /* ip6_plen will be filled in ip6_output, so not fill it here. */ ip6->ip6_nxt = in6p->in6p_ip6_nxt; ip6->ip6_hlim = in6_selecthlim(in6p, oifp); @@ -406,8 +411,6 @@ rip6_output(m, so, dstsock, control) int off; u_int16_t *p; -#define offsetof(type, member) ((size_t)(&((type *)0)->member)) /* XXX */ - /* compute checksum */ if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) off = offsetof(struct icmp6_hdr, icmp6_cksum); @@ -432,16 +435,20 @@ rip6_output(m, so, dstsock, control) } #if IPSEC - ipsec_setsocket(m, so); + if (ipsec_bypass == 0 && ipsec_setsocket(m, so) != 0) { + error = ENOBUFS; + goto bad; + } #endif /*IPSEC*/ - error = ip6_output(m, optp, &in6p->in6p_route, 0, in6p->in6p_moptions, - &oifp); + error = ip6_output(m, optp, &in6p->in6p_route, 0, + in6p->in6p_moptions, &oifp); if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { if (oifp) icmp6_ifoutstat_inc(oifp, type, code); icmp6stat.icp6s_outhist[type]++; - } + } else + rip6stat.rip6s_opackets++; goto freectl; @@ -451,7 +458,7 @@ rip6_output(m, so, dstsock, control) freectl: if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt) - RTFREE(optp->ip6po_route.ro_rt); + rtfree(optp->ip6po_route.ro_rt); if (control) { if (optp == &opt) ip6_clearpktopts(optp, 0, -1); @@ -532,11 +539,9 @@ rip6_attach(struct socket *so, int proto, struct proc *p) if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) return error; - if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { - error = soreserve(so, rip_sendspace, rip_recvspace); - if (error) - return error; - } + error = soreserve(so, rip_sendspace, rip_recvspace); + if (error) + return error; s = splnet(); error = in_pcballoc(so, &ripcbinfo, p); splx(s); @@ -547,19 +552,8 @@ rip6_attach(struct socket *so, int proto, struct proc *p) inp->in6p_ip6_nxt = (long)proto; inp->in6p_hops = -1; /* use kernel default */ inp->in6p_cksum = -1; -#if IPSEC - error = ipsec_init_policy(so, &inp->in6p_sp); - if (error != 0) { - in6_pcbdetach(inp); - return (error); - } -#endif /*IPSEC*/ MALLOC(inp->in6p_icmp6filt, struct icmp6_filter *, sizeof(struct icmp6_filter), M_PCB, M_NOWAIT); - - if (inp->in6p_icmp6filt == NULL) - return(ENOBUFS); - ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt); return 0; } @@ -572,9 +566,9 @@ rip6_detach(struct socket *so) inp = sotoinpcb(so); if (inp == 0) panic("rip6_detach"); + /* xxx: RSVP */ if (so == ip6_mrouter) ip6_mrouter_done(); - /* xxx: RSVP */ if (inp->in6p_icmp6filt) { FREE(inp->in6p_icmp6filt, M_PCB); inp->in6p_icmp6filt = NULL; @@ -613,6 +607,11 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct proc *p) if (TAILQ_EMPTY(&ifnet) || addr->sin6_family != AF_INET6) return EADDRNOTAVAIL; +#if ENABLE_DEFAULT_SCOPE + if (addr->sin6_scope_id == 0) { /* not change if specified */ + addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr); + } +#endif if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) && (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0) return EADDRNOTAVAIL; @@ -633,6 +632,9 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct proc *p) struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam; struct in6_addr *in6a = NULL; int error = 0; +#if ENABLE_DEFAULT_SCOPE + struct sockaddr_in6 tmp; +#endif if (nam->sa_len != sizeof(*addr)) return EINVAL; @@ -640,7 +642,14 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct proc *p) return EADDRNOTAVAIL; if (addr->sin6_family != AF_INET6) return EAFNOSUPPORT; - +#if ENABLE_DEFAULT_SCOPE + if (addr->sin6_scope_id == 0) { /* not change if specified */ + /* avoid overwrites */ + tmp = *addr; + addr = &tmp; + addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr); + } +#endif /* Source address selection. XXX: need pcblookup? */ in6a = in6_selectsrc(addr, inp->in6p_outputopts, inp->in6p_moptions, &inp->in6p_route, @@ -668,6 +677,7 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct sockaddr_in6 tmp; struct sockaddr_in6 *dst; + /* always copy sockaddr to avoid overwrites */ if (so->so_state & SS_ISCONNECTED) { if (nam) { m_freem(m); @@ -685,8 +695,14 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, m_freem(m); return ENOTCONN; } - dst = (struct sockaddr_in6 *)nam; + tmp = *(struct sockaddr_in6 *)nam; + dst = &tmp; } +#if ENABLE_DEFAULT_SCOPE + if (dst->sin6_scope_id == 0) { /* not change if specified */ + dst->sin6_scope_id = scope6_addr2default(&dst->sin6_addr); + } +#endif return rip6_output(m, so, dst, control); } @@ -694,6 +710,6 @@ struct pr_usrreqs rip6_usrreqs = { rip6_abort, pru_accept_notsupp, rip6_attach, rip6_bind, rip6_connect, pru_connect2_notsupp, in6_control, rip6_detach, rip6_disconnect, pru_listen_notsupp, in6_setpeeraddr, pru_rcvd_notsupp, - pru_rcvoob_notsupp, rip6_send, pru_sense_null, rip6_shutdown, + pru_rcvoob_notsupp, rip6_send, pru_sense_null, rip6_shutdown, in6_setsockaddr, sosend, soreceive, sopoll };