コード例 #1
0
ファイル: ifvxlan.c プロジェクト: 2asoft/freebsd
static
DECL_CMD_FUNC(setvxlan_group, addr, d)
{
	struct ifvxlancmd cmd;
	struct addrinfo *ai;
	struct sockaddr *sa;
	int error;

	bzero(&cmd, sizeof(cmd));

	if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0)
		errx(1, "error in parsing group address string: %s",
		    gai_strerror(error));

	sa = ai->ai_addr;

	switch (ai->ai_family) {
#ifdef INET
	case AF_INET: {
		struct in_addr addr = ((struct sockaddr_in *)sa)->sin_addr;

		if (!IN_MULTICAST(ntohl(addr.s_addr)))
			errx(1, "group address must be multicast");

		cmd.vxlcmd_sa.in4.sin_family = AF_INET;
		cmd.vxlcmd_sa.in4.sin_addr = addr;
		break;
	}
#endif
#ifdef INET6
	case AF_INET6: {
		struct in6_addr *addr = &((struct sockaddr_in6 *)sa)->sin6_addr;

		if (!IN6_IS_ADDR_MULTICAST(addr))
			errx(1, "group address must be multicast");

		cmd.vxlcmd_sa.in6.sin6_family = AF_INET6;
		cmd.vxlcmd_sa.in6.sin6_addr = *addr;
		break;
	}
#endif
	default:
		errx(1, "group address %s not supported", addr);
	}

	freeaddrinfo(ai);

	if (!vxlan_exists(s)) {
		if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) {
			params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4;
			params.vxlp_remote_in4 = cmd.vxlcmd_sa.in4.sin_addr;
		} else {
			params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6;
			params.vxlp_remote_in6 = cmd.vxlcmd_sa.in6.sin6_addr;
		}
		return;
	}

	if (do_cmd(s, VXLAN_CMD_SET_REMOTE_ADDR, &cmd, sizeof(cmd), 1) < 0)
		err(1, "VXLAN_CMD_SET_REMOTE_ADDR");
}
コード例 #2
0
ファイル: ip6_forward.c プロジェクト: orumin/openbsd-efivars
void
ip6_forward(struct mbuf *m, int srcrt)
{
    struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
    struct sockaddr_in6 *dst;
    struct rtentry *rt;
    int error = 0, type = 0, code = 0;
    struct mbuf *mcopy = NULL;
#ifdef IPSEC
    u_int8_t sproto = 0;
    struct m_tag *mtag;
    union sockaddr_union sdst;
    struct tdb_ident *tdbi;
    u_int32_t sspi;
    struct tdb *tdb;
#if NPF > 0
    struct ifnet *encif;
#endif
#endif /* IPSEC */
    u_int rtableid = 0;
    char src6[INET6_ADDRSTRLEN], dst6[INET6_ADDRSTRLEN];

    /*
     * Do not forward packets to multicast destination (should be handled
     * by ip6_mforward().
     * Do not forward packets with unspecified source.  It was discussed
     * in July 2000, on ipngwg mailing list.
     */
    if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
            IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
            IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
        ip6stat.ip6s_cantforward++;
        if (ip6_log_time + ip6_log_interval < time_second) {
            ip6_log_time = time_second;
            inet_ntop(AF_INET6, &ip6->ip6_src, src6, sizeof(src6));
            inet_ntop(AF_INET6, &ip6->ip6_dst, dst6, sizeof(dst6));
            log(LOG_DEBUG,
                "cannot forward "
                "from %s to %s nxt %d received on inteface %u\n",
                src6, dst6,
                ip6->ip6_nxt,
                m->m_pkthdr.ph_ifidx);
        }
        m_freem(m);
        return;
    }

    if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
        icmp6_error(m, ICMP6_TIME_EXCEEDED,
                    ICMP6_TIME_EXCEED_TRANSIT, 0);
        return;
    }
    ip6->ip6_hlim -= IPV6_HLIMDEC;

    /*
     * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU -
     * size of IPv6 + ICMPv6 headers) bytes of the packet in case
     * we need to generate an ICMP6 message to the src.
     * Thanks to M_EXT, in most cases copy will not occur.
     *
     * It is important to save it before IPsec processing as IPsec
     * processing may modify the mbuf.
     */
    mcopy = m_copym(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN),
                    M_NOWAIT);

#if NPF > 0
reroute:
#endif

#ifdef IPSEC
    if (!ipsec_in_use)
        goto done_spd;

    /*
     * Check if there was an outgoing SA bound to the flow
     * from a transport protocol.
     */

    /* Do we have any pending SAs to apply ? */
    tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr),
                          &error, IPSP_DIRECTION_OUT, NULL, NULL, 0);

    if (tdb == NULL) {
        if (error == 0) {
            /*
            * No IPsec processing required, we'll just send the
             * packet out.
             */
            sproto = 0;

            /* Fall through to routing/multicast handling */
        } else {
            /*
            * -EINVAL is used to indicate that the packet should
             * be silently dropped, typically because we've asked
             * key management for an SA.
             */
            if (error == -EINVAL) /* Should silently drop packet */
                error = 0;

            m_freem(m);
            goto freecopy;
        }
    } else {
        /* Loop detection */
        for (mtag = m_tag_first(m); mtag != NULL;
                mtag = m_tag_next(m, mtag)) {
            if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE)
                continue;
            tdbi = (struct tdb_ident *)(mtag + 1);
            if (tdbi->spi == tdb->tdb_spi &&
                    tdbi->proto == tdb->tdb_sproto &&
                    tdbi->rdomain == tdb->tdb_rdomain &&
                    !bcmp(&tdbi->dst, &tdb->tdb_dst,
                          sizeof(union sockaddr_union))) {
                sproto = 0; /* mark as no-IPsec-needed */
                goto done_spd;
            }
        }

        /* We need to do IPsec */
        bcopy(&tdb->tdb_dst, &sdst, sizeof(sdst));
        sspi = tdb->tdb_spi;
        sproto = tdb->tdb_sproto;
    }

    /* Fall through to the routing/multicast handling code */
done_spd:
#endif /* IPSEC */

#if NPF > 0
    rtableid = m->m_pkthdr.ph_rtableid;
