Example #1
0
int
getifmaddrs(struct ifmaddrs **pif)
{
	int icnt = 1;
	int dcnt = 0;
	int ntry = 0;
	size_t len;
	size_t needed;
	int mib[6];
	int i;
	char *buf;
	char *data;
	char *next;
	char *p;
	struct ifma_msghdr *ifmam;
	struct ifmaddrs *ifa, *ift;
	struct rt_msghdr *rtm;
	struct sockaddr *sa;

	mib[0] = CTL_NET;
	mib[1] = PF_ROUTE;
	mib[2] = 0;             /* protocol */
	mib[3] = 0;             /* wildcard address family */
	mib[4] = NET_RT_IFMALIST;
	mib[5] = 0;             /* no flags */
	do {
		if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
			return (-1);
		if ((buf = malloc(needed)) == NULL)
			return (-1);
		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
			if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
				free(buf);
				return (-1);
			}
			free(buf);
			buf = NULL;
		} 
	} while (buf == NULL);

	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_NEWMADDR:
			ifmam = (struct ifma_msghdr *)(void *)rtm;
			if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
				break;
			icnt++;
			p = (char *)(ifmam + 1);
			for (i = 0; i < RTAX_MAX; i++) {
				if ((RTA_MASKS & ifmam->ifmam_addrs &
				    (1 << i)) == 0)
					continue;
				sa = (struct sockaddr *)(void *)p;
				len = SA_RLEN(sa);
				dcnt += len;
				p += len;
			}
			break;
		}
	}

	data = malloc(sizeof(struct ifmaddrs) * icnt + dcnt);
	if (data == NULL) {
		free(buf);
		return (-1);
	}

	ifa = (struct ifmaddrs *)(void *)data;
	data += sizeof(struct ifmaddrs) * icnt;

	memset(ifa, 0, sizeof(struct ifmaddrs) * icnt);
	ift = ifa;

	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_NEWMADDR:
			ifmam = (struct ifma_msghdr *)(void *)rtm;
			if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
				break;

			p = (char *)(ifmam + 1);
			for (i = 0; i < RTAX_MAX; i++) {
				if ((RTA_MASKS & ifmam->ifmam_addrs &
				    (1 << i)) == 0)
					continue;
				sa = (struct sockaddr *)(void *)p;
				len = SA_RLEN(sa);
				switch (i) {
				case RTAX_GATEWAY:
					ift->ifma_lladdr =
					    (struct sockaddr *)(void *)data;
					memcpy(data, p, len);
					data += len;
					break;

				case RTAX_IFP:
					ift->ifma_name =
					    (struct sockaddr *)(void *)data;
					memcpy(data, p, len);
					data += len;
					break;

				case RTAX_IFA:
					ift->ifma_addr =
					    (struct sockaddr *)(void *)data;
					memcpy(data, p, len);
					data += len;
					break;

				default:
					data += len;
					break;
				}
				p += len;
			}
			ift->ifma_next = ift + 1;
			ift = ift->ifma_next;
			break;
		}
	}

	free(buf);

	if (ift > ifa) {
		ift--;
		ift->ifma_next = NULL;
		*pif = ifa;
	} else {
		*pif = NULL;
		free(ifa);
	}
	return (0);
}
Example #2
0
int
getifaddrs(struct ifaddrs **pif)
{
    int icnt = 1;  // Interface count
    int dcnt = 0;  // Data [length] count
    int ncnt = 0;  // Length of interface names
    char buf[1024];
    int i, sock;
    struct ifconf ifc;
    struct ifreq *ifr, *lifr;
    char *data, *names;
    struct ifaddrs *ifa, *ift;

    ifc.ifc_buf = buf;
    ifc.ifc_len = sizeof(buf);

    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        return (-1);
    i =  ioctl(sock, SIOCGIFCONF, (char *)&ifc);
    close(sock);
    if (i < 0)
        return (-1);

    ifr = ifc.ifc_req;
    lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];

    while (ifr < lifr) {
        struct sockaddr *sa;

        sa = &ifr->ifr_addr;
        ++icnt;
        dcnt += SA_RLEN(sa);
        ncnt += sizeof(ifr->ifr_name) + 1;
		
        if (SA_LEN(sa) < sizeof(*sa))
            ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa));
        else
            ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
    }

    if (icnt + dcnt + ncnt == 1) {
        // Nothing found
        *pif = NULL;
        free(buf);
        return (0);
    }
    data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
    if (data == NULL) {
        free(buf);
        return(-1);
    }

    ifa = (struct ifaddrs *)(void *)data;
    data += sizeof(struct ifaddrs) * icnt;
    names = data + dcnt;

    memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
    ift = ifa;

    ifr = ifc.ifc_req;
    lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];

    while (ifr < lifr) {
        struct sockaddr *sa;

        ift->ifa_name = names;
        names[sizeof(ifr->ifr_name)] = 0;
        strncpy(names, ifr->ifr_name, sizeof(ifr->ifr_name));
        while (*names++) ;

        ift->ifa_addr = (struct sockaddr *)data;
        sa = &ifr->ifr_addr;
        memcpy(data, sa, SA_LEN(sa));
        data += SA_RLEN(sa);
		
        if (SA_LEN(sa) < sizeof(*sa))
            ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa));
        else
            ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
        ift = (ift->ifa_next = ift + 1);
    }

    if (--ift >= ifa) {
        ift->ifa_next = NULL;
        *pif = ifa;
    } else {
        *pif = NULL;
        free(ifa);
    }
    return (0);
}
Example #3
0
void
ProcessInterfaceWatchNotify(int s)
{
	char buf[4096];
	ssize_t len;
	char tmp[64];
	struct rt_msghdr * rtm;
	struct if_msghdr * ifm;
	struct ifa_msghdr * ifam;
#ifdef RTM_IFANNOUNCE
	struct if_announcemsghdr * ifanm;
#endif
	char * p;
	struct sockaddr * sa;
	unsigned int ext_if_name_index = 0;

	len = recv(s, buf, sizeof(buf), 0);
	if(len < 0) {
		syslog(LOG_ERR, "ProcessInterfaceWatchNotify recv: %m");
		return;
	}
	if(ext_if_name) {
		ext_if_name_index = if_nametoindex(ext_if_name);
	}
	rtm = (struct rt_msghdr *)buf;
	syslog(LOG_DEBUG, "%u rt_msg : msglen=%d version=%d type=%d", (unsigned)len,
	       rtm->rtm_msglen, rtm->rtm_version, rtm->rtm_type);
	switch(rtm->rtm_type) {
	case RTM_IFINFO:	/* iface going up/down etc. */
		ifm = (struct if_msghdr *)buf;
		syslog(LOG_DEBUG, " RTM_IFINFO: addrs=%x flags=%x index=%hu",
		       ifm->ifm_addrs, ifm->ifm_flags, ifm->ifm_index);
		break;
	case RTM_ADD:	/* Add Route */
		syslog(LOG_DEBUG, " RTM_ADD");
		break;
	case RTM_DELETE:	/* Delete Route */
		syslog(LOG_DEBUG, " RTM_DELETE");
		break;
	case RTM_CHANGE:	/* Change Metrics or flags */
		syslog(LOG_DEBUG, " RTM_CHANGE");
		break;
	case RTM_GET:	/* Report Metrics */
		syslog(LOG_DEBUG, " RTM_GET");
		break;
#ifdef RTM_IFANNOUNCE
	case RTM_IFANNOUNCE:	/* iface arrival/departure */
		ifanm = (struct if_announcemsghdr *)buf;
		syslog(LOG_DEBUG, " RTM_IFANNOUNCE: index=%hu what=%hu ifname=%s",
		       ifanm->ifan_index, ifanm->ifan_what, ifanm->ifan_name);
		break;
#endif
#ifdef RTM_IEEE80211
	case RTM_IEEE80211:	/* IEEE80211 wireless event */
		syslog(LOG_DEBUG, " RTM_IEEE80211");
		break;
#endif
	case RTM_NEWADDR:	/* address being added to iface */
		ifam = (struct ifa_msghdr *)buf;
		syslog(LOG_DEBUG, " RTM_NEWADDR: addrs=%x flags=%x index=%hu",
		       ifam->ifam_addrs, ifam->ifam_flags, ifam->ifam_index);
		p = buf + sizeof(struct ifa_msghdr);
		while(p < buf + len) {
			sa = (struct sockaddr *)p;
			sockaddr_to_string(sa, tmp, sizeof(tmp));
			syslog(LOG_DEBUG, "  %s", tmp);
			p += SA_RLEN(sa);
		}
		if(ifam->ifam_index == ext_if_name_index) {
			should_send_public_address_change_notif = 1;
		}
		break;
	case RTM_DELADDR:	/* address being removed from iface */
		ifam = (struct ifa_msghdr *)buf;
		if(ifam->ifam_index == ext_if_name_index) {
			should_send_public_address_change_notif = 1;
		}
		break;
	default:
		syslog(LOG_DEBUG, "unprocessed RTM message type=%d", rtm->rtm_type);
	}
}
Example #4
0
int
getifaddrs(struct ifaddrs **pif)
{
	int icnt = 1;
	int dcnt = 0;
	int ncnt = 0;
	int ntry = 0;
	int mib[6];
	size_t needed;
	char *buf;
	char *next;
	struct ifaddrs *cif = NULL;
	char *p, *p0;
	struct rt_msghdr *rtm;
	struct if_msghdr *ifm;
	struct ifa_msghdr *ifam;
	struct sockaddr_dl *dl;
	struct sockaddr *sa;
	struct ifaddrs *ifa, *ift;
	u_short idx = 0;
	int i;
	size_t len, alen;
	char *data;
	char *names;

	mib[0] = CTL_NET;
	mib[1] = PF_ROUTE;
	mib[2] = 0;             /* protocol */
	mib[3] = 0;             /* wildcard address family */
	mib[4] = NET_RT_IFLIST;
	mib[5] = 0;             /* no flags */
	do {
		/*
		 * We'll try to get addresses several times in case that
		 * the number of addresses is unexpectedly increased during
		 * the two sysctl calls.  This should rarely happen, but we'll
		 * try to do our best for applications that assume success of
		 * this library (which should usually be the case).
		 * Portability note: since FreeBSD does not add margin of
		 * memory at the first sysctl, the possibility of failure on
		 * the second sysctl call is a bit higher.
		 */

		if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
			return (-1);
		if ((buf = malloc(needed)) == NULL)
			return (-1);
		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
			if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
				free(buf);
				return (-1);
			}
			free(buf);
			buf = NULL;
		} 
	} while (buf == NULL);

	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) {
				idx = ifm->ifm_index;
				++icnt;
				dl = (struct sockaddr_dl *)(void *)(ifm + 1);
				dcnt += SA_RLEN((struct sockaddr *)(void*)dl) +
				    ALIGNBYTES;
				dcnt += sizeof(ifm->ifm_data);
				ncnt += dl->sdl_nlen + 1;
			} else
				idx = 0;
			break;

		case RTM_NEWADDR:
			ifam = (struct ifa_msghdr *)(void *)rtm;
			if (idx && ifam->ifam_index != idx)
				abort();	/* this cannot happen */

