Пример #1
0
/*
 * generate standard sockaddr_in6 from embedded form.
 */
int
sa6_recoverscope(struct sockaddr_in6 *sin6)
{
	char ip6buf[INET6_ADDRSTRLEN];
	u_int32_t zoneid;

	if (sin6->sin6_scope_id != 0) {
		log(LOG_NOTICE,
		    "sa6_recoverscope: assumption failure (non 0 ID): %s%%%d\n",
		    ip6_sprintf(ip6buf, &sin6->sin6_addr), sin6->sin6_scope_id);
		/* XXX: proceed anyway... */
	}
	if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
	    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) {
		/*
		 * KAME assumption: link id == interface id
		 */
		zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]);
		if (zoneid) {
			/* sanity check */
			if (zoneid < 0 || V_if_index < zoneid)
				return (ENXIO);
			if (!ifnet_byindex(zoneid))
				return (ENXIO);
			sin6->sin6_addr.s6_addr16[1] = 0;
			sin6->sin6_scope_id = zoneid;
		}
	}

	return 0;
}
Пример #2
0
/*
 * generate standard sockaddr_in6 from embedded form.
 */
int
sa6_recoverscope(struct sockaddr_in6 *sin6)
{
	u_int32_t zoneid;

	if (sin6->sin6_scope_id != 0) {
		log(LOG_NOTICE,
		    "sa6_recoverscope: assumption failure (non 0 ID): %s%%%d\n",
		    ip6_sprintf(&sin6->sin6_addr), sin6->sin6_scope_id);
		/* XXX: proceed anyway... */
	}
	if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
	    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) {
		/*
		 * KAME assumption: link id == interface id
		 */
		zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]);
		if (zoneid) {
			/* sanity check */
			if (zoneid < 0 || if_indexlim <= zoneid)
				return (ENXIO);
#ifdef __FreeBSD__
			if (ifnet_byindex(zoneid) == NULL)
#else
			if (ifindex2ifnet[zoneid] == NULL)
#endif
				return (ENXIO);
			sin6->sin6_addr.s6_addr16[1] = 0;
			sin6->sin6_scope_id = zoneid;
		}
	}

	return 0;
}
Пример #3
0
/*
 * Determine the appropriate scope zone ID for in6 and ifp.  If ret_id is
 * non NULL, it is set to the zone ID.  If the zone ID needs to be embedded
 * in the in6_addr structure, in6 will be modified. 
 *
 * ret_id - unnecessary?
 */
int
in6_setscope(struct in6_addr *in6, struct ifnet *ifp, u_int32_t *ret_id)
{
	int scope;
	u_int32_t zoneid = 0;
	struct scope6_id *sid = SID(ifp);

#ifdef DIAGNOSTIC
	if (sid == NULL) { /* should not happen */
		panic("in6_setscope: scope array is NULL");
		/* NOTREACHED */
	}
#endif

	/*
	 * special case: the loopback address can only belong to a loopback
	 * interface.
	 */
	if (IN6_IS_ADDR_LOOPBACK(in6)) {
		if (!(ifp->if_flags & IFF_LOOPBACK))
			return (EINVAL);
		else {
			if (ret_id != NULL)
				*ret_id = 0; /* there's no ambiguity */
			return (0);
		}
	}

	scope = in6_addrscope(in6);

	switch (scope) {
	case IPV6_ADDR_SCOPE_INTFACELOCAL: /* should be interface index */
		zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL];
		break;

	case IPV6_ADDR_SCOPE_LINKLOCAL:
		zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL];
		break;

	case IPV6_ADDR_SCOPE_SITELOCAL:
		zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL];
		break;

	case IPV6_ADDR_SCOPE_ORGLOCAL:
		zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL];
		break;

	default:
		zoneid = 0;	/* XXX: treat as global. */
		break;
	}

	if (ret_id != NULL)
		*ret_id = zoneid;

	if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6))
		in6->s6_addr16[1] = htons(zoneid & 0xffff); /* XXX */

	return (0);
}
Пример #4
0
/*
 * Validate the specified scope zone ID in the sin6_scope_id field.  If the ID
 * is unspecified (=0), needs to be specified, and the default zone ID can be
 * used, the default value will be used.
 * This routine then generates the kernel-internal form: if the address scope
 * of is interface-local or link-local, embed the interface index in the
 * address.
 */
int
sa6_embedscope(struct sockaddr_in6 *sin6, int defaultok)
{
	struct ifnet *ifp;
	u_int32_t zoneid;

	if ((zoneid = sin6->sin6_scope_id) == 0 && defaultok)
		zoneid = scope6_addr2default(&sin6->sin6_addr);

	if (zoneid != 0 &&
	    (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
	    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr))) {
		/*
		 * At this moment, we only check interface-local and
		 * link-local scope IDs, and use interface indices as the
		 * zone IDs assuming a one-to-one mapping between interfaces
		 * and links.
		 */
		if (V_if_index < zoneid)
			return (ENXIO);
		ifp = ifnet_byindex(zoneid);
		if (ifp == NULL) /* XXX: this can happen for some OS */
			return (ENXIO);

		/* XXX assignment to 16bit from 32bit variable */
		sin6->sin6_addr.s6_addr16[1] = htons(zoneid & 0xffff);

		sin6->sin6_scope_id = 0;
	}

	return 0;
}
Пример #5
0
/*
 * generate standard sockaddr_in6 from embedded form.
 */
