Exemple #1
0
int
_intf_get_noalias(intf_t *intf, struct intf_entry *entry)
{
	struct lifreq lifr;

	/* Get interface index. */
	entry->intf_index = if_nametoindex(entry->intf_name);
	if (entry->intf_index == 0)
		return (-1);

	strlcpy(lifr.lifr_name, entry->intf_name, sizeof(lifr.lifr_name));

	/* Get interface flags. */
	if (ioctl(intf->fd, SIOCGLIFFLAGS, &lifr) < 0)
		return (-1);
	
	entry->intf_flags = intf_iff_to_flags(lifr.lifr_flags);
	_intf_set_type(entry);
	
	/* Get interface MTU. */
#ifdef SIOCSIFMTU
	if (ioctl(intf->fd, SIOCGLIFMTU, &lifr) < 0)
#endif
		return (-1);
	entry->intf_mtu = lifr.lifr_mtu;

	entry->intf_addr.addr_type = entry->intf_dst_addr.addr_type =
	    entry->intf_link_addr.addr_type = ADDR_TYPE_NONE;
	
	/* Get primary interface address. */
	if (ioctl(intf->fd, SIOCGLIFADDR, &lifr) == 0) {
		addr_ston((struct sockaddr *)&lifr.lifr_addr, &entry->intf_addr);
		if (ioctl(intf->fd, SIOCGLIFNETMASK, &lifr) < 0)
			return (-1);
		addr_stob((struct sockaddr *)&lifr.lifr_addr, &entry->intf_addr.addr_bits);
	}
	/* Get other addresses. */
	if (entry->intf_type == INTF_TYPE_TUN) {
		if (ioctl(intf->fd, SIOCGLIFDSTADDR, &lifr) == 0) {
			if (addr_ston((struct sockaddr *)&lifr.lifr_addr,
			    &entry->intf_dst_addr) < 0)
				return (-1);
		}
	} else if (entry->intf_type == INTF_TYPE_ETH) {
		eth_t *eth;
		
		if ((eth = eth_open(entry->intf_name)) != NULL) {
			if (!eth_get(eth, &entry->intf_link_addr.addr_eth)) {
				entry->intf_link_addr.addr_type =
				    ADDR_TYPE_ETH;
				entry->intf_link_addr.addr_bits =
				    ETH_ADDR_BITS;
			}
			eth_close(eth);
		}
	}
	return (0);
}
Exemple #2
0
int
arp_get(arp_t *a, struct arp_entry *entry)
{
	struct arpreq ar;

	memset(&ar, 0, sizeof(ar));
	
	if (addr_ntos(&entry->arp_pa, &ar.arp_pa) < 0)
		return (-1);
	
#ifdef HAVE_ARPREQ_ARP_DEV
	if (intf_loop(a->intf, _arp_set_dev, &ar) != 1) {
		errno = ESRCH;
		return (-1);
	}
#endif
	if (ioctl(a->fd, SIOCGARP, &ar) < 0)
		return (-1);

	if ((ar.arp_flags & ATF_COM) == 0) {
		errno = ESRCH;
		return (-1);
	}
	return (addr_ston(&ar.arp_ha, &entry->arp_ha));
}
Exemple #3
0
static int
_radix_walk(int fd, struct radix_node *rn, arp_handler callback, void *arg)
{
	struct radix_node rnode;
	struct rtentry rt;
	struct sockaddr_in sin;
	struct arptab at;
	struct arp_entry entry;
	int ret = 0;
 again:
	_kread(fd, rn, &rnode, sizeof(rnode));
	if (rnode.rn_b < 0) {
		if (!(rnode.rn_flags & RNF_ROOT)) {
			_kread(fd, rn, &rt, sizeof(rt));
			_kread(fd, rt_key(&rt), &sin, sizeof(sin));
			addr_ston((struct sockaddr *)&sin, &entry.arp_pa);
			_kread(fd, rt.rt_llinfo, &at, sizeof(at));
			if (at.at_flags & ATF_COM) {
				addr_pack(&entry.arp_ha, ADDR_TYPE_ETH,
				    ETH_ADDR_BITS, at.at_hwaddr, ETH_ADDR_LEN);
				if ((ret = callback(&entry, arg)) != 0)
					return (ret);
			}
		}
		if ((rn = rnode.rn_dupedkey))
			goto again;
	} else {
		rn = rnode.rn_r;
		if ((ret = _radix_walk(fd, rnode.rn_l, callback, arg)) != 0)
			return (ret);
		if ((ret = _radix_walk(fd, rn, callback, arg)) != 0)
			return (ret);
	}
	return (ret);
}
int
intf_get_src(intf_t *intf, struct intf_entry *entry, struct addr *src)
{
	IP_ADAPTER_ADDRESSES *a;
	IP_ADAPTER_UNICAST_ADDRESS *addr;

	if (src->addr_type != ADDR_TYPE_IP) {
		errno = EINVAL;
		return (-1);
	}
	if (_refresh_tables(intf) < 0)
		return (-1);
	
	for (a = intf->iftable; a != NULL; a = a->Next) {
		for (addr = a->FirstUnicastAddress; addr != NULL; addr = addr->Next) {
			struct addr dnet_addr;

			addr_ston(addr->Address.lpSockaddr, &dnet_addr);
			if (addr_cmp(&dnet_addr, src) == 0) {
				_adapter_address_to_entry(intf, a, entry);
				return (0);
			}
		}
	}
	errno = ENXIO;
	return (-1);
}
Exemple #5
0
/* XXX - aliases on IRIX don't show up in SIOCGIFCONF */
static int
_intf_get_aliases(intf_t *intf, struct intf_entry *entry)
{
    struct dnet_ifaliasreq ifra;
    struct addr *ap, *lap;

    strlcpy(ifra.ifra_name, entry->intf_name, sizeof(ifra.ifra_name));
    addr_ntos(&entry->intf_addr, &ifra.ifra_addr);
    addr_btos(entry->intf_addr.addr_bits, &ifra.ifra_mask);
    memset(&ifra.ifra_brdaddr, 0, sizeof(ifra.ifra_brdaddr));
    ifra.ifra_cookie = 1;

    ap = entry->intf_alias_addrs;
    lap = (struct addr *)((u_char *)entry + entry->intf_len);

    while (ioctl(intf->fd, SIOCLIFADDR, &ifra) == 0 &&
            ifra.ifra_cookie > 0 && (ap + 1) < lap) {
        if (addr_ston(&ifra.ifra_addr, ap) < 0)
            break;
        ap++, entry->intf_alias_num++;
    }
    entry->intf_len = (u_char *)ap - (u_char *)entry;

    return (0);
}
Exemple #6
0
int
intf_get_dst(intf_t *intf, struct intf_entry *entry, struct addr *dst)
{
    struct sockaddr_in sin;
    int n;

    if (dst->addr_type != ADDR_TYPE_IP) {
        errno = EINVAL;
        return (-1);
    }
    addr_ntos(dst, (struct sockaddr *)&sin);
    sin.sin_port = htons(666);

    if (connect(intf->fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
        return (-1);

    n = sizeof(sin);
    if (getsockname(intf->fd, (struct sockaddr *)&sin, &n) < 0)
        return (-1);

    addr_ston((struct sockaddr *)&sin, &entry->intf_addr);

    if (intf_loop(intf, _match_intf_src, entry) != 1)
        return (-1);

    return (0);
}
Exemple #7
0
int
arp_loop(arp_t *arp, arp_handler callback, void *arg)
{
	struct arp_entry entry;
	struct rt_msghdr *rtm;
	struct sockaddr_in *sin;
	struct sockaddr *sa;
	char *buf, *lim, *next;
	size_t len;
	int ret, mib[6] = { CTL_NET, PF_ROUTE, 0, AF_INET,
			    NET_RT_FLAGS, RTF_LLINFO };

	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
		return (-1);

	if (len == 0)
		return (0);

	if ((buf = malloc(len)) == NULL)
		return (-1);

	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
		free(buf);
		return (-1);
	}
	lim = buf + len;
	ret = 0;

	for (next = buf; next < lim; next += rtm->rtm_msglen) {
		rtm = (struct rt_msghdr *)next;
		sin = (struct sockaddr_in *)(rtm + 1);
		sa = (struct sockaddr *)(sin + 1);

		if (addr_ston((struct sockaddr *)sin, &entry.arp_pa) < 0 ||
		    addr_ston(sa, &entry.arp_ha) < 0)
			continue;

		if ((ret = callback(&entry, arg)) != 0)
			break;
	}
	free(buf);

	return (ret);
}
Exemple #8
0
static int
_radix_walk(int fd, struct radix_node *rn, route_handler callback, void *arg)
{
	struct radix_node rnode;
	struct rtentry rt;
	struct sockaddr_in sin;
	struct route_entry entry;
	int ret = 0;
 again:
	_kread(fd, rn, &rnode, sizeof(rnode));
	if (rnode.rn_b < 0) {
		if (!(rnode.rn_flags & RNF_ROOT)) {
			entry.intf_name[0] = '\0';
			_kread(fd, rn, &rt, sizeof(rt));
			_kread(fd, rt_key(&rt), &sin, sizeof(sin));
			addr_ston((struct sockaddr *)&sin, &entry.route_dst);
			if (!(rt.rt_flags & RTF_HOST)) {
				_kread(fd, rt_mask(&rt), &sin, sizeof(sin));
				addr_stob((struct sockaddr *)&sin,
				    &entry.route_dst.addr_bits);
			}
			_kread(fd, rt.rt_gateway, &sin, sizeof(sin));
			addr_ston((struct sockaddr *)&sin, &entry.route_gw);
			entry.metric = 0;
			if ((ret = callback(&entry, arg)) != 0)
				return (ret);
		}
		if ((rn = rnode.rn_dupedkey))
			goto again;
	} else {
		rn = rnode.rn_r;
		if ((ret = _radix_walk(fd, rnode.rn_l, callback, arg)) != 0)
			return (ret);
		if ((ret = _radix_walk(fd, rn, callback, arg)) != 0)
			return (ret);
	}
	return (ret);
}
Exemple #9
0
int
eth_get(eth_t *e, eth_addr_t *ea)
{
	struct addr ha;
	
	if (ioctl(e->fd, SIOCGIFHWADDR, &e->ifr) < 0)
		return (-1);
	
	if (addr_ston(&e->ifr.ifr_hwaddr, &ha) < 0)
		return (-1);

	memcpy(ea, &ha.addr_eth, sizeof(*ea));
	return (0);
}
Exemple #10
0
int
eth_get(eth_t *e, eth_addr_t *ea)
{
	struct if_msghdr *ifm;
	struct sockaddr_dl *sdl;
	struct addr ha;
	u_char *p, *buf;
	size_t len;
	int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };

	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
		return (-1);

	if ((buf = malloc(len)) == NULL)
		return (-1);

	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
		free(buf);
		return (-1);
	}
	for (p = buf; p < buf + len; p += ifm->ifm_msglen) {
		ifm = (struct if_msghdr *)p;
		sdl = (struct sockaddr_dl *)(ifm + 1);

		if (ifm->ifm_type != RTM_IFINFO ||
		    (ifm->ifm_addrs & RTA_IFP) == 0)
			continue;

		if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
		    memcmp(sdl->sdl_data, e->device, sdl->sdl_nlen) != 0)
			continue;

		if (addr_ston((struct sockaddr *)sdl, &ha) == 0)
			break;
	}
	free(buf);

	if (p >= buf + len) {
		errno = ESRCH;
		return (-1);
	}
	memcpy(ea, &ha.addr_eth, sizeof(*ea));

	return (0);
}
int
eth_get(eth_t *e, eth_addr_t *ea)
{
	struct addr ha;
	
	if (ioctl(e->fd, SIOCGIFADDR, &e->ifr) < 0)
		return (-1);

	if (addr_ston(&e->ifr.ifr_addr, &ha) < 0)
		return (-1);

	if (ha.addr_type != ADDR_TYPE_ETH) {
		errno = EINVAL;
		return (-1);
	}
	memcpy(ea, &ha.addr_eth, sizeof(*ea));
	
	return (0);
}
Exemple #12
0
static int
_arp_set_dev(const struct intf_entry *entry, void *arg)
{
	struct arpreq *ar = (struct arpreq *)arg;
	struct addr dst;
	uint32_t mask;

	if (entry->intf_type == INTF_TYPE_ETH &&
	    entry->intf_addr.addr_type == ADDR_TYPE_IP) {
		addr_btom(entry->intf_addr.addr_bits, &mask, IP_ADDR_LEN);
		addr_ston((struct sockaddr *)&ar->arp_pa, &dst);
	
		if ((entry->intf_addr.addr_ip & mask) ==
		    (dst.addr_ip & mask)) {
			strlcpy(ar->arp_dev, entry->intf_name,
			    sizeof(ar->arp_dev));
			return (1);
		}
	}
	return (0);
}
Exemple #13
0
/* This wrapper around addr_ston, on failure, checks for a gateway address
 * family of AF_LINK, and if it finds one, stores an all-zero address of the
 * same type as dst. The all-zero address is a convention for same-subnet
 * routing table entries. */