#define	RTA_MASKS	(RTA_NETMASK | RTA_IFA | RTA_BRD)
			if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
				break;
			p = (char *)(void *)(ifam + 1);
			++icnt;
			/* Scan to look for length of address */
			alen = 0;
			for (p0 = p, i = 0; i < RTAX_MAX; i++) {
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
				    == 0)
					continue;
				sa = (struct sockaddr *)(void *)p;
				len = SA_RLEN(sa);
				if (i == RTAX_IFA) {
					alen = len;
					break;
				}
				p += len;
			}
			for (p = p0, i = 0; i < RTAX_MAX; i++) {
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
				    == 0)
					continue;
				sa = (struct sockaddr *)(void *)p;
				len = SA_RLEN(sa);
				if (i == RTAX_NETMASK && SA_LEN(sa) == 0)
					dcnt += alen;
				else
					dcnt += len;
				p += len;
			}
			break;
		}
	}

	if (icnt + dcnt + ncnt == 1) {
		*pif = NULL;
		free(buf);
		return (0);
	}
	data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
	if (data == NULL) {
		free(buf);
		return(-1);
	}

	ifa = (struct ifaddrs *)(void *)data;
	data += sizeof(struct ifaddrs) * icnt;
	names = data + dcnt;

	memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
	ift = ifa;

	idx = 0;
	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) {
				idx = ifm->ifm_index;
				dl = (struct sockaddr_dl *)(void *)(ifm + 1);

				cif = ift;
				ift->ifa_name = names;
				ift->ifa_flags = (int)ifm->ifm_flags;
				memcpy(names, dl->sdl_data,
				    (size_t)dl->sdl_nlen);
				names[dl->sdl_nlen] = 0;
				names += dl->sdl_nlen + 1;

				ift->ifa_addr = (struct sockaddr *)(void *)data;
				memcpy(data, dl,
				    (size_t)SA_LEN((struct sockaddr *)
				    (void *)dl));
				data += SA_RLEN((struct sockaddr *)(void *)dl);

				/* ifm_data needs to be aligned */
				ift->ifa_data = data = (void *)ALIGN(data);
				memcpy(data, &ifm->ifm_data, sizeof(ifm->ifm_data));
 				data += sizeof(ifm->ifm_data);
				ift = (ift->ifa_next = ift + 1);
			} else
				idx = 0;
			break;

		case RTM_NEWADDR:
			ifam = (struct ifa_msghdr *)(void *)rtm;
			if (idx && ifam->ifam_index != idx)
				abort();	/* this cannot happen */

			if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
				break;
			ift->ifa_name = cif->ifa_name;
			ift->ifa_flags = cif->ifa_flags;
			ift->ifa_data = NULL;
			p = (char *)(void *)(ifam + 1);
			/* Scan to look for length of address */
			alen = 0;
			for (p0 = p, i = 0; i < RTAX_MAX; i++) {
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
				    == 0)
					continue;
				sa = (struct sockaddr *)(void *)p;
				len = SA_RLEN(sa);
				if (i == RTAX_IFA) {
					alen = len;
					break;
				}
				p += len;
			}
			for (p = p0, i = 0; i < RTAX_MAX; i++) {
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
				    == 0)
					continue;
				sa = (struct sockaddr *)(void *)p;
				len = SA_RLEN(sa);
				switch (i) {
				case RTAX_IFA:
					ift->ifa_addr =
					    (struct sockaddr *)(void *)data;
					memcpy(data, p, len);
					data += len;
					break;

				case RTAX_NETMASK:
					ift->ifa_netmask =
					    (struct sockaddr *)(void *)data;
					if (SA_LEN(sa) == 0) {
						memset(data, 0, alen);
						data += alen;
						break;
					}
					memcpy(data, p, len);
					data += len;
					break;

				case RTAX_BRD:
					ift->ifa_broadaddr =
					    (struct sockaddr *)(void *)data;
					memcpy(data, p, len);
					data += len;
					break;
				}
				p += len;
			}

			ift = (ift->ifa_next = ift + 1);
			break;
		}
	}

	free(buf);
	if (--ift >= ifa) {
		ift->ifa_next = NULL;
		*pif = ifa;
	} else {
		*pif = NULL;
		free(ifa);
	}
	return (0);
}
Example #5
0
/**
 * Process the message and add/drop multicast membership if needed
 */
