⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 icmp6.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	 */	bzero(&sin6, sizeof(sin6));	sin6.sin6_family = AF_INET6;	sin6.sin6_len = sizeof(struct sockaddr_in6);	bcopy(&ip6->ip6_dst, &sin6.sin6_addr, sizeof(sin6.sin6_addr));	/* XXX scopeid */	if ((ia6 = (struct in6_ifaddr *)ifa_ifwithaddr((struct sockaddr *)&sin6)) != NULL) {		/* unicast/anycast, fine */		if ((ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0 &&		    (icmp6_nodeinfo & 4) == 0) {			nd6log((LOG_DEBUG, "ni6_input: ignore node info to "				"a temporary address in %s:%d",			       __FILE__, __LINE__));			goto bad;		}	} else if (IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr))		; /* link-local multicast, fine */	else		goto bad;	/* validate query Subject field. */	qtype = ntohs(ni6->ni_qtype);	subjlen = m->m_pkthdr.len - off - sizeof(struct icmp6_nodeinfo);	switch (qtype) {	case NI_QTYPE_NOOP:	case NI_QTYPE_SUPTYPES:		/* 07 draft */		if (ni6->ni_code == ICMP6_NI_SUBJ_FQDN && subjlen == 0)			break;		/* FALLTHROUGH */	case NI_QTYPE_FQDN:	case NI_QTYPE_NODEADDR:	case NI_QTYPE_IPV4ADDR:		switch (ni6->ni_code) {		case ICMP6_NI_SUBJ_IPV6:#if ICMP6_NI_SUBJ_IPV6 != 0		case 0:#endif			/*			 * backward compatibility - try to accept 03 draft			 * format, where no Subject is present.			 */			if (qtype == NI_QTYPE_FQDN && ni6->ni_code == 0 &&			    subjlen == 0) {				oldfqdn++;				break;			}#if ICMP6_NI_SUBJ_IPV6 != 0			if (ni6->ni_code != ICMP6_NI_SUBJ_IPV6)				goto bad;#endif			if (subjlen != sizeof(sin6.sin6_addr))				goto bad;			/*			 * Validate Subject address.			 *			 * Not sure what exactly "address belongs to the node"			 * means in the spec, is it just unicast, or what?			 *			 * At this moment we consider Subject address as			 * "belong to the node" if the Subject address equals			 * to the IPv6 destination address; validation for			 * IPv6 destination address should have done enough			 * check for us.			 *			 * We do not do proxy at this moment.			 */			/* m_pulldown instead of copy? */			m_copydata(m, off + sizeof(struct icmp6_nodeinfo),			    subjlen, (caddr_t)&sin6.sin6_addr);			if ((zoneid = in6_addr2zoneid(m->m_pkthdr.rcvif,						      &sin6.sin6_addr)) < 0)				goto bad;			sin6.sin6_scope_id = zoneid;							     			if (in6_embedscope(&sin6.sin6_addr, &sin6))				goto bad; /* XXX should not happen */			bzero(&sin6_d, sizeof(sin6_d));			sin6_d.sin6_family = AF_INET6; /* not used, actually */			sin6_d.sin6_len = sizeof(sin6_d); /* ditto */			sin6_d.sin6_addr = ip6->ip6_dst;			if ((zoneid = in6_addr2zoneid(m->m_pkthdr.rcvif,						      &ip6->ip6_dst)) < 0)				goto bad;			sin6_d.sin6_scope_id = zoneid;			if (in6_embedscope(&sin6_d.sin6_addr, &sin6_d))				goto bad; /* XXX should not happen */			subj = (char *)&sin6;			if (SA6_ARE_ADDR_EQUAL(&sin6, &sin6_d))				break;			/*			 * XXX if we are to allow other cases, we should really			 * be careful about scope here.			 * basically, we should disallow queries toward IPv6			 * destination X with subject Y, if scope(X) > scope(Y).			 * if we allow scope(X) > scope(Y), it will result in			 * information leakage across scope boundary.			 */			goto bad;		case ICMP6_NI_SUBJ_FQDN:			/*			 * Validate Subject name with gethostname(3).			 *			 * The behavior may need some debate, since:			 * - we are not sure if the node has FQDN as			 *   hostname (returned by gethostname(3)).			 * - the code does wildcard match for truncated names.			 *   however, we are not sure if we want to perform			 *   wildcard match, if gethostname(3) side has			 *   truncated hostname.			 */			n = ni6_nametodns(hostname, hostnamelen, 0);			if (!n || n->m_next || n->m_len == 0)				goto bad;			IP6_EXTHDR_GET(subj, char *, m,			    off + sizeof(struct icmp6_nodeinfo), subjlen);			if (subj == NULL)				goto bad;			if (!ni6_dnsmatch(subj, subjlen, mtod(n, const char *),					n->m_len)) {				goto bad;			}			m_freem(n);			n = NULL;			break;		case ICMP6_NI_SUBJ_IPV4:	/* XXX: to be implemented? */		default:			goto bad;		}		break;	}	/* refuse based on configuration.  XXX ICMP6_NI_REFUSED? */	switch (qtype) {	case NI_QTYPE_FQDN:		if ((icmp6_nodeinfo & 1) == 0)			goto bad;		break;	case NI_QTYPE_NODEADDR:	case NI_QTYPE_IPV4ADDR:		if ((icmp6_nodeinfo & 2) == 0)			goto bad;		break;	}	/* guess reply length */	switch (qtype) {	case NI_QTYPE_NOOP:		break;		/* no reply data */	case NI_QTYPE_SUPTYPES:		replylen += sizeof(u_int32_t);		break;	case NI_QTYPE_FQDN:		/* XXX will append an mbuf */		replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);		break;	case NI_QTYPE_NODEADDR:		addrs = ni6_addrs(ni6, m, &ifp, subj);		if ((replylen += addrs * (sizeof(struct in6_addr) +					  sizeof(u_int32_t))) > MCLBYTES)			replylen = MCLBYTES; /* XXX: will truncate pkt later */		break;	case NI_QTYPE_IPV4ADDR:		/* unsupported - should respond with unknown Qtype? */		goto bad;	default:		/*		 * XXX: We must return a reply with the ICMP6 code		 * `unknown Qtype' in this case.  However we regard the case		 * as an FQDN query for backward compatibility.		 * Older versions set a random value to this field,		 * so it rarely varies in the defined qtypes.		 * But the mechanism is not reliable...		 * maybe we should obsolete older versions.		 */		qtype = NI_QTYPE_FQDN;		/* XXX will append an mbuf */		replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);		oldfqdn++;		break;	}	/* allocate an mbuf to reply. */	MGETHDR(n, M_DONTWAIT, m->m_type);	if (n == NULL) {		m_freem(m);		return(NULL);	}#ifdef __OpenBSD__	M_DUP_PKTHDR(n, m); /* just for rcvif */#else	M_COPY_PKTHDR(n, m); /* just for rcvif */#endif	if (replylen > MHLEN) {		if (replylen > MCLBYTES) {			/*			 * XXX: should we try to allocate more? But MCLBYTES			 * is probably much larger than IPV6_MMTU...			 */			goto bad;		}		MCLGET(n, M_DONTWAIT);		if ((n->m_flags & M_EXT) == 0) {			goto bad;		}	}	n->m_pkthdr.len = n->m_len = replylen;	/* copy mbuf header and IPv6 + Node Information base headers */	bcopy(mtod(m, caddr_t), mtod(n, caddr_t), sizeof(struct ip6_hdr));	nni6 = (struct icmp6_nodeinfo *)(mtod(n, struct ip6_hdr *) + 1);	bcopy((caddr_t)ni6, (caddr_t)nni6, sizeof(struct icmp6_nodeinfo));	/* qtype dependent procedure */	switch (qtype) {	case NI_QTYPE_NOOP:		nni6->ni_code = ICMP6_NI_SUCCESS;		nni6->ni_flags = 0;		break;	case NI_QTYPE_SUPTYPES:	{		u_int32_t v;		nni6->ni_code = ICMP6_NI_SUCCESS;		nni6->ni_flags = htons(0x0000);	/* raw bitmap */		/* supports NOOP, SUPTYPES, FQDN, and NODEADDR */		v = (u_int32_t)htonl(0x0000000f);		bcopy(&v, nni6 + 1, sizeof(u_int32_t));		break;	}	case NI_QTYPE_FQDN:		nni6->ni_code = ICMP6_NI_SUCCESS;		fqdn = (struct ni_reply_fqdn *)(mtod(n, caddr_t) +						sizeof(struct ip6_hdr) +						sizeof(struct icmp6_nodeinfo));		nni6->ni_flags = 0; /* XXX: meaningless TTL */		fqdn->ni_fqdn_ttl = 0;	/* ditto. */		/*		 * XXX do we really have FQDN in variable "hostname"?		 */		n->m_next = ni6_nametodns(hostname, hostnamelen, oldfqdn);		if (n->m_next == NULL)			goto bad;		/* XXX we assume that n->m_next is not a chain */		if (n->m_next->m_next != NULL)			goto bad;		n->m_pkthdr.len += n->m_next->m_len;		break;	case NI_QTYPE_NODEADDR:	{		int lenlim, copied;		nni6->ni_code = ICMP6_NI_SUCCESS;		n->m_pkthdr.len = n->m_len =		    sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo);		lenlim = M_TRAILINGSPACE(n);		copied = ni6_store_addrs(ni6, nni6, ifp, lenlim);		/* XXX: reset mbuf length */		n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +			sizeof(struct icmp6_nodeinfo) + copied;		break;	}	default:		break;		/* XXX impossible! */	}	nni6->ni_type = ICMP6_NI_REPLY;	m_freem(m);	return(n);  bad:	m_freem(m);	if (n)		m_freem(n);	return(NULL);}#undef hostnamelen/* * make a mbuf with DNS-encoded string.  no compression support. * * XXX names with less than 2 dots (like "foo" or "foo.section") will be * treated as truncated name (two \0 at the end).  this is a wild guess. */static struct mbuf *ni6_nametodns(name, namelen, old)	const char *name;	int namelen;	int old;	/* return pascal string if non-zero */{	struct mbuf *m;	char *cp, *ep;	const char *p, *q;	int i, len, nterm;	if (old)		len = namelen + 1;	else		len = MCLBYTES;	/* because MAXHOSTNAMELEN is usually 256, we use cluster mbuf */	MGET(m, M_DONTWAIT, MT_DATA);	if (m && len > MLEN) {		MCLGET(m, M_DONTWAIT);		if ((m->m_flags & M_EXT) == 0)			goto fail;	}	if (!m)		goto fail;	m->m_next = NULL;	if (old) {		m->m_len = len;		*mtod(m, char *) = namelen;		bcopy(name, mtod(m, char *) + 1, namelen);		return m;	} else {		m->m_len = 0;		cp = mtod(m, char *);		ep = mtod(m, char *) + M_TRAILINGSPACE(m);		/* if not certain about my name, return empty buffer */		if (namelen == 0)			return m;		/*		 * guess if it looks like shortened hostname, or FQDN.		 * shortened hostname needs two trailing "\0".		 */		i = 0;		for (p = name; p < name + namelen; p++) {			if (*p && *p == '.')				i++;		}		if (i < 2)			nterm = 2;		else			nterm = 1;		p = name;		while (cp < ep && p < name + namelen) {			i = 0;			for (q = p; q < name + namelen && *q && *q != '.'; q++)				i++;			/* result does not fit into mbuf */			if (cp + i + 1 >= ep)				goto fail;			/*			 * DNS label length restriction, RFC1035 page 8.			 * "i == 0" case is included here to avoid returning			 * 0-length label on "foo..bar".			 */			if (i <= 0 || i >= 64)				goto fail;			*cp++ = i;			bcopy(p, cp, i);			cp += i;			p = q;			if (p < name + namelen && *p == '.')				p++;		}		/* termination */		if (cp + nterm >= ep)			goto fail;		while (nterm-- > 0)			*cp++ = '\0';		m->m_len = cp - mtod(m, char *);		return m;	}	panic("should not reach here");	/* NOTREACHED */ fail:	if (m)		m_freem(m);	return NULL;}/* * check if two DNS-encoded string matches.  takes care of truncated * form (with \0\0 at the end).  no compression support. * XXX upper/lowercase match (see RFC2065) */static intni6_dnsmatch(a, alen, b, blen)	const char *a;	int alen;	const char *b;	int blen;{	const char *a0, *b0;	int l;	/* simplest case - need validation? */	if (alen == blen && bcmp(a, b, alen) == 0)		return 1;	a0 = a;	b0 = b;	/* termination is mandatory */	if (alen < 2 || blen < 2)		return 0;	if (a0[alen - 1] != '\0' || b0[blen - 1] != '\0')		return 0;	alen--;	blen--;	while (a - a0 < alen && b - b0 < blen) {		if (a - a0 + 1 > alen || b - b0 + 1 > blen)			return 0;		if ((signed char)a[0] < 0 || (signed char)b[0] < 0)			return 0;		/* we don't support compression yet */		if (a[0] >= 64 || b[0] >= 64)			return 0;		/* truncated case */		if (a[0] == 0 && a - a0 == alen - 1)			return 1;		if (b[0] == 0 && b - b0 == blen - 1)			return 1;		if (a[0] == 0 || b[0] == 0)			return 0;		if (a[0] != b[0])			return 0;		l = a[0];		if (a - a0 + 1 + l > alen || b - b0 + 1 + l > blen)			return 0;		if (bcmp(a + 1, b + 1, l) != 0)			return 0;		a += 1 + l;		b += 1 + l;	}	if (a - a0 == alen && b - b0 == blen)		return 1;	else		return 0;}/* * calculate the number of addresses to be returned in the node info reply. */static intni6_addrs(ni6, m, ifpp, subj)	struct icmp6_nodeinfo *ni6;	struct mbuf *m;	struct ifnet **ifpp;	char *subj;{	struct ifnet *ifp;	struct in6_ifaddr *ifa6;	struct ifaddr *ifa;	struct sockaddr_in6 *subj_ip6 = NULL; /* XXX pedant */	int addrs = 0, addrsofif, iffound = 0;	int niflags = ni6->ni_flags;	if ((niflags & NI_NODEADDR_FLAG_ALL) == 0) {		switch (ni6->ni_code) {		case ICMP6_NI_SUBJ_IPV6:			if (subj == NULL) /* must be impossible... */				return(0);			subj_ip6 = (struct sockaddr_in6 *)subj;			break;		default:			/*			 * XXX: we only support IPv6 subject address for			 * this Qtype.			 */			return(0);		}	}#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)	for (ifp = ifnet; ifp; ifp = ifp->if_next)#else	for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))#endif	{		addrsofif = 0;#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)#elif defined(__FreeBSD__) && __FreeBSD__ >= 4		TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)#else

⌨️ 快捷键说明

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