static int
addr_ston_gateway(const struct addr *dst,
	const struct sockaddr *sa, struct addr *a)
{
	int rc;

	rc = addr_ston(sa, a);
	if (rc == 0)
		return rc;

#ifdef HAVE_NET_IF_DL_H
# ifdef AF_LINK
	if (sa->sa_family == AF_LINK) {
		memset(a, 0, sizeof(*a));
		a->addr_type = dst->addr_type;
		return (0);
	}
# endif
#endif

	return (-1);
}
Exemple #14
0
int
arp_get(arp_t *arp, struct arp_entry *entry)
{
	struct arpmsg msg;
	struct sockaddr_in *sin;
	struct sockaddr *sa;

	if (entry->arp_pa.addr_type != ADDR_TYPE_IP) {
		errno = EAFNOSUPPORT;
		return (-1);
	}
	sin = (struct sockaddr_in *)msg.addrs;
	sa = (struct sockaddr *)(sin + 1);

	if (addr_ntos(&entry->arp_pa, (struct sockaddr *)sin) < 0)
		return (-1);

	memset(&msg.rtm, 0, sizeof(msg.rtm));
	msg.rtm.rtm_type = RTM_GET;
	msg.rtm.rtm_addrs = RTA_DST;
	msg.rtm.rtm_flags = RTF_LLINFO;
	msg.rtm.rtm_msglen = sizeof(msg.rtm) + sizeof(*sin);

	if (arp_msg(arp, &msg) < 0)
		return (-1);

	if (msg.rtm.rtm_msglen < (int)sizeof(msg.rtm) +
	    sizeof(*sin) + sizeof(*sa) ||
	    sin->sin_addr.s_addr != entry->arp_pa.addr_ip ||
	    sa->sa_family != AF_LINK) {
		errno = ESRCH;
		return (-1);
	}
	if (addr_ston(sa, &entry->arp_ha) < 0)
		return (-1);

	return (0);
}
Exemple #15
0
int
route_loop(route_t *r, route_handler callback, void *arg)
{
	struct route_entry entry;
	struct strbuf msg;
	struct T_optmgmt_req *tor;
	struct T_optmgmt_ack *toa;
	struct T_error_ack *tea;
	struct opthdr *opt;
	u_char buf[8192];
	int flags, rc, rtable, ret;

	tor = (struct T_optmgmt_req *)buf;
	toa = (struct T_optmgmt_ack *)buf;
	tea = (struct T_error_ack *)buf;

	tor->PRIM_type = T_OPTMGMT_REQ;
	tor->OPT_offset = sizeof(*tor);
	tor->OPT_length = sizeof(*opt);
	tor->MGMT_flags = T_CURRENT;
	
	opt = (struct opthdr *)(tor + 1);
	opt->level = MIB2_IP;
	opt->name = opt->len = 0;
	
	msg.maxlen = sizeof(buf);
	msg.len = sizeof(*tor) + sizeof(*opt);
	msg.buf = buf;
	
	if (putmsg(r->ip_fd, &msg, NULL, 0) < 0)
		return (-1);
	
	opt = (struct opthdr *)(toa + 1);
	msg.maxlen = sizeof(buf);
	
	for (;;) {
		mib2_ipRouteEntry_t *rt, *rtend;

		flags = 0;
		if ((rc = getmsg(r->ip_fd, &msg, NULL, &flags)) < 0)
			return (-1);

		/* See if we're finished. */
		if (rc == 0 &&
		    msg.len >= sizeof(*toa) &&
		    toa->PRIM_type == T_OPTMGMT_ACK &&
		    toa->MGMT_flags == T_SUCCESS && opt->len == 0)
			break;

		if (msg.len >= sizeof(*tea) && tea->PRIM_type == T_ERROR_ACK)
			return (-1);
		
		if (rc != MOREDATA || msg.len < (int)sizeof(*toa) ||
		    toa->PRIM_type != T_OPTMGMT_ACK ||
		    toa->MGMT_flags != T_SUCCESS)
			return (-1);
		
		rtable = (opt->level == MIB2_IP && opt->name == MIB2_IP_21);
		
		msg.maxlen = sizeof(buf) - (sizeof(buf) % sizeof(*rt));
		msg.len = 0;
		flags = 0;
		
		do {
			struct sockaddr_in sin;

			rc = getmsg(r->ip_fd, NULL, &msg, &flags);
			
			if (rc != 0 && rc != MOREDATA)
				return (-1);
			
			if (!rtable)
				continue;
			
			rt = (mib2_ipRouteEntry_t *)msg.buf;
			rtend = (mib2_ipRouteEntry_t *)(msg.buf + msg.len);

			sin.sin_family = AF_INET;

			for ( ; rt < rtend; rt++) {
				if ((rt->ipRouteInfo.re_ire_type &
				    (IRE_BROADCAST|IRE_ROUTE_REDIRECT|
					IRE_LOCAL|IRE_ROUTE)) != 0 ||
				    rt->ipRouteNextHop == IP_ADDR_ANY)
					continue;
				
				sin.sin_addr.s_addr = rt->ipRouteNextHop;
				addr_ston((struct sockaddr *)&sin,
				    &entry.route_gw);
				
				sin.sin_addr.s_addr = rt->ipRouteDest;
				addr_ston((struct sockaddr *)&sin,
				    &entry.route_dst);
				
				sin.sin_addr.s_addr = rt->ipRouteMask;
				addr_stob((struct sockaddr *)&sin,
				    &entry.route_dst.addr_bits);
				
				if ((ret = callback(&entry, arg)) != 0)
					return (ret);
			}
		} while (rc == MOREDATA);
	}

	tor = (struct T_optmgmt_req *)buf;
	toa = (struct T_optmgmt_ack *)buf;
	tea = (struct T_error_ack *)buf;

	tor->PRIM_type = T_OPTMGMT_REQ;
	tor->OPT_offset = sizeof(*tor);
	tor->OPT_length = sizeof(*opt);
	tor->MGMT_flags = T_CURRENT;
	
	opt = (struct opthdr *)(tor + 1);
	opt->level = MIB2_IP6;
	opt->name = opt->len = 0;
	
	msg.maxlen = sizeof(buf);
	msg.len = sizeof(*tor) + sizeof(*opt);
	msg.buf = buf;
	
	if (putmsg(r->ip_fd, &msg, NULL, 0) < 0)
		return (-1);
	
	opt = (struct opthdr *)(toa + 1);
	msg.maxlen = sizeof(buf);
	
	for (;;) {
		mib2_ipv6RouteEntry_t *rt, *rtend;

		flags = 0;
		if ((rc = getmsg(r->ip_fd, &msg, NULL, &flags)) < 0)
			return (-1);

		/* See if we're finished. */
		if (rc == 0 &&
		    msg.len >= sizeof(*toa) &&
		    toa->PRIM_type == T_OPTMGMT_ACK &&
		    toa->MGMT_flags == T_SUCCESS && opt->len == 0)
			break;

		if (msg.len >= sizeof(*tea) && tea->PRIM_type == T_ERROR_ACK)
			return (-1);
		
		if (rc != MOREDATA || msg.len < (int)sizeof(*toa) ||
		    toa->PRIM_type != T_OPTMGMT_ACK ||
		    toa->MGMT_flags != T_SUCCESS)
			return (-1);
		
		rtable = (opt->level == MIB2_IP6 && opt->name == MIB2_IP6_ROUTE);
		
		msg.maxlen = sizeof(buf) - (sizeof(buf) % sizeof(*rt));
		msg.len = 0;
		flags = 0;
		
		do {
			struct sockaddr_in6 sin6;

			rc = getmsg(r->ip_fd, NULL, &msg, &flags);
			
			if (rc != 0 && rc != MOREDATA)
				return (-1);
			
			if (!rtable)
				continue;
			
			rt = (mib2_ipv6RouteEntry_t *)msg.buf;
			rtend = (mib2_ipv6RouteEntry_t *)(msg.buf + msg.len);

			sin6.sin6_family = AF_INET6;

			for ( ; rt < rtend; rt++) {
				if ((rt->ipv6RouteInfo.re_ire_type &
				    (IRE_BROADCAST|IRE_ROUTE_REDIRECT|
					IRE_LOCAL|IRE_ROUTE)) != 0 ||
				    memcmp(&rt->ipv6RouteNextHop, IP6_ADDR_UNSPEC, IP6_ADDR_LEN) == 0)
					continue;
				
				sin6.sin6_addr = rt->ipv6RouteNextHop;
				addr_ston((struct sockaddr *)&sin6,
				    &entry.route_gw);
				
				sin6.sin6_addr = rt->ipv6RouteDest;
				addr_ston((struct sockaddr *)&sin6,
				    &entry.route_dst);
				
				entry.route_dst.addr_bits = rt->ipv6RoutePfxLength;
				
				if ((ret = callback(&entry, arg)) != 0)
					return (ret);
			}
		} while (rc == MOREDATA);
	}
	return (0);
}
Exemple #16
0
static int
_intf_get_noalias(intf_t *intf, struct intf_entry *entry)
{
	struct ifreq ifr;
#ifdef HAVE_GETKERNINFO
  int size;
  struct kinfo_ndd *nddp;
  void *end;
#endif

	/* Get interface index. */
	entry->intf_index = if_nametoindex(entry->intf_name);
	if (entry->intf_index == 0)
		return (-1);

	strlcpy(ifr.ifr_name, entry->intf_name, sizeof(ifr.ifr_name));

	/* Get interface flags. */
	if (ioctl(intf->fd, SIOCGIFFLAGS, &ifr) < 0)
		return (-1);

	entry->intf_flags = intf_iff_to_flags(ifr.ifr_flags);
	_intf_set_type(entry);

	/* Get interface MTU. */
#ifdef SIOCGIFMTU
	if (ioctl(intf->fd, SIOCGIFMTU, &ifr) < 0)
#endif
		return (-1);
	entry->intf_mtu = ifr.ifr_mtu;

	entry->intf_addr.addr_type = entry->intf_dst_addr.addr_type =
	    entry->intf_link_addr.addr_type = ADDR_TYPE_NONE;

	/* Get primary interface address. */
	if (ioctl(intf->fd, SIOCGIFADDR, &ifr) == 0) {
		addr_ston(&ifr.ifr_addr, &entry->intf_addr);
		if (ioctl(intf->fd, SIOCGIFNETMASK, &ifr) < 0)
			return (-1);
		addr_stob(&ifr.ifr_addr, &entry->intf_addr.addr_bits);
	}
	/* Get other addresses. */
	if (entry->intf_type == INTF_TYPE_TUN) {
		if (ioctl(intf->fd, SIOCGIFDSTADDR, &ifr) == 0) {
			if (addr_ston(&ifr.ifr_addr,
			    &entry->intf_dst_addr) < 0)
				return (-1);
		}
	} else if (entry->intf_type == INTF_TYPE_ETH) {
#if defined(HAVE_GETKERNINFO)
	  /* AIX also defines SIOCGIFHWADDR, but it fails silently?
	   * This is the method IBM recommends here:
	   * http://www-01.ibm.com/support/knowledgecenter/ssw_aix_53/com.ibm.aix.progcomm/doc/progcomc/skt_sndother_ex.htm%23ssqinc2joyc?lang=en
	   */
	  /* How many bytes will be returned? */
    size = getkerninfo(KINFO_NDD, 0, 0, 0);
    if (size <= 0) {
      return -1;
    }
    nddp = (struct kinfo_ndd *)malloc(size);

    if (!nddp) {
      return -1;
    }
    /* Get all Network Device Driver (NDD) info */
    if (getkerninfo(KINFO_NDD, nddp, &size, 0) < 0) {
      free(nddp);
      return -1;
    }
    /* Loop over the returned values until we find a match */
    end = (void *)nddp + size;
    while ((void *)nddp < end) {
      if (!strcmp(nddp->ndd_alias, entry->intf_name) ||
          !strcmp(nddp->ndd_name, entry->intf_name)) {
        addr_pack(&entry->intf_link_addr, ADDR_TYPE_ETH, ETH_ADDR_BITS,
            nddp->ndd_addr, ETH_ADDR_LEN);
        break;
      } else
        nddp++;
    }
    free(nddp);
#elif defined(SIOCGIFHWADDR)
		if (ioctl(intf->fd, SIOCGIFHWADDR, &ifr) < 0)
			return (-1);
		if (addr_ston(&ifr.ifr_addr, &entry->intf_link_addr) < 0)
			return (-1);
#elif defined(SIOCRPHYSADDR)
		/* Tru64 */
		struct ifdevea *ifd = (struct ifdevea *)&ifr; /* XXX */

		if (ioctl(intf->fd, SIOCRPHYSADDR, ifd) < 0)
			return (-1);
		addr_pack(&entry->intf_link_addr, ADDR_TYPE_ETH, ETH_ADDR_BITS,
		    ifd->current_pa, ETH_ADDR_LEN);
#else
		eth_t *eth;

		if ((eth = eth_open(entry->intf_name)) != NULL) {
			if (!eth_get(eth, &entry->intf_link_addr.addr_eth)) {
				entry->intf_link_addr.addr_type =
				    ADDR_TYPE_ETH;
				entry->intf_link_addr.addr_bits =
				    ETH_ADDR_BITS;
			}
			eth_close(eth);
		}
#endif
	}
	return (0);
}
Exemple #17
0
static int
_intf_get_aliases(intf_t *intf, struct intf_entry *entry)
{
    struct ifreq *ifr, *lifr;
    struct ifreq tmpifr;
    struct addr *ap, *lap;
    char *p;

    if (intf->ifc.ifc_len < (int)sizeof(*ifr)) {
        errno = EINVAL;
        return (-1);
    }
    entry->intf_alias_num = 0;
    ap = entry->intf_alias_addrs;
    lifr = (struct ifreq *)intf->ifc.ifc_buf +
           (intf->ifc.ifc_len / sizeof(*lifr));
    lap = (struct addr *)((u_char *)entry + entry->intf_len);

    /* Get addresses for this interface. */
    for (ifr = intf->ifc.ifc_req; ifr < lifr && (ap + 1) < lap;
            ifr = NEXTIFR(ifr)) {
        /* XXX - Linux, Solaris ifaliases */
        if ((p = strchr(ifr->ifr_name, ':')) != NULL)
            *p = '\0';

        if (strcmp(ifr->ifr_name, entry->intf_name) != 0) {
            if (p) *p = ':';
            continue;
        }

        if (p) *p = ':'; /* Fix the name back up */
        if (addr_ston(&ifr->ifr_addr, ap) < 0)
            continue;

        /* XXX */
        if (ap->addr_type == ADDR_TYPE_ETH) {
            memcpy(&entry->intf_link_addr, ap, sizeof(*ap));
            continue;
        } else if (ap->addr_type == ADDR_TYPE_IP) {
            if (ap->addr_ip == entry->intf_addr.addr_ip ||
                    ap->addr_ip == entry->intf_dst_addr.addr_ip)
                continue;
            strlcpy(tmpifr.ifr_name, ifr->ifr_name,
                    sizeof(tmpifr.ifr_name));
            if (ioctl(intf->fd, SIOCGIFNETMASK, &tmpifr) == 0)
                addr_stob(&tmpifr.ifr_addr, &ap->addr_bits);

        }
#ifdef SIOCGIFNETMASK_IN6
        else if (ap->addr_type == ADDR_TYPE_IP6 && intf->fd6 != -1) {
            struct in6_ifreq ifr6;

            /* XXX - sizeof(ifr) < sizeof(ifr6) */
            memcpy(&ifr6, ifr, sizeof(ifr6));

            if (ioctl(intf->fd6, SIOCGIFNETMASK_IN6, &ifr6) == 0) {
                addr_stob((struct sockaddr *)&ifr6.ifr_addr,
                          &ap->addr_bits);
            }
            else perror("SIOCGIFNETMASK_IN6");
        }
#endif
        ap++, entry->intf_alias_num++;
    }
    entry->intf_len = (u_char *)ap - (u_char *)entry;

    return (0);
}
Exemple #18
0
int
_intf_get_noalias(intf_t *intf, struct intf_entry *entry)
{
	struct lifreq lifr;
	int fd;

	/* Get interface index. */
	entry->intf_index = if_nametoindex(entry->intf_name);
	if (entry->intf_index == 0)
		return (-1);

	strlcpy(lifr.lifr_name, entry->intf_name, sizeof(lifr.lifr_name));

	/* Get interface flags. Here he also check whether we need to use fd or
	 * fd6 in the rest of the function. Using the wrong address family in
	 * the ioctls gives ENXIO on Solaris. */
	if (ioctl(intf->fd, SIOCGLIFFLAGS, &lifr) >= 0)
		fd = intf->fd;
	else if (intf->fd6 != -1 && ioctl(intf->fd6, SIOCGLIFFLAGS, &lifr) >= 0)
		fd = intf->fd6;
	else
		return (-1);
	
	entry->intf_flags = intf_iff_to_flags(lifr.lifr_flags);
	_intf_set_type(entry);
	
	/* Get interface MTU. */
#ifdef SIOCGLIFMTU
	if (ioctl(fd, SIOCGLIFMTU, &lifr) < 0)
#endif
		return (-1);
	entry->intf_mtu = lifr.lifr_mtu;

	entry->intf_addr.addr_type = entry->intf_dst_addr.addr_type =
	    entry->intf_link_addr.addr_type = ADDR_TYPE_NONE;
	
	/* Get primary interface address. */
	if (ioctl(fd, SIOCGLIFADDR, &lifr) == 0) {
		addr_ston((struct sockaddr *)&lifr.lifr_addr, &entry->intf_addr);
		if (ioctl(fd, SIOCGLIFNETMASK, &lifr) < 0)
			return (-1);
		addr_stob((struct sockaddr *)&lifr.lifr_addr, &entry->intf_addr.addr_bits);
	}
	/* Get other addresses. */
	if (entry->intf_type == INTF_TYPE_TUN) {
		if (ioctl(fd, SIOCGLIFDSTADDR, &lifr) == 0) {
			if (addr_ston((struct sockaddr *)&lifr.lifr_addr,
			    &entry->intf_dst_addr) < 0)
				return (-1);
		}
	} else if (entry->intf_type == INTF_TYPE_ETH) {
		eth_t *eth;
		
		if ((eth = eth_open(entry->intf_name)) != NULL) {
			if (!eth_get(eth, &entry->intf_link_addr.addr_eth)) {
				entry->intf_link_addr.addr_type =
				    ADDR_TYPE_ETH;
				entry->intf_link_addr.addr_bits =
				    ETH_ADDR_BITS;
			}
			eth_close(eth);
		}
	}
	return (0);
}
Exemple #19
0
static int
_intf_get_noalias(intf_t *intf, struct intf_entry *entry)
{
    struct ifreq ifr;

    strlcpy(ifr.ifr_name, entry->intf_name, sizeof(ifr.ifr_name));

    /* Get interface flags. */
    if (ioctl(intf->fd, SIOCGIFFLAGS, &ifr) < 0)
        return (-1);

    entry->intf_flags = intf_iff_to_flags(ifr.ifr_flags);
    _intf_set_type(entry);

    /* Get interface MTU. */
#ifdef SIOCGIFMTU
    if (ioctl(intf->fd, SIOCGIFMTU, &ifr) < 0)
#endif
        return (-1);
    entry->intf_mtu = ifr.ifr_mtu;

    entry->intf_addr.addr_type = entry->intf_dst_addr.addr_type =
                                     entry->intf_link_addr.addr_type = ADDR_TYPE_NONE;

    /* Get primary interface address. */
    if (ioctl(intf->fd, SIOCGIFADDR, &ifr) == 0) {
        addr_ston(&ifr.ifr_addr, &entry->intf_addr);
        if (ioctl(intf->fd, SIOCGIFNETMASK, &ifr) < 0)
            return (-1);
        addr_stob(&ifr.ifr_addr, &entry->intf_addr.addr_bits);
    }
    /* Get other addresses. */
    if (entry->intf_type == INTF_TYPE_TUN) {
        if (ioctl(intf->fd, SIOCGIFDSTADDR, &ifr) == 0) {
            if (addr_ston(&ifr.ifr_addr,
                          &entry->intf_dst_addr) < 0)
                return (-1);
        }
    } else if (entry->intf_type == INTF_TYPE_ETH) {
#if defined(SIOCGIFHWADDR)
        if (ioctl(intf->fd, SIOCGIFHWADDR, &ifr) < 0)
            return (-1);
        if (addr_ston(&ifr.ifr_addr, &entry->intf_link_addr) < 0)
            return (-1);
#elif defined(SIOCRPHYSADDR)
        /* Tru64 */
        struct ifdevea *ifd = (struct ifdevea *)&ifr; /* XXX */

        if (ioctl(intf->fd, SIOCRPHYSADDR, ifd) < 0)
            return (-1);
        addr_pack(&entry->intf_link_addr, ADDR_TYPE_ETH, ETH_ADDR_BITS,
                  ifd->current_pa, ETH_ADDR_LEN);
#else
        eth_t *eth;

        if ((eth = eth_open(entry->intf_name)) != NULL) {
            if (!eth_get(eth, &entry->intf_link_addr.addr_eth)) {
                entry->intf_link_addr.addr_type =
                    ADDR_TYPE_ETH;
                entry->intf_link_addr.addr_bits =
                    ETH_ADDR_BITS;
            }
            eth_close(eth);
        }
#endif
    }
    return (0);
}
Exemple #20
0
static int
_intf_get_aliases(intf_t *intf, struct intf_entry *entry)
{
	struct ifreq *ifr, *lifr;
	struct ifreq tmpifr;
	struct addr *ap, *lap;
	char *p;
	
	if (intf->ifc.ifc_len < (int)sizeof(*ifr)) {
		errno = EINVAL;
		return (-1);
	}
	entry->intf_alias_num = 0;
	ap = entry->intf_alias_addrs;
	lifr = (struct ifreq *)intf->ifc.ifc_buf + 
	    (intf->ifc.ifc_len / sizeof(*lifr));
	lap = (struct addr *)((u_char *)entry + entry->intf_len);
	
	/* Get addresses for this interface. */
	for (ifr = intf->ifc.ifc_req; ifr < lifr && (ap + 1) < lap;
	    ifr = NEXTIFR(ifr)) {
		/* XXX - Linux, Solaris ifaliases */
		if ((p = strchr(ifr->ifr_name, ':')) != NULL)
			*p = '\0';
		
		if (strcmp(ifr->ifr_name, entry->intf_name) != 0) {
			if (p) *p = ':';
			continue;
		}
		
		/* Fix the name back up */
		if (p) *p = ':';

		if (addr_ston(&ifr->ifr_addr, ap) < 0)
			continue;
		
		/* XXX */
		if (ap->addr_type == ADDR_TYPE_ETH) {
			memcpy(&entry->intf_link_addr, ap, sizeof(*ap));
			continue;
		} else if (ap->addr_type == ADDR_TYPE_IP) {
			if (ap->addr_ip == entry->intf_addr.addr_ip ||
			    ap->addr_ip == entry->intf_dst_addr.addr_ip)
				continue;
			strlcpy(tmpifr.ifr_name, ifr->ifr_name, sizeof(tmpifr.ifr_name));
			if (ioctl(intf->fd, SIOCGIFNETMASK, &tmpifr) == 0)
				addr_stob(&tmpifr.ifr_addr, &ap->addr_bits);
		}
#ifdef SIOCGIFNETMASK_IN6
		else if (ap->addr_type == ADDR_TYPE_IP6 && intf->fd6 != -1) {
			struct in6_ifreq ifr6;

			/* XXX - sizeof(ifr) < sizeof(ifr6) */
			memcpy(&ifr6, ifr, sizeof(ifr6));
			
			if (ioctl(intf->fd6, SIOCGIFNETMASK_IN6, &ifr6) == 0) {
				addr_stob((struct sockaddr *)&ifr6.ifr_addr,
				    &ap->addr_bits);
			}
			else perror("SIOCGIFNETMASK_IN6");
		}
#else
#ifdef SIOCGIFNETMASK6
		else if (ap->addr_type == ADDR_TYPE_IP6 && intf->fd6 != -1) {
			struct in6_ifreq ifr6;

			/* XXX - sizeof(ifr) < sizeof(ifr6) */
			memcpy(&ifr6, ifr, sizeof(ifr6));
			
			if (ioctl(intf->fd6, SIOCGIFNETMASK6, &ifr6) == 0) {
				/* For some reason this is 0 after the ioctl. */
				ifr6.ifr_Addr.sin6_family = AF_INET6;
				addr_stob((struct sockaddr *)&ifr6.ifr_Addr,
				    &ap->addr_bits);
			}
			else perror("SIOCGIFNETMASK6");
		}
#endif
#endif
		ap++, entry->intf_alias_num++;
	}
#ifdef HAVE_LINUX_PROCFS
#define PROC_INET6_FILE	"/proc/net/if_inet6"
	{
		FILE *f;
		char buf[256], s[8][5], name[INTF_NAME_LEN];
		u_int idx, bits, scope, flags;
		
		if ((f = fopen(PROC_INET6_FILE, "r")) != NULL) {
			while (ap < lap &&
			       fgets(buf, sizeof(buf), f) != NULL) {
				sscanf(buf, "%04s%04s%04s%04s%04s%04s%04s%04s %x %02x %02x %02x %32s\n",
				    s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7],
				    &idx, &bits, &scope, &flags, name);
				if (strcmp(name, entry->intf_name) == 0) {
					snprintf(buf, sizeof(buf), "%s:%s:%s:%s:%s:%s:%s:%s/%d",
					    s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], bits);
					addr_aton(buf, ap);
					ap++, entry->intf_alias_num++;
				}
			}
			fclose(f);
		}
	}