int
ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6)
{
	struct lan_addr_s * lan_addr;
	ssize_t len;
	char buffer[4096];
#ifdef __linux__
	struct iovec iov;
	struct msghdr hdr;
	struct nlmsghdr *nlhdr;
	struct ifaddrmsg *ifa;
	struct rtattr *rta;
	int ifa_len;

	iov.iov_base = buffer;
	iov.iov_len = sizeof(buffer);

	memset(&hdr, 0, sizeof(hdr));
	hdr.msg_iov = &iov;
	hdr.msg_iovlen = 1;

	len = recvmsg(s, &hdr, 0);
	if(len < 0) {
		syslog(LOG_ERR, "recvmsg(s, &hdr, 0): %m");
		return -1;
	}

	for(nlhdr = (struct nlmsghdr *)buffer;
		NLMSG_OK(nlhdr, len);
		nlhdr = NLMSG_NEXT(nlhdr, len)) {
		int is_del = 0;
		char address[48];
		char ifname[IFNAMSIZ];
		address[0] = '\0';
		ifname[0] = '\0';
		if(nlhdr->nlmsg_type == NLMSG_DONE)
			break;
		switch(nlhdr->nlmsg_type) {
		/* case RTM_NEWLINK: */
		/* case RTM_DELLINK: */
		case RTM_DELADDR:
			is_del = 1;
		case RTM_NEWADDR:
			/* http://linux-hacks.blogspot.fr/2009/01/sample-code-to-learn-netlink.html */
			ifa = (struct ifaddrmsg *)NLMSG_DATA(nlhdr);
			rta = (struct rtattr *)IFA_RTA(ifa);
			ifa_len = IFA_PAYLOAD(nlhdr);
			syslog(LOG_DEBUG, "%s %s index=%d fam=%d prefixlen=%d flags=%d scope=%d",
			       "ProcessInterfaceWatchNotify", is_del ? "RTM_DELADDR" : "RTM_NEWADDR",
			       ifa->ifa_index, ifa->ifa_family, ifa->ifa_prefixlen,
			       ifa->ifa_flags, ifa->ifa_scope);
			for(;RTA_OK(rta, ifa_len); rta = RTA_NEXT(rta, ifa_len)) {
				/*RTA_DATA(rta)*/
				/*rta_type : IFA_ADDRESS, IFA_LOCAL, etc. */
				char tmp[128];
				memset(tmp, 0, sizeof(tmp));
				switch(rta->rta_type) {
				case IFA_ADDRESS:
				case IFA_LOCAL:
				case IFA_BROADCAST:
				case IFA_ANYCAST:
					inet_ntop(ifa->ifa_family, RTA_DATA(rta), tmp, sizeof(tmp));
					if(rta->rta_type == IFA_ADDRESS)
						strncpy(address, tmp, sizeof(address));
					break;
				case IFA_LABEL:
					strncpy(tmp, RTA_DATA(rta), sizeof(tmp));
					strncpy(ifname, tmp, sizeof(ifname));
					break;
				case IFA_CACHEINFO:
					{
						struct ifa_cacheinfo *cache_info;
						cache_info = RTA_DATA(rta);
						snprintf(tmp, sizeof(tmp), "valid=%u prefered=%u",
						         cache_info->ifa_valid, cache_info->ifa_prefered);
					}
					break;
				default:
					strncpy(tmp, "*unknown*", sizeof(tmp));
				}
				syslog(LOG_DEBUG, " rta_len=%d rta_type=%d '%s'", rta->rta_len, rta->rta_type, tmp);
			}
			syslog(LOG_INFO, "%s: %s/%d %s",
			       is_del ? "RTM_DELADDR" : "RTM_NEWADDR",
			       address, ifa->ifa_prefixlen, ifname);
			for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) {
				if((0 == strcmp(address, lan_addr->str)) ||
				   (0 == strcmp(ifname, lan_addr->ifname)) ||
				   (ifa->ifa_index == lan_addr->index)) {
					if(ifa->ifa_family == AF_INET)
						AddDropMulticastMembership(s_ssdp, lan_addr, 0, is_del);
					else if(ifa->ifa_family == AF_INET6)
						AddDropMulticastMembership(s_ssdp6, lan_addr, 1, is_del);
					break;
				}
			}
			break;
		default:
			syslog(LOG_DEBUG, "unknown nlmsg_type=%d", nlhdr->nlmsg_type);
		}
	}
