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); } }
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; } }
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); }