Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/netinet6/ip6_input.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/netinet6/ip6_input.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.1.2.3 retrieving revision 1.21 diff -u -p -r1.1.2.3 -r1.21 --- src/sys/netinet6/ip6_input.c 1999/11/30 13:35:53 1.1.2.3 +++ src/sys/netinet6/ip6_input.c 2000/05/19 20:09:27 1.21 @@ -1,7 +1,10 @@ +/* $NetBSD: ip6_input.c,v 1.21 2000/05/19 20:09:27 itojun Exp $ */ +/* $KAME: ip6_input.c,v 1.89 2000/05/19 19:59:05 itojun Exp $ */ + /* * 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 +16,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 @@ -62,15 +65,9 @@ * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 */ -#ifdef __FreeBSD__ -#include "opt_ip6fw.h" -#endif -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) #include "opt_inet.h" -#ifdef __NetBSD__ /*XXX*/ #include "opt_ipsec.h" -#endif -#endif +#include "opt_pfil_hooks.h" #include #include @@ -84,15 +81,16 @@ #include #include #include -#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) #include -#endif #include #include #include #include #include +#ifdef PFIL_HOOKS +#include +#endif #include #include @@ -100,16 +98,11 @@ #include #include #endif /*INET*/ -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) -#include -#endif +#include #include -#include -#if !((defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802)) -#include -#endif #include -#include +#include +#include #include #include #include @@ -118,16 +111,10 @@ #include #endif -#ifdef ALTQ -#include -#endif - #include /* we need it for NLOOP. */ -#ifndef __bsdi__ #include "loop.h" -#endif #include "faith.h" #include "gif.h" @@ -135,27 +122,14 @@ #include -#ifdef __OpenBSD__ /*KAME IPSEC*/ -#undef IPSEC -#endif - extern struct domain inet6domain; -extern struct ip6protosw inet6sw[]; -#if (defined(__bsdi__) && _BSDI_VERSION < 199802) || defined(__OpenBSD__) -extern struct ifnet loif; -#endif -#if defined(__bsdi__) && _BSDI_VERSION >= 199802 -extern struct ifnet *loifp; -#endif u_char ip6_protox[IPPROTO_MAX]; static int ip6qmaxlen = IFQ_MAXLEN; struct in6_ifaddr *in6_ifaddr; struct ifqueue ip6intrq; -#ifdef __NetBSD__ extern struct ifnet loif[NLOOP]; -#endif int ip6_forward_srcrt; /* XXX */ int ip6_sourcecheck; /* XXX */ int ip6_sourcecheck_interval; /* XXX */ @@ -172,13 +146,6 @@ static void ip6_init2 __P((void *)); static int ip6_hopopts_input __P((u_int32_t *, u_int32_t *, struct mbuf **, int *)); -#if defined(PTR) -extern int ip6_protocol_tr; - -int ptr_in6 __P((struct mbuf *, struct mbuf **)); -extern void ip_forward __P((struct mbuf *, int)); -#endif - /* * IP6 initialization: fill in IP6 protocol switch table. * All protocols not implemented in kernel go to raw IP6 protocol handler. @@ -213,52 +180,27 @@ ip6_init() microtime(&tv); ip6_flow_seq = random() ^ tv.tv_usec; -#ifndef __FreeBSD__ ip6_init2((void *)0); -#endif } static void ip6_init2(dummy) void *dummy; { -#if !(defined(__bsdi__) || defined(__OpenBSD__)) - int i; -#endif - int ret; -#if (defined(__bsdi__) && _BSDI_VERSION < 199802) || defined(__OpenBSD__) - struct ifnet *loifp = &loif; -#endif - - /* get EUI64 from somewhere */ - ret = in6_ifattach_getifid(NULL); - /* * to route local address of p2p link to loopback, - * assign loopback address first. + * assign loopback address first. */ -#if defined(__bsdi__) || defined(__OpenBSD__) - in6_ifattach(loifp, IN6_IFT_LOOP, NULL, 0); -#else - for (i = 0; i < NLOOP; i++) - in6_ifattach(&loif[i], IN6_IFT_LOOP, NULL, 0); -#endif - - /* attach pseudo interfaces */ - if (ret == 0) - in6_ifattach_p2p(); + in6_ifattach(&loif[0], NULL); /* nd6_timer_init */ - timeout(nd6_timer, (caddr_t)0, hz); + callout_init(&nd6_timer_ch); + callout_reset(&nd6_timer_ch, hz, nd6_timer, NULL); /* router renumbering prefix list maintenance */ - timeout(in6_rr_timer, (caddr_t)0, hz); + callout_init(&in6_rr_timer_ch); + callout_reset(&in6_rr_timer_ch, hz, in6_rr_timer, NULL); } -#ifdef __FreeBSD__ -/* cheat */ -SYSINIT(netinet6init2, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, ip6_init2, NULL); -#endif - /* * IP6 input interrupt handling. Just pass the packet to ip6_input. */ @@ -278,10 +220,6 @@ ip6intr() } } -#ifdef __FreeBSD__ -NETISR_SET(NETISR_IPV6, ip6intr); -#endif - extern struct route_in6 ip6_forward_rt; void @@ -294,9 +232,11 @@ ip6_input(m) u_int32_t rtalert = ~0; int nxt, ours = 0; struct ifnet *deliverifp = NULL; -#if (defined(__bsdi__) && _BSDI_VERSION < 199802) || defined(__OpenBSD__) - struct ifnet *loifp = &loif; -#endif +#ifdef PFIL_HOOKS + struct packet_filter_hook *pfh; + struct mbuf *m0; + int rv; +#endif /* PFIL_HOOKS */ #ifdef IPSEC /* @@ -320,11 +260,7 @@ ip6_input(m) } else { if (m->m_next) { if (m->m_flags & M_LOOP) { -#if defined(__bsdi__) || defined(__OpenBSD__) - ip6stat.ip6s_m2m[loifp->if_index]++; /*XXX*/ -#else ip6stat.ip6s_m2m[loif[0].if_index]++; /*XXX*/ -#endif } else if (m->m_pkthdr.rcvif->if_index <= 31) ip6stat.ip6s_m2m[m->m_pkthdr.rcvif->if_index]++; @@ -360,6 +296,30 @@ ip6_input(m) goto bad; } +#ifdef PFIL_HOOKS + /* + * Run through list of hooks for input packets. If there are any + * filters which require that additional packets in the flow are + * not fast-forwarded, they must clear the M_CANFASTFWD flag. + * Note that filters must _never_ set this flag, as another filter + * in the list may have previously cleared it. + */ + m0 = m; + pfh = pfil_hook_get(PFIL_IN, &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh); + for (; pfh; pfh = pfh->pfil_link.tqe_next) + if (pfh->pfil_func) { + rv = pfh->pfil_func(ip6, sizeof(*ip6), + m->m_pkthdr.rcvif, 0, &m0); + if (rv) + return; + m = m0; + if (m == NULL) + return; + ip6 = mtod(m, struct ip6_hdr *); + } +#endif /* PFIL_HOOKS */ + + ip6stat.ip6s_nxthist[ip6->ip6_nxt]++; #ifdef IPV6FIREWALL @@ -379,13 +339,6 @@ ip6_input(m) } #endif -#ifdef ALTQ - if (altq_input != NULL && (*altq_input)(m, AF_INET6) == 0) { - /* packet is dropped by traffic conditioner */ - return; - } -#endif - /* * Scope check */ @@ -395,6 +348,33 @@ ip6_input(m) in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); goto bad; } + /* + * The following check is not documented in the spec. Malicious party + * may be able to use IPv4 mapped addr to confuse tcp/udp stack and + * bypass security checks (act as if it was from 127.0.0.1 by using + * IPv6 src ::ffff:127.0.0.1). Be cautious. + */ + if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || + IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { + ip6stat.ip6s_badscope++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); + goto bad; + } +#if 0 + /* + * Reject packets with IPv4 compatible addresses (auto tunnel). + * + * The code forbids auto tunnel relay case in RFC1933 (the check is + * stronger than RFC1933). We may want to re-enable it if mech-xx + * is revised to forbid relaying case. + */ + if (IN6_IS_ADDR_V4COMPAT(&ip6->ip6_src) || + IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) { + ip6stat.ip6s_badscope++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); + goto bad; + } +#endif if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) || IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) { if (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) { @@ -408,13 +388,12 @@ ip6_input(m) } } - if (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) { - if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) { - ours = 1; - deliverifp = m->m_pkthdr.rcvif; - goto hbhcheck; - } - } else { +#ifndef FAKE_LOOPBACK_IF + if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) +#else + if (1) +#endif + { if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) ip6->ip6_src.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); @@ -423,32 +402,20 @@ ip6_input(m) = htons(m->m_pkthdr.rcvif->if_index); } -#if defined(PTR) /* - * + * XXX we need this since we do not have "goto ours" hack route + * for some of our ifaddrs on loopback interface. + * we should correct it by changing in6_ifattach to install + * "goto ours" hack route. */ - if (ip6_protocol_tr) - { - struct mbuf *m1 = NULL; - - switch (ptr_in6(m, &m1)) - { - case IPPROTO_IP: goto mcastcheck; - case IPPROTO_IPV4: ip_forward(m1, 0); break; - case IPPROTO_IPV6: ip6_forward(m1, 0); break; - case IPPROTO_MAX: /* discard this packet */ - default: - } - - if (m != m1) - m_freem(m); - - return; + if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) != 0) { + if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) { + ours = 1; + deliverifp = m->m_pkthdr.rcvif; + goto hbhcheck; + } } - mcastcheck: -#endif - /* * Multicast check */ @@ -488,12 +455,7 @@ ip6_input(m) ip6_forward_rt.ro_dst.sin6_family = AF_INET6; ip6_forward_rt.ro_dst.sin6_addr = ip6->ip6_dst; -#if defined(__bsdi__) || defined(__NetBSD__) rtalloc((struct route *)&ip6_forward_rt); -#endif -#ifdef __FreeBSD__ - rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING); -#endif } #define rt6_key(r) ((struct sockaddr_in6 *)((r)->rt_nodes->rn_key)) @@ -550,7 +512,7 @@ ip6_input(m) } #endif -#ifdef __OpenBSD__ +#if 0 { /* * Last resort: check in6_ifaddr for incoming interface. @@ -573,6 +535,7 @@ ip6_input(m) } } #endif + /* * Now there is no reason to process the packet if it's not our own * and we're not a router. @@ -672,7 +635,7 @@ ip6_input(m) /* * Tell launch routine the next header */ -#if defined(__NetBSD__) && defined(IFA_STATS) +#ifdef IFA_STATS if (IFA_STATS && deliverifp != NULL) { struct in6_ifaddr *ia6; ip6 = mtod(m, struct ip6_hdr *); @@ -931,39 +894,17 @@ ip6_unknown_opt(optp, m, off) */ void ip6_savecontrol(in6p, mp, ip6, m) -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(HAVE_NRL_INPCB) - register struct inpcb *in6p; -#else register struct in6pcb *in6p; -#endif register struct mbuf **mp; register struct ip6_hdr *ip6; register struct mbuf *m; { -#ifdef HAVE_NRL_INPCB -# define in6p_flags inp_flags -#endif -#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3) struct proc *p = curproc; /* XXX */ -#endif -#ifdef __bsdi__ -# define sbcreatecontrol so_cmsg -#endif int privileged; privileged = 0; -#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3) if (p && !suser(p->p_ucred, &p->p_acflag)) privileged++; -#else -#ifdef HAVE_NRL_INPCB - if ((in6p->inp_socket->so_state & SS_PRIV) != 0) - privileged++; -#else - if ((in6p->in6p_socket->so_state & SS_PRIV) != 0) - privileged++; -#endif -#endif #ifdef SO_TIMESTAMP if (in6p->in6p_socket->so_options & SO_TIMESTAMP) { @@ -1168,12 +1109,6 @@ ip6_savecontrol(in6p, mp, ip6, m) } /* IN6P_RTHDR - to be done */ -#ifdef __bsdi__ -# undef sbcreatecontrol -#endif -#ifdef __OpenBSD__ -# undef in6p_flags -#endif } /* @@ -1227,6 +1162,115 @@ ip6_get_prevhdr(m, off) } /* + * get next header offset. m will be retained. + */ +int +ip6_nexthdr(m, off, proto, nxtp) + struct mbuf *m; + int off; + int proto; + int *nxtp; +{ + struct ip6_hdr ip6; + struct ip6_ext ip6e; + struct ip6_frag fh; + + /* just in case */ + if (m == NULL) + panic("ip6_nexthdr: m == NULL"); + if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.len < off) + return -1; + + switch (proto) { + case IPPROTO_IPV6: + if (m->m_pkthdr.len < off + sizeof(ip6)) + return -1; + m_copydata(m, off, sizeof(ip6), (caddr_t)&ip6); + if (nxtp) + *nxtp = ip6.ip6_nxt; + off += sizeof(ip6); + return off; + + case IPPROTO_FRAGMENT: + /* + * terminate parsing if it is not the first fragment, + * it does not make sense to parse through it. + */ + if (m->m_pkthdr.len < off + sizeof(fh)) + return -1; + m_copydata(m, off, sizeof(fh), (caddr_t)&fh); + if ((ntohs(fh.ip6f_offlg) & IP6F_OFF_MASK) != 0) + return -1; + if (nxtp) + *nxtp = fh.ip6f_nxt; + off += sizeof(struct ip6_frag); + return off; + + case IPPROTO_AH: + if (m->m_pkthdr.len < off + sizeof(ip6e)) + return -1; + m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); + if (nxtp) + *nxtp = ip6e.ip6e_nxt; + off += (ip6e.ip6e_len + 2) << 2; + return off; + + case IPPROTO_HOPOPTS: + case IPPROTO_ROUTING: + case IPPROTO_DSTOPTS: + if (m->m_pkthdr.len < off + sizeof(ip6e)) + return -1; + m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); + if (nxtp) + *nxtp = ip6e.ip6e_nxt; + off += (ip6e.ip6e_len + 1) << 3; + return off; + + case IPPROTO_NONE: + case IPPROTO_ESP: + case IPPROTO_IPCOMP: + /* give up */ + return -1; + + default: + return -1; + } + + return -1; +} + +/* + * get offset for the last header in the chain. m will be kept untainted. + */ +int +ip6_lasthdr(m, off, proto, nxtp) + struct mbuf *m; + int off; + int proto; + int *nxtp; +{ + int newoff; + int nxt; + + if (!nxtp) { + nxt = -1; + nxtp = &nxt; + } + while (1) { + newoff = ip6_nexthdr(m, off, proto, nxtp); + if (newoff < 0) + return off; + else if (newoff < off) + return -1; /* invalid */ + else if (newoff == off) + return newoff; + + off = newoff; + proto = *nxtp; + } +} + +/* * System control for IP6 */ @@ -1239,7 +1283,6 @@ u_char inet6ctlerrmap[PRC_NCMDS] = { ENOPROTOOPT }; -#if defined(__NetBSD__) || defined(__OpenBSD__) #include #include @@ -1296,37 +1339,15 @@ ip6_sysctl(name, namelen, oldp, oldlenp, case IPV6CTL_USE_DEPRECATED: return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_use_deprecated); + case IPV6CTL_RR_PRUNE: + return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_rr_prune); +#ifndef INET6_BINDV6ONLY + case IPV6CTL_BINDV6ONLY: + return sysctl_int(oldp, oldlenp, newp, newlen, + &ip6_bindv6only); +#endif default: return EOPNOTSUPP; } /* NOTREACHED */ } -#endif /* __NetBSD__ || __OpenBSD__ */ - -#ifdef __bsdi__ -int *ip6_sysvars[] = IPV6CTL_VARS; - -int -ip6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) - int *name; - u_int namelen; - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; -{ - if (name[0] >= IPV6CTL_MAXID) - return (EOPNOTSUPP); - - switch (name[0]) { - case IPV6CTL_STATS: - return sysctl_rdtrunc(oldp, oldlenp, newp, &ip6stat, - sizeof(ip6stat)); - case IPV6CTL_KAME_VERSION: - return sysctl_rdstring(oldp, oldlenp, newp, __KAME_VERSION); - default: - return (sysctl_int_arr(ip6_sysvars, name, namelen, - oldp, oldlenp, newp, newlen)); - } -} -#endif /* __bsdi__ */