#else /* __linux__ */
	struct rt_msghdr * rtm;
	struct ifa_msghdr * ifam;
	int is_del = 0;
	char tmp[64];
	char * p;
	struct sockaddr * sa;
	int addr;
	char address[48];
	char ifname[IFNAMSIZ];
	int family = AF_UNSPEC;
	int prefixlen = 0;

	address[0] = '\0';
	ifname[0] = '\0';

	len = recv(s, buffer, sizeof(buffer), 0);
	if(len < 0) {
		syslog(LOG_ERR, "%s recv: %m", "ProcessInterfaceWatchNotify");
		return -1;
	}
	rtm = (struct rt_msghdr *)buffer;
	switch(rtm->rtm_type) {
	case RTM_DELADDR:
		is_del = 1;
	case RTM_NEWADDR:
		ifam = (struct ifa_msghdr *)buffer;
		syslog(LOG_DEBUG, "%s %s len=%d/%hu index=%hu addrs=%x flags=%x",
		       "ProcessInterfaceWatchNotify", is_del?"RTM_DELADDR":"RTM_NEWADDR",
		       (int)len, ifam->ifam_msglen,
		       ifam->ifam_index, ifam->ifam_addrs, ifam->ifam_flags);
		p = buffer + sizeof(struct ifa_msghdr);
		addr = 1;
		while(p < buffer + len) {
			sa = (struct sockaddr *)p;
			while(!(addr & ifam->ifam_addrs) && (addr <= ifam->ifam_addrs))
				addr = addr << 1;
			sockaddr_to_string(sa, tmp, sizeof(tmp));
			syslog(LOG_DEBUG, " %s", tmp);
			switch(addr) {
			case RTA_DST:
			case RTA_GATEWAY:
				break;
			case RTA_NETMASK:
				if(sa->sa_family == AF_INET
#if defined(__OpenBSD__)
				   || (sa->sa_family == 0 &&
				       sa->sa_len <= sizeof(struct sockaddr_in))
#endif
				   ) {
					uint32_t sin_addr = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
					while((prefixlen < 32) &&
					      ((sin_addr & (1 << (31 - prefixlen))) != 0))
						prefixlen++;
				} else if(sa->sa_family == AF_INET6
#if defined(__OpenBSD__)
				          || (sa->sa_family == 0 &&
				              sa->sa_len == sizeof(struct sockaddr_in6))
#endif
				          ) {
					int i = 0;
					uint8_t * q =  ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr;
					while((*q == 0xff) && (i < 16)) {
						prefixlen += 8;
						q++; i++;
					}
					if(i < 16) {
						i = 0;
						while((i < 8) &&
						      ((*q & (1 << (7 - i))) != 0))
							i++;
						prefixlen += i;
					}
				}
				break;
			case RTA_GENMASK:
				break;
			case RTA_IFP:
#ifdef AF_LINK
				if(sa->sa_family == AF_LINK) {
					struct sockaddr_dl * sdl = (struct sockaddr_dl *)sa;
					memset(ifname, 0, sizeof(ifname));
					memcpy(ifname, sdl->sdl_data, sdl->sdl_nlen);
				}
#endif
				break;
			case RTA_IFA:
				family = sa->sa_family;
				if(sa->sa_family == AF_INET) {
					inet_ntop(sa->sa_family,
					          &((struct sockaddr_in *)sa)->sin_addr,
					          address, sizeof(address));
				} else if(sa->sa_family == AF_INET6) {
					inet_ntop(sa->sa_family,
					          &((struct sockaddr_in6 *)sa)->sin6_addr,
					          address, sizeof(address));
				}
				break;
			case RTA_AUTHOR:
				break;
			case RTA_BRD:
				break;
			}
#if 0
			syslog(LOG_DEBUG, " %d.%d.%d.%d %02x%02x%02x%02x",
			       (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2], (uint8_t)p[3],
			       (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2], (uint8_t)p[3]); 
			syslog(LOG_DEBUG, " %d.%d.%d.%d %02x%02x%02x%02x",
			       (uint8_t)p[4], (uint8_t)p[5], (uint8_t)p[6], (uint8_t)p[7],
			       (uint8_t)p[4], (uint8_t)p[5], (uint8_t)p[6], (uint8_t)p[7]); 
#endif
			p += SA_RLEN(sa);
			addr = addr << 1;
		}
		syslog(LOG_INFO, "%s: %s/%d %s",
		       is_del ? "RTM_DELADDR" : "RTM_NEWADDR",
		       address, prefixlen, ifname);
		for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) {
			if((0 == strcmp(address, lan_addr->str)) ||
			   (0 == strcmp(ifname, lan_addr->ifname)) ||
			   (ifam->ifam_index == lan_addr->index)) {
				if(family == AF_INET)
					AddDropMulticastMembership(s_ssdp, lan_addr, 0, is_del);
				else if(family == AF_INET6)
					AddDropMulticastMembership(s_ssdp6, lan_addr, 1, is_del);
				break;
			}
		}
		break;
	default:
		syslog(LOG_DEBUG, "Unknown RTM message : rtm->rtm_type=%d len=%d",
		       rtm->rtm_type, (int)len);
	}
