ip6_input.c

来自「eCos操作系统源码」· C语言 代码 · 共 2,515 行 · 第 1/5 页

C
2,515
字号
	if (m && m->m_next != NULL && m->m_pkthdr.len < MCLBYTES) {		struct mbuf *n;		MGETHDR(n, M_DONTWAIT, MT_HEADER);		if (n != NULL) {#ifdef __OpenBSD__			M_MOVE_PKTHDR(n, m);#else			M_COPY_PKTHDR(n, m);#endif		}		if (n != NULL && m->m_pkthdr.len > MHLEN) {			MCLGET(n, M_DONTWAIT);			if ((n->m_flags & M_EXT) == 0) {				m_freem(n);				n = NULL;			}		}		if (n == NULL) {			m_freem(m);			return;	/* ENOBUFS */		}		m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t));		n->m_len = m->m_pkthdr.len;		m_freem(m);		m = n;	}	IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), /* nothing */);#endif#if defined(__OpenBSD__) && NPF > 0 	/*	 * Packet filter	 */	if (pf_test6(PF_IN, m->m_pkthdr.rcvif, &m) != PF_PASS)		goto bad;#endif	if (m->m_len < sizeof(struct ip6_hdr)) {		struct ifnet *inifp;		inifp = m->m_pkthdr.rcvif;		if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == 0) {			ip6stat.ip6s_toosmall++;			in6_ifstat_inc(inifp, ifs6_in_hdrerr);			return;		}	}	ip6 = mtod(m, struct ip6_hdr *);	if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {		ip6stat.ip6s_badvers++;		in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr);		goto bad;	}#if defined(__NetBSD__) && defined(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.	 */	/*	 * let ipfilter look at packet on the wire,	 * not the decapsulated packet.	 */#ifdef IPSEC	if (!ipsec_getnhist(m))#else	if (1 /* CONSTCOND */)#endif	{		m0 = m;		pfh = pfil_hook_get(PFIL_IN,		    &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);	} else		pfh = NULL;	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]++;#if defined(IPV6FIREWALL) || (defined(__FreeBSD__) && __FreeBSD__ >= 4)	/*	 * Check with the firewall...	 */#if defined(__FreeBSD__) && __FreeBSD__ >= 4	if (ip6_fw_enable && ip6_fw_chk_ptr)#else	if (ip6_fw_chk_ptr)#endif	{		/* If ipfw says divert, we have to just drop packet */		/* use port as a dummy argument */		if ((*ip6_fw_chk_ptr)(&ip6, NULL, &m)) {			m_freem(m);			m = NULL;		}		if (!m)			return;	}#endif#ifdef ALTQ	if (altq_input != NULL && (*altq_input)(m, AF_INET6) == 0) {		/* packet is dropped by traffic conditioner */		return;	}#endif	/*	 * Check against address spoofing/corruption.	 */#if 0            diag_printf("%s.%d\n", __FUNCTION__, __LINE__);            diag_dump_buf(&ip6->ip6_src, 16);            diag_dump_buf(&ip6->ip6_dst, 16);#endif	if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src) ||	    IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) {		/*		 * XXX: "badscope" is not very suitable for a multicast source.		 */		ip6stat.ip6s_badscope++;		in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);                log(LOG_FAIL, "%s.%d\n", __FUNCTION__, __LINE__);		goto bad;	}	if ((IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) ||	     IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) &&	    (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) {		ip6stat.ip6s_badscope++;		in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);                log(LOG_FAIL, "%s.%d\n", __FUNCTION__, __LINE__);		goto bad;	}	if (IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) &&	    !(m->m_flags & M_LOOP)) {		/*		 * In this case, the packet should come from the loopback		 * interface.  However, we cannot just check the if_flags,		 * because ip6_mloopback() passes the "actual" interface		 * as the outgoing/incoming interface.		 */		ip6stat.ip6s_badscope++;		in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);                log(LOG_FAIL, "%s.%d\n", __FUNCTION__, __LINE__);		goto bad;	}	     	/*	 * The following check is not documented in specs.  A 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.	 *	 * This check chokes if we are in an SIIT cloud.  As none of BSDs	 * support IPv4-less kernel compilation, we cannot support SIIT	 * environment at all.  So, it makes more sense for us to reject any	 * malicious packets for non-SIIT environment, than try to do a	 * partical support for SIIT environment.	 */	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);                log(LOG_FAIL, "%s.%d\n", __FUNCTION__, __LINE__);		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	/* drop packets if interface ID portion is already filled */	if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) {		if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src) &&		    ip6->ip6_src.s6_addr16[1]) {			ip6stat.ip6s_badscope++;                        log(LOG_FAIL, "%s.%d\n", __FUNCTION__, __LINE__);			goto bad;		}		if ((IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) ||		     IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) &&		    ip6->ip6_dst.s6_addr16[1]) {			ip6stat.ip6s_badscope++;                        log(LOG_FAIL, "%s.%d\n", __FUNCTION__, __LINE__);			goto bad;		}	}	/*	 * Embed interface ID as the zone ID for interface-local and	 * link-local addresses.	 * XXX: KAME assumes one-to-one mapping between interfaces and	 * links.	 */	if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))		ip6->ip6_src.s6_addr16[1]			= htons(m->m_pkthdr.rcvif->if_index);	if (IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) ||	    IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))		ip6->ip6_dst.s6_addr16[1]			= htons(m->m_pkthdr.rcvif->if_index);#if 0 /* this case seems to be unnecessary. (jinmei, 20010401) */	/*	 * We use rt->rt_ifp to determine if the address is ours or not.	 * If rt_ifp is lo0, the address is ours.	 * The problem here is, rt->rt_ifp for fe80::%lo0/64 is set to lo0,	 * so any address under fe80::%lo0/64 will be mistakenly considered	 * local.  The special case is supplied to handle the case properly	 * by actually looking at interface addresses	 * (using in6ifa_ifpwithaddr).	 */	if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) != 0 &&	    IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) {		if (!in6ifa_ifpwithaddr(m->m_pkthdr.rcvif, &ip6->ip6_dst)) {			icmp6_error(m, ICMP6_DST_UNREACH,			    ICMP6_DST_UNREACH_ADDR, 0);			/* m is already freed */			return;		}		ours = 1;		deliverifp = m->m_pkthdr.rcvif;		goto hbhcheck;	}#endif	/*	 * Multicast check	 */	if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {	  	struct	in6_multi *in6m = 0;		in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mcast);		/*		 * See if we belong to the destination multicast group on the		 * arrival interface.		 */		IN6_LOOKUP_MULTI(ip6->ip6_dst, m->m_pkthdr.rcvif, in6m);// TEMP                if (0) {                    struct in6_addr *_addr = &ip6->ip6_dst;                    struct ifnet *_ifp = m->m_pkthdr.rcvif;                    struct ifmultiaddr *_ifma;                     diag_printf("Lookup Multi = %p\n", in6m);                    diag_dump_buf(_addr, 16);                    diag_printf("=====================================================================\n");                    for (_ifma = (_ifp)->if_multiaddrs.lh_first; _ifma;                          _ifma = _ifma->ifma_link.le_next) {                         diag_dump_buf(&((struct sockaddr_in6 *)_ifma->ifma_addr)->sin6_addr, 16);                        diag_printf("---------------------------------------------------------------------\n");                    }                 }// TEMP		if (in6m)			ours = 1;		else if (!ip6_mrouter) {			ip6stat.ip6s_notmember++;			ip6stat.ip6s_cantforward++;			in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);                        log(LOG_FAIL, "%s.%d - wrong multi group\n",                             __FUNCTION__, __LINE__);                        log_dump(LOG_FAIL, &ip6->ip6_dst, 16);			goto bad;		}		deliverifp = m->m_pkthdr.rcvif;		goto hbhcheck;	}	/*	 *  Unicast check	 */#ifdef MEASURE_PERFORMANCE	ctr_beg = read_tsc();#endif	switch (ip6_ours_check_algorithm) {#ifdef MEASURE_PERFORMANCE	case OURS_CHECK_ALG_LINEAR:	/* traditional linear search: just for measurement */	{		struct in6_ifaddr *ia;		for (ia = in6_ifaddr; ia; ia = ia->ia_next) {			if ((ia->ia6_flags & IN6_IFF_NOTREADY) == 0 &&			    IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr,					       &ip6->ip6_dst)) {#ifdef MEASURE_PERFORMANCE				ctr_end = read_tsc();#ifdef MEASURE_PERFORMANCE_UDPONLY				if (ip6->ip6_nxt == IPPROTO_UDP)#else				if (1)#endif					add_performance_log(ctr_end - ctr_beg,							    &ip6->ip6_dst);#endif				/* record address information into m_aux. */				(void)ip6_setdstifaddr(m, ia);				ours = 1;				deliverifp = ia->ia_ifp;				goto hbhcheck;			}		}	}	break;	case OURS_CHECK_ALG_HASH:	case OURS_CHECK_ALG_LARGEHASH:	{		struct in6_ifaddr *ia;		struct in6hash *ih = NULL;		if ((ih = in6h_lookup(&ip6->ip6_dst, m->m_pkthdr.rcvif)) !=		    NULL && (ia = ih->in6h_ifa) != NULL) {#ifdef MEASURE_PERFORMANCE			ctr_end = read_tsc();#ifdef MEASURE_PERFORMANCE_UDPONLY			if (ip6->ip6_nxt == IPPROTO_UDP)#else			if (1)#endif				add_performance_log(ctr_end - ctr_beg,						    &ip6->ip6_dst);#endif			/* record address information into m_aux. */			(void)ip6_setdstifaddr(m, ia);			ours = 1;			deliverifp = m->m_pkthdr.rcvif;			goto hbhcheck;		}	}	break;#endif /* MEASURE_PERFORMANCE */	default:		/*		 * XXX: I intentionally broke our indentation rule here,		 *      since this switch-case is just for measurement and		 *      therefore should soon be removed.		 */	if (ip6_forward_rt.ro_rt != NULL &&	    (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) != 0 && 	    IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,			       &((struct sockaddr_in6 *)(&ip6_forward_rt.ro_dst))->sin6_addr))		ip6stat.ip6s_forward_cachehit++;	else {		struct sockaddr_in6 *dst6;#ifdef SCOPEDROUTING		int64_t dstzone;#endif		if (ip6_forward_rt.ro_rt) {			/* route is down or destination is different */			ip6stat.ip6s_forward_cachemiss++;			RTFREE(ip6_forward_rt.ro_rt);			ip6_forward_rt.ro_rt = 0;		}		bzero(&ip6_forward_rt.ro_dst, sizeof(struct sockaddr_in6));		dst6 = (struct sockaddr_in6 *)&ip6_forward_rt.ro_dst;		dst6->sin6_len = sizeof(struct sockaddr_in6);		dst6->sin6_family = AF_INET6;		dst6->sin6_addr = ip6->ip6_dst;#ifdef SCOPEDROUTING		if ((dstzone = in6_addr2zoneid(m->m_pkthdr.rcvif,					       &ip6->ip6_dst)) < 0) {			ip6stat.ip6s_badscope++;			in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);                        log(LOG_FAIL, "%s.%d\n", __FUNCTION__, __LINE__);			goto bad;		}		ip6_forward_rt.ro_dst.sin6_scope_id = dstzone;#endif#ifdef __FreeBSD__		rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING);#else		rtalloc((struct route *)&ip6_forward_rt);#endif	}#define rt6_key(r) ((struct sockaddr_in6 *)((r)->rt_nodes->rn_key))	/*	 * Accept the packet if the forwarding interface to the destination	 * according to the routing table is the loopback interface,	 * unless the associated route has a gateway.	 * Note that this approach causes to accept a packet if there is a	 * route to the loopback interface for the destination of the packet.	 * But we think it's even useful in some situations, e.g. when using	 * a special daemon which wants to intercept the packet.	 *	 * XXX: some OSes automatically make a cloned route for the destination	 * of an outgoing packet.  If the outgoing interface of the packet	 * is a loopback one, the kernel would consider the packet to be	 * accepted, even if we have no such address assinged on the interface.	 * We check the cloned flag of the route entry to reject such cases,	 * assuming that route entries for our own addresses are not made by	 * cloning (it should be true because in6_addloop explicitly installs	 * the host route).  However, we might have to do an explicit check	 * while it would be less efficient.  Or, should we rather install a	 * reject route for such a case?	 */	if (ip6_forward_rt.ro_rt &&	    (ip6_forward_rt.ro_rt->rt_flags &	     (RTF_HOST|RTF_GATEWAY)) == RTF_HOST &&#ifdef RTF_WASCLONED	    !(ip6_forward_rt.ro_rt->rt_flags & RTF_WASCLONED) &&#endif#ifdef RTF_CLONED	    !(ip6_forward_rt.ro_rt->rt_flags & RTF_CLONED) &&#endif#if 0	    /*	     * The check below is redundant since the comparison of	     * the destination and the key of the rtentry has	     * already done through looking up the routing table.	     */	    IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,				&rt6_key(ip6_forward_rt.ro_rt)->sin6_addr)#endif	    ip6_forward_rt.ro_rt->rt_ifp->if_type == IFT_LOOP) {		struct in6_ifaddr *ia6 =			(struct in6_ifaddr *)ip6_forward_rt.ro_rt->rt_ifa;#ifdef MEASURE_PERFORMANCE		ctr_end = read_tsc();#ifdef MEASURE_PERFORMANCE_UDPONLY		if (ip6->ip6_nxt == IPPROTO_UDP)#else		if (1)#endif			add_performance_log(ctr_end - ctr_beg, &ip6->ip6_dst);#endif		/*		 * record address information into m_aux.		 */		(void)ip6_setdstifaddr(m, ia6);		/*		 * packets to a tentative, duplicated, or somehow invalid		 * address must not be accepted.		 */		if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) {			/* this address is ready */			ours = 1;			deliverifp = ia6->ia_ifp;	/* correct? */#if defined(__FreeBSD__) && __FreeBSD__ >= 4			/* Count the packet in the ip address stats */			ia6->ia_ifa.if_ipackets++;			ia6->ia_ifa.if_ibytes += m->m_pkthdr.len;#elif defined(__bsdi__) && _BSDI_VERSION >= 199802			/* Count the packet in the ip address stats */			ia6->ia_ifa.ifa_ipackets++;			ia6->ia_ifa.ifa_ibytes += m->m_pkthdr.len;#endif			goto hbhcheck;		} else {			/* address is not ready, so discard the packet. */			nd6log((LOG_INFO,			    "ip6_input: packet to an unready address %s->%s\n",			    ip6_sprintf(&ip6->ip6_src),			    ip6_sprintf(&ip6->ip6_dst)));			goto bad;		}	}	} /* XXX indentation (see above) */#ifdef MEASURE_PERFORMANCE	/* we detected that packet is not ours thru the basic algorithm */	ctr_end = read_tsc();#ifdef MEASURE_PERFORMANCE_UDPONLY	if (ip6->ip6_nxt == IPPROTO_UDP)#else

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?