#endif

    dst = &ip6_forward_rt.ro_dst;
    if (!srcrt) {
        /*
         * ip6_forward_rt.ro_dst.sin6_addr is equal to ip6->ip6_dst
         */
        if (ip6_forward_rt.ro_rt == NULL ||
                (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) == 0 ||
                ip6_forward_rt.ro_tableid != rtableid) {
            if (ip6_forward_rt.ro_rt) {
                rtfree(ip6_forward_rt.ro_rt);
                ip6_forward_rt.ro_rt = NULL;
            }
            /* this probably fails but give it a try again */
            ip6_forward_rt.ro_tableid = rtableid;
            ip6_forward_rt.ro_rt = rtalloc_mpath(
                                       sin6tosa(&ip6_forward_rt.ro_dst),
                                       &ip6->ip6_src.s6_addr32[0],
                                       ip6_forward_rt.ro_tableid);
        }

        if (ip6_forward_rt.ro_rt == NULL) {
            ip6stat.ip6s_noroute++;
            if (mcopy) {
                icmp6_error(mcopy, ICMP6_DST_UNREACH,
                            ICMP6_DST_UNREACH_NOROUTE, 0);
            }
            m_freem(m);
            return;
        }
    } else if (ip6_forward_rt.ro_rt == NULL ||
               (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) == 0 ||
               !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst->sin6_addr) ||
               ip6_forward_rt.ro_tableid != rtableid) {
        if (ip6_forward_rt.ro_rt) {
            rtfree(ip6_forward_rt.ro_rt);
            ip6_forward_rt.ro_rt = NULL;
        }
        bzero(dst, sizeof(*dst));
        dst->sin6_len = sizeof(struct sockaddr_in6);
        dst->sin6_family = AF_INET6;
        dst->sin6_addr = ip6->ip6_dst;
        ip6_forward_rt.ro_tableid = rtableid;
        ip6_forward_rt.ro_rt = rtalloc_mpath(
                                   sin6tosa(&ip6_forward_rt.ro_dst),
                                   &ip6->ip6_src.s6_addr32[0],
                                   ip6_forward_rt.ro_tableid);

        if (ip6_forward_rt.ro_rt == NULL) {
            ip6stat.ip6s_noroute++;
            if (mcopy) {
                icmp6_error(mcopy, ICMP6_DST_UNREACH,
                            ICMP6_DST_UNREACH_NOROUTE, 0);
            }
            m_freem(m);
            return;
        }
    }
    rt = ip6_forward_rt.ro_rt;

    /*
     * Scope check: if a packet can't be delivered to its destination
     * for the reason that the destination is beyond the scope of the
     * source address, discard the packet and return an icmp6 destination
     * unreachable error with Code 2 (beyond scope of source address).
     * [draft-ietf-ipngwg-icmp-v3-00.txt, Section 3.1]
     */
    if (in6_addr2scopeid(m->m_pkthdr.ph_ifidx, &ip6->ip6_src) !=
            in6_addr2scopeid(rt->rt_ifp->if_index, &ip6->ip6_src)) {
        ip6stat.ip6s_cantforward++;
        ip6stat.ip6s_badscope++;

        if (ip6_log_time + ip6_log_interval < time_second) {
            ip6_log_time = time_second;
            inet_ntop(AF_INET6, &ip6->ip6_src, src6, sizeof(src6));
            inet_ntop(AF_INET6, &ip6->ip6_dst, dst6, sizeof(dst6));
            log(LOG_DEBUG,
                "cannot forward "
                "src %s, dst %s, nxt %d, rcvif %u, outif %u\n",
                src6, dst6,
                ip6->ip6_nxt,
                m->m_pkthdr.ph_ifidx, rt->rt_ifp->if_index);
        }
        if (mcopy)
            icmp6_error(mcopy, ICMP6_DST_UNREACH,
                        ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
        m_freem(m);
        goto freert;
    }

#ifdef IPSEC
    /*
     * Check if the packet needs encapsulation.
     * ipsp_process_packet will never come back to here.
     * XXX ipsp_process_packet() calls ip6_output(), and there'll be no
     * PMTU notification.  is it okay?
     */
    if (sproto != 0) {
        tdb = gettdb(rtable_l2(m->m_pkthdr.ph_rtableid),
                     sspi, &sdst, sproto);
        if (tdb == NULL) {
            error = EHOSTUNREACH;
            m_freem(m);
            goto senderr;	/*XXX*/
        }

#if NPF > 0
        if ((encif = enc_getif(tdb->tdb_rdomain,
                               tdb->tdb_tap)) == NULL ||
                pf_test(AF_INET6, PF_FWD, encif, &m) != PF_PASS) {
            error = EHOSTUNREACH;
            m_freem(m);
            goto senderr;
        }
        if (m == NULL)
            goto senderr;
        ip6 = mtod(m, struct ip6_hdr *);
        /*
         * PF_TAG_REROUTE handling or not...
         * Packet is entering IPsec so the routing is
         * already overruled by the IPsec policy.
         * Until now the change was not reconsidered.
         * What's the behaviour?
         */
        in6_proto_cksum_out(m, encif);
#endif
        m->m_flags &= ~(M_BCAST | M_MCAST);	/* just in case */

        /* Callee frees mbuf */
        error = ipsp_process_packet(m, tdb, AF_INET6, 0);
        m_freem(mcopy);
        goto freert;
    }
コード例 #3
0
ファイル: nd6_nbr.c プロジェクト: chrisinthemorning/m0n0wall2
/*
 * Output a Neighbor Solicitation Message. Caller specifies:
 *	- ICMP6 header source IP6 address
 *	- ND6 header target IP6 address
 *	- ND6 header source datalink address
 *
 * Based on RFC 2461
 * Based on RFC 2462 (duplicate address detection)
 *
 *   ln - for source address determination
 *  dad - duplicate address detection
 */
void
nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6, 
    const struct in6_addr *taddr6, struct llentry *ln, int dad)
{
	struct mbuf *m;
	struct ip6_hdr *ip6;
	struct nd_neighbor_solicit *nd_ns;
	struct ip6_moptions im6o;
	int icmp6len;
	int maxlen;
	caddr_t mac;
	struct route_in6 ro;

	if (IN6_IS_ADDR_MULTICAST(taddr6))
		return;

	/* estimate the size of message */
	maxlen = sizeof(*ip6) + sizeof(*nd_ns);
	maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
	if (max_linkhdr + maxlen >= MCLBYTES) {
#ifdef DIAGNOSTIC
		printf("nd6_ns_output: max_linkhdr + maxlen >= MCLBYTES "
		    "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES);
#endif
		return;
	}

	MGETHDR(m, M_DONTWAIT, MT_DATA);
	if (m && max_linkhdr + maxlen >= MHLEN) {
		MCLGET(m, M_DONTWAIT);
		if ((m->m_flags & M_EXT) == 0) {
			m_free(m);
			m = NULL;
		}
	}
	if (m == NULL)
		return;
	m->m_pkthdr.rcvif = NULL;

	bzero(&ro, sizeof(ro));

	if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) {
		m->m_flags |= M_MCAST;
		im6o.im6o_multicast_ifp = ifp;
		im6o.im6o_multicast_hlim = 255;
		im6o.im6o_multicast_loop = 0;
	}

	icmp6len = sizeof(*nd_ns);
	m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len;
	m->m_data += max_linkhdr;	/* or MH_ALIGN() equivalent? */

	/* fill neighbor solicitation packet */
	ip6 = mtod(m, struct ip6_hdr *);
	ip6->ip6_flow = 0;
	ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
	ip6->ip6_vfc |= IPV6_VERSION;
	/* ip6->ip6_plen will be set later */
	ip6->ip6_nxt = IPPROTO_ICMPV6;
	ip6->ip6_hlim = 255;
	if (daddr6)
		ip6->ip6_dst = *daddr6;
	else {
		ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
		ip6->ip6_dst.s6_addr16[1] = 0;
		ip6->ip6_dst.s6_addr32[1] = 0;
		ip6->ip6_dst.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
		ip6->ip6_dst.s6_addr32[3] = taddr6->s6_addr32[3];
		ip6->ip6_dst.s6_addr8[12] = 0xff;
		if (in6_setscope(&ip6->ip6_dst, ifp, NULL) != 0)
			goto bad;
	}
	if (!dad) {
		struct ifaddr *ifa;

		/*
		 * RFC2461 7.2.2:
		 * "If the source address of the packet prompting the
		 * solicitation is the same as one of the addresses assigned
		 * to the outgoing interface, that address SHOULD be placed
		 * in the IP Source Address of the outgoing solicitation.
		 * Otherwise, any one of the addresses assigned to the
		 * interface should be used."
		 *
		 * We use the source address for the prompting packet
		 * (saddr6), if:
		 * - saddr6 is given from the caller (by giving "ln"), and
		 * - saddr6 belongs to the outgoing interface.
		 * Otherwise, we perform the source address selection as usual.
		 */
		struct in6_addr *hsrc;

		hsrc = NULL;
		if (ln != NULL) {
			LLE_RLOCK(ln);
			if (ln->la_hold != NULL) {
				struct ip6_hdr *hip6;		/* hold ip6 */

				/*
				 * assuming every packet in la_hold has the same IP
				 * header
				 */
				hip6 = mtod(ln->la_hold, struct ip6_hdr *);
				/* XXX pullup? */
				if (sizeof(*hip6) < ln->la_hold->m_len) {
					ip6->ip6_src = hip6->ip6_src;
					hsrc = &hip6->ip6_src;
				}
			}
			LLE_RUNLOCK(ln);
		}
		if (hsrc && (ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp,
		    hsrc)) != NULL) {
			/* ip6_src set already. */
			ifa_free(ifa);
		} else {
			int error;
			struct sockaddr_in6 dst_sa;
			struct in6_addr src_in;

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

			error = in6_selectsrc(&dst_sa, NULL,
			    NULL, &ro, NULL, NULL, &src_in);
			if (error) {
				char ip6buf[INET6_ADDRSTRLEN];
				nd6log((LOG_DEBUG,
				    "nd6_ns_output: source can't be "
				    "determined: dst=%s, error=%d\n",
				    ip6_sprintf(ip6buf, &dst_sa.sin6_addr),
				    error));
				goto bad;
			}
			ip6->ip6_src = src_in;
		}
	} else {
コード例 #4
0
ファイル: nd6_nbr.c プロジェクト: chrisinthemorning/m0n0wall2
/*
 * Input a Neighbor Solicitation Message.
 *
 * Based on RFC 2461
 * Based on RFC 2462 (duplicate address detection)
 */
void
nd6_ns_input(struct mbuf *m, int off, int icmp6len)
{
	struct ifnet *ifp = m->m_pkthdr.rcvif;
	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
	struct nd_neighbor_solicit *nd_ns;
	struct in6_addr saddr6 = ip6->ip6_src;
	struct in6_addr daddr6 = ip6->ip6_dst;
	struct in6_addr taddr6;
	struct in6_addr myaddr6;
	char *lladdr = NULL;
	struct ifaddr *ifa = NULL;
	int lladdrlen = 0;
	int anycast = 0, proxy = 0, tentative = 0;
	int tlladdr;
	union nd_opts ndopts;
	struct sockaddr_dl *proxydl = NULL;
	char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];

#ifndef PULLDOWN_TEST
	IP6_EXTHDR_CHECK(m, off, icmp6len,);
	nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off);