#endif
	return 0;
}
Example #6
0
int
getifaddrs(struct ifaddrs **pif)
{
    int icnt = 1;  // Interface count
    int dcnt = 0;  // Data [length] count
    int ncnt = 0;  // Length of interface names
    char *buf;
#define	IF_WORK_SPACE_SZ	1024
    int i, sock;
#ifdef CYGPKG_NET_INET6
    int sock6;
    struct in6_ifreq ifrq6;
#endif
    struct ifconf ifc;
    struct ifreq *ifr, *lifr;
    struct ifreq ifrq;
    char *data, *names;
    struct ifaddrs *ifa, *ift;

    buf = malloc(IF_WORK_SPACE_SZ);
    if (buf == NULL)
        return (-1);
    ifc.ifc_buf = buf;
    ifc.ifc_len = IF_WORK_SPACE_SZ;

    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        free(buf);
        return (-1);
    }
    i =  ioctl(sock, SIOCGIFCONF, (char *)&ifc);

    if (i < 0) {
        close(sock); 
        free(buf);
        return (-1);
    }

    ifr = ifc.ifc_req;
    lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];

    while (ifr < lifr) {
        struct sockaddr *sa;

        sa = &ifr->ifr_addr;
        ++icnt;
        dcnt += SA_RLEN(sa) * 3;  /* addr, mask, brdcst */
        ncnt += sizeof(ifr->ifr_name) + 1;
		
        if (SA_LEN(sa) < sizeof(*sa))
            ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa));
        else
            ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
    }

    if (icnt + dcnt + ncnt == 1) {
        // Nothing found
        *pif = NULL;
        free(buf);
        close(sock);
        return (0);
    }
    data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
    if (data == NULL) {
        free(buf);
        close(sock);
        return(-1);
    }

    ifa = (struct ifaddrs *)(void *)data;
    data += sizeof(struct ifaddrs) * icnt;
    names = data + dcnt;

    memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
    ift = ifa;

    ifr = ifc.ifc_req;

