Exemple #1
0
int
rx_getAllAddrMaskMtu(afs_uint32 addrBuffer[], afs_uint32 maskBuffer[],
		     afs_uint32 mtuBuffer[], int maxSize)
{
    int s;

    size_t needed;
    int mib[6];
    struct if_msghdr *ifm, *nextifm;
    struct ifa_msghdr *ifam;
    struct sockaddr_dl *sdl;
    struct rt_addrinfo info;
    char *buf, *lim, *next;
    int count = 0, addrcount = 0;

    mib[0] = CTL_NET;
    mib[1] = PF_ROUTE;
    mib[2] = 0;
    mib[3] = AF_INET;		/* address family */
    mib[4] = NET_RT_IFLIST;
    mib[5] = 0;
    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
	return 0;
    if ((buf = malloc(needed)) == NULL)
	return 0;
    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
	free(buf);
	return 0;
    }
#if defined(AFS_OBSD42_ENV)
    ifm_fixversion(buf, &needed);
#endif
    s = socket(PF_INET, SOCK_DGRAM, 0);
    if (s < 0)
	return 0;
    lim = buf + needed;
    next = buf;
    while (next < lim) {
	ifm = (struct if_msghdr *)next;
	if (ifm->ifm_type != RTM_IFINFO) {
	    dpf(("out of sync parsing NET_RT_IFLIST\n"));
	    free(buf);
	    return 0;
	}
	sdl = (struct sockaddr_dl *)(ifm + 1);
	next += ifm->ifm_msglen;
	ifam = NULL;
	addrcount = 0;
	while (next < lim) {
	    nextifm = (struct if_msghdr *)next;
	    if (nextifm->ifm_type != RTM_NEWADDR)
		break;
	    if (ifam == NULL)
		ifam = (struct ifa_msghdr *)nextifm;
	    addrcount++;
	    next += nextifm->ifm_msglen;
	}
	if ((ifm->ifm_flags & IFF_UP) == 0)
	    continue;		/* not up */
	while (addrcount > 0) {
	    struct sockaddr_in *a;

	    info.rti_addrs = ifam->ifam_addrs;

	    /* Expand the compacted addresses */
	    rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
		      &info);
	    if (info.rti_info[RTAX_IFA]->sa_family != AF_INET) {
		addrcount--;
		continue;
	    }
	    a = (struct sockaddr_in *) info.rti_info[RTAX_IFA];

	    if (a->sin_addr.s_addr != htonl(0x7f000001) ) {
		if (count >= maxSize) {	/* no more space */
		    dpf(("Too many interfaces..ignoring 0x%x\n",
			   a->sin_addr.s_addr));
		} else {
		    struct ifreq ifr;
		    
		    addrBuffer[count] = a->sin_addr.s_addr;
		    a = (struct sockaddr_in *) info.rti_info[RTAX_NETMASK];
		    if (a)
			maskBuffer[count] = a->sin_addr.s_addr;
		    else
			maskBuffer[count] = htonl(0xffffffff);
		    memset(&ifr, 0, sizeof(ifr));
		    ifr.ifr_addr.sa_family = AF_INET;
		    strncpy(ifr.ifr_name, sdl->sdl_data, sdl->sdl_nlen);
		    if (ioctl(s, SIOCGIFMTU, (caddr_t) & ifr) < 0)
			mtuBuffer[count] = htonl(1500);
		    else
			mtuBuffer[count] = htonl(ifr.ifr_mtu);
		    count++;
		}
	    }
	    addrcount--;
	    ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
	}
    }
    free(buf);
    return count;
}
Exemple #2
0
/*
 * Figure out device configuration and select
 * networks which deserve status information.
 */
int
configure(int so)
{
	struct neighbor *np;
	struct if_msghdr *ifm;
	struct ifa_msghdr *ifam;
	struct sockaddr_dl *sdl;
	size_t needed;
	int mib[6], flags, lflags, len;
	char *buf, *lim, *next;
	struct rt_addrinfo info;

	flags = 0;
	if (multicast_mode != NO_MULTICAST) {
		multicast_addr.sin_addr.s_addr = htonl(INADDR_WHOD_GROUP);
		multicast_addr.sin_port = sp->s_port;
	}

	if (multicast_mode == SCOPED_MULTICAST) {
		struct ip_mreq mreq;
		unsigned char ttl;

		mreq.imr_multiaddr.s_addr = htonl(INADDR_WHOD_GROUP);
		mreq.imr_interface.s_addr = htonl(INADDR_ANY);
		if (setsockopt(so, IPPROTO_IP, IP_ADD_MEMBERSHIP,
		    &mreq, sizeof(mreq)) < 0) {
			syslog(LOG_ERR,
			    "setsockopt IP_ADD_MEMBERSHIP: %m");
			return (0);
		}
		ttl = multicast_scope;
		if (setsockopt(so, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
		    sizeof(ttl)) < 0) {
			syslog(LOG_ERR,
			    "setsockopt IP_MULTICAST_TTL: %m");
			return (0);
		}
		return (1);
	}

	mib[0] = CTL_NET;
	mib[1] = PF_ROUTE;
	mib[2] = 0;
	mib[3] = AF_INET;
	mib[4] = NET_RT_IFLIST;
	mib[5] = 0;
	if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0)
		quit("route-sysctl-estimate");
	if ((buf = malloc(needed)) == NULL)
		quit("malloc");
	if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0)
		quit("actual retrieval of interface table");
	lim = buf + needed;

	sdl = NULL;		/* XXX just to keep gcc -Wall happy */
	for (next = buf; next < lim; next += ifm->ifm_msglen) {
		ifm = (struct if_msghdr *)next;
		if (ifm->ifm_type == RTM_IFINFO) {
			sdl = (struct sockaddr_dl *)(ifm + 1);
			flags = ifm->ifm_flags;
			continue;
		}
		if ((flags & IFF_UP) == 0)
			continue;
		lflags = IFF_BROADCAST | iff_flag;
		if (multicast_mode == PER_INTERFACE_MULTICAST)
			lflags |= IFF_MULTICAST;
		if ((flags & lflags) == 0)
			continue;
		if (ifm->ifm_type != RTM_NEWADDR)
			quit("out of sync parsing NET_RT_IFLIST");
		ifam = (struct ifa_msghdr *)ifm;
		info.rti_addrs = ifam->ifam_addrs;
		rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
		    &info);
		/* gag, wish we could get rid of Internet dependencies */