#endif
	entry->intf_len = (u_char *)ap - (u_char *)entry;
	
	return (0);
}
static void
_adapter_address_to_entry(intf_t *intf, IP_ADAPTER_ADDRESSES *a,
	struct intf_entry *entry)
{
	struct addr *ap, *lap;
	int i;
	int type;
	IP_ADAPTER_UNICAST_ADDRESS *addr;
	
	/* The total length of the entry may be passed inside entry.
           Remember it and clear the entry. */
	u_int intf_len = entry->intf_len;
	memset(entry, 0, sizeof(*entry));
	entry->intf_len = intf_len;

	type = _if_type_canonicalize(a->IfType);
	for (i = 0; i < intf->ifcombo[type].cnt; i++) {
		if (intf->ifcombo[type].idx[i].ipv4 == a->IfIndex &&
		    intf->ifcombo[type].idx[i].ipv6 == a->Ipv6IfIndex) {
			break;
		}
	}
	/* XXX - type matches MIB-II ifType. */
	snprintf(entry->intf_name, sizeof(entry->intf_name), "%s%lu",
	    _ifcombo_name(a->IfType), i);
	entry->intf_type = (uint16_t)type;
	
	/* Get interface flags. */
	entry->intf_flags = 0;
	if (a->OperStatus == IfOperStatusUp)
		entry->intf_flags |= INTF_FLAG_UP;
	if (a->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
		entry->intf_flags |= INTF_FLAG_LOOPBACK;
	else
		entry->intf_flags |= INTF_FLAG_MULTICAST;
	
	/* Get interface MTU. */
	entry->intf_mtu = a->Mtu;
	
	/* Get hardware address. */
	if (a->PhysicalAddressLength == ETH_ADDR_LEN) {
		entry->intf_link_addr.addr_type = ADDR_TYPE_ETH;
		entry->intf_link_addr.addr_bits = ETH_ADDR_BITS;
		memcpy(&entry->intf_link_addr.addr_eth, a->PhysicalAddress,
		    ETH_ADDR_LEN);
	}
	/* Get addresses. */
	ap = entry->intf_alias_addrs;
	lap = ap + ((entry->intf_len - sizeof(*entry)) /
	    sizeof(entry->intf_alias_addrs[0]));
	for (addr = a->FirstUnicastAddress; addr != NULL; addr = addr->Next) {
		IP_ADAPTER_PREFIX *prefix;
		unsigned short bits;

		/* Find the netmask length. This is stored in a parallel list.
		   We just take the first one with a matching address family,
		   but that may not be right. Windows Vista and later has an
		   OnLinkPrefixLength member that is stored right with the
		   unicast address. */
		bits = 0;
		for (prefix = a->FirstPrefix; prefix != NULL; prefix = prefix->Next) {
			if (prefix->Address.lpSockaddr->sa_family == addr->Address.lpSockaddr->sa_family) {
				bits = (unsigned short) prefix->PrefixLength;
				break;
			}
		}

		if (entry->intf_addr.addr_type == ADDR_TYPE_NONE) {
			/* Set primary address if unset. */
			addr_ston(addr->Address.lpSockaddr, &entry->intf_addr);
			entry->intf_addr.addr_bits = bits;
		} else if (ap < lap) {
			/* Set aliases. */
			addr_ston(addr->Address.lpSockaddr, ap);
			ap->addr_bits = bits;
			ap++;
			entry->intf_alias_num++;
		}
	}
	entry->intf_len = (u_int) ((u_char *)ap - (u_char *)entry);
}
Exemple #22
0
static int
route_msg(route_t *r, int type, struct addr *dst, struct addr *gw)
{
	struct addr net;
	struct rt_msghdr *rtm;
	struct sockaddr *sa;
	u_char buf[BUFSIZ];
	pid_t pid;
	int len;

	memset(buf, 0, sizeof(buf));

	rtm = (struct rt_msghdr *)buf;
	rtm->rtm_version = RTM_VERSION;
	if ((rtm->rtm_type = type) != RTM_DELETE)
		rtm->rtm_flags = RTF_UP;
	rtm->rtm_addrs = RTA_DST;
	rtm->rtm_seq = ++r->seq;

	/* Destination */
	sa = (struct sockaddr *)(rtm + 1);
	if (addr_net(dst, &net) < 0 || addr_ntos(&net, sa) < 0)
		return (-1);
	sa = NEXTSA(sa);

	/* Gateway */
	if (gw != NULL && type != RTM_GET) {
		rtm->rtm_flags |= RTF_GATEWAY;
		rtm->rtm_addrs |= RTA_GATEWAY;
		if (addr_ntos(gw, sa) < 0)
			return (-1);
		sa = NEXTSA(sa);
	}
	/* Netmask */
	if (dst->addr_ip == IP_ADDR_ANY || dst->addr_bits < IP_ADDR_BITS) {
		rtm->rtm_addrs |= RTA_NETMASK;
		if (addr_btos(dst->addr_bits, sa) < 0)
			return (-1);
		sa = NEXTSA(sa);
	} else
		rtm->rtm_flags |= RTF_HOST;
	
	rtm->rtm_msglen = (u_char *)sa - buf;
#ifdef DEBUG
	route_msg_print(rtm);
#endif
#ifdef HAVE_STREAMS_ROUTE
	if (ioctl(r->fd, RTSTR_SEND, rtm) < 0)
		return (-1);
#else
	if (write(r->fd, buf, rtm->rtm_msglen) < 0)
		return (-1);

	pid = getpid();
	
	while (type == RTM_GET && (len = read(r->fd, buf, sizeof(buf))) > 0) {
		if (len < (int)sizeof(*rtm)) {
			return (-1);
		}
		if (rtm->rtm_type == type && rtm->rtm_pid == pid &&
		    rtm->rtm_seq == r->seq) {
			if (rtm->rtm_errno) {
				errno = rtm->rtm_errno;
				return (-1);
			}
			break;
		}
	}
#endif
	if (type == RTM_GET && (rtm->rtm_addrs & (RTA_DST|RTA_GATEWAY)) ==
	    (RTA_DST|RTA_GATEWAY)) {
		sa = (struct sockaddr *)(rtm + 1);
		sa = NEXTSA(sa);
		
		if (addr_ston(sa, gw) < 0 || gw->addr_type != ADDR_TYPE_IP) {
			errno = ESRCH;
			return (-1);
		}
	}
	return (0);
}
int
route_loop(route_t *r, route_handler callback, void *arg)
{
    struct rt_msghdr *rtm;
    struct route_entry entry;
    struct sockaddr *sa;
    char *buf, *lim, *next;
    int ret;
#ifdef HAVE_SYS_SYSCTL_H
    int mib[6] = { CTL_NET, PF_ROUTE, 0, 0 /* XXX */, NET_RT_DUMP, 0 };
    size_t len;

    if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
        return (-1);

    if (len == 0)
        return (0);

    if ((buf = malloc(len)) == NULL)
        return (-1);

    if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
        free(buf);
        return (-1);
    }
    lim = buf + len;
    next = buf;
#else /* HAVE_STREAMS_ROUTE */
    struct rt_giarg giarg, *gp;