#ifdef CYGPKG_NET_INET6
    if ((sock6 = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
      free(buf);
      free(ifa);
      close(sock);
      return (-1);
    }
#endif

    while (ifr < lifr) {
       struct sockaddr * sa;

        ift->ifa_name = names;
        names[sizeof(ifr->ifr_name)] = 0;
        strncpy(names, ifr->ifr_name, sizeof(ifr->ifr_name));
        while (*names++) ;

        ift->ifa_addr = (struct sockaddr *)data;
        sa = &ifr->ifr_addr;
        memcpy(data, sa, SA_LEN(sa));
        data += SA_RLEN(sa);

        if ((sa->sa_family == AF_INET) || (sa->sa_family == AF_INET6)) {
          struct sockaddr *sa_netmask = NULL;
          struct sockaddr *sa_broadcast = NULL;
          struct sockaddr *sa_dst = NULL;
          
          memset(&ifrq,0,sizeof(ifrq));
          strcpy(ifrq.ifr_name,ifr->ifr_name);
          ioctl( sock, SIOCGIFFLAGS, &ifrq );

          ift->ifa_flags = ifrq.ifr_flags;

          memcpy(&ifrq.ifr_addr, ift->ifa_addr,sizeof(struct sockaddr));
          if (sa->sa_family == AF_INET) {
            ioctl(sock, SIOCGIFNETMASK, &ifrq); 
            sa_netmask = &ifrq.ifr_addr;
          }
#ifdef CYGPKG_NET_INET6
          if (sa->sa_family == AF_INET6) {
            memset(&ifrq6,0,sizeof(ifrq));
            strcpy(ifrq6.ifr_name,ifr->ifr_name);
            memcpy(&ifrq6.ifr_addr, ift->ifa_addr,sizeof(struct sockaddr));
          
            ioctl(sock6, SIOCGIFNETMASK_IN6, &ifrq6);
            sa_netmask = (struct sockaddr *)&ifrq6.ifr_addr;
          }
#endif
          ift->ifa_netmask = (struct sockaddr *)data;
          memcpy(data, sa_netmask, SA_LEN(sa_netmask));
          data += SA_RLEN(sa_netmask);

          memcpy(&ifrq.ifr_addr, ift->ifa_addr,sizeof(struct sockaddr));
          if ((sa->sa_family == AF_INET) && (ift->ifa_flags & IFF_BROADCAST)) {
            if (ioctl(sock, SIOCGIFBRDADDR, &ifrq) == 0) {
              sa_broadcast = &ifrq.ifr_addr;
              ift->ifa_broadaddr = (struct sockaddr *)data;
              memcpy(data, sa_broadcast, SA_LEN(sa_broadcast));
              data += SA_RLEN(sa_broadcast);
            }
          }

          memcpy(&ifrq.ifr_addr, ift->ifa_addr,sizeof(struct sockaddr));
          if ((sa->sa_family == AF_INET) && 
              (ift->ifa_flags & IFF_POINTOPOINT)) {
            if (ioctl(sock, SIOCGIFDSTADDR, &ifrq) == 0) {
              sa_dst = &ifrq.ifr_addr;
              ift->ifa_dstaddr = (struct sockaddr *)data;
              memcpy(data, sa_dst, SA_LEN(sa_dst));
              data += SA_RLEN(sa_dst);
            }
          }
        }
        
        if (SA_LEN(sa) < sizeof(*sa))
            ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa));
        else
            ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
        ift = (ift->ifa_next = ift + 1);
    }
    free(buf);

    if (--ift >= ifa) {
        ift->ifa_next = NULL;
        *pif = ifa;
    } else {
        *pif = NULL;
        free(ifa);
    }
#ifdef CYGPKG_NET_INET6
    close(sock6);
#endif
    close(sock);
    return (0);
}
Example #7
0
int
getifaddrs(struct ifaddrs **pif)
{
	int icnt = 1;
	int dcnt = 0;
	int ncnt = 0;
	int mib[6];
	size_t needed;
	char *buf;
	char *next;
	struct ifaddrs cif;
	char *p, *p0;
	struct rt_msghdr *rtm;
	struct if_msghdr *ifm;
	struct ifa_msghdr *ifam;
	struct sockaddr *sa;
	struct ifaddrs *ifa, *ift;
	u_short idx = 0;
	int i;
	size_t len, alen;
	char *data;
	char *names;

	_DIAGASSERT(pif != NULL);

	mib[0] = CTL_NET;
	mib[1] = PF_ROUTE;
	mib[2] = 0;             /* protocol */
	mib[3] = 0;             /* wildcard address family */
	mib[4] = NET_RT_IFLIST;
	mib[5] = 0;             /* no flags */
	if (sysctl(mib, __arraycount(mib), NULL, &needed, NULL, 0) < 0)
		return (-1);
	if ((buf = malloc(needed)) == NULL)
		return (-1);
	if (sysctl(mib, __arraycount(mib), buf, &needed, NULL, 0) < 0) {
		free(buf);
		return (-1);
	}

	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) {
				const struct sockaddr_dl *dl;

				idx = ifm->ifm_index;
				++icnt;
				dl = (struct sockaddr_dl *)(void *)(ifm + 1);
				dcnt += SA_RLEN((const struct sockaddr *)(const void *)dl) +
				    ALIGNBYTES;
				dcnt += sizeof(ifm->ifm_data);
				ncnt += dl->sdl_nlen + 1;
			} else
				idx = 0;
			break;

		case RTM_NEWADDR:
			ifam = (struct ifa_msghdr *)(void *)rtm;
			if (idx && ifam->ifam_index != idx)
				abort();	/* this cannot happen */