#else
	IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len);
	if (nd_ns == NULL) {
		ICMP6STAT_INC(icp6s_tooshort);
		return;
	}
#endif
	ip6 = mtod(m, struct ip6_hdr *); /* adjust pointer for safety */
	taddr6 = nd_ns->nd_ns_target;
	if (in6_setscope(&taddr6, ifp, NULL) != 0)
		goto bad;

	if (ip6->ip6_hlim != 255) {
		nd6log((LOG_ERR,
		    "nd6_ns_input: invalid hlim (%d) from %s to %s on %s\n",
		    ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src),
		    ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp)));
		goto bad;
	}

	if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
		/* dst has to be a solicited node multicast address. */
		if (daddr6.s6_addr16[0] == IPV6_ADDR_INT16_MLL &&
		    /* don't check ifindex portion */
		    daddr6.s6_addr32[1] == 0 &&
		    daddr6.s6_addr32[2] == IPV6_ADDR_INT32_ONE &&
		    daddr6.s6_addr8[12] == 0xff) {
			; /* good */
		} else {
			nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet "
			    "(wrong ip6 dst)\n"));
			goto bad;
		}
	} else if (!V_nd6_onlink_ns_rfc4861) {
		struct sockaddr_in6 src_sa6;

		/*
		 * According to recent IETF discussions, it is not a good idea
		 * to accept a NS from an address which would not be deemed
		 * to be a neighbor otherwise.  This point is expected to be
		 * clarified in future revisions of the specification.
		 */
		bzero(&src_sa6, sizeof(src_sa6));
		src_sa6.sin6_family = AF_INET6;
		src_sa6.sin6_len = sizeof(src_sa6);
		src_sa6.sin6_addr = saddr6;
		if (nd6_is_addr_neighbor(&src_sa6, ifp) == 0) {
			nd6log((LOG_INFO, "nd6_ns_input: "
				"NS packet from non-neighbor\n"));
			goto bad;
		}
	}

	if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
		nd6log((LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n"));
		goto bad;
	}

	icmp6len -= sizeof(*nd_ns);
	nd6_option_init(nd_ns + 1, icmp6len, &ndopts);
	if (nd6_options(&ndopts) < 0) {
		nd6log((LOG_INFO,
		    "nd6_ns_input: invalid ND option, ignored\n"));
		/* nd6_options have incremented stats */
		goto freeit;
	}

	if (ndopts.nd_opts_src_lladdr) {
		lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
	}

	if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && lladdr) {
		nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet "
		    "(link-layer address option)\n"));
		goto bad;
	}

	/*
	 * Attaching target link-layer address to the NA?
	 * (RFC 2461 7.2.4)
	 *
	 * NS IP dst is unicast/anycast			MUST NOT add
	 * NS IP dst is solicited-node multicast	MUST add
	 *
	 * In implementation, we add target link-layer address by default.
	 * We do not add one in MUST NOT cases.
	 */
	if (!IN6_IS_ADDR_MULTICAST(&daddr6))
		tlladdr = 0;
	else
		tlladdr = 1;

	/*
	 * Target address (taddr6) must be either:
	 * (1) Valid unicast/anycast address for my receiving interface,
	 * (2) Unicast address for which I'm offering proxy service, or
	 * (3) "tentative" address on which DAD is being performed.
	 */
	/* (1) and (3) check. */
	if (ifp->if_carp)
		ifa = (*carp_iamatch6_p)(ifp, &taddr6);
	if (ifa == NULL)
		ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);

	/* (2) check. */
	if (ifa == NULL) {
		struct rtentry *rt;
		struct sockaddr_in6 tsin6;
		int need_proxy;
#ifdef RADIX_MPATH
		struct route_in6 ro;
#endif

		bzero(&tsin6, sizeof tsin6);
		tsin6.sin6_len = sizeof(struct sockaddr_in6);
		tsin6.sin6_family = AF_INET6;
		tsin6.sin6_addr = taddr6;

#ifdef RADIX_MPATH
		bzero(&ro, sizeof(ro));
		ro.ro_dst = tsin6;
		rtalloc_mpath((struct route *)&ro, RTF_ANNOUNCE);
		rt = ro.ro_rt;
#else
		rt = rtalloc1((struct sockaddr *)&tsin6, 0, 0);
#endif
		need_proxy = (rt && (rt->rt_flags & RTF_ANNOUNCE) != 0 &&
		    rt->rt_gateway->sa_family == AF_LINK);
		if (rt)
			RTFREE_LOCKED(rt);
		if (need_proxy) {
			/*
			 * proxy NDP for single entry
			 */
			ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
				IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
			if (ifa) {
				proxy = 1;
				proxydl = SDL(rt->rt_gateway);
			}
		}
	}
	if (ifa == NULL) {
		/*
		 * We've got an NS packet, and we don't have that adddress
		 * assigned for us.  We MUST silently ignore it.
		 * See RFC2461 7.2.3.
		 */
		goto freeit;
	}
	myaddr6 = *IFA_IN6(ifa);
	anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST;
	tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE;
	if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED)
		goto freeit;

	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
		nd6log((LOG_INFO, "nd6_ns_input: lladdrlen mismatch for %s "
		    "(if %d, NS packet %d)\n",
		    ip6_sprintf(ip6bufs, &taddr6),
		    ifp->if_addrlen, lladdrlen - 2));
		goto bad;
	}

	if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) {
		nd6log((LOG_INFO, "nd6_ns_input: duplicate IP6 address %s\n",
		    ip6_sprintf(ip6bufs, &saddr6)));
		goto freeit;
	}

	/*
	 * We have neighbor solicitation packet, with target address equals to
	 * one of my tentative address.
	 *
	 * src addr	how to process?
	 * ---		---
	 * multicast	of course, invalid (rejected in ip6_input)
	 * unicast	somebody is doing address resolution -> ignore
	 * unspec	dup address detection
	 *
	 * The processing is defined in RFC 2462.
	 */
	if (tentative) {
		/*
		 * If source address is unspecified address, it is for
		 * duplicate address detection.
		 *
		 * If not, the packet is for addess resolution;
		 * silently ignore it.
		 */
		if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
			nd6_dad_ns_input(ifa);

		goto freeit;
	}

	/*
	 * If the source address is unspecified address, entries must not
	 * be created or updated.
	 * It looks that sender is performing DAD.  Output NA toward
	 * all-node multicast address, to tell the sender that I'm using
	 * the address.
	 * S bit ("solicited") must be zero.
	 */
	if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
		struct in6_addr in6_all;

		in6_all = in6addr_linklocal_allnodes;
		if (in6_setscope(&in6_all, ifp, NULL) != 0)
			goto bad;
		nd6_na_output(ifp, &in6_all, &taddr6,
		    ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
		    (V_ip6_forwarding ? ND_NA_FLAG_ROUTER : 0),
		    tlladdr, (struct sockaddr *)proxydl);
		goto freeit;
	}

	nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen,
	    ND_NEIGHBOR_SOLICIT, 0);

	nd6_na_output(ifp, &saddr6, &taddr6,
	    ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
	    (V_ip6_forwarding ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED,
	    tlladdr, (struct sockaddr *)proxydl);
 freeit:
	if (ifa != NULL)
		ifa_free(ifa);
	m_freem(m);
	return;

 bad:
	nd6log((LOG_ERR, "nd6_ns_input: src=%s\n",
		ip6_sprintf(ip6bufs, &saddr6)));
	nd6log((LOG_ERR, "nd6_ns_input: dst=%s\n",
		ip6_sprintf(ip6bufs, &daddr6)));
	nd6log((LOG_ERR, "nd6_ns_input: tgt=%s\n",
		ip6_sprintf(ip6bufs, &taddr6)));
	ICMP6STAT_INC(icp6s_badns);
	if (ifa != NULL)
		ifa_free(ifa);
	m_freem(m);
}
コード例 #5
0
/*
 * Copy the osockaddr structure pointed to by osa to kernel, adjust
 * family and convert to sockaddr.
 */