int
sa6_recoverscope(struct sockaddr_in6 *sin6)
{
	uint32_t zoneid;

	if (sin6->sin6_scope_id != 0) {
		log(LOG_NOTICE,
		    "sa6_recoverscope: assumption failure (non 0 ID): %s%%%d\n",
		    ip6_sprintf(&sin6->sin6_addr), sin6->sin6_scope_id);
		/* XXX: proceed anyway... */
	}
	if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
	    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) {
		/*
		 * KAME assumption: link id == interface id
		 */
		zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]);
		if (zoneid) {
			int s = pserialize_read_enter();
			if (!if_byindex(zoneid)) {
				pserialize_read_exit(s);
				return (ENXIO);
			}
			pserialize_read_exit(s);
			sin6->sin6_addr.s6_addr16[1] = 0;
			sin6->sin6_scope_id = zoneid;
		}
	}

	return 0;
}
Пример #6
0
/*
 * Return the scope identifier or zero.
 */
uint16_t
in6_getscope(struct in6_addr *in6)
{

	if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6))
		return (in6->s6_addr16[1]);

	return (0);
}
Пример #7
0
/*
 * Just clear the embedded scope identifier.  Return 0 if the original address
 * is intact; return non 0 if the address is modified.
 */
int
in6_clearscope(struct in6_addr *in6)
{
	int modified = 0;

	if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) {
		if (in6->s6_addr16[1] != 0)
			modified = 1;
		in6->s6_addr16[1] = 0;
	}

	return (modified);
}
Пример #8
0
/*
 * Print the textual representation (as given by inet_ntop(3)) of the address
 * set in "sa".
 *
 * Return the total length of the string it tried to create or 0 if an error
 * occured, in which case errno is set.  On success, the constructed string
 * is guaranteed to be NUL-terminated.  Overflow must be detected by checking
 * the returned size against buflen.
 *
 */
static size_t
asr_print_addr(const struct sockaddr *sa, char *buf, size_t buflen)
{
	unsigned int ifidx;
	char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
	char scope[IF_NAMESIZE + 1], *ifname;
	const void *addr;
	size_t s;

	switch(sa->sa_family) {
	case AF_INET:
		addr = &SA_IN(sa)->sin_addr;
		break;
	case AF_INET6:
		addr = &SA_IN6(sa)->sin6_addr;
		break;
	default:
		errno = EINVAL;
		return (0);
	}

	if (inet_ntop(sa->sa_family, addr, tmp, sizeof(tmp)) == NULL)
		return (0); /* errno set */

	s = strlcpy(buf, tmp, buflen);

	if (sa->sa_family == AF_INET6 && SA_IN6(sa)->sin6_scope_id) {

		scope[0] = SCOPE_DELIMITER;
		scope[1] = '\0';

		ifidx = SA_IN6(sa)->sin6_scope_id;
		ifname = NULL;

		if (IN6_IS_ADDR_LINKLOCAL(&(SA_IN6(sa)->sin6_addr)) ||
		    IN6_IS_ADDR_MC_LINKLOCAL(&(SA_IN6(sa)->sin6_addr)) ||
		    IN6_IS_ADDR_MC_INTFACELOCAL(&(SA_IN6(sa)->sin6_addr)))
			ifname = if_indextoname(ifidx, scope + 1);

		if (ifname == NULL)
			(void)snprintf(scope + 1, sizeof(scope) - 1, "%u", ifidx);

		if (s < buflen)
			(void)strlcat(buf, scope, buflen);

		s += strlen(scope);
	}

	return (s);
}
Пример #9
0
/*
 * generate standard sockaddr_in6 from embedded form.
 */
int
sa6_recoverscope(struct sockaddr_in6 *sin6, boolean_t attachcheck)
{
	u_int32_t zoneid;

	if (sin6->sin6_scope_id != 0) {
		log(LOG_NOTICE,
		    "sa6_recoverscope: assumption failure (non 0 ID): %s%%%d\n",
		    ip6_sprintf(&sin6->sin6_addr), sin6->sin6_scope_id);
		/* XXX: proceed anyway... */
	}
	if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
	    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) {
		/*
		 * KAME assumption: link id == interface id
		 */
		zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]);
		if (zoneid) {
			/* sanity check */
			if (if_index < zoneid)
				return (ENXIO);
			/*
			 * We use the attachcheck parameter to skip the
			 * interface attachment check.
			 * Some callers might hold the ifnet_head lock in
			 * exclusive mode. This means that:
			 * 1) the interface can't go away -- hence we don't
			 *    need to perform this check
			 * 2) we can't perform this check because the lock is
			 *    in exclusive mode and trying to lock it in shared
			 *    mode would cause a deadlock.
			 */
			if (attachcheck) {
				ifnet_head_lock_shared();
				if (ifindex2ifnet[zoneid] == NULL) {
					ifnet_head_done();
					return (ENXIO);
				}
				ifnet_head_done();
			}
			sin6->sin6_addr.s6_addr16[1] = 0;
			sin6->sin6_scope_id = zoneid;
		}
	}

	return (0);
}
Пример #10
0
Файл: if.c Проект: yellowman/nsh
void
ipv6ll_db_store(struct sockaddr_in6 *sin6, struct sockaddr_in6 *sin6mask,
    int dbflag, char *ifname)
{
	/*
	 * If linklocal, store a version that will match conf output
	 * with no scope id, ifname in separate database field
	 */
	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
	    IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr) ||
	    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) {
		sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
		sin6->sin6_scope_id = 0;
		db_delete_flag_x_ctl_data("ipv6linklocal", ifname,
		    netname6(sin6, sin6mask));
		if (dbflag != DB_X_REMOVE)
			db_insert_flag_x("ipv6linklocal", ifname, 0,
			    dbflag, netname6(sin6, sin6mask));
	}
}
Пример #11
0
/*
 * generate standard sockaddr_in6 from embedded form.
 */
