Пример #1
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);
}
Пример #2
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);
}
Пример #3
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);
}