Beispiel #1
0
static int
send_output(struct mbuf *m, struct ifnet *ifp, int direction)
{
	struct ip6_hdr *ip6;
	struct sockaddr_in6 dst;
	struct icmp6_hdr *icmp6;
	int icmp6len;

	/*
	 * Receive incoming (SeND-protected) or outgoing traffic
	 * (SeND-validated) from the SeND user space application.
	 */

	switch (direction) {
	case SND_IN:
		if (m->m_len < (sizeof(struct ip6_hdr) +
		    sizeof(struct icmp6_hdr))) {
			m = m_pullup(m, sizeof(struct ip6_hdr) +
			    sizeof(struct icmp6_hdr));
			if (!m)
				return (ENOBUFS);
		}

		/* Before passing off the mbuf record the proper interface. */
		m->m_pkthdr.rcvif = ifp;

		if (m->m_flags & M_PKTHDR)
			icmp6len = m->m_pkthdr.len - sizeof(struct ip6_hdr);
		else
			panic("Doh! not the first mbuf.");

		ip6 = mtod(m, struct ip6_hdr *);
		icmp6 = (struct icmp6_hdr *)(ip6 + 1);

		/*
		 * Output the packet as icmp6.c:icpm6_input() would do.
		 * The mbuf is always consumed, so we do not have to
		 * care about that.
		 */
		switch (icmp6->icmp6_type) {
		case ND_NEIGHBOR_SOLICIT:
			nd6_ns_input(m, sizeof(struct ip6_hdr), icmp6len);
			break;
		case ND_NEIGHBOR_ADVERT:
			nd6_na_input(m, sizeof(struct ip6_hdr), icmp6len);
			break;
		case ND_REDIRECT:
			icmp6_redirect_input(m, sizeof(struct ip6_hdr));
			break;
		case ND_ROUTER_SOLICIT:
			nd6_rs_input(m, sizeof(struct ip6_hdr), icmp6len);
			break;
		case ND_ROUTER_ADVERT:
			nd6_ra_input(m, sizeof(struct ip6_hdr), icmp6len);
			break;
		default:
			m_freem(m);
			return (ENOSYS);
		}
		return (0);

	case SND_OUT:
		if (m->m_len < sizeof(struct ip6_hdr)) {
			m = m_pullup(m, sizeof(struct ip6_hdr));
			if (!m)
				return (ENOBUFS);
		}
		ip6 = mtod(m, struct ip6_hdr *);
		if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst))
			m->m_flags |= M_MCAST;

		bzero(&dst, sizeof(dst));
		dst.sin6_family = AF_INET6;
		dst.sin6_len = sizeof(dst);
		dst.sin6_addr = ip6->ip6_dst;

		m_clrprotoflags(m);	/* Avoid confusing lower layers. */

		IP_PROBE(send, NULL, NULL, ip6, ifp, NULL, ip6);

		/*
		 * Output the packet as nd6.c:nd6_output_lle() would do.
		 * The mbuf is always consumed, so we do not have to care
		 * about that.
		 * XXX-BZ as we added data, what about fragmenting,
		 * if now needed?
		 */
		int error;
		error = ((*ifp->if_output)(ifp, m, (struct sockaddr *)&dst,
		    NULL));
		if (error)
			error = ENOENT;
		return (error);

	default:
		panic("%s: direction %d neither SND_IN nor SND_OUT.",
		     __func__, direction);
	}
}
Beispiel #2
0
struct mbuf*
ip6_tryforward(struct mbuf *m)
{
	struct sockaddr_in6 dst;
	struct nhop6_basic nh;
	struct m_tag *fwd_tag;
	struct ip6_hdr *ip6;
	struct ifnet *rcvif;
	uint32_t plen;
	int error;

	/*
	 * Fallback conditions to ip6_input for slow path processing.
	 */
	ip6 = mtod(m, struct ip6_hdr *);
	if (ip6->ip6_nxt == IPPROTO_HOPOPTS ||
	    IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
	    IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst) ||
	    IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src) ||
	    IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) ||
	    in6_localip(&ip6->ip6_dst))
		return (m);
	/*
	 * 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.
	 */
	rcvif = m->m_pkthdr.rcvif;
	plen = ntohs(ip6->ip6_plen);
	if (plen == 0) {
		/*
		 * Jumbograms must have hop-by-hop header and go via
		 * slow path.
		 */
		IP6STAT_INC(ip6s_badoptions);
		goto dropin;
	}
	if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) {
		IP6STAT_INC(ip6s_tooshort);
		in6_ifstat_inc(rcvif, ifs6_in_truncated);
		goto dropin;
	}
	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);
	}

	/*
	 * Hop limit.
	 */
#ifdef IPSTEALTH
	if (!V_ip6stealth)