    memset(&giarg, 0, sizeof(giarg));
    giarg.gi_op = KINFO_RT_DUMP;

    if (ioctl(r->fd, RTSTR_GETROUTE, &giarg) < 0)
        return (-1);

    if ((buf = malloc(giarg.gi_size)) == NULL)
        return (-1);

    gp = (struct rt_giarg *)buf;
    gp->gi_size = giarg.gi_size;
    gp->gi_op = KINFO_RT_DUMP;
    gp->gi_where = buf;
    gp->gi_arg = RTF_UP | RTF_GATEWAY;

    if (ioctl(r->fd, RTSTR_GETROUTE, buf) < 0) {
        free(buf);
        return (-1);
    }
    lim = buf + gp->gi_size;
    next = buf + sizeof(giarg);
#endif
    for (ret = 0; next < lim; next += rtm->rtm_msglen) {
        rtm = (struct rt_msghdr *)next;
        sa = (struct sockaddr *)(rtm + 1);

        if (addr_ston(sa, &entry.route_dst) < 0 ||
                (rtm->rtm_addrs & RTA_GATEWAY) == 0)
            continue;

        sa = NEXTSA(sa);

        if (addr_ston(sa, &entry.route_gw) < 0)
            continue;

        if (entry.route_dst.addr_type != entry.route_gw.addr_type ||
                (entry.route_dst.addr_type != ADDR_TYPE_IP &&
                 entry.route_dst.addr_type != ADDR_TYPE_IP6))
            continue;

        if (rtm->rtm_addrs & RTA_NETMASK) {
            sa = NEXTSA(sa);
            if (addr_stob(sa, &entry.route_dst.addr_bits) < 0)
                continue;
        }
        if ((ret = callback(&entry, arg)) != 0)
            break;
    }
    free(buf);

