Exemple #1
0
int
atmresolve(struct rtentry *rt0, struct mbuf *m, const struct sockaddr *dst,
    struct atm_pseudohdr *desten /* OUT */)
{
	const struct sockaddr_dl *sdl;
	struct rtentry *rt = rt0;

	if (m->m_flags & (M_BCAST|M_MCAST)) {
		log(LOG_INFO, "atmresolve: BCAST/MCAST packet detected/dumped\n");
		goto bad;
	}

	if (rt == NULL) {
		rt = RTALLOC1(dst, 0);
		if (rt == NULL)
			goto bad; /* failed */
		if ((rt->rt_flags & RTF_GATEWAY) != 0 ||
		    /* XXX: are we using LLINFO? */
		    rt->rt_gateway->sa_family != AF_LINK) {
			rtfree(rt);
			goto bad;
		}
	}

	/*
	 * note that rt_gateway is a sockaddr_dl which contains the
	 * atm_pseudohdr data structure for this route.   we currently
	 * don't need any rt_llinfo info (but will if we want to support
	 * ATM ARP [c.f. if_ether.c]).
	 */

	sdl = satocsdl(rt->rt_gateway);

	/*
	 * Check the address family and length is valid, the address
	 * is resolved; otherwise, try to resolve.
	 */

	if (sdl->sdl_family == AF_LINK && sdl->sdl_alen == sizeof(*desten)) {
		memcpy(desten, CLLADDR(sdl), sdl->sdl_alen);
		if (rt != rt0)
			rtfree(rt);
		return (1);	/* ok, go for it! */
	}

	if (rt != rt0)
		rtfree(rt);