#define	RTA_MASKS	(RTA_NETMASK | RTA_IFA | RTA_BRD)
			if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
				break;
			p = (char *)(void *)(ifam + 1);
			++icnt;
			/* Scan to look for length of address */
			alen = 0;
			for (p0 = p, i = 0; i < RTAX_MAX; i++) {
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
				    == 0)
					continue;
				sa = (struct sockaddr *)(void *)p;
				len = SA_RLEN(sa);
				if (i == RTAX_IFA) {
					alen = len;
					break;
				}
				p += len;
			}
			for (p = p0, i = 0; i < RTAX_MAX; i++) {
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
				    == 0)
					continue;
				sa = (struct sockaddr *)(void *)p;
				len = SA_RLEN(sa);
				if (i == RTAX_NETMASK && sa->sa_len == 0)
					dcnt += alen;
				else
					dcnt += len;
				p += len;
			}
			break;
		}
	}

	if (icnt + dcnt + ncnt == 1) {
		*pif = NULL;
		free(buf);
		return (0);
	}
	data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
	if (data == NULL) {
		free(buf);
		return(-1);
	}

	ifa = (struct ifaddrs *)(void *)data;
	data += sizeof(struct ifaddrs) * icnt;
	names = data + dcnt;

	memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
	ift = ifa;

	idx = 0;
	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) {
				const struct sockaddr_dl *dl;

				idx = ifm->ifm_index;
				dl = (struct sockaddr_dl *)(void *)(ifm + 1);

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

				cif.ifa_name = names;
				cif.ifa_flags = (int)ifm->ifm_flags;
				memcpy(names, dl->sdl_data,
				    (size_t)dl->sdl_nlen);
				names[dl->sdl_nlen] = 0;
				names += dl->sdl_nlen + 1;

				cif.ifa_addr = (struct sockaddr *)(void *)data;
				memcpy(data, dl, (size_t)dl->sdl_len);
				data += SA_RLEN((const struct sockaddr *)(const void *)dl);

				/* ifm_data needs to be aligned */
				cif.ifa_data = data = (void *)ALIGN(data);
				memcpy(data, &ifm->ifm_data, sizeof(ifm->ifm_data));
 				data += sizeof(ifm->ifm_data);
			} else
				idx = 0;
			break;

		case RTM_NEWADDR:
			ifam = (struct ifa_msghdr *)(void *)rtm;
			if (idx && ifam->ifam_index != idx)
				abort();	/* this cannot happen */

			if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
				break;
			ift->ifa_name = cif.ifa_name;
			ift->ifa_flags = cif.ifa_flags;
			ift->ifa_data = NULL;
			p = (char *)(void *)(ifam + 1);
			/* Scan to look for length of address */
			alen = 0;
			for (p0 = p, i = 0; i < RTAX_MAX; i++) {
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
				    == 0)
					continue;
				sa = (struct sockaddr *)(void *)p;
				len = SA_RLEN(sa);
				if (i == RTAX_IFA) {
					alen = len;
					break;
				}
				p += len;
			}
			for (p = p0, i = 0; i < RTAX_MAX; i++) {
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
				    == 0)
					continue;
				sa = (struct sockaddr *)(void *)p;
				len = SA_RLEN(sa);
				switch (i) {
				case RTAX_IFA:
					ift->ifa_addr =
					    (struct sockaddr *)(void *)data;
					memcpy(data, p, len);
					data += len;
					if (ift->ifa_addr->sa_family == AF_LINK)
						ift->ifa_data = cif.ifa_data;
					break;

				case RTAX_NETMASK:
					ift->ifa_netmask =
					    (struct sockaddr *)(void *)data;
					if (sa->sa_len == 0) {
						memset(data, 0, alen);
						data += alen;
						break;
					}
					memcpy(data, p, len);
					data += len;
					break;

				case RTAX_BRD:
					ift->ifa_broadaddr =
					    (struct sockaddr *)(void *)data;
					memcpy(data, p, len);
					data += len;
					break;
				}
				p += len;
			}


			ift = (ift->ifa_next = ift + 1);
			break;
		}
	}

	free(buf);
	if (--ift >= ifa) {
		ift->ifa_next = NULL;
		*pif = ifa;
	} else {
		*pif = NULL;
		free(ifa);
	}
	return (0);
}
int
getifaddrs(struct ifaddrs **pif)
{
	int icnt = 1;
	int dcnt = 0;
	int ncnt = 0;
#ifdef	NET_RT_IFLIST
	int mib[6];
	size_t needed;
	char *buf;
	char *next;
	struct ifaddrs *cif = 0;
	char *p, *p0;
	struct rt_msghdr *rtm;
	struct if_msghdr *ifm;
	struct ifa_msghdr *ifam;
	struct sockaddr_dl *dl;
	struct sockaddr *sa;
	struct ifaddrs *ifa, *ift;
	u_short idx = 0;
#else	/* NET_RT_IFLIST */
	struct ifaddrs *ifa, *ift;
	char buf[1024];
	int m, sock;
	struct ifconf ifc;
	struct ifreq *ifr;
	struct ifreq *lifr;
#endif	/* NET_RT_IFLIST */
	int i;
	size_t len, alen;
	char *data;
	char *names;

#ifdef	NET_RT_IFLIST
	mib[0] = CTL_NET;
	mib[1] = PF_ROUTE;
	mib[2] = 0;             /* protocol */
	mib[3] = 0;             /* wildcard address family */
	mib[4] = NET_RT_IFLIST;
	mib[5] = 0;             /* no flags */
	if (__sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
		return (-1);
	if ((buf = malloc(needed)) == NULL)
		return (-1);
	if (__sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
		free(buf);
		return (-1);
	}

	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) {
				idx = ifm->ifm_index;
				++icnt;
				dl = (struct sockaddr_dl *)(void *)(ifm + 1);
				dcnt += SA_RLEN((struct sockaddr *)(void*)dl) +
				    ALIGNBYTES;
#ifdef	HAVE_IFM_DATA
				dcnt += sizeof(ifm->ifm_data);
#endif	/* HAVE_IFM_DATA */
				ncnt += dl->sdl_nlen + 1;
			} else
				idx = 0;
			break;

		case RTM_NEWADDR:
			ifam = (struct ifa_msghdr *)(void *)rtm;
			if (idx && ifam->ifam_index != idx)
				abort();	/* this cannot happen */

#define	RTA_MASKS	(RTA_NETMASK | RTA_IFA | RTA_BRD)
			if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
				break;
			p = (char *)(void *)(ifam + 1);
			++icnt;
#ifdef	HAVE_IFAM_DATA
			dcnt += sizeof(ifam->ifam_data) + ALIGNBYTES;
#endif	/* HAVE_IFAM_DATA */
			/* Scan to look for length of address */
			alen = 0;
			for (p0 = p, i = 0; i < RTAX_MAX; i++) {
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
				    == 0)
					continue;
				sa = (struct sockaddr *)(void *)p;
				len = SA_RLEN(sa);
				if (i == RTAX_IFA) {
					alen = len;
					break;
				}
				p += len;
			}
			for (p = p0, i = 0; i < RTAX_MAX; i++) {
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
				    == 0)
					continue;
				sa = (struct sockaddr *)(void *)p;
				len = SA_RLEN(sa);
				if (i == RTAX_NETMASK && SA_LEN(sa) == 0)
					dcnt += alen;
				else
					dcnt += len;
				p += len;
			}
			break;
		}
	}