int
sa6_recoverscope(struct sockaddr_in6 *sin6)
{
	char ip6buf[INET6_ADDRSTRLEN];
	u_int32_t zoneid;

	if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
	    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) {
		/*
		 * KAME assumption: link id == interface id
		 */
		zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]);
		if (zoneid) {
			/* sanity check */
			if (V_if_index < zoneid)
				return (ENXIO);
#if 0
			/* XXX: Disabled due to possible deadlock. */
			if (!ifnet_byindex(zoneid))
				return (ENXIO);
#endif
			if (sin6->sin6_scope_id != 0 &&
			    zoneid != sin6->sin6_scope_id) {
				log(LOG_NOTICE,
				    "%s: embedded scope mismatch: %s%%%d. "
				    "sin6_scope_id was overridden.", __func__,
				    ip6_sprintf(ip6buf, &sin6->sin6_addr),
				    sin6->sin6_scope_id);
			}
			sin6->sin6_addr.s6_addr16[1] = 0;
			sin6->sin6_scope_id = zoneid;
		}
	}

	return 0;
}
Пример #12
0
Файл: conf.c Проект: sthen/nsh
int
ipv6ll_db_compare(struct sockaddr_in6 *sin6, struct sockaddr_in6 *sin6mask,
    char *ifname)
{
	int count, scope;
	StringList *data;
	struct in6_addr store;

	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
	    IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr) ||
	    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) {
		/*
		 * Save any scope or embedded scope.
		 * The kernel does not set sin6_scope_id.
		 * But if it ever does, we're already prepared.
		 */
		store.s6_addr[0] = sin6->sin6_addr.s6_addr[2];
		store.s6_addr[1] = sin6->sin6_addr.s6_addr[3];
		sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
		scope = sin6->sin6_scope_id;
		sin6->sin6_scope_id = 0;
		
		data = sl_init();
		db_select_flag_x_ctl_data(data, "ipv6linklocal", ifname,
		    netname6(sin6, sin6mask));
		count = data->sl_cur;
		sl_free(data, 1);

		/* restore any scope or embedded scope */
		sin6->sin6_addr.s6_addr[2] = store.s6_addr[0];
		sin6->sin6_addr.s6_addr[3] = store.s6_addr[1];
		sin6->sin6_scope_id = scope;
		return(count);
	}
	return 1;
}
Пример #13
0
/*
 * Determine the appropriate scope zone ID for in6 and ifp.  If ret_id is
 * non NULL, it is set to the zone ID.  If the zone ID needs to be embedded
 * in the in6_addr structure, in6 will be modified.
 *
 * ret_id - unnecessary?
 */
int
in6_setscope(struct in6_addr *in6, struct ifnet *ifp, u_int32_t *ret_id)
{
	int scope;
	u_int32_t zoneid = 0;
	struct scope6_id *sid;

	/*
	 * special case: the loopback address can only belong to a loopback
	 * interface.
	 */
	if (IN6_IS_ADDR_LOOPBACK(in6)) {
		if (!(ifp->if_flags & IFF_LOOPBACK)) {
			return (EINVAL);
		} else {
			if (ret_id != NULL)
				*ret_id = 0; /* there's no ambiguity */
			return (0);
		}
	}

	scope = in6_addrscope(in6);

	if_inet6data_lock_shared(ifp);
	if (IN6_IFEXTRA(ifp) == NULL) {
		if_inet6data_lock_done(ifp);
		if (ret_id)
			*ret_id = 0;
		return (EINVAL);
	}
	sid = SID(ifp);
	switch (scope) {
	case IPV6_ADDR_SCOPE_INTFACELOCAL: /* should be interface index */
		zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL];
		break;

	case IPV6_ADDR_SCOPE_LINKLOCAL:
		zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL];
		break;

	case IPV6_ADDR_SCOPE_SITELOCAL:
		zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL];
		break;

	case IPV6_ADDR_SCOPE_ORGLOCAL:
		zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL];
		break;
	default:
		zoneid = 0;	/* XXX: treat as global. */
		break;
	}
	if_inet6data_lock_done(ifp);

	if (ret_id != NULL)
		*ret_id = zoneid;

	if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6))
		in6->s6_addr16[1] = htons(zoneid & 0xffff); /* XXX */

	return (0);
}
Пример #14
0
int
ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
{
	struct mf6c *rt;
	struct mif6 *mifp;
	struct mbuf *mm;
	int s;
	mifi_t mifi;
	struct sockaddr_in6 sin6;
	char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN];

	inet_ntop(AF_INET6, &ip6->ip6_src, src, sizeof(src));
	inet_ntop(AF_INET6, &ip6->ip6_dst, dst, sizeof(dst));