    return (ret);
}
Exemple #24
0
int
route_loop(route_t *r, route_handler callback, void *arg)
{
	struct rt_msghdr *rtm;
	struct route_entry entry;
	struct sockaddr *sa;
	char *buf, *lim, *next;
	int ret;
#ifdef HAVE_SYS_SYSCTL_H
	int mib[6] = { CTL_NET, PF_ROUTE, 0, 0 /* XXX */, NET_RT_DUMP, 0 };
	size_t len;
	
	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
		return (-1);

	if (len == 0)
		return (0);
	
	if ((buf = malloc(len)) == NULL)
		return (-1);
	
	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
		free(buf);
		return (-1);
	}
	lim = buf + len;
	next = buf;
#elif defined(HAVE_GETKERNINFO)
	int len = getkerninfo(KINFO_RT_DUMP,0,0,0);

	if (len == 0)
		return (0);

	if ((buf = malloc(len)) == NULL)
		return (-1);

	if (getkerninfo(KINFO_RT_DUMP,buf,&len,0) < 0) {
		free(buf);
		return (-1);
	}
	lim = buf + len;
	next = buf;
#else /* HAVE_STREAMS_ROUTE */
	struct rt_giarg giarg, *gp;

	memset(&giarg, 0, sizeof(giarg));
	giarg.gi_op = KINFO_RT_DUMP;

	if (ioctl(r->fd, RTSTR_GETROUTE, &giarg) < 0)
		return (-1);

	if ((buf = malloc(giarg.gi_size)) == NULL)
		return (-1);

	gp = (struct rt_giarg *)buf;
	gp->gi_size = giarg.gi_size;
	gp->gi_op = KINFO_RT_DUMP;
	gp->gi_where = buf;
	gp->gi_arg = RTF_UP | RTF_GATEWAY;

	if (ioctl(r->fd, RTSTR_GETROUTE, buf) < 0) {
		free(buf);
		return (-1);
	}
	lim = buf + gp->gi_size;
	next = buf + sizeof(giarg);
