static int nss_ubdns_add_result(struct address **_list, unsigned *_n_list, struct ub_result *res, int af) { struct address *list = *_list; unsigned n_list = *_n_list; int i; if (!nss_ubdns_check_result(res)) return (0); for (i = 0; res->data[i] != NULL; i++) { if (res->len[i] == PROTO_ADDRESS_SIZE(af)) { list = realloc(list, (n_list + 1) * sizeof(struct address)); if (!list) return (-1); list[n_list].family = af; list[n_list].scope = 0; memcpy(list[n_list].address, res->data[i], PROTO_ADDRESS_SIZE(af)); n_list += 1; } } *_list = list; *_n_list = n_list; return (0); }
static enum nss_status _fill_hostent ( const char *name, int af, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop) { char *r_addr, *r_name, *r_aliases, *r_addr_list; size_t l, idx, ms, alen; alen = PROTO_ADDRESS_SIZE(af); l = strlen(name); ms = ALIGN(l+1)+ sizeof(char*); if (buflen < ms) { *errnop = ENOMEM; *h_errnop = NO_RECOVERY; return NSS_STATUS_TRYAGAIN; } // hostname r_name = buffer; memcpy(r_name, name, l+1); idx = ALIGN(l+1); // empty list of aliases r_aliases = buffer + idx; *(char**) r_aliases = NULL; idx += sizeof(char*); // address (local) r_addr = buffer+idx; if (af == AF_INET) { result->h_addrtype = AF_INET; *(uint32_t*) r_addr = LOCALADDRESS_IPV4; } else { result->h_addrtype = AF_INET6; memcpy(r_addr, LOCALADDRESS_IPV6, 16); } idx += ALIGN(alen); // address list r_addr_list = buffer + idx; ((char**) r_addr_list)[0] = r_addr; ((char**) r_addr_list)[1] = NULL; idx += 2*sizeof(char*); result->h_name = r_name; result->h_aliases = (char**) r_aliases; result->h_length = alen; result->h_addr_list = (char**) r_addr_list; return NSS_STATUS_SUCCESS; }
enum nss_status _nss_myhostname_gethostbyaddr2_r( const void* addr, socklen_t len, int af, struct hostent *host, char *buffer, size_t buflen, int *errnop, int *h_errnop, int32_t *ttlp) { char hn[HOST_NAME_MAX+1] = {}; struct address *addresses = NULL; struct address *a; unsigned n_addresses = 0, n; uint32_t local_address_ipv4 = LOCALADDRESS_IPV4; const char *canonical = NULL, *additional = NULL; if (len != PROTO_ADDRESS_SIZE(af)) { *errnop = EINVAL; *h_errnop = NO_RECOVERY; return NSS_STATUS_UNAVAIL; } if (af == AF_INET) { if ((*(uint32_t*) addr) == LOCALADDRESS_IPV4) goto found; if ((*(uint32_t*) addr) == htonl(INADDR_LOOPBACK)) { canonical = "localhost"; local_address_ipv4 = htonl(INADDR_LOOPBACK); goto found; } } else if (af == AF_INET6) { if (memcmp(addr, LOCALADDRESS_IPV6, 16) == 0) { additional = "localhost"; goto found; } } else { *errnop = EAFNOSUPPORT; *h_errnop = NO_DATA; return NSS_STATUS_UNAVAIL; } ifconf_acquire_addresses(&addresses, &n_addresses); for (a = addresses, n = 0; n < n_addresses; n++, a++) { if (af != a->family) continue; if (memcmp(addr, a->address, PROTO_ADDRESS_SIZE(af)) == 0) goto found; } *errnop = ENOENT; *h_errnop = HOST_NOT_FOUND; free(addresses); return NSS_STATUS_NOTFOUND; found: if (!canonical) { if (gethostname(hn, sizeof(hn)-1) < 0) { *errnop = errno; *h_errnop = NO_RECOVERY; free(addresses); return NSS_STATUS_UNAVAIL; } canonical = hn; } return fill_in_hostent( canonical, additional, af, addresses, n_addresses, local_address_ipv4, host, buffer, buflen, errnop, h_errnop, ttlp, NULL); }
static enum nss_status fill_in_hostent( const char *canonical, const char *additional, int af, struct address *addresses, unsigned n_addresses, uint32_t local_address_ipv4, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop, int32_t *ttlp, char **canonp) { size_t l_canonical, l_additional, idx, ms; char *r_addr, *r_name, *r_aliases, *r_alias = NULL, *r_addr_list; size_t alen; struct address *a; unsigned n, c; alen = PROTO_ADDRESS_SIZE(af); for (a = addresses, n = 0, c = 0; n < n_addresses; a++, n++) if (af == a->family) c++; l_canonical = strlen(canonical); l_additional = additional ? strlen(additional) : 0; ms = ALIGN(l_canonical+1)+ (additional ? ALIGN(l_additional+1) : 0) + sizeof(char*)+ (additional ? sizeof(char*) : 0) + (c > 0 ? c : 1)*ALIGN(alen)+ (c > 0 ? c+1 : 2)*sizeof(char*); if (buflen < ms) { *errnop = ENOMEM; *h_errnop = NO_RECOVERY; free(addresses); return NSS_STATUS_TRYAGAIN; } /* First, fill in hostnames */ r_name = buffer; memcpy(r_name, canonical, l_canonical+1); idx = ALIGN(l_canonical+1); if (additional) { r_alias = buffer + idx; memcpy(r_alias, additional, l_additional+1); idx += ALIGN(l_additional+1); } /* Second, create aliases array */ r_aliases = buffer + idx; if (additional) { ((char**) r_aliases)[0] = r_alias; ((char**) r_aliases)[1] = NULL; idx += 2*sizeof(char*); } else { ((char**) r_aliases)[0] = NULL; idx += sizeof(char*); } /* Third, add addresses */ r_addr = buffer + idx; if (c > 0) { unsigned i = 0; for (a = addresses, n = 0; n < n_addresses; a++, n++) { if (af != a->family) continue; memcpy(r_addr + i*ALIGN(alen), a->address, alen); i++; } assert(i == c); idx += c*ALIGN(alen); } else { if (af == AF_INET) *(uint32_t*) r_addr = local_address_ipv4; else memcpy(r_addr, LOCALADDRESS_IPV6, 16); idx += ALIGN(alen); } /* Fourth, add address pointer array */ r_addr_list = buffer + idx; if (c > 0) { unsigned i = 0; for (a = addresses, n = 0; n < n_addresses; a++, n++) { if (af != a->family) continue; ((char**) r_addr_list)[i] = (r_addr + i*ALIGN(alen)); i++; } assert(i == c); ((char**) r_addr_list)[c] = NULL; idx += (c+1)*sizeof(char*); } else { ((char**) r_addr_list)[0] = r_addr; ((char**) r_addr_list)[1] = NULL; idx += 2*sizeof(char*); } /* Verify the size matches */ assert(idx == ms); result->h_name = r_name; result->h_aliases = (char**) r_aliases; result->h_addrtype = af; result->h_length = alen; result->h_addr_list = (char**) r_addr_list; if (ttlp) *ttlp = 0; if (canonp) *canonp = r_name; free(addresses); return NSS_STATUS_SUCCESS; }