static int
do_sa_get(struct sockaddr **sap, const struct osockaddr *osa, int *osalen,
          struct malloc_type *mtype)
{
    int error=0, bdom;
    struct sockaddr *sa;
    struct osockaddr *kosa;
    int alloclen;
#ifdef INET6
    int oldv6size;
    struct sockaddr_in6 *sin6;
#endif

    if (*osalen < 2 || *osalen > UCHAR_MAX || !osa)
        return (EINVAL);

    alloclen = *osalen;
#ifdef INET6
    oldv6size = 0;
    /*
     * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
     * if it's a v4-mapped address, so reserve the proper space
     * for it.
     */
    if (alloclen == sizeof (struct sockaddr_in6) - sizeof (u_int32_t)) {
        alloclen = sizeof (struct sockaddr_in6);
        oldv6size = 1;
    }
#endif

    kosa = malloc(alloclen, mtype, M_WAITOK);

    if ((error = copyin(osa, kosa, *osalen)))
        goto out;

    bdom = linux_to_bsd_domain(kosa->sa_family);
    if (bdom == -1) {
        error = EINVAL;
        goto out;
    }

#ifdef INET6
    /*
     * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
     * which lacks the scope id compared with RFC2553 one. If we detect
     * the situation, reject the address and write a message to system log.
     *
     * Still accept addresses for which the scope id is not used.
     */
    if (oldv6size && bdom == AF_INET6) {
        sin6 = (struct sockaddr_in6 *)kosa;
        if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
                (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
                 !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
                 !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
                 !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
                 !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
            sin6->sin6_scope_id = 0;
        } else {
            log(LOG_DEBUG,
                "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
            error = EINVAL;
            goto out;
        }
    } else
#endif
        if (bdom == AF_INET)
            alloclen = sizeof(struct sockaddr_in);

    sa = (struct sockaddr *) kosa;
    sa->sa_family = bdom;
    sa->sa_len = alloclen;

    *sap = sa;
    *osalen = alloclen;
    return (0);

out:
    free(kosa, mtype);
    return (error);
}
コード例 #6
0
/*
 * Reads a linux sockaddr and does any necessary translation.
 * Linux sockaddrs don't have a length field, only a family.
 * Copy the osockaddr structure pointed to by osa to kernel, adjust
 * family and convert to sockaddr.
 */
static int
linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int salen)
{
	struct sockaddr *sa;
	struct osockaddr *kosa;
#ifdef INET6
	struct sockaddr_in6 *sin6;
	int oldv6size;
#endif
	char *name;
	int bdom, error, hdrlen, namelen;

	if (salen < 2 || salen > UCHAR_MAX || !osa)
		return (EINVAL);

#ifdef INET6
	oldv6size = 0;
	/*
	 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
	 * if it's a v4-mapped address, so reserve the proper space
	 * for it.
	 */
	if (salen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) {
		salen += sizeof(uint32_t);
		oldv6size = 1;
	}
#endif

	kosa = malloc(salen, M_SONAME, M_WAITOK);

	if ((error = copyin(osa, kosa, salen)))
		goto out;

	bdom = linux_to_bsd_domain(kosa->sa_family);
	if (bdom == -1) {
		error = EAFNOSUPPORT;
		goto out;
	}

#ifdef INET6
	/*
	 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
	 * which lacks the scope id compared with RFC2553 one. If we detect
	 * the situation, reject the address and write a message to system log.
	 *
	 * Still accept addresses for which the scope id is not used.
	 */
	if (oldv6size) {
		if (bdom == AF_INET6) {
			sin6 = (struct sockaddr_in6 *)kosa;
			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
			    (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
			     !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
			     !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
			     !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
			     !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
				sin6->sin6_scope_id = 0;
			} else {
				log(LOG_DEBUG,
				    "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
				error = EINVAL;
				goto out;
			}
		} else
			salen -= sizeof(uint32_t);
	}
#endif
	if (bdom == AF_INET) {
		if (salen < sizeof(struct sockaddr_in)) {
			error = EINVAL;
			goto out;
		}
		salen = sizeof(struct sockaddr_in);
	}

	if (bdom == AF_LOCAL && salen > sizeof(struct sockaddr_un)) {
		hdrlen = offsetof(struct sockaddr_un, sun_path);
		name = ((struct sockaddr_un *)kosa)->sun_path;
		if (*name == '\0') {
			/*
		 	 * Linux abstract namespace starts with a NULL byte.
			 * XXX We do not support abstract namespace yet.
			 */
			namelen = strnlen(name + 1, salen - hdrlen - 1) + 1;
		} else
			namelen = strnlen(name, salen - hdrlen);
		salen = hdrlen + namelen;
		if (salen > sizeof(struct sockaddr_un)) {
			error = ENAMETOOLONG;
			goto out;
		}
	}
コード例 #7
0
inline int IN6_IS_ADDR_MC_SITELOCAL(const in6_addr_emulation* a)
{
  return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 5);
}
コード例 #8
0
inline int IN6_IS_ADDR_MC_GLOBAL(const in6_addr_emulation* a)
{
  return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 0xe);
}
コード例 #9
0
ファイル: if.c プロジェクト: coyizumi/cs111
char *
get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter)
{
	struct rt_msghdr *rtm;
	struct ifa_msghdr *ifam;
	struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX];

	*lenp = 0;
	for (rtm = (struct rt_msghdr *)buf;
	     rtm < (struct rt_msghdr *)lim;
	     rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) {
		/* just for safety */
		if (!rtm->rtm_msglen) {
			syslog(LOG_WARNING, "<%s> rtm_msglen is 0 "
			    "(buf=%p lim=%p rtm=%p)", __func__,
			    buf, lim, rtm);
			break;
		}
		if (((struct rt_msghdr *)buf)->rtm_version != RTM_VERSION) {
			syslog(LOG_WARNING,
			    "<%s> routing message version mismatch "
			    "(buf=%p lim=%p rtm=%p)", __func__,
			    buf, lim, rtm);
			continue;
		}

		if (FILTER_MATCH(rtm->rtm_type, filter) == 0)
			continue;

		switch (rtm->rtm_type) {
		case RTM_GET:
		case RTM_ADD:
		case RTM_DELETE:
			/* address related checks */
			sa = (struct sockaddr *)(rtm + 1);
			get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
			if ((dst = rti_info[RTAX_DST]) == NULL ||
			    dst->sa_family != AF_INET6)
				continue;

			if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) ||
			    IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr))
				continue;

			if ((gw = rti_info[RTAX_GATEWAY]) == NULL ||
			    gw->sa_family != AF_LINK)
				continue;
			if (ifindex && SDL(gw)->sdl_index != ifindex)
				continue;

			if (rti_info[RTAX_NETMASK] == NULL)
				continue;

			/* found */
			*lenp = rtm->rtm_msglen;
			return (char *)rtm;
			/* NOTREACHED */
		case RTM_NEWADDR:
		case RTM_DELADDR:
			ifam = (struct ifa_msghdr *)rtm;

			/* address related checks */
			sa = (struct sockaddr *)(ifam + 1);
			get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
			if ((ifa = rti_info[RTAX_IFA]) == NULL ||
			    (ifa->sa_family != AF_INET &&
			     ifa->sa_family != AF_INET6))
				continue;

			if (ifa->sa_family == AF_INET6 &&
			    (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) ||
			     IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr)))
				continue;

			if (ifindex && ifam->ifam_index != ifindex)
				continue;

			/* found */
			*lenp = ifam->ifam_msglen;
			return (char *)rtm;
			/* NOTREACHED */
		case RTM_IFINFO:
		case RTM_IFANNOUNCE:
			/* found */
			*lenp = rtm->rtm_msglen;
			return (char *)rtm;
			/* NOTREACHED */
		}
	}

	return ((char *)rtm);
}
コード例 #10
0
int
_load_v6(netsnmp_container *container, int idx_offset)
{
    FILE           *in;
    char            line[80], addr[40], if_name[IFNAMSIZ];
    u_char          *buf;
    int             if_index, pfx_len, scope, flags, rc = 0;
    size_t          in_len, out_len;
    netsnmp_ipaddress_entry *entry;
    _ioctl_extras           *extras;
    static int      log_open_err = 1;
    
    netsnmp_assert(NULL != container);

#define PROCFILE "/proc/net/if_inet6"
    if (!(in = fopen(PROCFILE, "r"))) {
        if (1 == log_open_err) {
            snmp_log(LOG_ERR,"could not open " PROCFILE "\n");
            log_open_err = 0;
        }
        return -2;
    }
    /*
     * if we hadn't been able to open file and turned of err logging,
     * turn it back on now that we opened the file.
     */
    if (0 == log_open_err)
        log_open_err = 1;

    /*
     * address index prefix_len scope status if_name
     */
    while (fgets(line, sizeof(line), in)) {
        /*
         * fe800000000000000200e8fffe5b5c93 05 40 20 80 eth0
         *             A                    D  P  S  F  I
         * A: address
         * D: device number
         * P: prefix len
         * S: scope (see include/net/ipv6.h, net/ipv6/addrconf.c)
         * F: flags (see include/linux/rtnetlink.h, net/ipv6/addrconf.c)
         * I: interface
         */
        rc = sscanf(line, "%39s %02x %02x %02x %02x %8s\n",
                    addr, &if_index, &pfx_len, &scope, &flags, if_name);
        if( 6 != rc ) {
            snmp_log(LOG_ERR, PROCFILE " data format error (%d!=6), line ==|%s|\n",
                     rc, line);
            continue;
        }
        DEBUGMSGTL(("access:ipaddress:container",
                    "addr %s, index %d, pfx %d, scope %d, flags 0x%X, name %s\n",
                    addr, if_index, pfx_len, scope, flags, if_name));
        /*
         */
        entry = netsnmp_access_ipaddress_entry_create();
        if(NULL == entry) {
            rc = -3;
            break;
        }

        in_len = entry->ia_address_len = sizeof(entry->ia_address);
        netsnmp_assert(16 == in_len);
        out_len = 0;
        buf = entry->ia_address;
        if(1 != netsnmp_hex_to_binary(&buf, &in_len,
                                      &out_len, 0, addr, ":")) {
            snmp_log(LOG_ERR,"error parsing '%s', skipping\n",
                     entry->ia_address);
            netsnmp_access_ipaddress_entry_free(entry);
            continue;
        }
        netsnmp_assert(16 == out_len);
        entry->ia_address_len = out_len;

        entry->ns_ia_index = ++idx_offset;

        /*
         * save if name
         */
        extras = netsnmp_ioctl_ipaddress_extras_get(entry);
        memcpy(extras->name, if_name, sizeof(extras->name));
        extras->flags = flags;

        /*
         * yyy-rks: optimization: create a socket outside the loop and use
         * netsnmp_access_interface_ioctl_ifindex_get() here, since
         * netsnmp_access_interface_index_find will open/close a socket
         * every time it is called.
         */
     //   entry->if_index = netsnmp_access_interface_index_find(if_name); //cz modified

        /*
          #define IPADDRESSSTATUSTC_PREFERRED  1
          #define IPADDRESSSTATUSTC_DEPRECATED  2
          #define IPADDRESSSTATUSTC_INVALID  3
          #define IPADDRESSSTATUSTC_INACCESSIBLE  4
          #define IPADDRESSSTATUSTC_UNKNOWN  5
          #define IPADDRESSSTATUSTC_TENTATIVE  6
          #define IPADDRESSSTATUSTC_DUPLICATE  7
        */
        if(flags & IFA_F_PERMANENT)
            entry->ia_status = IPADDRESSSTATUSTC_PREFERRED; /* ?? */
        else if(flags & IFA_F_DEPRECATED)
            entry->ia_status = IPADDRESSSTATUSTC_DEPRECATED;
        else if(flags & IFA_F_TENTATIVE)
            entry->ia_status = IPADDRESSSTATUSTC_TENTATIVE;
        else {
            entry->ia_status = IPADDRESSSTATUSTC_UNKNOWN;
            DEBUGMSGTL(("access:ipaddress:ipv6",
                        "unknown flags 0x%x\n", flags));
        }

        /*
         * if it's not multi, it must be uni.
         *  (an ipv6 address is never broadcast)
         */
        if (IN6_IS_ADDR_MULTICAST(entry->ia_address))
            entry->ia_type = IPADDRESSTYPE_ANYCAST;
        else
            entry->ia_type = IPADDRESSTYPE_UNICAST;


        entry->ia_prefix_len = pfx_len;

        /*
         * can we figure out if an address is from DHCP?
         * use manual until then...
         *
         *#define IPADDRESSORIGINTC_OTHER  1
         *#define IPADDRESSORIGINTC_MANUAL  2
         *#define IPADDRESSORIGINTC_DHCP  4
         *#define IPADDRESSORIGINTC_LINKLAYER  5
         *#define IPADDRESSORIGINTC_RANDOM  6
         *
         * are 'local' address assigned by link layer??
         */
        if (IN6_IS_ADDR_LINKLOCAL(entry->ia_address) ||
            IN6_IS_ADDR_SITELOCAL(entry->ia_address))
            entry->ia_origin = IPADDRESSORIGINTC_LINKLAYER;
        else
            entry->ia_origin = IPADDRESSORIGINTC_MANUAL;

        /* xxx-rks: what can we do with scope? */

        /*
         * add entry to container
         */
        CONTAINER_INSERT(container, entry);
    }

    fclose(in);

    if(rc<0)
        return rc;

    return idx_offset;
}
コード例 #11
0
/*
 * Input an Neighbor Solicitation Message.
 *
 * Based on RFC 2461
 * Based on RFC 2462 (duplicated address detection)
 */