#else	/* NET_RT_IFLIST */
	ifc.ifc_buf = buf;
	ifc.ifc_len = sizeof(buf);

	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		return (-1);
	i =  ioctl(sock, SIOCGIFCONF, (char *)&ifc);
	close(sock);
	if (i < 0)
		return (-1);

	ifr = ifc.ifc_req;
	lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];

	while (ifr < lifr) {
		struct sockaddr *sa;

		sa = &ifr->ifr_addr;
		++icnt;
		dcnt += SA_RLEN(sa);
		ncnt += sizeof(ifr->ifr_name) + 1;
		
		if (SA_LEN(sa) < sizeof(*sa))
			ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa));
		else
			ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
	}
#endif	/* NET_RT_IFLIST */

	if (icnt + dcnt + ncnt == 1) {
		*pif = NULL;
		free(buf);
		return (0);
	}
	data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
	if (data == NULL) {
		free(buf);
		return(-1);
	}

	ifa = (struct ifaddrs *)(void *)data;
	data += sizeof(struct ifaddrs) * icnt;
	names = data + dcnt;

	memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
	ift = ifa;

#ifdef	NET_RT_IFLIST
	idx = 0;
	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) {
				idx = ifm->ifm_index;
				dl = (struct sockaddr_dl *)(void *)(ifm + 1);

				cif = ift;
				ift->ifa_name = names;
				ift->ifa_flags = (int)ifm->ifm_flags;
				memcpy(names, dl->sdl_data,
				    (size_t)dl->sdl_nlen);
				names[dl->sdl_nlen] = 0;
				names += dl->sdl_nlen + 1;

				ift->ifa_addr = (struct sockaddr *)(void *)data;
				memcpy(data, dl,
				    (size_t)SA_LEN((struct sockaddr *)
				    (void *)dl));
				data += SA_RLEN((struct sockaddr *)(void *)dl);

#ifdef	HAVE_IFM_DATA
				/* ifm_data needs to be aligned */
				ift->ifa_data = data = (void *)ALIGN(data);
				memcpy(data, &ifm->ifm_data, sizeof(ifm->ifm_data));
 				data += sizeof(ifm->ifm_data);
#else	/* HAVE_IFM_DATA */
				ift->ifa_data = NULL;
#endif	/* HAVE_IFM_DATA */

				ift = (ift->ifa_next = ift + 1);
			} else
				idx = 0;
			break;

		case RTM_NEWADDR:
			ifam = (struct ifa_msghdr *)(void *)rtm;
			if (idx && ifam->ifam_index != idx)
				abort();	/* this cannot happen */

			if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
				break;
			ift->ifa_name = cif->ifa_name;
			ift->ifa_flags = cif->ifa_flags;
			ift->ifa_data = NULL;
			p = (char *)(void *)(ifam + 1);
			/* Scan to look for length of address */
			alen = 0;
			for (p0 = p, i = 0; i < RTAX_MAX; i++) {
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
				    == 0)
					continue;
				sa = (struct sockaddr *)(void *)p;
				len = SA_RLEN(sa);
				if (i == RTAX_IFA) {
					alen = len;
					break;
				}
				p += len;
			}
			for (p = p0, i = 0; i < RTAX_MAX; i++) {
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
				    == 0)
					continue;
				sa = (struct sockaddr *)(void *)p;
				len = SA_RLEN(sa);
				switch (i) {
				case RTAX_IFA:
					ift->ifa_addr =
					    (struct sockaddr *)(void *)data;
					memcpy(data, p, len);
					data += len;
					break;

				case RTAX_NETMASK:
					ift->ifa_netmask =
					    (struct sockaddr *)(void *)data;
					if (SA_LEN(sa) == 0) {
						memset(data, 0, alen);
						data += alen;
						break;
					}
					memcpy(data, p, len);
					data += len;
					break;

				case RTAX_BRD:
					ift->ifa_broadaddr =
					    (struct sockaddr *)(void *)data;
					memcpy(data, p, len);
					data += len;
					break;
				}
				p += len;
			}

#ifdef	HAVE_IFAM_DATA
			/* ifam_data needs to be aligned */
			ift->ifa_data = data = (void *)ALIGN(data);
			memcpy(data, &ifam->ifam_data, sizeof(ifam->ifam_data));
			data += sizeof(ifam->ifam_data);
#endif	/* HAVE_IFAM_DATA */

			ift = (ift->ifa_next = ift + 1);
			break;
		}
	}

	free(buf);
#else	/* NET_RT_IFLIST */
	ifr = ifc.ifc_req;
	lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];

	while (ifr < lifr) {
		struct sockaddr *sa;

		ift->ifa_name = names;
		names[sizeof(ifr->ifr_name)] = 0;
		strncpy(names, ifr->ifr_name, sizeof(ifr->ifr_name));
		while (*names++)
			;

		ift->ifa_addr = (struct sockaddr *)data;
		sa = &ifr->ifr_addr;
		memcpy(data, sa, SA_LEN(sa));
		data += SA_RLEN(sa);
		
		ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
		ift = (ift->ifa_next = ift + 1);
	}
#endif	/* NET_RT_IFLIST */
	if (--ift >= ifa) {
		ift->ifa_next = NULL;
		*pif = ifa;
	} else {
		*pif = NULL;
		free(ifa);
	}
	return (0);
}