#endif
	/* This loop assumes that RTA_DST, RTA_GATEWAY, and RTA_NETMASK have the
	 * values, 1, 2, and 4 respectively. Cf. Unix Network Programming,
	 * p. 494, function get_rtaddrs. */
	for (ret = 0; next < lim; next += rtm->rtm_msglen) {
		rtm = (struct rt_msghdr *)next;
		sa = (struct sockaddr *)(rtm + 1);

		if ((rtm->rtm_addrs & RTA_DST) == 0)
			/* Need a destination. */
			continue;
		if (addr_ston(sa, &entry.route_dst) < 0)
			continue;

		if ((rtm->rtm_addrs & RTA_GATEWAY) == 0)
			/* Need a gateway. */
			continue;
		sa = NEXTSA(sa);
		if (addr_ston_gateway(&entry.route_dst, sa, &entry.route_gw) < 0)
			continue;
		
		if (entry.route_dst.addr_type != entry.route_gw.addr_type ||
		    (entry.route_dst.addr_type != ADDR_TYPE_IP &&
			entry.route_dst.addr_type != ADDR_TYPE_IP6))
			continue;

		if (rtm->rtm_addrs & RTA_NETMASK) {
			sa = NEXTSA(sa);
			if (addr_stob(sa, &entry.route_dst.addr_bits) < 0)
				continue;
		}

		if ((ret = callback(&entry, arg)) != 0)
			break;
	}
	free(buf);
	
	return (ret);
}