void
nd6_ns_input(struct mbuf *m, int off, int icmp6len)
{
	struct ifnet *ifp = m->m_pkthdr.rcvif;
	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
	struct nd_neighbor_solicit *nd_ns;
	struct in6_addr saddr6 = ip6->ip6_src;
	struct in6_addr daddr6 = ip6->ip6_dst;
	struct in6_addr taddr6;
	struct in6_addr myaddr6;
	char *lladdr = NULL;
	struct ifaddr *ifa = NULL;
	int lladdrlen = 0;
	int anycast = 0, proxy = 0, tentative = 0;
	int router = ip6_forwarding;
	int tlladdr;
	union nd_opts ndopts;
	struct sockaddr_dl *proxydl = NULL;

	IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len);
	if (nd_ns == NULL) {
		icmp6stat.icp6s_tooshort++;
		return;
	}
	ip6 = mtod(m, struct ip6_hdr *); /* adjust pointer for safety */
	taddr6 = nd_ns->nd_ns_target;

	if (ip6->ip6_hlim != 255) {
		nd6log((LOG_ERR,
		    "nd6_ns_input: invalid hlim (%d) from %s to %s on %s\n",
		    ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
		    ip6_sprintf(&ip6->ip6_dst), ifp->if_xname));
		goto bad;
	}

	if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
		/* dst has to be solicited node multicast address. */
		/* don't check ifindex portion */
		if (daddr6.s6_addr16[0] == IPV6_ADDR_INT16_MLL &&
		    daddr6.s6_addr32[1] == 0 &&
		    daddr6.s6_addr32[2] == IPV6_ADDR_INT32_ONE &&
		    daddr6.s6_addr8[12] == 0xff) {
			; /*good*/
		} else {
			nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet "
			    "(wrong ip6 dst)\n"));
			goto bad;
		}
	} else {
		/*
		 * Make sure the source address is from a neighbor's address.
		 */
		if (in6ifa_ifplocaladdr(ifp, &saddr6) == NULL) {
			nd6log((LOG_INFO, "nd6_ns_input: "
			    "NS packet from non-neighbor\n"));
			goto bad;
		}
	}


	if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
		nd6log((LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n"));
		goto bad;
	}

	if (IN6_IS_SCOPE_EMBED(&taddr6))
		taddr6.s6_addr16[1] = htons(ifp->if_index);

	icmp6len -= sizeof(*nd_ns);
	nd6_option_init(nd_ns + 1, icmp6len, &ndopts);
	if (nd6_options(&ndopts) < 0) {
		nd6log((LOG_INFO,
		    "nd6_ns_input: invalid ND option, ignored\n"));
		/* nd6_options have incremented stats */
		goto freeit;
	}

	if (ndopts.nd_opts_src_lladdr) {
		lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
	}

	if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && lladdr) {
		nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet "
		    "(link-layer address option)\n"));
		goto bad;
	}

	/*
	 * Attaching target link-layer address to the NA?
	 * (RFC 2461 7.2.4)
	 *
	 * NS IP dst is unicast/anycast			MUST NOT add
	 * NS IP dst is solicited-node multicast	MUST add
	 *
	 * In implementation, we add target link-layer address by default.
	 * We do not add one in MUST NOT cases.
	 */