#ifdef MRT6DEBUG
	if (mrt6debug & DEBUG_FORWARD)
		log(LOG_DEBUG, "ip6_mforward: src %s, dst %s, ifindex %d\n",
		    src, dst, ifp->if_index);
#endif

	/*
	 * Don't forward a packet with Hop limit of zero or one,
	 * or a packet destined to a local-only group.
	 */
	if (ip6->ip6_hlim <= 1 || IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) ||
	    IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst))
		return 0;
	ip6->ip6_hlim--;

	/*
	 * Source address check: do not forward packets with unspecified
	 * source. It was discussed in July 2000, on ipngwg mailing list.
	 * This is rather more serious than unicast cases, because some
	 * MLD packets can be sent with the unspecified source address
	 * (although such packets must normally set 1 to the hop limit field).
	 */
	if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
		ip6stat.ip6s_cantforward++;
		if (ip6_log_time + ip6_log_interval < time_second) {
			ip6_log_time = time_second;
			log(LOG_DEBUG,
			    "cannot forward "
			    "from %s to %s nxt %d received on interface %u\n",
			    src, dst,
			    ip6->ip6_nxt,
			    m->m_pkthdr.ph_ifidx);
		}
		return 0;
	}

	/*
	 * Determine forwarding mifs from the forwarding cache table
	 */
	s = splsoftnet();
	MF6CFIND(ip6->ip6_src, ip6->ip6_dst, rt);

	/* Entry exists, so forward if necessary */
	if (rt) {
		splx(s);
		return (ip6_mdq(m, ifp, rt));
	} else {
		/*
		 * If we don't have a route for packet's origin,
		 * Make a copy of the packet &
		 * send message to routing daemon
		 */

		struct mbuf *mb0;
		struct rtdetq *rte;
		u_long hash;

		mrt6stat.mrt6s_no_route++;
#ifdef MRT6DEBUG
		if (mrt6debug & (DEBUG_FORWARD | DEBUG_MFC))
			log(LOG_DEBUG, "ip6_mforward: no rte s %s g %s\n",
			    src, dst);
#endif

		/*
		 * Allocate mbufs early so that we don't do extra work if we
		 * are just going to fail anyway.
		 */
		rte = (struct rtdetq *)malloc(sizeof(*rte), M_MRTABLE,
					      M_NOWAIT);
		if (rte == NULL) {
			splx(s);
			return ENOBUFS;
		}
		mb0 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
		/*
		 * Pullup packet header if needed before storing it,
		 * as other references may modify it in the meantime.
		 */
		if (mb0 &&
		    (M_READONLY(mb0) || mb0->m_len < sizeof(struct ip6_hdr)))
			mb0 = m_pullup(mb0, sizeof(struct ip6_hdr));
		if (mb0 == NULL) {
			free(rte, M_MRTABLE, 0);
			splx(s);
			return ENOBUFS;
		}

		/* is there an upcall waiting for this packet? */
		hash = MF6CHASH(ip6->ip6_src, ip6->ip6_dst);
		for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) {
			if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src,
					       &rt->mf6c_origin.sin6_addr) &&
			    IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
					       &rt->mf6c_mcastgrp.sin6_addr) &&
			    (rt->mf6c_stall != NULL))
				break;
		}

		if (rt == NULL) {
			struct mrt6msg *im;

			/* no upcall, so make a new entry */
			rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE,
						  M_NOWAIT);
			if (rt == NULL) {
				free(rte, M_MRTABLE, 0);
				m_freem(mb0);
				splx(s);
				return ENOBUFS;
			}
			/*
			 * Make a copy of the header to send to the user
			 * level process
			 */
			mm = m_copym(mb0, 0, sizeof(struct ip6_hdr), M_NOWAIT);

			if (mm == NULL) {
				free(rte, M_MRTABLE, 0);
				m_freem(mb0);
				free(rt, M_MRTABLE, 0);
				splx(s);
				return ENOBUFS;
			}

			/*
			 * Send message to routing daemon
			 */
			(void)memset(&sin6, 0, sizeof(sin6));
			sin6.sin6_len = sizeof(sin6);
			sin6.sin6_family = AF_INET6;
			sin6.sin6_addr = ip6->ip6_src;

			im = NULL;
			switch (ip6_mrouter_ver) {
			case MRT6_INIT:
				im = mtod(mm, struct mrt6msg *);
				im->im6_msgtype = MRT6MSG_NOCACHE;
				im->im6_mbz = 0;
				break;
			default:
				free(rte, M_MRTABLE, 0);
				m_freem(mb0);
				free(rt, M_MRTABLE, 0);
				splx(s);
				return EINVAL;
			}

#ifdef MRT6DEBUG
			if (mrt6debug & DEBUG_FORWARD)
				log(LOG_DEBUG,
				    "getting the iif info in the kernel\n");