#define	dstaddr		info.rti_info[RTAX_BRD]
#define	ifaddr		info.rti_info[RTAX_IFA]
#define	IPADDR_SA(x)	((struct sockaddr_in *)(x))->sin_addr.s_addr
#define	PORT_SA(x)	((struct sockaddr_in *)(x))->sin_port
		if (dstaddr == 0 || dstaddr->sa_family != AF_INET)
			continue;
		PORT_SA(dstaddr) = sp->s_port;
		for (np = neighbors; np != NULL; np = np->n_next) {
			if (memcmp(sdl->sdl_data, np->n_name,
			    sdl->sdl_nlen) == 0 &&
			    IPADDR_SA(np->n_addr) == IPADDR_SA(dstaddr)) {
				break;
			}
		}
		if (np != NULL)
			continue;
		len = sizeof(*np) + dstaddr->sa_len + sdl->sdl_nlen + 1;
		np = malloc(len);
		if (np == NULL)
			quit("malloc of neighbor structure");
		memset(np, 0, len);
		np->n_flags = flags;
		np->n_addr = (struct sockaddr *)(np + 1);
		np->n_addrlen = dstaddr->sa_len;
		np->n_name = np->n_addrlen + (char *)np->n_addr;
		memcpy((char *)np->n_addr, (char *)dstaddr, np->n_addrlen);
		memcpy(np->n_name, sdl->sdl_data, sdl->sdl_nlen);
		if (multicast_mode == PER_INTERFACE_MULTICAST &&
		    (flags & IFF_MULTICAST) != 0 &&
		    (flags & IFF_LOOPBACK) == 0) {
			struct ip_mreq mreq;

			memcpy((char *)np->n_addr, (char *)ifaddr,
			    np->n_addrlen);
			mreq.imr_multiaddr.s_addr = htonl(INADDR_WHOD_GROUP);
			mreq.imr_interface.s_addr =
			    ((struct sockaddr_in *)np->n_addr)->sin_addr.s_addr;
			if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
			    &mreq, sizeof(mreq)) < 0) {
				syslog(LOG_ERR,
				    "setsockopt IP_ADD_MEMBERSHIP: %m");
#if 0
				/* Fall back to broadcast on this if. */
				np->n_flags &= ~IFF_MULTICAST;
#else
				free(np);
				continue;
#endif
			}
		}
		np->n_next = neighbors;
		neighbors = np;
	}
	free(buf);
	return (1);
}
Exemple #3
0
int
rx_getAllAddr_internal(afs_uint32 buffer[], int maxSize, int loopbacks)
{
    size_t needed;
    int mib[6];
    struct if_msghdr *ifm, *nextifm;
    struct ifa_msghdr *ifam;
    struct sockaddr_dl *sdl;
    struct rt_addrinfo info;
    char *buf, *lim, *next;
    int count = 0, addrcount = 0;

    mib[0] = CTL_NET;
    mib[1] = PF_ROUTE;
    mib[2] = 0;
    mib[3] = AF_INET;		/* address family */
    mib[4] = NET_RT_IFLIST;
    mib[5] = 0;
    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
	return 0;
    if ((buf = malloc(needed)) == NULL)
	return 0;
    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
	free(buf);
	return 0;
    }
#if defined(AFS_OBSD42_ENV)
    ifm_fixversion(buf, &needed);
#endif
    lim = buf + needed;
    next = buf;
    while (next < lim) {
	ifm = (struct if_msghdr *)next;
	if (ifm->ifm_type != RTM_IFINFO) {
	    dpf(("out of sync parsing NET_RT_IFLIST\n"));
	    free(buf);
	    return 0;
	}
	sdl = (struct sockaddr_dl *)(ifm + 1);
	next += ifm->ifm_msglen;
	ifam = NULL;
	addrcount = 0;
	while (next < lim) {
	    nextifm = (struct if_msghdr *)next;
	    if (nextifm->ifm_type != RTM_NEWADDR)
		break;
	    if (ifam == NULL)
		ifam = (struct ifa_msghdr *)nextifm;
	    addrcount++;
	    next += nextifm->ifm_msglen;
	}
	if ((ifm->ifm_flags & IFF_UP) == 0)
	    continue;		/* not up */
	while (addrcount > 0) {
	    struct sockaddr_in *a;

	    info.rti_addrs = ifam->ifam_addrs;

	    /* Expand the compacted addresses */
	    rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
		      &info);
	    if (info.rti_info[RTAX_IFA]->sa_family != AF_INET) {
		addrcount--;
		continue;
	    }
	    a = (struct sockaddr_in *) info.rti_info[RTAX_IFA];

	    if (count >= maxSize)	/* no more space */
		dpf(("Too many interfaces..ignoring 0x%x\n",
		       a->sin_addr.s_addr));
	    else if (!loopbacks && a->sin_addr.s_addr == htonl(0x7f000001)) {
		addrcount--;
		continue;	/* skip loopback address as well. */
	    } else if (loopbacks && ifm->ifm_flags & IFF_LOOPBACK) {
		addrcount--;
		continue;	/* skip aliased loopbacks as well. */
	    } else
		buffer[count++] = a->sin_addr.s_addr;
	    addrcount--;
	    ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
	}
    }
    free(buf);
    return count;
}
Exemple #4
0
/*
 * Print the status of the interface.  If an address family was
 * specified, show only it; otherwise, show them all.
 */
static void
status(const struct afswtch *afp, int addrcount, struct	sockaddr_dl *sdl,
       struct if_msghdr *ifm, struct ifa_msghdr *ifam)
{
    struct	rt_addrinfo info;
    int allfamilies, s;
    struct ifstat ifs;

    if (afp == NULL) {
        allfamilies = 1;
        afp = af_getbyname("inet");
    } else
        allfamilies = 0;

    ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af;
    strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));

    s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
    if (s < 0)
        err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family);

    printf("%s: ", name);
    printb("flags", flags, IFFBITS);
    if (ifm->ifm_data.ifi_metric)
        printf(" metric %ld", ifm->ifm_data.ifi_metric);
    if (ifm->ifm_data.ifi_mtu)
        printf(" mtu %ld", ifm->ifm_data.ifi_mtu);
    putchar('\n');

    if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) {
        if (ifr.ifr_curcap != 0) {
            printb("\toptions", ifr.ifr_curcap, IFCAPBITS);
            putchar('\n');
        }
        if (supmedia && ifr.ifr_reqcap != 0) {
            printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS);
            putchar('\n');
        }
    }

    tunnel_status(s);

    while (addrcount > 0) {
        info.rti_addrs = ifam->ifam_addrs;
        /* Expand the compacted addresses */
        rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
                  &info);

        if (allfamilies) {
            const struct afswtch *p;
            p = af_getbyfamily(info.rti_info[RTAX_IFA]->sa_family);
            if (p != NULL && p->af_status != NULL)
                p->af_status(s, &info);
        } else if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family)
            afp->af_status(s, &info);
        addrcount--;
        ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
    }
    if (allfamilies || afp->af_af == AF_LINK) {
        const struct afswtch *lafp;

        /*
         * Hack; the link level address is received separately
         * from the routing information so any address is not
         * handled above.  Cobble together an entry and invoke
         * the status method specially.
         */
        lafp = af_getbyname("lladdr");
        if (lafp != NULL) {
            info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl;
            lafp->af_status(s, &info);
        }
    }
    if (allfamilies)
        af_other_status(s);
    else if (afp->af_other_status != NULL)
        afp->af_other_status(s);

    strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
    if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0)
        printf("%s", ifs.ascii);

    if (flags & IFF_POLLING) {
        if (ioctl(s, SIOCGIFPOLLCPU, &ifr) == 0 && ifr.ifr_pollcpu >= 0)
            printf("\tpollcpu: %d\n", ifr.ifr_pollcpu);
    }

    close(s);
    return;
}
Exemple #5
0
/*
 * Print the status of the interface.  If an address family was
 * specified, show it and it only; otherwise, show them all.
 */