#if 0 /* too much! */
	ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &daddr6);
	if (ifa && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST))
		tlladdr = 0;
	else
#endif
	if (!IN6_IS_ADDR_MULTICAST(&daddr6))
		tlladdr = 0;
	else
		tlladdr = 1;

	/*
	 * Target address (taddr6) must be either:
	 * (1) Valid unicast/anycast address for my receiving interface,
	 * (2) Unicast address for which I'm offering proxy service, or
	 * (3) "tentative" address on which DAD is being performed.
	 */
	/* (1) and (3) check. */
#if NCARP > 0
	if (ifp->if_type == IFT_CARP) {
		ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
		if (ifa && !carp_iamatch6(ifp, lladdr, &proxydl))
			ifa = NULL;
	} else {
		ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
	}
#else
	ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
#endif

	/* (2) check. */
	if (!ifa) {
		struct rtentry *rt;
		struct sockaddr_in6 tsin6;

		bzero(&tsin6, sizeof tsin6);
		tsin6.sin6_len = sizeof(struct sockaddr_in6);
		tsin6.sin6_family = AF_INET6;
		tsin6.sin6_addr = taddr6;

		rt = rtalloc1((struct sockaddr *)&tsin6, 0, 0);
		if (rt && (rt->rt_flags & RTF_ANNOUNCE) != 0 &&
		    rt->rt_gateway->sa_family == AF_LINK) {
			/*
			 * proxy NDP for single entry
			 */
			ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
				IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
			if (ifa) {
				proxy = 1;
				proxydl = SDL(rt->rt_gateway);
				router = 0;	/* XXX */
			}
		}
		if (rt)
			rtfree(rt);
	}
	if (!ifa) {
		/*
		 * We've got an NS packet, and we don't have that address
		 * assigned for us.  We MUST silently ignore it.
		 * See RFC2461 7.2.3.
		 */
		goto freeit;
	}
	myaddr6 = *IFA_IN6(ifa);
	anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST;
	tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE;
	if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED)
		goto freeit;

	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
		nd6log((LOG_INFO, "nd6_ns_input: lladdrlen mismatch for %s "
		    "(if %d, NS packet %d)\n",
		    ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2));
		goto bad;
	}

	if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) {
		log(LOG_INFO, "nd6_ns_input: duplicate IP6 address %s\n",
		    ip6_sprintf(&saddr6));
		goto freeit;
	}

	/*
	 * We have neighbor solicitation packet, with target address equals to
	 * one of my tentative address.
	 *
	 * src addr	how to process?
	 * ---		---
	 * multicast	of course, invalid (rejected in ip6_input)
	 * unicast	somebody is doing address resolution -> ignore
	 * unspec	dup address detection
	 *
	 * The processing is defined in RFC 2462.
	 */
	if (tentative) {
		/*
		 * If source address is unspecified address, it is for
		 * duplicated address detection.
		 *
		 * If not, the packet is for address resolution;
		 * silently ignore it.
		 */
		if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
			nd6_dad_ns_input(ifa);

		goto freeit;
	}

	/*
	 * If the source address is unspecified address, entries must not
	 * be created or updated.
	 * It looks that sender is performing DAD.  Output NA toward
	 * all-node multicast address, to tell the sender that I'm using
	 * the address.
	 * S bit ("solicited") must be zero.
	 */
	if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
		saddr6 = in6addr_linklocal_allnodes;
		saddr6.s6_addr16[1] = htons(ifp->if_index);
		nd6_na_output(ifp, &saddr6, &taddr6,
		    ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
		    (router ? ND_NA_FLAG_ROUTER : 0),
		    tlladdr, (struct sockaddr *)proxydl);
		goto freeit;
	}

	nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_NEIGHBOR_SOLICIT, 0);

	nd6_na_output(ifp, &saddr6, &taddr6,
	    ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
	    (router ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED,
	    tlladdr, (struct sockaddr *)proxydl);
 freeit:
	m_freem(m);
	return;

 bad:
	nd6log((LOG_ERR, "nd6_ns_input: src=%s\n", ip6_sprintf(&saddr6)));
	nd6log((LOG_ERR, "nd6_ns_input: dst=%s\n", ip6_sprintf(&daddr6)));
	nd6log((LOG_ERR, "nd6_ns_input: tgt=%s\n", ip6_sprintf(&taddr6)));
	icmp6stat.icp6s_badns++;
	m_freem(m);
}
コード例 #12
0
/*
 * Output an Neighbor Solicitation Message. Caller specifies:
 *	- ICMP6 header source IP6 address
 *	- ND6 header target IP6 address
 *	- ND6 header source datalink address
 *
 * Based on RFC 2461
 * Based on RFC 2462 (duplicated address detection)
 *
 * ln - for source address determination
 * dad - duplicated address detection
 */