#endif
	if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
		icmp6_error(m, ICMP6_TIME_EXCEEDED,
		    ICMP6_TIME_EXCEED_TRANSIT, 0);
		m = NULL;
		goto dropin;
	}

	bzero(&dst, sizeof(dst));
	dst.sin6_family = AF_INET6;
	dst.sin6_len = sizeof(dst);
	dst.sin6_addr = ip6->ip6_dst;

	/*
	 * Incoming packet firewall processing.
	 */
	if (!PFIL_HOOKED(&V_inet6_pfil_hook))
		goto passin;
	if (pfil_run_hooks(&V_inet6_pfil_hook, &m, rcvif, PFIL_IN,
	    NULL) != 0 || m == NULL)
		goto dropin;
	/*
	 * If packet filter sets the M_FASTFWD_OURS flag, this means
	 * that new destination or next hop is our local address.
	 * So, we can just go back to ip6_input.
	 * XXX: should we decrement ip6_hlim in such case?
	 *
	 * Also it can forward packet to another destination, e.g.
	 * M_IP6_NEXTHOP flag is set and fwd_tag is attached to mbuf.
	 */
	if (m->m_flags & M_FASTFWD_OURS)
		return (m);

	ip6 = mtod(m, struct ip6_hdr *);
	if ((m->m_flags & M_IP6_NEXTHOP) &&
	    (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) {
		/*
		 * Now we will find route to forwarded by pfil destination.
		 */
		bcopy((fwd_tag + 1), &dst, sizeof(dst));
		m->m_flags &= ~M_IP6_NEXTHOP;
		m_tag_delete(m, fwd_tag);
	} else {
		/* Update dst since pfil could change it */
		dst.sin6_addr = ip6->ip6_dst;
	}
passin:
	/*
	 * Find route to destination.
	 */
	if (ip6_findroute(&nh, &dst, m) != 0) {
		m = NULL;
		in6_ifstat_inc(rcvif, ifs6_in_noroute);
		goto dropin;
	}
	/*
	 * We used slow path processing for packets with scoped addresses.
	 * So, scope checks aren't needed here.
	 */
	if (m->m_pkthdr.len > nh.nh_mtu) {
		in6_ifstat_inc(nh.nh_ifp, ifs6_in_toobig);
		icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, nh.nh_mtu);
		m = NULL;
		goto dropout;
	}

	/*
	 * Outgoing packet firewall processing.
	 */
	if (!PFIL_HOOKED(&V_inet6_pfil_hook))
		goto passout;
	if (pfil_run_hooks(&V_inet6_pfil_hook, &m, nh.nh_ifp, PFIL_OUT,
	    NULL) != 0 || m == NULL)
		goto dropout;
	/*
	 * If packet filter sets the M_FASTFWD_OURS flag, this means
	 * that new destination or next hop is our local address.
	 * So, we can just go back to ip6_input.
	 *
	 * Also it can forward packet to another destination, e.g.
	 * M_IP6_NEXTHOP flag is set and fwd_tag is attached to mbuf.
	 */
	if (m->m_flags & M_FASTFWD_OURS) {
		/*
		 * XXX: we did one hop and should decrement hop limit. But
		 * now we are the destination and just don't pay attention.
		 */
		return (m);
	}
	/*
	 * Again. A packet filter could change the destination address.
	 */
	ip6 = mtod(m, struct ip6_hdr *);
	if (m->m_flags & M_IP6_NEXTHOP)
		fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
	else
		fwd_tag = NULL;

	if (fwd_tag != NULL ||
	    !IN6_ARE_ADDR_EQUAL(&dst.sin6_addr, &ip6->ip6_dst)) {
		if (fwd_tag != NULL) {
			bcopy((fwd_tag + 1), &dst, sizeof(dst));
			m->m_flags &= ~M_IP6_NEXTHOP;
			m_tag_delete(m, fwd_tag);
		} else
			dst.sin6_addr = ip6->ip6_dst;
		/*
		 * Redo route lookup with new destination address
		 */
		if (ip6_findroute(&nh, &dst, m) != 0) {
			m = NULL;
			goto dropout;
		}
	}
passout:
#ifdef IPSTEALTH
	if (!V_ip6stealth)
#endif
	{
		ip6->ip6_hlim -= IPV6_HLIMDEC;
	}

	m_clrprotoflags(m);	/* Avoid confusing lower layers. */
	IP_PROBE(send, NULL, NULL, ip6, nh.nh_ifp, NULL, ip6);

	/*
	 * XXX: we need to use destination address with embedded scope
	 * zone id, because LLTABLE uses such form of addresses for lookup.
	 */
	dst.sin6_addr = nh.nh_addr;
	if (IN6_IS_SCOPE_LINKLOCAL(&dst.sin6_addr))
		dst.sin6_addr.s6_addr16[1] = htons(nh.nh_ifp->if_index & 0xffff);

	error = (*nh.nh_ifp->if_output)(nh.nh_ifp, m,
	    (struct sockaddr *)&dst, NULL);
	if (error != 0) {
		in6_ifstat_inc(nh.nh_ifp, ifs6_out_discard);
		IP6STAT_INC(ip6s_cantforward);
	} else {
		in6_ifstat_inc(nh.nh_ifp, ifs6_out_forward);
		IP6STAT_INC(ip6s_forward);
	}
	return (NULL);
dropin:
	in6_ifstat_inc(rcvif, ifs6_in_discard);
	goto drop;
dropout:
	in6_ifstat_inc(nh.nh_ifp, ifs6_out_discard);
drop:
	if (m != NULL)
		m_freem(m);
	return (NULL);
}