void
status(void)
{
	struct afswtch *p = NULL;
	char *mynext;
	struct if_msghdr *myifm;

	printf("%s: ", name);
	printb("flags", flags, IFFBITS);
	if (metric)
		printf(" metric %d", metric);
	if (mtu)
		printf(" mtu %d", mtu);
	putchar('\n');

	/*
	 * XXX: Sigh. This is bad, I know.  At this point, we may have
	 * *zero* RTM_NEWADDR's, so we have to "feel the water" before
	 * incrementing the loop.  One day, I might feel inspired enough
	 * to get the top level loop to pass a count down here so we
	 * dont have to mess with this.  -Peter
	 */
	myifm = ifm;

	while (1) {

		mynext = next + ifm->ifm_msglen;

		if (mynext >= lim)
			break;

		myifm = (struct if_msghdr *)mynext;

		if (myifm->ifm_type != RTM_NEWADDR)
			break;

		next = mynext;

		ifm = (struct if_msghdr *)next;

		ifam = (struct ifa_msghdr *)myifm;
		info.rti_addrs = ifam->ifam_addrs;

		/* Expand the compacted addresses */
		rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
			  &info);

		if (afp) {
			if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family &&
			    afp->af_status != ether_status) {
				p = afp;
				if (p->af_status != ether_status)
					(*p->af_status)(1);
			}
		} else for (p = afs; p->af_name; p++) {
			if (p->af_af == info.rti_info[RTAX_IFA]->sa_family &&
			    p->af_status != ether_status)
				(*p->af_status)(0);
		}
	}
	if (afp == NULL || afp->af_status == ether_status)
		ether_status(0);
	else if (afp && !p) {
		warnx("%s has no %s IFA address!", name, afp->af_name);
	}

	phys_status(0);
}
Exemple #6
0
/*
 * Find the network interfaces which have configured themselves.
 * If the interface is present but not yet up (for example an
 * ARPANET IMP), set the lookforinterfaces flag so we'll
 * come back later and look again.
 */
