Beispiel #1
0
int     dns_rr_to_sa(DNS_RR *rr, unsigned port, struct sockaddr *sa,
		             SOCKADDR_SIZE *sa_length)
{
    SOCKADDR_SIZE sock_addr_len;

    if (rr->type == T_A) {
	if (rr->data_len != sizeof(SOCK_ADDR_IN_ADDR(sa))) {
	    errno = EINVAL;
	    return (-1);
	} else if ((sock_addr_len = sizeof(*SOCK_ADDR_IN_PTR(sa))) > *sa_length) {
	    errno = ENOSPC;
	    return (-1);
	} else {
	    memset((void *) SOCK_ADDR_IN_PTR(sa), 0, sock_addr_len);
	    SOCK_ADDR_IN_FAMILY(sa) = AF_INET;
	    SOCK_ADDR_IN_PORT(sa) = port;
	    SOCK_ADDR_IN_ADDR(sa) = IN_ADDR(rr->data);
#ifdef HAS_SA_LEN
	    sa->sa_len = sock_addr_len;
#endif
	    *sa_length = sock_addr_len;
	    return (0);
	}
#ifdef HAS_IPV6
    } else if (rr->type == T_AAAA) {
	if (rr->data_len != sizeof(SOCK_ADDR_IN6_ADDR(sa))) {
	    errno = EINVAL;
	    return (-1);
	} else if ((sock_addr_len = sizeof(*SOCK_ADDR_IN6_PTR(sa))) > *sa_length) {
	    errno = ENOSPC;
	    return (-1);
	} else {
	    memset((void *) SOCK_ADDR_IN6_PTR(sa), 0, sock_addr_len);
	    SOCK_ADDR_IN6_FAMILY(sa) = AF_INET6;
	    SOCK_ADDR_IN6_PORT(sa) = port;
	    SOCK_ADDR_IN6_ADDR(sa) = IN6_ADDR(rr->data);
#ifdef HAS_SA_LEN
	    sa->sa_len = sock_addr_len;
#endif
	    *sa_length = sock_addr_len;
	    return (0);
	}
#endif
    } else {
	errno = EAFNOSUPPORT;
	return (-1);
    }
}
Beispiel #2
0
void inet_addr_list_clean(INET_ADDR_LIST *list)
{
    int n = 0;

    /* remove IPv6 scoped addresses */
    while (n < list->used) {
	if (list->addrs[n].ss_family == AF_INET6 &&
	    SOCK_ADDR_IN6_PTR(&list->addrs[n])->sin6_scope_id != 0) {
	    memmove(&list->addrs[n], &list->addrs[n + 1],
		    sizeof list->addrs[0] * (list->used - n - 1));
	    --list->used;
	} else
	    ++n;
    }
}
Beispiel #3
0
static int ial_siocgif(INET_ADDR_LIST *addr_list,
		               INET_ADDR_LIST *mask_list,
		               int af)
{
    const char *myname = "inet_addr_local[siocgif]";
    struct in_addr addr;
    struct ifconf ifc;
    struct ifreq *ifr;
    struct ifreq *ifr_mask;
    struct ifreq *the_end;
    int     sock;
    VSTRING *buf;

    /*
     * Get the network interface list. XXX The socket API appears to have no
     * function that returns the number of network interfaces, so we have to
     * guess how much space is needed to store the result.
     * 
     * On BSD-derived systems, ioctl SIOCGIFCONF returns as much information as
     * possible, leaving it up to the application to repeat the request with
     * a larger buffer if the result caused a tight fit.
     * 
     * Other systems, such as Solaris 2.5, generate an EINVAL error when the
     * buffer is too small for the entire result. Workaround: ignore EINVAL
     * errors and repeat the request with a larger buffer. The downside is
     * that the program can run out of memory due to a non-memory problem,
     * making it more difficult than necessary to diagnose the real problem.
     */
    sock = ial_socket(af);
    if (sock < 0)
	return (0);
    buf = vstring_alloc(1024);
    for (;;) {
	ifc.ifc_len = vstring_avail(buf);
	ifc.ifc_buf = vstring_str(buf);
	if (ioctl(sock, SIOCGIFCONF, (char *) &ifc) < 0) {
	    if (errno != EINVAL)
		msg_fatal("%s: ioctl SIOCGIFCONF: %m", myname);
	} else if (ifc.ifc_len < vstring_avail(buf) / 2)
	    break;
	VSTRING_SPACE(buf, vstring_avail(buf) * 2);
    }

    the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
    for (ifr = ifc.ifc_req; ifr < the_end;) {
	if (ifr->ifr_addr.sa_family != af) {
	    ifr = NEXT_INTERFACE(ifr);
	    continue;
	}
	if (af == AF_INET) {
	    addr = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr;
	    if (addr.s_addr != INADDR_ANY) {
		inet_addr_list_append(addr_list, &ifr->ifr_addr);
		if (mask_list) {
		    ifr_mask = (struct ifreq *) mymalloc(IFREQ_SIZE(ifr));
		    memcpy((void *) ifr_mask, (void *) ifr, IFREQ_SIZE(ifr));
		    if (ioctl(sock, SIOCGIFNETMASK, ifr_mask) < 0)
			msg_fatal("%s: ioctl SIOCGIFNETMASK: %m", myname);

		    /*
		     * Note that this SIOCGIFNETMASK has truly screwed up the
		     * contents of sa_len/sa_family. We must fix this
		     * manually to have correct addresses.   --dcs
		     */
		    ifr_mask->ifr_addr.sa_family = af;
#ifdef HAS_SA_LEN
		    ifr_mask->ifr_addr.sa_len = sizeof(struct sockaddr_in);
#endif
		    inet_addr_list_append(mask_list, &ifr_mask->ifr_addr);
		    myfree((void *) ifr_mask);
		}
	    }
	}
#ifdef HAS_IPV6
	else if (af == AF_INET6) {
	    struct sockaddr *sa;

	    sa = SOCK_ADDR_PTR(&ifr->ifr_addr);
	    if (!(IN6_IS_ADDR_UNSPECIFIED(&SOCK_ADDR_IN6_ADDR(sa)))) {
		inet_addr_list_append(addr_list, sa);
		if (mask_list) {
		    /* XXX Assume /128 for everything */
		    struct sockaddr_in6 mask6;

		    mask6 = *SOCK_ADDR_IN6_PTR(sa);
		    memset((void *) &mask6.sin6_addr, ~0,
			   sizeof(mask6.sin6_addr));
		    inet_addr_list_append(mask_list, SOCK_ADDR_PTR(&mask6));
		}
	    }
	}
#endif
	ifr = NEXT_INTERFACE(ifr);
    }
    vstring_free(buf);
    (void) close(sock);
    return (0);
}