#endif

			for (mifp = mif6table, mifi = 0;
			     mifi < nummifs && mifp->m6_ifp != ifp;
			     mifp++, mifi++)
				;

			switch (ip6_mrouter_ver) {
			case MRT6_INIT:
				im->im6_mif = mifi;
				break;
			}

			if (socket6_send(ip6_mrouter, mm, &sin6) < 0) {
				log(LOG_WARNING, "ip6_mforward: ip6_mrouter "
				    "socket queue full\n");
				mrt6stat.mrt6s_upq_sockfull++;
				free(rte, M_MRTABLE, 0);
				m_freem(mb0);
				free(rt, M_MRTABLE, 0);
				splx(s);
				return ENOBUFS;
			}

			mrt6stat.mrt6s_upcalls++;

			/* insert new entry at head of hash chain */
			bzero(rt, sizeof(*rt));
			rt->mf6c_origin.sin6_family = AF_INET6;
			rt->mf6c_origin.sin6_len = sizeof(struct sockaddr_in6);
			rt->mf6c_origin.sin6_addr = ip6->ip6_src;
			rt->mf6c_mcastgrp.sin6_family = AF_INET6;
			rt->mf6c_mcastgrp.sin6_len = sizeof(struct sockaddr_in6);
			rt->mf6c_mcastgrp.sin6_addr = ip6->ip6_dst;
			rt->mf6c_expire = UPCALL_EXPIRE;
			n6expire[hash]++;
			rt->mf6c_parent = MF6C_INCOMPLETE_PARENT;

			/* link into table */
			rt->mf6c_next  = mf6ctable[hash];
			mf6ctable[hash] = rt;
			/* Add this entry to the end of the queue */
			rt->mf6c_stall = rte;
		} else {
			/* determine if q has overflowed */
			struct rtdetq **p;
			int npkts = 0;

			for (p = &rt->mf6c_stall; *p != NULL; p = &(*p)->next)
				if (++npkts > MAX_UPQ6) {
					mrt6stat.mrt6s_upq_ovflw++;
					free(rte, M_MRTABLE, 0);
					m_freem(mb0);
					splx(s);
					return 0;
				}

			/* Add this entry to the end of the queue */
			*p = rte;
		}

		rte->next = NULL;
		rte->m = mb0;
		rte->ifp = ifp;
		splx(s);

		return 0;
	}