	/*
	 * we got an entry, but it doesn't have valid link address
	 * info in it (it is prob. the interface route, which has
	 * sdl_alen == 0).    dump packet.  (fall through to "bad").
	 */

bad:
	m_freem(m);
	return (0);
}
void
print_link_addresses(prop_dictionary_t env, bool print_active_only)
{
	char hbuf[NI_MAXHOST];
	const char *ifname;
	int s;
	struct ifaddrs *ifa, *ifap;
	const struct sockaddr_dl *sdl;
	struct if_laddrreq iflr;

	if ((ifname = getifname(env)) == NULL)
		err(EXIT_FAILURE, "%s: getifname", __func__);

	if ((s = getsock(AF_LINK)) == -1)
		err(EXIT_FAILURE, "%s: getsock", __func__);

	if (getifaddrs(&ifap) == -1)
		err(EXIT_FAILURE, "%s: getifaddrs", __func__);

	memset(&iflr, 0, sizeof(iflr));

	strlcpy(iflr.iflr_name, ifname, sizeof(iflr.iflr_name));

	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
		if (strcmp(ifname, ifa->ifa_name) != 0)
			continue;
		if (ifa->ifa_addr->sa_family != AF_LINK)
			continue;

		sdl = satocsdl(ifa->ifa_addr);

		memcpy(&iflr.addr, ifa->ifa_addr, MIN(ifa->ifa_addr->sa_len,
		    sizeof(iflr.addr)));
		iflr.flags = IFLR_PREFIX;
		iflr.prefixlen = sdl->sdl_alen * NBBY;

		if (prog_ioctl(s, SIOCGLIFADDR, &iflr) == -1)
			err(EXIT_FAILURE, "%s: ioctl", __func__);

		if (((iflr.flags & IFLR_ACTIVE) != 0) != print_active_only)
			continue;

		if (getnameinfo(ifa->ifa_addr, ifa->ifa_addr->sa_len,
			hbuf, sizeof(hbuf), NULL, 0,
			Nflag ? 0 : NI_NUMERICHOST) == 0 &&
		    hbuf[0] != '\0') {
			printf("\t%s %s\n",
			    print_active_only ? "address:" : "link", hbuf);
		}
	}
	freeifaddrs(ifap);
}
Exemple #3
0
void
atm_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
{
	struct sockaddr *gate = rt->rt_gateway;
	struct atm_pseudoioctl api;
#ifdef NATM
	const struct sockaddr_in *sin;
	struct natmpcb *npcb = NULL;
	const struct atm_pseudohdr *aph;
#endif
	const struct ifnet *ifp = rt->rt_ifp;
	uint8_t namelen = strlen(ifp->if_xname);
	uint8_t addrlen = ifp->if_addrlen;

	if (rt->rt_flags & RTF_GATEWAY)   /* link level requests only */
		return;

	switch (req) {

	case RTM_RESOLVE: /* resolve: only happens when cloning */
		printf("atm_rtrequest: RTM_RESOLVE request detected?\n");
		break;

	case RTM_ADD:

		/*
		 * route added by a command (e.g. ifconfig, route, arp...).
		 *
		 * first check to see if this is not a host route, in which
		 * case we are being called via "ifconfig" to set the address.
		 */

		if ((rt->rt_flags & RTF_HOST) == 0) {
			union {
				struct sockaddr sa;
				struct sockaddr_dl sdl;
				struct sockaddr_storage ss;
			} u;

			sockaddr_dl_init(&u.sdl, sizeof(u.ss),
			    ifp->if_index, ifp->if_type,
			    NULL, namelen, NULL, addrlen);
			rt_setgate(rt, &u.sa);
			gate = rt->rt_gateway;
			break;
		}

		if ((rt->rt_flags & RTF_CLONING) != 0) {
			printf("atm_rtrequest: cloning route detected?\n");
			break;
		}
		if (gate->sa_family != AF_LINK ||
		    gate->sa_len < sockaddr_dl_measure(namelen, addrlen)) {
			log(LOG_DEBUG, "atm_rtrequest: bad gateway value\n");
			break;
		}

#ifdef DIAGNOSTIC
		if (rt->rt_ifp->if_ioctl == NULL) panic("atm null ioctl");
#endif

#ifdef NATM
		/*
		 * let native ATM know we are using this VCI/VPI
		 * (i.e. reserve it)
		 */
		sin = satocsin(rt_getkey(rt));
		if (sin->sin_family != AF_INET)
			goto failed;
		aph = (const struct atm_pseudohdr *)CLLADDR(satosdl(gate));
		npcb = npcb_add(NULL, rt->rt_ifp, ATM_PH_VCI(aph),
						ATM_PH_VPI(aph));
		if (npcb == NULL)
			goto failed;
		npcb->npcb_flags |= NPCB_IP;
		npcb->ipaddr.s_addr = sin->sin_addr.s_addr;
		/* XXX: move npcb to llinfo when ATM ARP is ready */
		rt->rt_llinfo = (void *) npcb;
		rt->rt_flags |= RTF_LLINFO;
#endif
		/*
		 * let the lower level know this circuit is active
		 */
		memcpy(&api.aph, CLLADDR(satocsdl(gate)), sizeof(api.aph));
		api.rxhand = NULL;
		if (rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMENA, &api) != 0) {
			printf("atm: couldn't add VC\n");
			goto failed;
		}

		satosdl(gate)->sdl_type = rt->rt_ifp->if_type;
		satosdl(gate)->sdl_index = rt->rt_ifp->if_index;

		break;

failed:
#ifdef NATM
		if (npcb) {
			npcb_free(npcb, NPCB_DESTROY);
			rt->rt_llinfo = NULL;
			rt->rt_flags &= ~RTF_LLINFO;
		}
#endif
		rtrequest(RTM_DELETE, rt_getkey(rt), NULL,
			rt_mask(rt), 0, NULL);
		break;

	case RTM_DELETE:

#ifdef NATM
		/*
		 * tell native ATM we are done with this VC
		 */

		if (rt->rt_flags & RTF_LLINFO) {
			npcb_free((struct natmpcb *)rt->rt_llinfo,
								NPCB_DESTROY);
			rt->rt_llinfo = NULL;
			rt->rt_flags &= ~RTF_LLINFO;
		}
#endif
		/*
		 * tell the lower layer to disable this circuit
		 */

		memcpy(&api.aph, CLLADDR(satocsdl(gate)), sizeof(api.aph));
		api.rxhand = NULL;
		(void)rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMDIS, &api);

		break;
	}
}
Exemple #4
0
/*
 * 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;
    int lladdrlen = 0;
    int anycast = 0, proxy = 0, tentative = 0;
    int router = ip6_forwarding;
    int tlladdr;
    union nd_opts ndopts;
    const struct sockaddr_dl *proxydl = NULL;

    IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len);
    if (nd_ns == NULL) {
        ICMP6_STATINC(ICMP6_STAT_TOOSHORT);
        return;
    }
    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(&ip6->ip6_src),
                ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
        goto bad;
    }

    if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
        /* dst has to be a 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 {
        struct sockaddr_in6 ssin6;

        /*
         * Make sure the source address is from a neighbor's address.
         */
        sockaddr_in6_init(&ssin6, &saddr6, 0, 0, 0);
        if (nd6_is_addr_neighbor(&ssin6, 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 multicast			MUST add
     * Otherwise					MAY be omitted
     *
     * In this implementation, we omit the target link-layer address
     * in the "MAY" case.
     */
#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_carp && ifp->if_type != IFT_CARP)
        ifa = carp_iamatch6(ifp->if_carp, &taddr6);
    else
        ifa = NULL;
    if (!ifa)
        ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
#else
    ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
#endif

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

        sockaddr_in6_init(&tsin6, &taddr6, 0, 0, 0);

        rt = rtalloc1((struct sockaddr *)&tsin6, 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 = satocsdl(rt->rt_gateway);
                router = 0;	/* XXX */
            }
        }
        if (rt)
            rtfree(rt);
    }
    if (ifa == NULL) {
        /*
         * 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)) {
        nd6log((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
         * 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) |
                      (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0),
                      tlladdr, (const 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, (const 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)));
    ICMP6_STATINC(ICMP6_STAT_BADNS);
    m_freem(m);
}
Exemple #5
0
/*
 * Get interface identifier for the specified interface.
 *
 * in6 - upper 64bits are preserved
 */
int
in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
{
	struct ifaddr *ifa;
	const struct sockaddr_dl *sdl = NULL, *tsdl;
	const char *addr;
	size_t addrlen;
	static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
	static u_int8_t allone[8] =
		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

	IFADDR_FOREACH(ifa, ifp) {
		if (ifa->ifa_addr->sa_family != AF_LINK)
			continue;
		tsdl = satocsdl(ifa->ifa_addr);
		if (tsdl == NULL || tsdl->sdl_alen == 0)
			continue;
		if (sdl == NULL || ifa == ifp->if_dl || ifa == ifp->if_hwdl)
			sdl = tsdl;
		if (ifa == ifp->if_hwdl)
			break;
	}

	if (sdl == NULL)
		return -1;

	addr = CLLADDR(sdl);
	addrlen = sdl->sdl_alen;

	switch (ifp->if_type) {
	case IFT_IEEE1394:
	case IFT_IEEE80211:
		/* IEEE1394 uses 16byte length address starting with EUI64 */
		if (addrlen > 8)
			addrlen = 8;
		break;
	default:
		break;
	}

	/* get EUI64 */
	switch (ifp->if_type) {
	/* IEEE802/EUI64 cases - what others? */
	case IFT_ETHER:
	case IFT_FDDI:
	case IFT_ATM:
	case IFT_IEEE1394:
	case IFT_IEEE80211:
		/* look at IEEE802/EUI64 only */
		if (addrlen != 8 && addrlen != 6)
			return -1;

		/*
		 * check for invalid MAC address - on bsdi, we see it a lot
		 * since wildboar configures all-zero MAC on pccard before
		 * card insertion.
		 */
		if (memcmp(addr, allzero, addrlen) == 0)
			return -1;
		if (memcmp(addr, allone, addrlen) == 0)
			return -1;

		/* make EUI64 address */
		if (addrlen == 8)
			memcpy(&in6->s6_addr[8], addr, 8);
		else if (addrlen == 6) {
			in6->s6_addr[8] = addr[0];
			in6->s6_addr[9] = addr[1];
			in6->s6_addr[10] = addr[2];
			in6->s6_addr[11] = 0xff;
			in6->s6_addr[12] = 0xfe;
			in6->s6_addr[13] = addr[3];
			in6->s6_addr[14] = addr[4];
			in6->s6_addr[15] = addr[5];
		}
		break;

	case IFT_ARCNET:
		if (addrlen != 1)
			return -1;
		if (!addr[0])
			return -1;

		memset(&in6->s6_addr[8], 0, 8);
		in6->s6_addr[15] = addr[0];

		/*
		 * due to insufficient bitwidth, we mark it local.
		 */
		in6->s6_addr[8] &= ~EUI64_GBIT;	/* g bit to "individual" */
		in6->s6_addr[8] |= EUI64_UBIT;	/* u bit to "local" */
		break;

	case IFT_GIF:
#ifdef IFT_STF
	case IFT_STF:
#endif
		/*
		 * RFC2893 says: "SHOULD use IPv4 address as ifid source".
		 * however, IPv4 address is not very suitable as unique
		 * identifier source (can be renumbered).
		 * we don't do this.
		 */
		return -1;

	default:
		return -1;
	}

	/* sanity check: g bit must not indicate "group" */
	if (EUI64_GROUP(in6))
		return -1;

	/* convert EUI64 into IPv6 interface identifier */
	EUI64_TO_IFID(in6);

	/*
	 * sanity check: ifid must not be all zero, avoid conflict with
	 * subnet router anycast
	 */
	if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
	    memcmp(&in6->s6_addr[9], allzero, 7) == 0) {
		return -1;
	}

	return 0;
}