void
nd6_ns_output(struct ifnet *ifp, struct in6_addr *daddr6, 
    struct in6_addr *taddr6, struct llinfo_nd6 *ln, int dad)
{
	struct mbuf *m;
	struct ip6_hdr *ip6;
	struct nd_neighbor_solicit *nd_ns;
	struct sockaddr_in6 src_sa, dst_sa;
	struct ip6_moptions im6o;
	int icmp6len;
	int maxlen;
	caddr_t mac;
	struct route_in6 ro;

	bzero(&ro, sizeof(ro));

	if (IN6_IS_ADDR_MULTICAST(taddr6))
		return;

	/* estimate the size of message */
	maxlen = sizeof(*ip6) + sizeof(*nd_ns);
	maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
#ifdef DIAGNOSTIC
	if (max_linkhdr + maxlen >= MCLBYTES) {
		printf("nd6_ns_output: max_linkhdr + maxlen >= MCLBYTES "
		    "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES);
		panic("nd6_ns_output: insufficient MCLBYTES");
		/* NOTREACHED */
	}
#endif

	MGETHDR(m, M_DONTWAIT, MT_DATA);
	if (m && max_linkhdr + maxlen >= MHLEN) {
		MCLGET(m, M_DONTWAIT);
		if ((m->m_flags & M_EXT) == 0) {
			m_free(m);
			m = NULL;
		}
	}
	if (m == NULL)
		return;
	m->m_pkthdr.rcvif = NULL;

	if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) {
		m->m_flags |= M_MCAST;
		im6o.im6o_multicast_ifp = ifp;
		im6o.im6o_multicast_hlim = 255;
		im6o.im6o_multicast_loop = 0;
	}

