ip6_input.c

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

C
2,515
字号
	if (1)#endif		add_performance_log(ctr_end - ctr_beg, &ip6->ip6_dst);#endif	/*	 * FAITH(Firewall Aided Internet Translator)	 */#if defined(NFAITH) && 0 < NFAITH	if (ip6_keepfaith) {		if (ip6_forward_rt.ro_rt && ip6_forward_rt.ro_rt->rt_ifp		 && ip6_forward_rt.ro_rt->rt_ifp->if_type == IFT_FAITH) {			/* XXX do we need more sanity checks? */			ours = 1;			deliverifp = ip6_forward_rt.ro_rt->rt_ifp; /* faith */			goto hbhcheck;		}	}#endif#ifdef NATPT	/*	 * NAT-PT (Network Address Translation - Protocol Translation)	 */	if (ip6_protocol_tr) {		struct mbuf *m1 = NULL;		switch (natpt_in6(m, &m1)) {		case IPPROTO_IP:			goto processpacket;		case IPPROTO_IPV4:			ip_forward(m1, 0);			break;		case IPPROTO_IPV6:			ip6_forward(m1, 0);			break;		case IPPROTO_MAX:		/* discard this packet	*/		default:			break;		case IPPROTO_DONE:		/* discard without free	*/			return;		}		if (m != m1)			m_freem(m);		return;	} processpacket:#endif#if 0    {	/*	 * Last resort: check in6_ifaddr for incoming interface.	 * The code is here until I update the "goto ours hack" code above	 * working right.	 */	struct ifaddr *ifa;	for (ifa = m->m_pkthdr.rcvif->if_addrlist.tqh_first;	     ifa;	     ifa = ifa->ifa_list.tqe_next) {		if (ifa->ifa_addr == NULL)			continue;	/* just for safety */		if (ifa->ifa_addr->sa_family != AF_INET6)			continue;		if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ip6->ip6_dst)) {			ours = 1;			deliverifp = ifa->ifa_ifp;			goto hbhcheck;		}	}    }#endif	/*	 * Now there is no reason to process the packet if it's not our own	 * and we're not a router.	 */	if (!ip6_forwarding) {		ip6stat.ip6s_cantforward++;		in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);                log(LOG_FAIL, "%s.%d\n", __FUNCTION__, __LINE__);		goto bad;	} hbhcheck:	/*	 * record address information into m_aux, if we don't have one yet.	 * note that we are unable to record it, if the address is not listed	 * as our interface address (e.g. multicast addresses, addresses	 * within FAITH prefixes and such).	 */	if (deliverifp && !ip6_getdstifaddr(m)) {		struct in6_ifaddr *ia6;		ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst);		if (ia6) {			if (!ip6_setdstifaddr(m, ia6)) {				/*				 * XXX maybe we should drop the packet here,				 * as we could not provide enough information				 * to the upper layers.				 */			}		}	}	/*	 * Process Hop-by-Hop options header if it's contained.	 * m may be modified in ip6_hopopts_input().	 * If a JumboPayload option is included, plen will also be modified.	 */	plen = (u_int32_t)ntohs(ip6->ip6_plen);	if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {		struct ip6_hbh *hbh;		if (ip6_hopopts_input(&plen, &rtalert, &m, &off)) {#if 0	/*touches NULL pointer*/			in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);#endif			return;	/* m have already been freed */		}		/* adjust pointer */		ip6 = mtod(m, struct ip6_hdr *);		/*		 * if the payload length field is 0 and the next header field		 * indicates Hop-by-Hop Options header, then a Jumbo Payload		 * option MUST be included.		 */		if (ip6->ip6_plen == 0 && plen == 0) {			/*			 * Note that if a valid jumbo payload option is			 * contained, ip6_hoptops_input() must set a valid			 * (non-zero) payload length to the variable plen. 			 */			ip6stat.ip6s_badoptions++;			in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);			in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr);			icmp6_error(m, ICMP6_PARAM_PROB,				    ICMP6_PARAMPROB_HEADER,				    (caddr_t)&ip6->ip6_plen - (caddr_t)ip6);			return;		}#ifndef PULLDOWN_TEST		/* ip6_hopopts_input() ensures that mbuf is contiguous */		hbh = (struct ip6_hbh *)(ip6 + 1);#else		IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),			sizeof(struct ip6_hbh));		if (hbh == NULL) {			ip6stat.ip6s_tooshort++;			return;		}#endif		nxt = hbh->ip6h_nxt;		/*		 * accept the packet if a router alert option is included		 * and we act as an IPv6 router.		 */		if (rtalert != ~0 && ip6_forwarding)			ours = 1;	} else		nxt = ip6->ip6_nxt;	/*	 * Check that the amount of data in the buffers	 * is as at least much as the IPv6 header would have us expect.	 * Trim mbufs if longer than we expect.	 * Drop packet if shorter than we expect.	 */	if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) {		ip6stat.ip6s_tooshort++;		in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated);		goto bad;	}	if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) {		if (m->m_len == m->m_pkthdr.len) {			m->m_len = sizeof(struct ip6_hdr) + plen;			m->m_pkthdr.len = sizeof(struct ip6_hdr) + plen;		} else			m_adj(m, sizeof(struct ip6_hdr) + plen - m->m_pkthdr.len);	}	/*	 * Forward if desirable.	 */	if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {		/*		 * If we are acting as a multicast router, all		 * incoming multicast packets are passed to the		 * kernel-level multicast forwarding function.		 * The packet is returned (relatively) intact; if		 * ip6_mforward() returns a non-zero value, the packet		 * must be discarded, else it may be accepted below.		 */		if (ip6_mrouter && ip6_mforward(ip6, m->m_pkthdr.rcvif, m)) {			ip6stat.ip6s_cantforward++;			m_freem(m);			return;		}		if (!ours) {			m_freem(m);			return;		}	} else if (!ours) {		ip6_forward(m, 0);		return;	}		ip6 = mtod(m, struct ip6_hdr *);	/*	 * 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.	 *	 * For SIIT end node behavior, you may want to disable the check.	 * However, you will  become vulnerable to attacks using IPv4 mapped	 * source.	 */	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;	}	/*	 * Tell launch routine the next header	 */#if defined(__NetBSD__) && defined(IFA_STATS)	if (deliverifp != NULL) {		struct in6_ifaddr *ia6;		ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst);		if (ia6)			ia6->ia_ifa.ifa_data.ifad_inbytes += m->m_pkthdr.len;	}#endif	ip6stat.ip6s_delivered++;	in6_ifstat_inc(deliverifp, ifs6_in_deliver);	nest = 0;	while (nxt != IPPROTO_DONE) {		if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) {			ip6stat.ip6s_toomanyhdr++;                        log(LOG_FAIL, "%s.%d\n", __FUNCTION__, __LINE__);			goto bad;		}		/*		 * protection against faulty packet - there should be		 * more sanity checks in header chain processing.		 */		if (m->m_pkthdr.len < off) {			ip6stat.ip6s_tooshort++;			in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated);                        log(LOG_FAIL, "%s.%d\n", __FUNCTION__, __LINE__);			goto bad;		}#if 0		/*		 * do we need to do it for every header?  yeah, other		 * functions can play with it (like re-allocate and copy).		 */		mhist = ip6_addaux(m);		if (mhist && M_TRAILINGSPACE(mhist) >= sizeof(nxt)) {			hist = mtod(mhist, caddr_t) + mhist->m_len;			bcopy(&nxt, hist, sizeof(nxt));			mhist->m_len += sizeof(nxt);		} else {			ip6stat.ip6s_toomanyhdr++;                        log(LOG_FAIL, "%s.%d\n", __FUNCTION__, __LINE__);			goto bad;		}#endif#if defined(IPSEC) && !defined(__OpenBSD__)		/*		 * 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[ip6_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&		    ipsec6_in_reject(m, NULL)) {			ipsec6stat.in_polvio++;			goto bad;		}#endif#ifdef MIP6		/*		 * XXX		 * check if the packet was tunneled after all extion		 * headers have been processed.  get from Ericsson		 * code.  need more consideration.		 */		if ((nxt != IPPROTO_HOPOPTS) && (nxt != IPPROTO_DSTOPTS) &&		    (nxt != IPPROTO_ROUTING) && (nxt != IPPROTO_FRAGMENT) &&		    (nxt != IPPROTO_ESP) && (nxt != IPPROTO_AH)) {			if (mip6_route_optimize(m))				goto bad;		}#endif /* MIP6 */				nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt);	}	return; bad:	m_freem(m);}/* * set/grab in6_ifaddr correspond to IPv6 destination address. * XXX backward compatibility wrapper */static struct mbuf *ip6_setdstifaddr(m, ia6)	struct mbuf *m;	struct in6_ifaddr *ia6;{	struct mbuf *n;	n = ip6_addaux(m);	if (n)		mtod(n, struct ip6aux *)->ip6a_dstia6 = ia6;	return n;	/* NULL if failed to set */}struct in6_ifaddr *ip6_getdstifaddr(m)	struct mbuf *m;{	struct mbuf *n;	n = ip6_findaux(m);	if (n)		return mtod(n, struct ip6aux *)->ip6a_dstia6;	else		return NULL;}/* * Hop-by-Hop options header processing. If a valid jumbo payload option is * included, the real payload length will be stored in plenp. */static intip6_hopopts_input(plenp, rtalertp, mp, offp)	u_int32_t *plenp;	u_int32_t *rtalertp;	/* XXX: should be stored more smart way */	struct mbuf **mp;	int *offp;{	struct mbuf *m = *mp;	int off = *offp, hbhlen;	struct ip6_hbh *hbh;	u_int8_t *opt;	/* validation of the length of the header */#ifndef PULLDOWN_TEST	IP6_EXTHDR_CHECK(m, off, sizeof(*hbh), -1);	hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off);	hbhlen = (hbh->ip6h_len + 1) << 3;	IP6_EXTHDR_CHECK(m, off, hbhlen, -1);	hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off);#else	IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m,		sizeof(struct ip6_hdr), sizeof(struct ip6_hbh));	if (hbh == NULL) {		ip6stat.ip6s_tooshort++;		return -1;	}	hbhlen = (hbh->ip6h_len + 1) << 3;	IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),		hbhlen);	if (hbh == NULL) {		ip6stat.ip6s_tooshort++;		return -1;	}#endif	off += hbhlen;	hbhlen -= sizeof(struct ip6_hbh);	opt = (u_int8_t *)hbh + sizeof(struct ip6_hbh);	if (ip6_process_hopopts(m, (u_int8_t *)hbh + sizeof(struct ip6_hbh),				hbhlen, rtalertp, plenp) < 0)		return(-1);	*offp = off;	*mp = m;	return(0);}/* * Search header for all Hop-by-hop options and process each option. * This function is separate from ip6_hopopts_input() in order to * handle a case where the sending node itself process its hop-by-hop * options header. In such a case, the function is called from ip6_output(). * * The function assumes that hbh header is located right after the IPv6 header * (RFC2460 p7), opthead is pointer into data content in m, and opthead to * opthead + hbhlen is located in continuous memory region. */intip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp)	struct mbuf *m;	u_int8_t *opthead;	int hbhlen;	u_int32_t *rtalertp;	u_int32_t *plenp;{	struct ip6_hdr *ip6;	int optlen = 0;	u_int8_t *opt = opthead;	u_int16_t rtalert_val;	u_int32_t jumboplen;	const int erroff = sizeof(struct ip6_hdr) + sizeof(struct ip6_hbh);	for (; hbhlen > 0; hbhlen -= optlen, opt += optlen) {		switch (*opt) {		case IP6OPT_PAD1:			optlen = 1;			break;		case IP6OPT_PADN:			if (hbhlen < IP6OPT_MINLEN) {				ip6stat.ip6s_toosmall++;				goto bad;			}			optlen = *(opt + 1) + 2;			break;		case IP6OPT_RTALERT:			/* XXX may need check for alignment */			if (hbhlen < IP6OPT_RTALERT_LEN) {				ip6stat.ip6s_toosmall++;				goto bad;			}			if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2) {				/* XXX stat */				icmp6_error(m, ICMP6_PARAM_PROB,					    ICMP6_PARAMPROB_HEADER,					    erroff + opt + 1 - opthead);				return(-1);			}			optlen = IP6OPT_RTALERT_LEN;			bcopy((caddr_t)(opt + 2), (caddr_t)&rtalert_val, 2);			*rtalertp = ntohs(rtalert_val);			break;		case IP6OPT_JUMBO:			/* XXX may need check for alignment */			if (hbhlen < IP6OPT_JUMBO_LEN) {				ip6stat.ip6s_toosmall++;				goto bad;			}			if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2) {				/* XXX stat */				icmp6_error(m, ICMP6_PARAM_PROB,					    ICMP6_PARAMPROB_HEADER,					    erroff + opt + 1 - opthead);				return(-1);			}			optlen = IP6OPT_JUMBO_LEN;			/*			 * IPv6 packets that have non 0 payload length			 * must not contain a jumbo payload option.			 */			ip6 = mtod(m, struct ip6_hdr *);			if (ip6->ip6_plen) {				ip6stat.ip6s_badoptions++;				icmp6_error(m, ICMP6_PARAM_PROB,					    ICMP6_PARAMPROB_HEADER,					    erroff + opt - opthead);				return(-1);			}			/*			 * We may see jumbolen in unaligned location, so			 * we'd need to perform bcopy().			 */			bcopy(opt + 2, &jumboplen, sizeof(jumboplen));			jumboplen = (u_int32_t)htonl(jumboplen);#if 1			/*			 * if there are multiple jumbo payload options,			 * *plenp will be non-zero and the packet will be			 * rejected.			 * the behavior may need some debate in ipngwg -			 * multiple options does not make sense, however,			 * there's no explicit mention in specification.			 */			if (*plenp != 0) {				ip6stat.ip6s_badoptions++;				icmp6_error(m, ICMP6_PARAM_PROB,					    ICMP6_PARAMPROB_HEADER,					    erroff + opt + 2 - opthead);				return(-1);			}

⌨️ 快捷键说明

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