Пример #15
0
static void
print_addr(struct sockaddr *sa, struct sockaddr **rtinfo, struct if_data *ifd)
{
	struct sockaddr_dl *sdl;
	struct sockaddr_in *sin;
	struct sockaddr_in6 *sin6;
	char *cp;
	int m, n;

	switch (sa->sa_family) {
	case AF_UNSPEC:
		printf("%-11.11s ", "none");
		printf("%-17.17s ", "none");
		break;
	case AF_INET:
		sin = (struct sockaddr_in *)sa;
		cp = netname4(sin->sin_addr.s_addr,
		    ((struct sockaddr_in *)rtinfo[RTAX_NETMASK])->sin_addr.s_addr);
		if (vflag)
			n = strlen(cp) < 11 ? 11 : strlen(cp);
		else
			n = 11;
		printf("%-*.*s ", n, n, cp);
		cp = routename4(sin->sin_addr.s_addr);
		if (vflag)
			n = strlen(cp) < 17 ? 17 : strlen(cp);
		else
			n = 17;
		printf("%-*.*s ", n, n, cp);

#if 0
		if (aflag) {
			u_long multiaddr;
			struct in_multi inm;

			multiaddr = (u_long)LIST_FIRST(&ifaddr.in.ia_multiaddrs);
			while (multiaddr != 0) {
				kread(multiaddr, &inm, sizeof inm);
				printf("\n%25s %-17.17s ", "",
				    routename4(inm.inm_addr.s_addr));
				multiaddr = (u_long)LIST_NEXT(&inm, inm_list);
			}
		}
#endif
		break;
	case AF_INET6:
		sin6 = (struct sockaddr_in6 *)sa;
#ifdef __KAME__
		if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
			sin6->sin6_scope_id =
			    ntohs(*(u_int16_t *)
			    &sin6->sin6_addr.s6_addr[2]);
			sin6->sin6_addr.s6_addr[2] = 0;
			sin6->sin6_addr.s6_addr[3] = 0;
		}
#endif
		cp = netname6(sin6,
		    (struct sockaddr_in6 *)rtinfo[RTAX_NETMASK]);
		if (vflag)
			n = strlen(cp) < 11 ? 11 : strlen(cp);
		else
			n = 11;
		printf("%-*.*s ", n, n, cp);
		cp = routename6(sin6);
		if (vflag)
			n = strlen(cp) < 17 ? 17 : strlen(cp);
		else
			n = 17;
		printf("%-*.*s ", n, n, cp);
#if 0
		if (aflag) {
			u_long multiaddr;
			struct in6_multi inm;
			struct sockaddr_in6 m6;

			multiaddr = (u_long)LIST_FIRST(&ifaddr.in6.ia6_multiaddrs);
			while (multiaddr != 0) {
				kread(multiaddr, &inm, sizeof inm);
				memset(&m6, 0, sizeof(m6));
				m6.sin6_len = sizeof(struct sockaddr_in6);
				m6.sin6_family = AF_INET6;
				m6.sin6_addr = inm.in6m_addr;
#ifdef __KAME__
				if (IN6_IS_ADDR_MC_LINKLOCAL(&m6.sin6_addr) ||
				    IN6_IS_ADDR_MC_INTFACELOCAL(&m6.sin6_addr)) {
					m6.sin6_scope_id =
					    ntohs(*(u_int16_t *)
					    &m6.sin6_addr.s6_addr[2]);
					m6.sin6_addr.s6_addr[2] = 0;
					m6.sin6_addr.s6_addr[3] = 0;
				}
#endif
				cp = routename6(&m6);
				if (vflag)
					n = strlen(cp) < 17 ? 17 : strlen(cp);
				else
					n = 17;
				printf("\n%25s %-*.*s ", "",
				    n, n, cp);
				multiaddr = (u_long)LIST_NEXT(&inm, in6m_entry);
			}
		}
#endif
		break;
	case AF_LINK:
		sdl = (struct sockaddr_dl *)sa;
		m = printf("%-11.11s ", "<Link>");
		if (sdl->sdl_type == IFT_ETHER ||
		    sdl->sdl_type == IFT_CARP ||
		    sdl->sdl_type == IFT_FDDI ||
		    sdl->sdl_type == IFT_ISO88025)
			printf("%-17.17s ",
			    ether_ntoa((struct ether_addr *)LLADDR(sdl)));
		else {
			cp = (char *)LLADDR(sdl);
			n = sdl->sdl_alen;
			goto hexprint;
		}
		break;
	default:
		m = printf("(%d)", sa->sa_family);
		for (cp = sa->sa_len + (char *)sa;
			--cp > sa->sa_data && (*cp == 0);) {}
		n = cp - sa->sa_data + 1;
		cp = sa->sa_data;
hexprint:
		while (--n >= 0)
			m += printf("%x%c", *cp++ & 0xff,
				    n > 0 ? '.' : ' ');
		m = 30 - m;
		while (m-- > 0)
			putchar(' ');
		break;
	}
	if (bflag) {
		if (hflag) {
			char ibytes[FMT_SCALED_STRSIZE];
			char obytes[FMT_SCALED_STRSIZE];
			fmt_scaled(ifd->ifi_ibytes, ibytes);
			fmt_scaled(ifd->ifi_obytes, obytes);
			printf("%10s %10s", ibytes, obytes);
		} else
			printf("%10llu %10llu",
			    ifd->ifi_ibytes, ifd->ifi_obytes);
	} else
		printf("%8llu %5llu %8llu %5llu %5llu",
		    ifd->ifi_ipackets, ifd->ifi_ierrors,
		    ifd->ifi_opackets, ifd->ifi_oerrors,
		    ifd->ifi_collisions);
	if (tflag)
		printf(" %4d", 0 /* XXX ifnet.if_timer */);
	if (dflag)
		printf(" %4d", 0 /* XXX ifnet.if_snd.ifq_drops */);
	putchar('\n');
}
Пример #16
0
/*
 * Return an IPv6 address, which is the most appropriate for a given
 * destination and user specified options.
 * If necessary, this function lookups the routing table and returns
 * an entry to the caller for later use.
 */
int
in6_selectsrc(struct in6_addr **in6src, struct sockaddr_in6 *dstsock,
    struct ip6_pktopts *opts, struct ip6_moptions *mopts,
    struct route_in6 *ro, struct in6_addr *laddr, u_int rtableid)
{
	struct ifnet *ifp = NULL;
	struct in6_addr *dst;
	struct in6_ifaddr *ia6 = NULL;
	struct in6_pktinfo *pi = NULL;
	int	error;

	dst = &dstsock->sin6_addr;

	/*
	 * If the source address is explicitly specified by the caller,
	 * check if the requested source address is indeed a unicast address
	 * assigned to the node, and can be used as the packet's source
	 * address.  If everything is okay, use the address as source.
	 */
	if (opts && (pi = opts->ip6po_pktinfo) &&
	    !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
		struct sockaddr_in6 sa6;

		/* get the outgoing interface */
		error = in6_selectif(dstsock, opts, mopts, ro, &ifp, rtableid);
		if (error)
			return (error);

		bzero(&sa6, sizeof(sa6));
		sa6.sin6_family = AF_INET6;
		sa6.sin6_len = sizeof(sa6);
		sa6.sin6_addr = pi->ipi6_addr;

		if (ifp && IN6_IS_SCOPE_EMBED(&sa6.sin6_addr))
			sa6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
		if_put(ifp); /* put reference from in6_selectif */

		ia6 = ifatoia6(ifa_ifwithaddr(sin6tosa(&sa6), rtableid));
		if (ia6 == NULL ||
		    (ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY)))
			return (EADDRNOTAVAIL);

		pi->ipi6_addr = sa6.sin6_addr; /* XXX: this overrides pi */