	icmp6len = sizeof(*nd_ns);
	m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len;
	m->m_data += max_linkhdr;	/* or MH_ALIGN() equivalent? */

	/* fill neighbor solicitation packet */
	ip6 = mtod(m, struct ip6_hdr *);
	ip6->ip6_flow = 0;
	ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
	ip6->ip6_vfc |= IPV6_VERSION;
	/* ip6->ip6_plen will be set later */
	ip6->ip6_nxt = IPPROTO_ICMPV6;
	ip6->ip6_hlim = 255;
	/* determine the source and destination addresses */
	bzero(&src_sa, sizeof(src_sa));
	bzero(&dst_sa, sizeof(dst_sa));
	src_sa.sin6_family = dst_sa.sin6_family = AF_INET6;
	src_sa.sin6_len = dst_sa.sin6_len = sizeof(struct sockaddr_in6);
	if (daddr6)
		dst_sa.sin6_addr = *daddr6;
	else {
		dst_sa.sin6_addr.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
		dst_sa.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
		dst_sa.sin6_addr.s6_addr32[1] = 0;
		dst_sa.sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
		dst_sa.sin6_addr.s6_addr32[3] = taddr6->s6_addr32[3];
		dst_sa.sin6_addr.s6_addr8[12] = 0xff;
	}
	ip6->ip6_dst = dst_sa.sin6_addr;
	if (!dad) {
		/*
		 * RFC2461 7.2.2:
		 * "If the source address of the packet prompting the
		 * solicitation is the same as one of the addresses assigned
		 * to the outgoing interface, that address SHOULD be placed
		 * in the IP Source Address of the outgoing solicitation.
		 * Otherwise, any one of the addresses assigned to the
		 * interface should be used."
		 *
		 * We use the source address for the prompting packet
		 * (saddr6), if:
		 * - saddr6 is given from the caller (by giving "ln"), and
		 * - saddr6 belongs to the outgoing interface.
		 * Otherwise, we perform the source address selection as usual.
		 */
		struct ip6_hdr *hip6;		/* hold ip6 */
		struct in6_addr *saddr6;

		if (ln && ln->ln_hold) {
			hip6 = mtod(ln->ln_hold, struct ip6_hdr *);
			/* XXX pullup? */
			if (sizeof(*hip6) < ln->ln_hold->m_len)
				saddr6 = &hip6->ip6_src;
			else
				saddr6 = NULL;
		} else
コード例 #13
0
ファイル: network.c プロジェクト: Nekrofage/Quake2RPi
void
NET_SendPacket ( netsrc_t sock, int length, void *data, netadr_t to )
{
	int ret;
	struct sockaddr_storage addr;
	int net_socket;
	int addr_size = sizeof(struct sockaddr_in);

	switch (to.type)
	{
		case NA_LOOPBACK:
			NET_SendLoopPacket(sock, length, data, to);
			return;
			break;

		case NA_BROADCAST:
		case NA_IP:
			net_socket = ip_sockets[sock];

			if (!net_socket)
			{
				return;
			}

			break;

		case NA_IP6:
		case NA_MULTICAST6:
			net_socket = ip6_sockets[sock];
			addr_size = sizeof(struct sockaddr_in6);

			if (!net_socket)
			{
				return;
			}

			break;

		case NA_IPX:
		case NA_BROADCAST_IPX:
			net_socket = ipx_sockets[sock];

			if (!net_socket)
			{
				return;
			}

			break;

		default:
			Com_Error(ERR_FATAL, "NET_SendPacket: bad address type");
			return;
			break;
	}

	NetadrToSockadr(&to, &addr);

	/* Re-check the address family. If to.type is NA_IP6 but
	   contains an IPv4 mapped address, NetadrToSockadr will
	   return an AF_INET struct.  If so, switch back to AF_INET
	   socket.*/
	if ((to.type == NA_IP6) && (addr.ss_family == AF_INET))
	{
		net_socket = ip_sockets[sock];
		addr_size = sizeof(struct sockaddr_in);

		if (!net_socket)
		{
			return;
		}
	}

	if (addr.ss_family == AF_INET6)
	{
		struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)&addr;

		/* If multicast socket, must specify scope.
		   So multicast_interface must be specified */
		if (IN6_IS_ADDR_MULTICAST(&s6->sin6_addr))
		{
			struct addrinfo hints;
			struct addrinfo *res;
			char tmp[128], mcast_addr[128], mcast_port[10];
			int error;

			if (multicast_interface != NULL)
			{
				/* Do a getnameinfo/getaddrinfo cycle
				   to calculate the scope_id of the
				   multicast address. getaddrinfo is
				   passed a multicast address of the
				   form ff0x::xxx%multicast_interface */
#ifdef __FreeBSD__
				error = getnameinfo((struct sockaddr *)s6, s6->sin6_len, tmp,
						sizeof(tmp), NULL, 0, NI_NUMERICHOST);
#else
				error = getnameinfo((struct sockaddr *)s6, sizeof(struct sockaddr_in6),
							tmp, sizeof(tmp), NULL, 0, NI_NUMERICHOST);
#endif

				if (error)
				{
					Com_Printf("NET_SendPacket: getnameinfo: %s\n", gai_strerror(error));
					return;
				}

				Com_sprintf(mcast_addr, sizeof(mcast_addr), "%s%%%s", tmp,
						multicast_interface);
				Com_sprintf(mcast_port, sizeof(mcast_port), "%d",
						ntohs(s6->sin6_port));
				memset(&hints, 0, sizeof(hints));
				hints.ai_family = AF_INET6;
				hints.ai_socktype = SOCK_DGRAM;
				hints.ai_flags = AI_NUMERICHOST;

				error = getaddrinfo(mcast_addr, mcast_port, &hints, &res);

				if (error)
				{
					Com_Printf("NET_SendPacket: getaddrinfo: %s\n", gai_strerror(error));
					return;
				}

				/* sockaddr_in6 should now have a valid scope_id. */
				memcpy(s6, res->ai_addr, res->ai_addrlen);
			}
			else
			{
				Com_Printf("NET_SendPacket: IPv6 multicast destination but +set multicast not specified: %s\n",
						inet_ntop(AF_INET6, &s6->sin6_addr, tmp, sizeof(tmp)));
				return;
			}
		}
	}

	ret = sendto(net_socket, data, length, 0, (struct sockaddr *)&addr, addr_size);

	if (ret == -1)
	{
		Com_Printf("NET_SendPacket ERROR: %s to %s\n", NET_ErrorString(),
				NET_AdrToString(to));
	}
}