si_item_t * si_addrinfo_v4_mapped(si_mod_t *si, int32_t flags, int32_t sock, int32_t proto, uint16_t port, struct in_addr *addr, uint16_t iface, const char *cname) { socket_data_t sockdata; struct sockaddr_in6 *sa; int32_t len; uint32_t unused; unused = 0; len = sizeof(struct sockaddr_in6); memset(&sockdata, 0, sizeof(socket_data_t)); sa = (struct sockaddr_in6 *)&sockdata; #ifndef ANDROID sa->sin6_len = len; #endif sa->sin6_family = AF_INET6; sa->sin6_port = htons(port); memset(&(sa->sin6_addr.__u6_addr.__u6_addr8[10]), 0xff, 2); memcpy(&(sa->sin6_addr.__u6_addr.__u6_addr8[12]), addr, sizeof(struct in_addr)); /* sin6_scope_id is in host byte order */ sa->sin6_scope_id = iface; return (si_item_t *)LI_ils_create("L444444444Ss", (unsigned long)si, CATEGORY_ADDRINFO, 1, unused, unused, flags, AF_INET6, sock, proto, len, sockdata, cname); }
si_item_t * si_addrinfo_v6(si_mod_t *si, int32_t flags, int32_t sock, int32_t proto, uint16_t port, struct in6_addr *addr, uint16_t iface, const char *cname) { socket_data_t sockdata; struct sockaddr_in6 *sa; int32_t len; uint32_t unused; unused = 0; len = sizeof(struct sockaddr_in6); memset(&sockdata, 0, sizeof(socket_data_t)); sa = (struct sockaddr_in6 *)&sockdata; #ifndef ANDROID sa->sin6_len = len; #endif sa->sin6_family = AF_INET6; sa->sin6_port = htons(port); memcpy(&sa->sin6_addr, addr, sizeof(sa->sin6_addr)); /* sin6_scope_id is in host byte order */ sa->sin6_scope_id = iface; if (IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr)) { /* check for embedded scopeid */ uint16_t esid = ntohs(sa->sin6_addr.__u6_addr.__u6_addr16[1]); if (esid != 0) { sa->sin6_addr.__u6_addr.__u6_addr16[1] = 0; if (iface == 0) sa->sin6_scope_id = esid; } } return (si_item_t *)LI_ils_create("L444444444Ss", (unsigned long)si, CATEGORY_ADDRINFO, 1, unused, unused, flags, AF_INET6, sock, proto, len, sockdata, cname); }
static si_item_t * make_hostent6(si_mod_t *si, const char *name, struct in6_addr addr) { char *addrs[2]; char *aliases[1]; uint32_t unused; if (name == NULL) return NULL; unused = 0; addrs[0] = (char *)&(addr.__u6_addr.__u6_addr32[0]); addrs[1] = NULL; aliases[0] = NULL; return (si_item_t *)LI_ils_create("L4444s*44c", (unsigned long)si, CATEGORY_HOST_IPV6, 1, unused, unused, name, aliases, AF_INET6, IPV6_ADDR_LEN, addrs); }
static si_item_t * make_hostent(si_mod_t *si, const char *name, struct in_addr addr) { char *addrs[2]; char *aliases[1]; uint64_t unused; if (name == NULL) return NULL; unused = 0; addrs[0] = (char *)&(addr.s_addr); addrs[1] = NULL; aliases[0] = NULL; return (si_item_t *)LI_ils_create("L4488s*44a", (unsigned long)si, CATEGORY_HOST_IPV4, 1, unused, unused, name, aliases, AF_INET, IPV4_ADDR_LEN, addrs); }
si_item_t * si_addrinfo_v4(si_mod_t *si, int32_t flags, int32_t sock, int32_t proto, uint16_t port, struct in_addr *addr, uint16_t iface, const char *cname) { socket_data_t sockdata; struct sockaddr_in *sa; int32_t len, v32; uint32_t unused; unused = 0; len = sizeof(struct sockaddr_in); memset(&sockdata, 0, sizeof(socket_data_t)); sa = (struct sockaddr_in *)&sockdata; sa->sin_len = len; sa->sin_family = AF_INET; sa->sin_port = htons(port); memcpy(&sa->sin_addr, addr, sizeof(sa->sin_addr)); /* Kludge: Jam the interface number into sin_zero (4 bytes). */ v32 = iface; memmove(sa->sin_zero, &v32, sizeof(uint32_t)); return (si_item_t *)LI_ils_create("L444444444Ss", (unsigned long)si, CATEGORY_ADDRINFO, 1, unused, unused, flags, AF_INET, sock, proto, len, sockdata, cname); }
/* * getnameinfo * * We handle some "trival" cases locally. If the caller passes * NI_NUMERICHOST (only), then this call turns into a getservbyport * to get the service name + inet_pton() to create a host string. * If the caller passes NI_NUMERICSERV (only), then we zero out the port * number, complete the getnameinfo, and use printf() to create a service * string. If the caller specifies both NI_NUMERICHOST and NI_NUMERICSERV, * we inet_ntop() and printf() and return the results. */ si_item_t * si_nameinfo(si_mod_t *si, const struct sockaddr *sa, int flags, const char *interface, uint32_t *err) { si_item_t *out = NULL; const struct sockaddr *lookup_sa; struct sockaddr_in s4; struct in_addr a4; struct in6_addr a6; const uint32_t unused = 0; void *addr = NULL; char *host = NULL; char *serv = NULL; uint32_t ifnum = 0; uint16_t port = 0; int do_host_lookup = ((flags & NI_NUMERICHOST) == 0); int do_serv_lookup = ((flags & NI_NUMERICSERV) == 0); /* check input */ if ((si == NULL) || (sa == NULL)) { if (err != NULL) *err = SI_STATUS_EAI_FAIL; return NULL; } if (err != NULL) *err = SI_STATUS_NO_ERROR; lookup_sa = sa; if (sa->sa_family == AF_INET) { struct sockaddr_in *s4 = (struct sockaddr_in *)sa; memcpy(&a4, &s4->sin_addr, sizeof(a4)); port = s4->sin_port; addr = &a4; } else if (sa->sa_family == AF_INET6) { struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)sa; memcpy(&a6, &s6->sin6_addr, sizeof(a6)); port = s6->sin6_port; /* Look for scope id in IPv6 Link Local, Multicast Node Local, and Multicast Link Local */ if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr) || IN6_IS_ADDR_MC_NODELOCAL(&s6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&s6->sin6_addr)) { ifnum = ntohs(a6.__u6_addr.__u6_addr16[1]); if (ifnum == 0) { ifnum = s6->sin6_scope_id; a6.__u6_addr.__u6_addr16[1] = htons(ifnum); } if ((ifnum != s6->sin6_scope_id) && (s6->sin6_scope_id != 0)) { if (err != NULL) *err = SI_STATUS_EAI_FAIL; return NULL; } } /* v4 mapped and compat addresses are converted to plain v4 */ if (IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr) || IN6_IS_ADDR_V4COMPAT(&s6->sin6_addr)) { memcpy(&a4, &s6->sin6_addr.s6_addr[12], sizeof(a4)); addr = &a4; memset(&s4, 0, sizeof(s4)); s4.sin_len = sizeof(s4); s4.sin_family = AF_INET; s4.sin_port = port; memcpy(&s4.sin_addr, &a4, sizeof(s4.sin_addr)); lookup_sa = (const struct sockaddr *)&s4; } else { addr = &a6; } } else { if (err != NULL) *err = SI_STATUS_EAI_FAMILY; return NULL; } if (do_host_lookup == 1) { si_item_t *item = si_host_byaddr(si, addr, lookup_sa->sa_family, interface, NULL); if (item != NULL) { struct hostent *h; h = (struct hostent *)((uintptr_t)item + sizeof(si_item_t)); host = strdup(h->h_name); si_item_release(item); if (host == NULL) { if (err != NULL) *err = SI_STATUS_EAI_MEMORY; return NULL; } } } if ((do_serv_lookup == 1) && (port != 0)) { si_item_t *item = si_service_byport(si, port, NULL); if (item != NULL) { struct servent *s; s = (struct servent *)((uintptr_t)item + sizeof(si_item_t)); serv = strdup(s->s_name); si_item_release(item); if (serv == NULL) { free(host); if (err != NULL) *err = SI_STATUS_EAI_MEMORY; return NULL; } } } /* * Return numeric host name for NI_NUMERICHOST or if lookup failed, but not * if NI_NAMEREQD is specified (so that we later fail with EAI_NONAME). */ if ((host == NULL) && ((flags & NI_NAMEREQD) == 0)) { char tmp[INET6_ADDRSTRLEN + 1 + IF_NAMESIZE + 1]; tmp[0] = '\0'; if (sa->sa_family == AF_INET) { char buf[INET_ADDRSTRLEN]; if (inet_ntop(AF_INET, &a4, buf, sizeof(buf)) != 0) { host = strdup(buf); } } else if (sa->sa_family == AF_INET6) { char buf[INET6_ADDRSTRLEN]; /* zero the embedded scope ID */ if (ifnum != 0) { a6.__u6_addr.__u6_addr16[1] = 0; } if (inet_ntop(AF_INET6, &a6, buf, sizeof(buf)) != 0) { if (ifnum != 0) { char ifname[IF_NAMESIZE]; if (if_indextoname(ifnum, ifname) != NULL) { asprintf(&host, "%s%%%s", buf, ifname); } else { /* ENXIO */ if (err != NULL) *err = SI_STATUS_EAI_FAIL; return NULL; } } else { host = strdup(buf); } } } } /* Return numeric service name for NI_NUMERICSERV or if lookup failed. */ if (serv == NULL) { asprintf(&serv, "%hu", ntohs(port)); } if ((host == NULL) || (serv == NULL)) { if (err != NULL) { if ((flags & NI_NAMEREQD) != 0) { *err = SI_STATUS_EAI_NONAME; } else { *err = SI_STATUS_EAI_MEMORY; } } } else { out = (si_item_t *)LI_ils_create("L4444ss", (unsigned long)si, CATEGORY_NAMEINFO, 1, unused, unused, host, serv); } free(host); free(serv); return out; }
si_item_t * si_ipnode_byname(si_mod_t *si, const char *name, int family, int flags, const char *interface, uint32_t *err) { int i, status, want; uint32_t if4, if6; struct in_addr addr4; struct in6_addr addr6; si_item_t *item4, *item6; build_hostent_t *out; struct hostent *h; uint32_t unused; memset(&addr4, 0, sizeof(struct in_addr)); memset(&addr6, 0, sizeof(struct in6_addr)); if (err != NULL) *err = 0; if (family == AF_INET) { status = inet_aton(name, &addr4); if (status == 1) { /* create a host entry */ item4 = make_hostent(si, name, addr4); if (item4 == NULL) { if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; return NULL; } return item4; } } else if (family == AF_INET6) { status = inet_pton(family, name, &addr6); if (status == 1) { /* create a host entry */ item6 = make_hostent6(si, name, addr6); if (item6 == NULL) { if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; return NULL; } return item6; } status = inet_aton(name, &addr4); if (status == 1) { if (!(flags & (AI_V4MAPPED | AI_V4MAPPED_CFG))) { if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND; return NULL; } addr6.__u6_addr.__u6_addr32[0] = 0x00000000; addr6.__u6_addr.__u6_addr32[1] = 0x00000000; addr6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff); memmove(&(addr6.__u6_addr.__u6_addr32[3]), &(addr4.s_addr), IPV4_ADDR_LEN); /* create a host entry */ item6 = make_hostent6(si, name, addr6); if (item6 == NULL) { if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; return NULL; } return item6; } } else { if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; return NULL; } /* * IF AI_ADDRCONFIG is set, we need to know what interface flavors we really have. */ if4 = 0; if6 = 0; if (flags & AI_ADDRCONFIG) { if (si_inet_config(&if4, &if6) < 0) { if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; return NULL; } /* Bail out if there are no interfaces */ if ((if4 == 0) && (if6 == 0)) { if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; return NULL; } } /* * Figure out what we want. * If user asked for AF_INET, we only want V4 addresses. */ want = WANT_A4_ONLY; if (family == AF_INET) { if ((flags & AI_ADDRCONFIG) && (if4 == 0)) { if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; return NULL; } } else if (family == AF_INET6) { /* family == AF_INET6 */ want = WANT_A6_ONLY; if (flags & (AI_V4MAPPED | AI_V4MAPPED_CFG)) { if (flags & AI_ALL) { want = WANT_A6_PLUS_MAPPED_A4; } else { want = WANT_A6_OR_MAPPED_A4_IF_NO_A6; } } else { if ((flags & AI_ADDRCONFIG) && (if6 == 0)) { if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; return NULL; } } } else { if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; return NULL; } item6 = NULL; item4 = NULL; /* fetch IPv6 data if required */ if ((want == WANT_A6_ONLY) || (want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) || (want == WANT_A6_PLUS_MAPPED_A4)) { item6 = si_host_byname(si, name, AF_INET6, interface, (uint32_t *)err); } /* fetch IPv4 data if required */ if ((want == WANT_A4_ONLY) || (want == WANT_A6_PLUS_MAPPED_A4) || ((want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) && (item6 == NULL))) { item4 = si_host_byname(si, name, AF_INET, interface, (uint32_t *)err); } if (want == WANT_A4_ONLY) { si_item_release(item6); if ((item4 == NULL) && (err != NULL)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND; return item4; } if (want == WANT_A6_ONLY) { si_item_release(item4); if ((item6 == NULL) && (err != NULL)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND; return item6; } if ((item6 == NULL) && (item4 == NULL)) { if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND; return NULL; } /* output item will have IPv6 + mapped IPv4 addresses */ out = (build_hostent_t *)calloc(1, sizeof(build_hostent_t)); if (out == NULL) { si_item_release(item4); si_item_release(item6); if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; return NULL; } if (item4 != NULL) { h = (struct hostent *)((uintptr_t)item4 + sizeof(si_item_t)); out->host.h_name = lower_case(h->h_name); if (h->h_aliases != NULL) { for (i = 0; h->h_aliases[i] != NULL; i++) merge_alias(h->h_aliases[i], out); } for (i = 0; h->h_addr_list[i] != 0; i++) { addr6.__u6_addr.__u6_addr32[0] = 0x00000000; addr6.__u6_addr.__u6_addr32[1] = 0x00000000; addr6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff); memmove(&(addr6.__u6_addr.__u6_addr32[3]), h->h_addr_list[i], IPV4_ADDR_LEN); append_addr((const char *)&addr6, IPV6_ADDR_LEN, out); } } if (item6 != NULL) { h = (struct hostent *)((uintptr_t)item6 + sizeof(si_item_t)); if (out->host.h_name == NULL) out->host.h_name = lower_case(h->h_name); if (h->h_aliases != NULL) { for (i = 0; h->h_aliases[i] != NULL; i++) merge_alias(h->h_aliases[i], out); } for (i = 0; h->h_addr_list[i] != 0; i++) append_addr(h->h_addr_list[i], IPV6_ADDR_LEN, out); } si_item_release(item4); si_item_release(item6); unused = 0; item6 = (si_item_t *)LI_ils_create("L4444s*44c", (unsigned long)si, CATEGORY_HOST_IPV6, 1, unused, unused, out->host.h_name, out->host.h_aliases, AF_INET6, IPV6_ADDR_LEN, out->host.h_addr_list); free_build_hostent(out); return item6; }