void
ifinit(void)
{
	struct interface ifs, *ifp;
	size_t needed;
	int mib[6], no_ipxaddr = 0, flags = 0;
	char *buf, *cplim, *cp;
	struct if_msghdr *ifm;
	struct ifa_msghdr *ifam;
	struct sockaddr_dl *sdl = NULL;

        mib[0] = CTL_NET;
        mib[1] = PF_ROUTE;
        mib[2] = 0;
        mib[3] = AF_IPX;
        mib[4] = NET_RT_IFLIST;
        mib[5] = 0;
        if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
                quit("route-sysctl-estimate");
	if ((buf = malloc(needed)) == NULL)
		quit("malloc");
        if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
		lookforinterfaces = 0;
	cplim = buf + needed;
	for (cp = buf; cp < cplim; cp += ifm->ifm_msglen) {
		ifm = (struct if_msghdr *)cp;
		if (ifm->ifm_type == RTM_IFINFO) {
			bzero(&ifs, sizeof(ifs));
			ifs.int_flags = flags = ifm->ifm_flags | IFF_INTERFACE;
			if ((flags & IFF_UP) == 0 || no_ipxaddr)
				lookforinterfaces = 1;
			sdl = (struct sockaddr_dl *) (ifm + 1);
			sdl->sdl_data[sdl->sdl_nlen] = 0;
			no_ipxaddr = 1;
			continue;
		}
		if (ifm->ifm_type != RTM_NEWADDR)
			quit("ifinit: out of sync");
		if ((flags & IFF_UP) == 0)
			continue;
		ifam = (struct ifa_msghdr *)ifm;
		info.rti_addrs = ifam->ifam_addrs;
		rt_xaddrs((char *)(ifam + 1), cp + ifam->ifam_msglen, &info);
		if (ifaaddr == 0) {
			syslog(LOG_ERR, "%s: (get addr)", sdl->sdl_data);
			continue;
		}
		ifs.int_addr = *ifaaddr;
		if (ifs.int_addr.sa_family != AF_IPX)
			continue;
		no_ipxaddr = 0;
		if (ifs.int_flags & IFF_POINTOPOINT) {
			if (brdaddr == 0) {
				syslog(LOG_ERR, "%s: (get dstaddr)",
					sdl->sdl_data);
				continue;
			}
			if (brdaddr->sa_family == AF_UNSPEC) {
				lookforinterfaces = 1;
				continue;
			}
			ifs.int_dstaddr = *brdaddr;
		}
		if (ifs.int_flags & IFF_BROADCAST) {
			if (brdaddr == 0) {
				syslog(LOG_ERR, "%s: (get broadaddr)",
					sdl->sdl_data);
				continue;
			}
			ifs.int_dstaddr = *brdaddr;
		}
		if (ifs.int_flags & IFF_LOOPBACK) {
			ifs.int_dstaddr = ifs.int_addr;
		}
		/* 
		 * already known to us? 
		 * what makes a POINTOPOINT if unique is its dst addr,
		 * NOT its source address 
		 */
		if ( ((ifs.int_flags & IFF_POINTOPOINT) &&
			if_ifwithdstaddr(&ifs.int_dstaddr)) ||
			( ((ifs.int_flags & IFF_POINTOPOINT) == 0) &&
			if_ifwithaddr(&ifs.int_addr)))
			continue;
		ifp = (struct interface *)
			malloc(sdl->sdl_nlen + 1 + sizeof(ifs));
		if (ifp == NULL) {
			syslog(LOG_ERR, "IPXrouted: out of memory\n");
			lookforinterfaces = 1;
			break;
		}
		*ifp = ifs;
		/*
		 * Count the # of directly connected networks
		 * and point to point links which aren't looped
		 * back to ourself.  This is used below to
		 * decide if we should be a routing ``supplier''.
		 */
		if ((ifs.int_flags & IFF_POINTOPOINT) == 0 ||
		    if_ifwithaddr(&ifs.int_dstaddr) == 0)
			externalinterfaces++;
		/*
		 * If we have a point-to-point link, we want to act
		 * as a supplier even if it's our only interface,
		 * as that's the only way our peer on the other end
		 * can tell that the link is up.
		 */
		if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0)
			supplier = 1;
		ifp->int_name = (char *)(ifp + 1);
		strcpy(ifp->int_name, sdl->sdl_data);

		ifp->int_metric = ifam->ifam_metric;
		ifp->int_next = ifnet;
		ifnet = ifp;
		traceinit(ifp);
		addrouteforif(ifp);
	}
	if (externalinterfaces > 1 && supplier < 0)
		supplier = 1;
	free(buf);
}
Exemple #7
0
PRIVATE_EXTERN void
inet6_addrlist_copy(inet6_addrlist_t * addr_list_p, int if_index)
{
    int				addr_index = 0;
    char *			buf = NULL;
    char *			buf_end;
    int				buf_len;
    int				count;
    int				error;
    int				i;
    char			ifname[IFNAMSIZ + 1];
    inet6_addrinfo_t *		linklocal = NULL;
    inet6_addrinfo_t *		list = NULL;
    char *			scan;
    struct rt_msghdr *		rtm;
    int				s = -1;

    buf = get_if_info(if_index, AF_INET6, &buf_len);
    if (buf == NULL) {
	goto done;
    }
    buf_end = buf + buf_len;

    /* figure out how many IPv6 addresses there are */
    count = 0;
    ifname[0] = '\0';
    for (scan = buf; scan < buf_end; scan += rtm->rtm_msglen) {
	struct if_msghdr * 	ifm;
	
	/* ALIGN: buf aligned (from calling get_if_info), scan aligned, 
	 * cast ok. */
	rtm = (struct rt_msghdr *)(void *)scan;
	if (rtm->rtm_version != RTM_VERSION) {
	    continue;
	}
	switch (rtm->rtm_type) {
	case RTM_IFINFO:
	    ifm = (struct if_msghdr *)rtm;
	    if (ifm->ifm_addrs & RTA_IFP) {
		struct sockaddr_dl *	dl_p;
		
		dl_p = (struct sockaddr_dl *)(ifm + 1);
		if (dl_p->sdl_nlen == 0 
		    || dl_p->sdl_nlen >= sizeof(ifname)) {
		    goto done;
		}
		bcopy(dl_p->sdl_data, ifname, dl_p->sdl_nlen);
		ifname[dl_p->sdl_nlen] = '\0';
	    }
	    break;
	case RTM_NEWADDR:
	    count++;
	    break;
	default:
	    break;
	}
    }
    if (ifname[0] == '\0') {
	goto done;
    }
    if (count == 0) {
	goto done;
    }
    if (count > INET6_ADDRLIST_N_STATIC) {
	list = (inet6_addrinfo_t *)malloc(sizeof(*list) * count);
	if (list == NULL) {
	    goto done;
	}
    }
    else {
	list = addr_list_p->list_static;
    }
    for (scan = buf; scan < buf_end; scan += rtm->rtm_msglen) {
	boolean_t		got_address = FALSE;
	struct ifa_msghdr *	ifam;
	struct rt_addrinfo	info;

	rtm = (struct rt_msghdr *)(void *)scan;
	if (rtm->rtm_version != RTM_VERSION) {
	    continue;
	}
	if (rtm->rtm_type == RTM_NEWADDR) {
	    ifam = (struct ifa_msghdr *)rtm;
	    info.rti_addrs = ifam->ifam_addrs;
	    error = rt_xaddrs((char *)(ifam + 1),
			      ((char *)ifam) + ifam->ifam_msglen,
			      &info);
	    if (error) {
		fprintf(stderr, "couldn't extract rt_addrinfo %s (%d)\n",
			strerror(error), error);
		goto done;
	    }
	    for (i = 0; i < RTAX_MAX; i++) {
		struct sockaddr_in6 *	sin6_p;
		
		/* ALIGN: info.rti_info aligned (sockaddr), cast ok. */
		sin6_p = (struct sockaddr_in6 *)(void *)info.rti_info[i];
		if (sin6_p == NULL
		    || sin6_p->sin6_len < sizeof(struct sockaddr_in6)) {
		    continue;
		}
		switch (i) {
		case RTAX_NETMASK:
		    list[addr_index].prefix_length 
			= count_prefix_bits(&sin6_p->sin6_addr,
					    sizeof(sin6_p->sin6_addr));
		    break;
		case RTAX_IFA:
		    list[addr_index].addr = sin6_p->sin6_addr;
		    got_address = TRUE;
		    break;
		default:
		    break;
		}
	    }
	    if (got_address) {
		if (s < 0) {
		    s = inet6_dgram_socket();
		}
		if (s >= 0) {
		    siocgifaflag_in6(s, ifname, 
				     &list[addr_index].addr,
				     &list[addr_index].addr_flags);
		    siocgifalifetime_in6(s, ifname, 
					 &list[addr_index].addr,
					 &list[addr_index].valid_lifetime,
					 &list[addr_index].preferred_lifetime);
		}
		/* Mask the v6 LL scope id */
		if (IN6_IS_ADDR_LINKLOCAL(&list[addr_index].addr)) {
		    list[addr_index].addr.s6_addr16[1] = 0;
		    if (linklocal == NULL) {
			linklocal = &list[addr_index];
		    }
		}
		addr_index++;
	    }
	}
    }
    if (addr_index == 0) {
	if (list != addr_list_p->list_static) {
	    free(list);
	}
	list = NULL;
    }

 done:
    if (s >= 0) {
	close(s);
    }
    if (buf != NULL) {
	free(buf);
    }
    addr_list_p->list = list;
    addr_list_p->count = addr_index;
    addr_list_p->linklocal = linklocal;
    return;
}
Exemple #8
0
int
main(int argc, char **argv)
{
	int ch, sflag, rflag, ret, flag6, iflag;
	int silen = 0;
	char hostname[MAXHOSTNAMELEN];
	char *srflag, *siflag;
	struct hostent *hst;
	struct in_addr ia;
	struct in6_addr ia6;

	int mib[6];
	size_t needed;
	char *buf, *next, *p;
	int idx;
	struct sockaddr_dl *sdl;
	struct rt_msghdr *rtm;
	struct if_msghdr *ifm;
	struct ifa_msghdr *ifam;
	struct rt_addrinfo info;
	struct sockaddr_in *sai;
	struct sockaddr_in6 *sai6;

	srflag = NULL;
	siflag = NULL;
	iflag = sflag = rflag = 0;
	flag6 = 0;
	hst = NULL;

	while ((ch = getopt(argc, argv, "46i:r:s")) != -1) {
		switch (ch) {
		case '4':
			iflag |= HST_IF_V4;
			break;
		case '6':
			iflag |= HST_IF_V6;
			break;
		case 'i':
			siflag = optarg;
			silen = strlen(siflag);
			iflag |= HST_IF;
			break;
		case 'r':
			srflag = optarg;
			rflag = 1;
			break;
		case 's':
			sflag = 1;
			break;
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	if (argc > 1)
		usage();

	if (iflag && *argv)
		usage();

	if (rflag && *argv)
		usage();

	if (rflag && (iflag & HST_IF))
		usage();

	if ((iflag & HST_IF_V6) && (iflag & HST_IF_V4))
		usage();

	if (!(iflag & HST_IF) && ((iflag & HST_IF_V6)||iflag & HST_IF_V4))
		usage();

	if (iflag & HST_IF) {
		mib[0] = CTL_NET;
		mib[1] = PF_ROUTE;
		mib[2] = 0;
		mib[3] = 0;
		mib[4] = NET_RT_IFLIST;
		mib[5] = 0;

		idx = 0;
		needed = 1;

		if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
			err(1, "sysctl: iflist-sysctl-estimate");
		if ((buf = malloc(needed)) == NULL)
			err(1, "malloc failed");
		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
			err(1, "sysctl: retrieval of interface table");
	
		for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
			rtm = (struct rt_msghdr *)(void *)next;
			if (rtm->rtm_version != RTM_VERSION)
				continue;
			switch (rtm->rtm_type) {
			case RTM_IFINFO:
				ifm = (struct if_msghdr *)(void *)rtm;

				if ((ifm->ifm_addrs & RTA_IFP) == 0)
					break;
				sdl = (struct sockaddr_dl *)(ifm + 1);
				if (silen != sdl->sdl_nlen)
					break;
				if (!strncmp(siflag, sdl->sdl_data, silen)) {
					idx = ifm->ifm_index;
				}
				break;
			case RTM_NEWADDR:
				ifam = (struct ifa_msghdr *)(void *)rtm;

				if (ifam->ifam_index == idx) {
					info.rti_addrs = ifam->ifam_addrs;
					rt_xaddrs((char *)(ifam + 1),
						ifam->ifam_msglen + (char *)ifam, &info);
					sai = (struct sockaddr_in *)info.rti_info[RTAX_IFA];

					if (iflag & HST_IF_V6) {
						if (sai->sin_family == AF_INET6) {
							sai6 = (struct sockaddr_in6 *)info.rti_info[RTAX_IFA];
							hst = gethostbyaddr(&sai6->sin6_addr,
									sizeof(sai6->sin6_addr),AF_INET6);

							if (h_errno == NETDB_SUCCESS) {
								next = buf + needed;
								continue;
							}
						}
					} else {
						if ((sai->sin_family == AF_INET)) {

							hst = gethostbyaddr(&sai->sin_addr,
									sizeof(sai->sin_addr),AF_INET);

							if (h_errno == NETDB_SUCCESS) {
								next = buf + needed;
								continue;
							}
						}
					}
				}
				break;
			} /* switch */
		} /* loop */

		free(buf);

		if (idx == 0)
			errx(1,"interface not found");
		if (hst == NULL)
			errx(1, "ip not found on interface");

		if (h_errno == NETDB_SUCCESS) {
			if (sethostname(hst->h_name, (int)strlen(hst->h_name)))
				err(1, "sethostname");
		} else if (h_errno == HOST_NOT_FOUND) {
			errx(1,"hostname not found");
		} else {
			herror("gethostbyaddr");
			exit(1);
		}
	} else if (rflag) {
		ret = inet_pton(AF_INET, srflag, &ia);
		if (ret != 1) {
			/* check IPV6 */
			ret = inet_pton(AF_INET6, srflag, &ia6);

			if (ret != 1) {
				errx(1, "invalid ip address");
			}

			flag6 = 1;
		}
		
		if (flag6 == 1) 
			hst = gethostbyaddr(&ia6, sizeof(ia6), AF_INET6);
		else
			hst = gethostbyaddr(&ia, sizeof(ia), AF_INET);
		if (!hst) {
			if (h_errno == HOST_NOT_FOUND) 
				errx(1,"host not found\n");
		}

		if (sethostname(hst->h_name, (int)strlen(hst->h_name)))
			err(1, "sethostname");
	} else if (*argv) {
		if (sethostname(*argv, (int)strlen(*argv)))
			err(1, "sethostname");
	} else {
		if (gethostname(hostname, (int)sizeof(hostname)))
			err(1, "gethostname");
		if (sflag && (p = strchr(hostname, '.')))
			*p = '\0';
		printf("%s\n", hostname);
	}
	exit(0);
}
static int
get_ifinfo(const char *ifname, ifinfo_t *ifinfo)
{
    uint		i;
    int			rc = 0;
    int			ifindex = -1;
    size_t		needed;
    char		*buf = NULL;
    char		*lim = NULL;
    char		*next = NULL;
    struct if_msghdr 	*ifm;
    struct ifa_msghdr 	*ifam;
    struct sockaddr_in 	*sin;
    struct sockaddr_dl 	*sdl;
    struct rt_addrinfo 	info;
    char		iname[16];
    int			mib[6];

    memset(ifinfo, 0, sizeof(*ifinfo));

    /* trim interface name */

    for (i = 0; i < sizeof(iname) && ifname[i] && ifname[i] != '/'; i++)
	iname[i] = ifname[i];
	
    if (i == 0 || i == sizeof(iname))
    {
	report(stderr, GT_("Unable to parse interface name from %s"), ifname);
	return 0;
    }

    iname[i] = 0;


    /* get list of existing interfaces */

    mib[0] = CTL_NET;
    mib[1] = PF_ROUTE;
    mib[2] = 0;
    mib[3] = AF_INET;		/* Only IP addresses please. */
    mib[4] = NET_RT_IFLIST;
    mib[5] = 0;			/* List all interfaces. */


    /* Get interface data. */

    if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
    {
 	report(stderr, 
	    GT_("get_ifinfo: sysctl (iflist estimate) failed"));
	exit(1);
    }
    if ((buf = (char *)malloc(needed)) == NULL)
    {
 	report(stderr, 
	    GT_("get_ifinfo: malloc failed"));
	exit(1);
    }
    if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
    {
 	report(stderr, 
	    GT_("get_ifinfo: sysctl (iflist) failed"));
	exit(1);
    }

    lim = buf+needed;


    /* first look for the interface information */

    next = buf;
    while (next < lim)
    {
	ifm = (struct if_msghdr *)next;
	next += ifm->ifm_msglen;

	if (ifm->ifm_version != RTM_VERSION) 
	{
 	    report(stderr, 
		GT_("Routing message version %d not understood."),
		ifm->ifm_version);
	    exit(1);
	}

	if (ifm->ifm_type == RTM_IFINFO)
	{
	    sdl = (struct sockaddr_dl *)(ifm + 1);

	    if (!(strlen(iname) == sdl->sdl_nlen 
		&& strncmp(iname, sdl->sdl_data, sdl->sdl_nlen) == 0))
	    {
		continue;
	    }

	    if ( !(ifm->ifm_flags & IFF_UP) )
	    {
		/* the interface is down */
		goto get_ifinfo_end;
	    }

	    ifindex = ifm->ifm_index;
	    ifinfo->rx_packets = ifm->ifm_data.ifi_ipackets;
	    ifinfo->tx_packets = ifm->ifm_data.ifi_opackets;

	    break;
	}
    }

    if (ifindex < 0)
    {
	/* we did not find an interface with a matching name */
	report(stderr, GT_("No interface found with name %s"), iname);
	goto get_ifinfo_end;
    }

    /* now look for the interface's IP address */

    next = buf;
    while (next < lim)
    {
	ifam = (struct ifa_msghdr *)next;
	next += ifam->ifam_msglen;

	if (ifindex > 0
	    && ifam->ifam_type == RTM_NEWADDR
	    && ifam->ifam_index == ifindex)
	{
	    /* Expand the compacted addresses */
	    info.rti_addrs = ifam->ifam_addrs;
	    rt_xaddrs((char *)(ifam + 1), 
			ifam->ifam_msglen + (char *)ifam,
	  		&info);

	    /* Check for IPv4 address information only */
	    if (info.rti_info[RTAX_IFA]->sa_family != AF_INET)
	    {
		continue;
	    }

	    rc = 1;

	    sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA];
	    if (sin)
	    {
		ifinfo->addr = sin->sin_addr;
	    }

	    sin = (struct sockaddr_in *)info.rti_info[RTAX_NETMASK];
	    if (sin)
	    {
		ifinfo->netmask = sin->sin_addr;
	    }

	    /* note: RTAX_BRD contains the address at the other
	     * end of a point-to-point link or the broadcast address
	     * of non point-to-point link
	     */
	    sin = (struct sockaddr_in *)info.rti_info[RTAX_BRD];
	    if (sin)
	    {
		ifinfo->dstaddr = sin->sin_addr;
	    }

	    break;
	}
    }

    if (rc == 0)
    {
	report(stderr, GT_("No IP address found for %s"), iname);
    }

get_ifinfo_end:
    free(buf);
    return rc;
}
Exemple #10
0
/*
 * This is the ``callback function'' that is invoked by `sysctl_rtsock' in
 * order to copy data out.  On each invocation, we get a buffer containing:
 *
 *   + A `struct rt_msghdr'.  The `rtm_type' member of this structure should
 *     always be `RTM_GET'.
 *   + A set of zero or more `struct sockaddr's describing the addresses
 *     associated with the route.
 *
 * See the function `sysctl_rtsock' for further details.  Some of the code
 * below is modeled after code in the FreeBSD `route' utility; in FreeBSD, see
 * the file `/usr/src/sbin/route/route.c'.
 */