		*in6src = &pi->ipi6_addr;
		return (0);
	}

	/*
	 * If the source address is not specified but the socket(if any)
	 * is already bound, use the bound address.
	 */
	if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr)) {
		*in6src = laddr;
		return (0);
	}

	/*
	 * If the caller doesn't specify the source address but
	 * the outgoing interface, use an address associated with
	 * the interface.
	 */
	if (pi && pi->ipi6_ifindex) {
		ifp = if_get(pi->ipi6_ifindex);
		if (ifp == NULL)
			return (ENXIO); /* XXX: better error? */

		ia6 = in6_ifawithscope(ifp, dst, rtableid);
		if_put(ifp);

		if (ia6 == NULL)
			return (EADDRNOTAVAIL);

		*in6src = &ia6->ia_addr.sin6_addr;
		return (0);
	}

	/*
	 * If the destination address is a link-local unicast address or
	 * a link/interface-local multicast address, and if the outgoing
	 * interface is specified by the sin6_scope_id filed, use an address
	 * associated with the interface.
	 * XXX: We're now trying to define more specific semantics of
	 *      sin6_scope_id field, so this part will be rewritten in
	 *      the near future.
	 */
	if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MC_LINKLOCAL(dst) ||
	     IN6_IS_ADDR_MC_INTFACELOCAL(dst)) && dstsock->sin6_scope_id) {
		ifp = if_get(dstsock->sin6_scope_id);
		if (ifp == NULL)
			return (ENXIO); /* XXX: better error? */

		ia6 = in6_ifawithscope(ifp, dst, rtableid);
		if_put(ifp);

		if (ia6 == NULL)
			return (EADDRNOTAVAIL);

		*in6src = &ia6->ia_addr.sin6_addr;
		return (0);
	}

	/*
	 * If the destination address is a multicast address and
	 * the outgoing interface for the address is specified
	 * by the caller, use an address associated with the interface.
	 * Even if the outgoing interface is not specified, we also
	 * choose a loopback interface as the outgoing interface.
	 */
	if (IN6_IS_ADDR_MULTICAST(dst)) {
		ifp = mopts ? if_get(mopts->im6o_ifidx) : NULL;

		if (!ifp && dstsock->sin6_scope_id)
			ifp = if_get(htons(dstsock->sin6_scope_id));

		if (ifp) {
			ia6 = in6_ifawithscope(ifp, dst, rtableid);
			if_put(ifp);

			if (ia6 == NULL)
				return (EADDRNOTAVAIL);

			*in6src = &ia6->ia_addr.sin6_addr;
			return (0);
		}
	}

	/*
	 * If route is known or can be allocated now,
	 * our src addr is taken from the i/f, else punt.
	 */
	if (ro) {
		if (!rtisvalid(ro->ro_rt) || (ro->ro_tableid != rtableid) ||
		    !IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, dst)) {
			rtfree(ro->ro_rt);
			ro->ro_rt = NULL;
		}
		if (ro->ro_rt == NULL) {
			struct sockaddr_in6 *sa6;

			/* No route yet, so try to acquire one */
			bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
			ro->ro_tableid = rtableid;
			sa6 = &ro->ro_dst;
			sa6->sin6_family = AF_INET6;
			sa6->sin6_len = sizeof(struct sockaddr_in6);
			sa6->sin6_addr = *dst;
			sa6->sin6_scope_id = dstsock->sin6_scope_id;
			ro->ro_rt = rtalloc(sin6tosa(&ro->ro_dst),
			    RT_RESOLVE, ro->ro_tableid);
		}

		/*
		 * in_pcbconnect() checks out IFF_LOOPBACK to skip using
		 * the address. But we don't know why it does so.
		 * It is necessary to ensure the scope even for lo0
		 * so doesn't check out IFF_LOOPBACK.
		 */

		if (ro->ro_rt) {
			ifp = if_get(ro->ro_rt->rt_ifidx);
			if (ifp != NULL) {
				ia6 = in6_ifawithscope(ifp, dst, rtableid);
				if_put(ifp);
			}
			if (ia6 == NULL) /* xxx scope error ?*/
				ia6 = ifatoia6(ro->ro_rt->rt_ifa);
		}
		if (ia6 == NULL)
			return (EHOSTUNREACH);	/* no route */

		*in6src = &ia6->ia_addr.sin6_addr;
		return (0);
	}

	return (EADDRNOTAVAIL);
}
Пример #17
0
static void
encap_print(struct rtentry *rt)
{
	struct sockaddr_encap sen1, sen2, sen3;
	struct ipsec_policy ipo;
	struct sockaddr_in6 s61, s62;

	bcopy(kgetsa(rt_key(rt)), &sen1, sizeof(sen1));
	bcopy(kgetsa(rt_mask(rt)), &sen2, sizeof(sen2));
	bcopy(kgetsa(rt->rt_gateway), &sen3, sizeof(sen3));

	if (sen1.sen_type == SENT_IP4) {
		printf("%-18s %-5u ", netname4(sen1.sen_ip_src.s_addr,
		    sen2.sen_ip_src.s_addr), ntohs(sen1.sen_sport));
		printf("%-18s %-5u %-5u ", netname4(sen1.sen_ip_dst.s_addr,
		    sen2.sen_ip_dst.s_addr),
		    ntohs(sen1.sen_dport), sen1.sen_proto);
	}

	if (sen1.sen_type == SENT_IP6) {
		bzero(&s61, sizeof(s61));
		bzero(&s62, sizeof(s62));
		s61.sin6_family = s62.sin6_family = AF_INET6;
		s61.sin6_len = s62.sin6_len = sizeof(s61);
		bcopy(&sen1.sen_ip6_src, &s61.sin6_addr, sizeof(struct in6_addr));
#ifdef __KAME__
		if (IN6_IS_ADDR_LINKLOCAL(&s61.sin6_addr) ||
		    IN6_IS_ADDR_MC_LINKLOCAL(&s61.sin6_addr) ||
		    IN6_IS_ADDR_MC_INTFACELOCAL(&s61.sin6_addr)) {
			s61.sin6_scope_id =
			    ((u_int16_t)s61.sin6_addr.s6_addr[2] << 8) |
			    s61.sin6_addr.s6_addr[3];
			s61.sin6_addr.s6_addr[2] = s61.sin6_addr.s6_addr[3] = 0;
		}
#endif
		bcopy(&sen2.sen_ip6_src, &s62.sin6_addr, sizeof(struct in6_addr));
#ifdef __KAME__
		if (IN6_IS_ADDR_LINKLOCAL(&s62.sin6_addr) ||
		    IN6_IS_ADDR_MC_LINKLOCAL(&s62.sin6_addr) ||
		    IN6_IS_ADDR_MC_INTFACELOCAL(&s62.sin6_addr)) {
			s62.sin6_scope_id =
			    ((u_int16_t)s62.sin6_addr.s6_addr[2] << 8) |
			    s62.sin6_addr.s6_addr[3];
			s62.sin6_addr.s6_addr[2] = s62.sin6_addr.s6_addr[3] = 0;
		}
#endif

		printf("%-42s %-5u ", netname6(&s61, &s62),
		    ntohs(sen1.sen_ip6_sport));

		bzero(&s61, sizeof(s61));
		bzero(&s62, sizeof(s62));
		s61.sin6_family = s62.sin6_family = AF_INET6;
		s61.sin6_len = s62.sin6_len = sizeof(s61);
		bcopy(&sen1.sen_ip6_dst, &s61.sin6_addr, sizeof(struct in6_addr));
#ifdef __KAME__
		if (IN6_IS_ADDR_LINKLOCAL(&s61.sin6_addr) ||
		    IN6_IS_ADDR_MC_LINKLOCAL(&s61.sin6_addr) ||
		    IN6_IS_ADDR_MC_INTFACELOCAL(&s61.sin6_addr)) {
			s61.sin6_scope_id =
			    ((u_int16_t)s61.sin6_addr.s6_addr[2] << 8) |
			    s61.sin6_addr.s6_addr[3];
			s61.sin6_addr.s6_addr[2] = s61.sin6_addr.s6_addr[3] = 0;
		}
#endif
		bcopy(&sen2.sen_ip6_dst, &s62.sin6_addr, sizeof(struct in6_addr));
#ifdef __KAME__
		if (IN6_IS_ADDR_LINKLOCAL(&s62.sin6_addr) ||
		    IN6_IS_ADDR_MC_LINKLOCAL(&s62.sin6_addr) ||
		    IN6_IS_ADDR_MC_INTFACELOCAL(&s62.sin6_addr)) {
			s62.sin6_scope_id =
			    ((u_int16_t)s62.sin6_addr.s6_addr[2] << 8) |
			    s62.sin6_addr.s6_addr[3];
			s62.sin6_addr.s6_addr[2] = s62.sin6_addr.s6_addr[3] = 0;
		}
#endif

		printf("%-42s %-5u %-5u ", netname6(&s61, &s62),
		    ntohs(sen1.sen_ip6_dport), sen1.sen_ip6_proto);
	}

	if (sen3.sen_type == SENT_IPSP) {
		char hostn[NI_MAXHOST];

		kread((u_long)sen3.sen_ipsp, &ipo, sizeof(ipo));

		if (getnameinfo(&ipo.ipo_dst.sa, ipo.ipo_dst.sa.sa_len,
		    hostn, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0)
			strlcpy (hostn, "none", NI_MAXHOST);

		printf("%s", hostn);
		printf("/%-u", ipo.ipo_sproto);

		switch (ipo.ipo_type) {
		case IPSP_IPSEC_REQUIRE:
			printf("/require");
			break;
		case IPSP_IPSEC_ACQUIRE:
			printf("/acquire");
			break;
		case IPSP_IPSEC_USE:
			printf("/use");
			break;
		case IPSP_IPSEC_DONTACQ:
			printf("/dontacq");
			break;
		case IPSP_PERMIT:
			printf("/bypass");
			break;
		case IPSP_DENY:
			printf("/deny");
			break;
		default:
			printf("/<unknown type!>");
			break;
		}

		if ((ipo.ipo_addr.sen_type == SENT_IP4 &&
		    ipo.ipo_addr.sen_direction == IPSP_DIRECTION_IN) ||
		    (ipo.ipo_addr.sen_type == SENT_IP6 &&
		    ipo.ipo_addr.sen_ip6_direction == IPSP_DIRECTION_IN))
			printf("/in\n");
		else if ((ipo.ipo_addr.sen_type == SENT_IP4 &&
		    ipo.ipo_addr.sen_direction == IPSP_DIRECTION_OUT) ||
		    (ipo.ipo_addr.sen_type == SENT_IP6 &&
		    ipo.ipo_addr.sen_ip6_direction == IPSP_DIRECTION_OUT))
			printf("/out\n");
		else
			printf("/<unknown>\n");
	}
}