/*% Release the memory in resolver context ctx that was allocated to the lwres_gabnresponse_t. */ void lwres_gabnresponse_free(lwres_context_t *ctx, lwres_gabnresponse_t **structp) { lwres_gabnresponse_t *gabn; lwres_addr_t *addr; REQUIRE(ctx != NULL); REQUIRE(structp != NULL && *structp != NULL); gabn = *structp; *structp = NULL; if (gabn->naliases > 0) { CTXFREE(gabn->aliases, sizeof(char *) * gabn->naliases); CTXFREE(gabn->aliaslen, sizeof(lwres_uint16_t) * gabn->naliases); } addr = LWRES_LIST_HEAD(gabn->addrs); while (addr != NULL) { LWRES_LIST_UNLINK(gabn->addrs, addr, link); CTXFREE(addr, sizeof(lwres_addr_t)); addr = LWRES_LIST_HEAD(gabn->addrs); } if (gabn->base != NULL) CTXFREE(gabn->base, gabn->baselen); CTXFREE(gabn, sizeof(lwres_gabnresponse_t)); }
static void test_gabn(const char *target) { lwres_gabnresponse_t *res; lwres_addr_t *addr; int ret; unsigned int i; char outbuf[64]; res = NULL; ret = lwres_getaddrsbyname(ctx, target, LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6, &res); printf("gabn %s ret == %d\n", target, ret); if (ret != 0) { printf("FAILURE!\n"); if (res != NULL) lwres_gabnresponse_free(ctx, &res); return; } printf("Returned real name: (%u, %s)\n", res->realnamelen, res->realname); printf("%u aliases:\n", res->naliases); for (i = 0; i < res->naliases; i++) printf("\t(%u, %s)\n", res->aliaslen[i], res->aliases[i]); printf("%u addresses:\n", res->naddrs); addr = LWRES_LIST_HEAD(res->addrs); for (i = 0; i < res->naddrs; i++) { INSIST(addr != NULL); if (addr->family == LWRES_ADDRTYPE_V4) (void)inet_ntop(AF_INET, addr->address, outbuf, sizeof(outbuf)); else (void)inet_ntop(AF_INET6, addr->address, outbuf, sizeof(outbuf)); printf("\tAddr len %u family %08x %s\n", addr->length, addr->family, outbuf); addr = LWRES_LIST_NEXT(addr, link); } lwres_gabnresponse_free(ctx, &res); }
static struct hostent * hostfromname(lwres_gabnresponse_t *name, int af) { struct hostent *he; int i; lwres_addr_t *addr; he = malloc(sizeof(*he)); if (he == NULL) goto cleanup; memset(he, 0, sizeof(*he)); /* * Set family and length. */ he->h_addrtype = af; switch (af) { case AF_INET: he->h_length = INADDRSZ; break; case AF_INET6: he->h_length = IN6ADDRSZ; break; default: INSIST(0); } /* * Copy name. */ he->h_name = strdup(name->realname); if (he->h_name == NULL) goto cleanup; /* * Copy aliases. */ he->h_aliases = malloc(sizeof(char *) * (name->naliases + 1)); for (i = 0; i < name->naliases; i++) { he->h_aliases[i] = strdup(name->aliases[i]); if (he->h_aliases[i] == NULL) goto cleanup; } he->h_aliases[i] = NULL; /* * Copy addresses. */ he->h_addr_list = malloc(sizeof(char *) * (name->naddrs + 1)); addr = LWRES_LIST_HEAD(name->addrs); i = 0; while (addr != NULL) { he->h_addr_list[i] = malloc(he->h_length); if (he->h_addr_list[i] == NULL) goto cleanup; memcpy(he->h_addr_list[i], addr->address, he->h_length); addr = LWRES_LIST_NEXT(addr, link); i++; } he->h_addr_list[i] = NULL; return (he); cleanup: if (he != NULL && he->h_addr_list != NULL) { for (i = 0; he->h_addr_list[i] != NULL; i++) free(he->h_addr_list[i]); free(he->h_addr_list); } if (he != NULL && he->h_aliases != NULL) { for (i = 0; he->h_aliases[i] != NULL; i++) free(he->h_aliases[i]); free(he->h_aliases); } if (he != NULL && he->h_name != NULL) free(he->h_name); if (he != NULL) free(he); return (NULL); }
static void test_gabn(const char *target, lwres_result_t expected, const char *address, lwres_uint32_t af) { lwres_gabnresponse_t *res; unsigned char addrbuf[16]; lwres_addr_t *addr; char outbuf[64]; unsigned int len; lwres_result_t ret; res = NULL; ret = lwres_getaddrsbyname(ctx, target, LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6, &res); if (ret != expected) { printf("I:gabn(%s) failed: %d\n", target, ret); if (res != NULL) lwres_gabnresponse_free(ctx, &res); fails++; return; } if (ret == LWRES_R_SUCCESS) { if (af == LWRES_ADDRTYPE_V4) { len = 4; ret = inet_pton(AF_INET, address, addrbuf); assert(ret == 1); } else { len = 16; ret = inet_pton(AF_INET6, address, addrbuf); assert(ret == 1); } addr = LWRES_LIST_HEAD(res->addrs); if (addr == NULL) { printf("I:gabn(%s) returned empty list\n", target); fails++; return; } while (addr != NULL) { if (addr->family != af || addr->length != len || memcmp(addr->address, addrbuf, len) == 0) break; addr = LWRES_LIST_NEXT(addr, link); } if (addr == NULL) { addr = LWRES_LIST_HEAD(res->addrs); if (addr->family == LWRES_ADDRTYPE_V4) (void)inet_ntop(AF_INET, addr->address, outbuf, sizeof(outbuf)); else (void)inet_ntop(AF_INET6, addr->address, outbuf, sizeof(outbuf)); printf("I:gabn(%s) returned %s, expected %s\n", target, outbuf, address); fails++; return; } } if (res != NULL) lwres_gabnresponse_free(ctx, &res); }
static int add_ipv6(const char *hostname, int flags, struct addrinfo **aip, int socktype, int port) { struct addrinfo *ai; lwres_context_t *lwrctx = NULL; lwres_gabnresponse_t *by = NULL; lwres_addr_t *addr; lwres_result_t lwres; int result = 0; lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0); if (lwres != LWRES_R_SUCCESS) ERR(EAI_FAIL); (void) lwres_conf_parse(lwrctx, lwres_resolv_conf); if (hostname == NULL && (flags & AI_PASSIVE) == 0) { ai = ai_clone(*aip, AF_INET6); if (ai == NULL) { lwres_freeaddrinfo(*aip); ERR(EAI_MEMORY); } *aip = ai; ai->ai_socktype = socktype; SIN6(ai->ai_addr)->sin6_port = port; memcpy(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16); } else { lwres = lwres_getaddrsbyname(lwrctx, hostname, LWRES_ADDRTYPE_V6, &by); if (lwres != LWRES_R_SUCCESS) { if (lwres == LWRES_R_NOTFOUND) goto cleanup; else ERR(EAI_FAIL); } addr = LWRES_LIST_HEAD(by->addrs); while (addr != NULL) { ai = ai_clone(*aip, AF_INET6); if (ai == NULL) { lwres_freeaddrinfo(*aip); ERR(EAI_MEMORY); } *aip = ai; ai->ai_socktype = socktype; SIN6(ai->ai_addr)->sin6_port = port; memcpy(&SIN6(ai->ai_addr)->sin6_addr, addr->address, 16); if (flags & AI_CANONNAME) { ai->ai_canonname = strdup(by->realname); if (ai->ai_canonname == NULL) ERR(EAI_MEMORY); } addr = LWRES_LIST_NEXT(addr, link); } } cleanup: if (by != NULL) lwres_gabnresponse_free(lwrctx, &by); if (lwrctx != NULL) { lwres_conf_clear(lwrctx); lwres_context_destroy(&lwrctx); } return (result); }
lwres_result_t lwres_gabnresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b, lwres_lwpacket_t *pkt, lwres_gabnresponse_t **structp) { lwres_result_t ret; unsigned int x; lwres_uint32_t flags; lwres_uint16_t naliases; lwres_uint16_t naddrs; lwres_gabnresponse_t *gabn; lwres_addrlist_t addrlist; lwres_addr_t *addr; REQUIRE(ctx != NULL); REQUIRE(pkt != NULL); REQUIRE(b != NULL); REQUIRE(structp != NULL && *structp == NULL); gabn = NULL; if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0) return (LWRES_R_FAILURE); /* * Pull off the name itself */ if (!SPACE_REMAINING(b, 4 + 2 + 2)) return (LWRES_R_UNEXPECTEDEND); flags = lwres_buffer_getuint32(b); naliases = lwres_buffer_getuint16(b); naddrs = lwres_buffer_getuint16(b); gabn = CTXMALLOC(sizeof(lwres_gabnresponse_t)); if (gabn == NULL) return (LWRES_R_NOMEMORY); gabn->aliases = NULL; gabn->aliaslen = NULL; LWRES_LIST_INIT(gabn->addrs); gabn->base = NULL; gabn->flags = flags; gabn->naliases = naliases; gabn->naddrs = naddrs; LWRES_LIST_INIT(addrlist); if (naliases > 0) { gabn->aliases = CTXMALLOC(sizeof(char *) * naliases); if (gabn->aliases == NULL) { ret = LWRES_R_NOMEMORY; goto out; } gabn->aliaslen = CTXMALLOC(sizeof(lwres_uint16_t) * naliases); if (gabn->aliaslen == NULL) { ret = LWRES_R_NOMEMORY; goto out; } } for (x = 0; x < naddrs; x++) { addr = CTXMALLOC(sizeof(lwres_addr_t)); if (addr == NULL) { ret = LWRES_R_NOMEMORY; goto out; } LWRES_LINK_INIT(addr, link); LWRES_LIST_APPEND(addrlist, addr, link); } /* * Now, pull off the real name. */ ret = lwres_string_parse(b, &gabn->realname, &gabn->realnamelen); if (ret != LWRES_R_SUCCESS) goto out; /* * Parse off the aliases. */ for (x = 0; x < gabn->naliases; x++) { ret = lwres_string_parse(b, &gabn->aliases[x], &gabn->aliaslen[x]); if (ret != LWRES_R_SUCCESS) goto out; } /* * Pull off the addresses. We already strung the linked list * up above. */ addr = LWRES_LIST_HEAD(addrlist); for (x = 0; x < gabn->naddrs; x++) { INSIST(addr != NULL); ret = lwres_addr_parse(b, addr); if (ret != LWRES_R_SUCCESS) goto out; addr = LWRES_LIST_NEXT(addr, link); } if (LWRES_BUFFER_REMAINING(b) != 0) { ret = LWRES_R_TRAILINGDATA; goto out; } gabn->addrs = addrlist; *structp = gabn; return (LWRES_R_SUCCESS); out: if (gabn != NULL) { if (gabn->aliases != NULL) CTXFREE(gabn->aliases, sizeof(char *) * naliases); if (gabn->aliaslen != NULL) CTXFREE(gabn->aliaslen, sizeof(lwres_uint16_t) * naliases); addr = LWRES_LIST_HEAD(addrlist); while (addr != NULL) { LWRES_LIST_UNLINK(addrlist, addr, link); CTXFREE(addr, sizeof(lwres_addr_t)); addr = LWRES_LIST_HEAD(addrlist); } CTXFREE(gabn, sizeof(lwres_gabnresponse_t)); } return (ret); }
/*% converts a getaddrbyname response structure lwres_gabnresponse_t to the lightweight resolver's canonical format. */ lwres_result_t lwres_gabnresponse_render(lwres_context_t *ctx, lwres_gabnresponse_t *req, lwres_lwpacket_t *pkt, lwres_buffer_t *b) { unsigned char *buf; size_t buflen; int ret; size_t payload_length; lwres_uint16_t datalen; lwres_addr_t *addr; int x; REQUIRE(ctx != NULL); REQUIRE(req != NULL); REQUIRE(pkt != NULL); REQUIRE(b != NULL); /* naliases, naddrs */ payload_length = 4 + 2 + 2; /* real name encoding */ payload_length += 2 + req->realnamelen + 1; /* each alias */ for (x = 0; x < req->naliases; x++) payload_length += 2 + req->aliaslen[x] + 1; /* each address */ x = 0; addr = LWRES_LIST_HEAD(req->addrs); while (addr != NULL) { payload_length += 4 + 2; payload_length += addr->length; addr = LWRES_LIST_NEXT(addr, link); x++; } INSIST(x == req->naddrs); buflen = LWRES_LWPACKET_LENGTH + payload_length; buf = CTXMALLOC(buflen); if (buf == NULL) return (LWRES_R_NOMEMORY); lwres_buffer_init(b, buf, (unsigned int)buflen); pkt->length = (lwres_uint32_t)buflen; pkt->version = LWRES_LWPACKETVERSION_0; pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE; pkt->opcode = LWRES_OPCODE_GETADDRSBYNAME; pkt->authtype = 0; pkt->authlength = 0; ret = lwres_lwpacket_renderheader(b, pkt); if (ret != LWRES_R_SUCCESS) { lwres_buffer_invalidate(b); CTXFREE(buf, buflen); return (ret); } /* * Check space needed here. */ INSIST(SPACE_OK(b, payload_length)); /* Flags. */ lwres_buffer_putuint32(b, req->flags); /* encode naliases and naddrs */ lwres_buffer_putuint16(b, req->naliases); lwres_buffer_putuint16(b, req->naddrs); /* encode the real name */ datalen = req->realnamelen; lwres_buffer_putuint16(b, datalen); lwres_buffer_putmem(b, (unsigned char *)req->realname, datalen); lwres_buffer_putuint8(b, 0); /* encode the aliases */ for (x = 0; x < req->naliases; x++) { datalen = req->aliaslen[x]; lwres_buffer_putuint16(b, datalen); lwres_buffer_putmem(b, (unsigned char *)req->aliases[x], datalen); lwres_buffer_putuint8(b, 0); } /* encode the addresses */ addr = LWRES_LIST_HEAD(req->addrs); while (addr != NULL) { lwres_buffer_putuint32(b, addr->family); lwres_buffer_putuint16(b, addr->length); lwres_buffer_putmem(b, addr->address, addr->length); addr = LWRES_LIST_NEXT(addr, link); } INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0); INSIST(LWRES_BUFFER_USEDCOUNT(b) == pkt->length); return (LWRES_R_SUCCESS); }