static int
get_one_ipforward(
	struct sysctl_req *	req,
	const void *		buf,
	size_t			buf_size)
{
	get_ipforward_env_t *	env = (get_ipforward_env_t *) req;
	struct rt_msghdr *	rtm = (struct rt_msghdr *) buf;
	
	struct rt_addrinfo	rtinfo;
	struct sockaddr_in *	sin;
	
	oskit_mib_in_addr_t	dest;
	oskit_mib_in_addr_t	mask;
	/* oskit_s32_t		policy; */
	oskit_mib_in_addr_t	next_hop;
	oskit_s32_t		if_index;
	oskit_u32_t		type;
	oskit_u32_t		proto;
	/* oskit_s32_t		age; */
	oskit_s32_t		next_hop_as;
	oskit_s32_t		metric1;
	oskit_s32_t		metric2;
	oskit_s32_t		metric3;
	oskit_s32_t		metric4;
	oskit_s32_t		metric5;
	
	/*********************************************************************/
	
	if (rtm->rtm_version != RTM_VERSION) {
		/* A message we don't understand?  This should never happen. */
		assert(!"Received an unknown type of message.");
		goto done;
	}
	if (rtm->rtm_type != RTM_GET) {
		/* A message we don't understand?  This should never happen. */
		assert(!"Received an unknown type of message.");
		goto done;
	}
	
	/*
	 * Figure out what the socket addresses mean; i.e., assign them to the
	 * appropriate elements of the `rtinfo.rti_info' array.
	 */
	rtinfo.rti_addrs = rtm->rtm_addrs;
	rt_xaddrs(((char *) (rtm + 1)),
		  ((char *) rtm) + rtm->rtm_msglen,
		  &rtinfo);
	
	/* From `rtinfo', decode the fields of our table row. */
	sin = (struct sockaddr_in *) rtinfo.rti_info[RTAX_DST];
	if (!sin)
		/* No destination address?! */
		goto done;
	dest = sin->sin_addr.s_addr;
	
	sin = (struct sockaddr_in *) rtinfo.rti_info[RTAX_NETMASK];
	if (!sin)
		/* No network mask?! */
		goto done;
	mask = sin->sin_addr.s_addr;
	
	/*
	 * XXX --- RFC 1354 says that this should be an encoding of the IP TOS.
	 * I don't understand how I'm supposed to determine that for a route.
	 * The TOS is associated with a particular socket, not a route, right?
	 */
	/* policy = ...; */
	
	if (rtm->rtm_flags & RTF_LOCAL) {
		next_hop = INADDR_ANY; /* See RFC 1354. */
	} else {
		sin = (struct sockaddr_in *) rtinfo.rti_info[RTAX_GATEWAY];
		if (!sin)
			/* No next hop address?! */
			goto done;
		
		switch (sin->sin_family) {
		case AF_INET:
			next_hop = sin->sin_addr.s_addr;
			break;
		case AF_LINK:
			/*
			 * The gateway address is a link-layer address.  This
			 * means that we're talking about one of our own
			 * interfaces.
			 *
			 * RFC 1213 says (for `ipRouteNextHop'): ``In the case
			 * of a route bound to an interface which is realized
			 * via a broadcast media, the value of this field is
			 * the agent's IP address on that interface.''
			 *
			 * RFC 1354 says (for `ipForwardNextHop'): ``On remote
			 * routes, the address of the next system en route;
			 * Otherwise, 0.0.0.0.''
			 *
			 * We follow RFC 1354 because we *are* implementing the
			 * `ipForwardTable' after all.  Plus, we don't have our
			 * IP address on the interface handy at this point.
			 * (`dest' isn't it.  `dest' has had the subnet mask
			 * applied to it, so it's missing parts of our addr.)
			 */
#if 1
			next_hop = INADDR_ANY;
#else
			sdl = (struct sockaddr_dl *) sin;
			switch (sdl->sdl_type) {
			case IFT_ETHER:
			/* List other broadcast media here. */
				next_hop = /* Our IP address.  Not `dest'. */;
				break;
			default:
				next_hop = INADDR_ANY;
				break;
			}
#endif
			break;
		default:
			assert(!"Received an unrecognized kind of next-hop");
			next_hop = INADDR_ANY;
			break;
		}
	}
	
	if_index = rtm->rtm_index;
	type = ((rtm->rtm_flags & RTF_GATEWAY) ?
		OSKIT_MIB_IP_FORWARD_TYPE_REMOTE :
		OSKIT_MIB_IP_FORWARD_TYPE_LOCAL);
	
	proto = ((rtm->rtm_flags & RTF_LOCAL) ?
		 OSKIT_MIB_IP_FORWARD_PROTO_LOCAL :
		 (rtm->rtm_flags & RTF_DYNAMIC) ?
		 OSKIT_MIB_IP_FORWARD_PROTO_ICMP :
		 (rtm->rtm_flags & RTF_STATIC) ?
		 OSKIT_MIB_IP_FORWARD_PROTO_NETMGMT :
		 OSKIT_MIB_IP_FORWARD_PROTO_OTHER
		 );
	
	/* XXX --- I don't believe that route age is stored anywhere. */
	/* age = ...; */
	
	next_hop_as = 0; /* See IETF RFC 1354. */
	
	/*
	 * XXX --- I don't really understand the semantics of these values;
	 * e.g., are they supposed to have well-defined meanings?  I've just
	 * picked the most interesting set of metrics from our route info.
	 */
	metric1 = (rtm->rtm_flags & RTF_UP);	/* Is this route usable? */
	metric2 = rtm->rtm_rmx.rmx_hopcount;	/* Max hops expected. */
	metric3 = rtm->rtm_rmx.rmx_sendpipe;	/* Out delay-b'width product */
	metric4 = rtm->rtm_rmx.rmx_rtt;		/* Estimated round trip time */
	metric5 = rtm->rtm_rmx.rmx_rttvar;	/* Estimated RTT variance. */
	
	/*********************************************************************/
	
	/*
	 * Process the entry.
	 */
	if (ipforward_match(dest, mask, /* policy, */ next_hop,
			    if_index, type, proto, /* age, */ next_hop_as,
			    metric1, metric2, metric3, metric4, metric5,
			    env->args.matching)) {
		if (env->args.start_row > 0) {
			/* Skip this row. */
			env->args.start_row--;
		} else if (env->args.want_rows > 0) {
			/* Accumulate this row. */
#define COPY_OUT(slot_type, slot_name)				\
	oskit_mib_##slot_type##_set(				\
		&(env->args.table->ip_forward_##slot_name),	\
		slot_name)
#define CLEAR_OUT(slot_type, slot_name)				\
	oskit_mib_##slot_type##_clear(				\
		&(env->args.table->ip_forward_##slot_name))
			COPY_OUT(mib_in_addr,	dest);
			COPY_OUT(mib_in_addr,	mask);
			CLEAR_OUT(s32,		policy);	/* XXX */
			COPY_OUT(mib_in_addr,	next_hop);
			COPY_OUT(s32,		if_index);
			COPY_OUT(u32,		type);
			COPY_OUT(u32,		proto);
			CLEAR_OUT(s32,		age);		/* XXX */
			COPY_OUT(s32,		next_hop_as);
			COPY_OUT(s32,		metric1);
			COPY_OUT(s32,		metric2);
			COPY_OUT(s32,		metric3);
			COPY_OUT(s32,		metric4);
			COPY_OUT(s32,		metric5);
#undef COPY_OUT
			(*env->args.out_rows)++;
			env->args.table++;
			env->args.want_rows--;
			
		} else {
			/* Indicate that the table filled up. */
			*env->args.more_rows = 1;
		}
	}
	
 done:
	/* Indicate to the `sysctl_rtsock' function that no error occurred. */
	return 0;
}
Exemple #11
0
/*
 * This is the ``callback function'' that is invoked by `sysctl_rtsock' in
 * order to copy data out.  See the comments before `get_one_ipaddr' for
 * general information about the data we receive on each callback.
 */
static int
get_one_ipnettomedia(
	struct sysctl_req *	req,
	const void *		buf,
	size_t			buf_size)
{
	get_ipnettomedia_env_t *	env = (get_ipnettomedia_env_t *) req;
	struct ifa_msghdr *		ifam = (struct ifa_msghdr *) buf;
	
	struct rt_addrinfo	rtinfo;
	struct sockaddr_in *	sin;
	
	oskit_u32_t		if_index;
	/* oskit_mib_string_t	phys_address; --- not needed. */
	oskit_mib_in_addr_t	net_address;
	oskit_u32_t		type;
	
	/*********************************************************************/
	
	/*
	 * We get physical addresses from `RTM_IFINFO' messages, and we get IP
	 * addresses from subsequent `RTM_NEWADDR' messages.  Note that there
	 * may be more than one IP address per interface.
	 *
	 */
	if (ifam->ifam_type == RTM_IFINFO) {
		struct if_msghdr *	ifm = (struct if_msghdr *) buf;
		struct sockaddr_dl *	sdl = (struct sockaddr_dl *) (ifm+1);
		
		extract_phys_address(sdl, env);
		
		DEBUG_SET_STATE((env->state = SEEN_IFINFO));
		goto done;
	}
	
	if (ifam->ifam_type != RTM_NEWADDR) {
		assert(!"Received an unknown type of message.");
		goto done;
	}
	
	DEBUG_CHECK_STATE((env->state == SEEN_IFINFO));
	
	/*********************************************************************/
	
	/* If we don't have a valid physical address, bail early. */
	if (!env->phys_address.str)
		goto done;
	
	/*
	 * Figure out what the socket addresses mean; i.e., assign them to the
	 * appropriate elements of the `rtinfo.rti_info' array.
	 */
	rtinfo.rti_addrs = ifam->ifam_addrs;
	rt_xaddrs(((char *) (ifam + 1)),
		  ((char *) ifam) + ifam->ifam_msglen,
		  &rtinfo);
	
	/*
	 * From `env->phys_address' and `rtinfo', decode the fields of our
	 * table row.
	 */
	if_index = ifam->ifam_index;
	
	/* phys_address = env->phys_address; --- why bother? */
	
	sin = (struct sockaddr_in *) rtinfo.rti_info[RTAX_IFA];
	if (!sin)
		/* No interface address?! */
		goto done;
	net_address = sin->sin_addr.s_addr;
	
	/*
	 * XXX --- Perhaps this isn't right, but I'm not sure what is.  The
	 * UCD-SNMP code returns `static' for permanent ARP cache entries and
	 * `dynamic' for others.  But that doesn't seem right: what exactly is
	 * dynamic about a host's own IP-->Ethernet mappings?
	 */
	type = OSKIT_MIB_IP_NET_TO_MEDIA_TYPE_STATIC;
	
	/*********************************************************************/
	
	/*
	 * Process the entry.
	 */
	if (ipnettomedia_match(if_index, env->phys_address, net_address, type,
			       env->args.matching)) {
		if (env->args.start_row > 0) {
			/* Skip this row. */
			env->args.start_row--;
		} else if (env->args.want_rows > 0) {
			/* Accumulate this row. */
#define COPY_OUT(slot_type, slot_name)					\
	oskit_mib_##slot_type##_set(					\
		&(env->args.table->ip_net_to_media_##slot_name),	\
		slot_name)
			COPY_OUT(u32, if_index);
			copy_out_str(&(env->args.table->
				       ip_net_to_media_phys_address),
				     &(env->phys_address));
			COPY_OUT(mib_in_addr, net_address);
			COPY_OUT(u32, type);
#undef COPY_OUT
			(*env->args.out_rows)++;
			env->args.table++;
			env->args.want_rows--;
			
		} else {
			/* Indicate that the table filled up. */
			*env->args.more_rows = 1;
		}
	}
	
 done:
	/* Indicate to the `sysctl_rtsock' function that no error occurred. */
	return 0;
}
Exemple #12
0
/*
 * This is the ``callback function'' that is invoked by `sysctl_rtsock' in
 * order to copy data out.  The data that is given to us is as follows:
 *
 *   + First, we are called with a buffer containing a `struct if_msghdr', with
 *     the type member set to `RTM_IFINFO'.  This signals the start of a group
 *     of callbacks about a particular interface.  The `if_msghdr' is followed
 *     by zero of more `struct sockaddr_dl's (in the same buffer).
 *
 *   + Subsequent callbacks will receive a `struct ifa_msghdr' (with its type
 *     member set to `RTM_NEWADDR') followed immediatley by zero or more
 *     `struct sockaddr_in's.  This describes a particular group of (IP)
 *     addresses for an interface.
 *
 * These callbacks are performed one for each interface.  I.e., for each
 * interface, we will receive a `RTM_IFINFO' callback followed by zero or more
 * `RTM_NEWADDR' callbacks.
 *
 * See the function `sysctl_rtsock' for further details.  Some of the code
 * below is modeled after code in the FreeBSD `ifconfig' utility; in FreeBSD,
 * see the file `/usr/src/sbin/ifconfig/ifconfig.c'.
 */
static int
get_one_ipaddr(
	struct sysctl_req *	req,
	const void *		buf,
	size_t			buf_size)
{
	get_ipaddr_env_t *	env = (get_ipaddr_env_t *) req;
	struct ifa_msghdr *	ifam = (struct ifa_msghdr *) buf;
	
	struct rt_addrinfo	rtinfo;
	struct sockaddr_in *	sin;
	
	oskit_mib_in_addr_t	addr;
	oskit_u32_t		if_index;
	oskit_mib_in_addr_t	net_mask;
	oskit_u32_t		bcast_addr;
	oskit_u16_t		reasm_max_size;
	
	/*********************************************************************/
	
	/*
	 * Mainly, we care about `RTM_NEWADDR' messages.  Each of these
	 * messages contains a `struct ifa_msghdr' followed by a set of socket
	 * addresses (`struct sockaddr_in's).
	 *
	 * We need `RTM_IFINFO' messages only to set our `env->ifinfo_flags'.
	 * One of these messages contains a `struct if_msghdr' (followed by a
	 * set of `struct sockaddr_dl's, which we don't care about here).
	 */
	if (ifam->ifam_type == RTM_IFINFO) {
		env->ifinfo_flags = ((struct if_msghdr *) buf)->ifm_flags;
		DEBUG_SET_STATE((env->state = SEEN_IFINFO));
		goto done;
	}
	
	if (ifam->ifam_type != RTM_NEWADDR) {
		assert(!"Received an unknown type of message.");
		goto done;
	}
	
	DEBUG_CHECK_STATE((env->state == SEEN_IFINFO));
	
	/*********************************************************************/
	
	/*
	 * Figure out what the socket addresses mean; i.e., assign them to the
	 * appropriate elements of the `rtinfo.rti_info' array.
	 */
	rtinfo.rti_addrs = ifam->ifam_addrs;
	rt_xaddrs(((char *) (ifam + 1)),
		  ((char *) ifam) + ifam->ifam_msglen,
		  &rtinfo);
	
	/*
	 * From `rtinfo', decode the fields of our table row.
	 */
	
	sin = (struct sockaddr_in *) rtinfo.rti_info[RTAX_IFA];
	if (!sin)
		/* No interface address?! */
		goto done;
	addr = sin->sin_addr.s_addr;
	
	if_index = ifam->ifam_index;
	
	sin = (struct sockaddr_in *) rtinfo.rti_info[RTAX_NETMASK];
	if (!sin)
		/* No network mask?! */
		goto done;
	net_mask = sin->sin_addr.s_addr;
	
	/* XXX --- Default `bcast_addr' to one. */
	bcast_addr = 1;
	/*
	 * For point-to-point links, `rti_info[RTAX_BRD]' holds the destination
	 * address.  So, one must check for the `IFF_BROADCAST' flag.
	 */
	if (env->ifinfo_flags & IFF_BROADCAST) {
		sin = (struct sockaddr_in *) rtinfo.rti_info[RTAX_BRD];
		if (sin)
			bcast_addr = (ntohl(sin->sin_addr.s_addr) & 1);
	}
	
	/*
	 * I'm pretty sure that the `reasm_max_size' is `IP_MAXPACKET' for all
	 * interfaces.
	 */
	reasm_max_size = IP_MAXPACKET;
	
	/*********************************************************************/
	
	/*
	 * Process the entry.
	 */
	if (ipaddr_match(addr, if_index, net_mask, bcast_addr, reasm_max_size,
			 env->args.matching)) {
		if (env->args.start_row > 0) {
			/* Skip this row. */
			env->args.start_row--;
		} else if (env->args.want_rows > 0) {
			/* Accumulate this row. */
#define COPY_OUT(slot_type, slot_name)				\
	oskit_mib_##slot_type##_set(				\
		&(env->args.table->ip_ad_ent_##slot_name),	\
		slot_name)
			COPY_OUT(mib_in_addr, addr);
			COPY_OUT(u32, if_index);
			COPY_OUT(mib_in_addr, net_mask);
			COPY_OUT(u32, bcast_addr);
			COPY_OUT(u16, reasm_max_size);
#undef COPY_OUT
			(*env->args.out_rows)++;
			env->args.table++;
			env->args.want_rows--;
			
		} else {
			/* Indicate that the table filled up. */
			*env->args.more_rows = 1;
		}
	}
	
 done:
	/* Indicate to the `sysctl_rtsock' function that no error occurred. */
	return 0;
}