1135446Strhodes/* 2262706Serwin * Copyright (C) 2004, 2005, 2007, 2014 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 2000, 2001 Internet Software Consortium. 4135446Strhodes * 5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18234010Sdougb/* $Id: lwresutil.c,v 1.34 2007/06/19 23:47:22 tbox Exp $ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22170222Sdougb/** 23170222Sdougb * lwres_string_parse() retrieves a DNS-encoded string starting the 24170222Sdougb * current pointer of lightweight resolver buffer b: i.e. b->current. 25170222Sdougb * When the function returns, the address of the first byte of the 26170222Sdougb * encoded string is returned via *c and the length of that string is 27170222Sdougb * given by *len. The buffer's current pointer is advanced to point at 28170222Sdougb * the character following the string length, the encoded string, and 29170222Sdougb * the trailing NULL character. 30262706Serwin * 31170222Sdougb * lwres_addr_parse() extracts an address from the buffer b. The 32170222Sdougb * buffer's current pointer b->current is presumed to point at an 33170222Sdougb * encoded address: the address preceded by a 32-bit protocol family 34170222Sdougb * identifier and a 16-bit length field. The encoded address is copied 35170222Sdougb * to addr->address and addr->length indicates the size in bytes of 36170222Sdougb * the address that was copied. b->current is advanced to point at the 37170222Sdougb * next byte of available data in the buffer following the encoded 38170222Sdougb * address. 39262706Serwin * 40170222Sdougb * lwres_getaddrsbyname() and lwres_getnamebyaddr() use the 41170222Sdougb * lwres_gnbaresponse_t structure defined below: 42262706Serwin * 43170222Sdougb * \code 44170222Sdougb * typedef struct { 45170222Sdougb * lwres_uint32_t flags; 46170222Sdougb * lwres_uint16_t naliases; 47170222Sdougb * lwres_uint16_t naddrs; 48170222Sdougb * char *realname; 49170222Sdougb * char **aliases; 50170222Sdougb * lwres_uint16_t realnamelen; 51170222Sdougb * lwres_uint16_t *aliaslen; 52170222Sdougb * lwres_addrlist_t addrs; 53170222Sdougb * void *base; 54170222Sdougb * size_t baselen; 55170222Sdougb * } lwres_gabnresponse_t; 56170222Sdougb * \endcode 57262706Serwin * 58170222Sdougb * The contents of this structure are not manipulated directly but 59262706Serwin * they are controlled through the \link lwres_gabn.c lwres_gabn*\endlink functions. 60262706Serwin * 61170222Sdougb * The lightweight resolver uses lwres_getaddrsbyname() to perform 62170222Sdougb * foward lookups. Hostname name is looked up using the resolver 63262706Serwin * context ctx for memory allocation. addrtypes is a bitmask 64170222Sdougb * indicating which type of addresses are to be looked up. Current 65170222Sdougb * values for this bitmask are #LWRES_ADDRTYPE_V4 for IPv4 addresses 66170222Sdougb * and #LWRES_ADDRTYPE_V6 for IPv6 addresses. Results of the lookup are 67170222Sdougb * returned in *structp. 68262706Serwin * 69262706Serwin * lwres_getnamebyaddr() performs reverse lookups. Resolver context 70170222Sdougb * ctx is used for memory allocation. The address type is indicated by 71170222Sdougb * addrtype: #LWRES_ADDRTYPE_V4 or #LWRES_ADDRTYPE_V6. The address to be 72262706Serwin * looked up is given by addr and its length is addrlen bytes. The 73262706Serwin * result of the function call is made available through *structp. 74262706Serwin * 75170222Sdougb * \section lwresutil_return Return Values 76262706Serwin * 77170222Sdougb * Successful calls to lwres_string_parse() and lwres_addr_parse() 78262706Serwin * return #LWRES_R_SUCCESS. Both functions return #LWRES_R_FAILURE if 79262706Serwin * the buffer is corrupt or #LWRES_R_UNEXPECTEDEND if the buffer has 80170222Sdougb * less space than expected for the components of the encoded string 81170222Sdougb * or address. 82262706Serwin * 83170222Sdougb * lwres_getaddrsbyname() returns #LWRES_R_SUCCESS on success and it 84170222Sdougb * returns #LWRES_R_NOTFOUND if the hostname name could not be found. 85262706Serwin * 86170222Sdougb * #LWRES_R_SUCCESS is returned by a successful call to 87170222Sdougb * lwres_getnamebyaddr(). 88262706Serwin * 89170222Sdougb * Both lwres_getaddrsbyname() and lwres_getnamebyaddr() return 90170222Sdougb * #LWRES_R_NOMEMORY when memory allocation requests fail and 91170222Sdougb * #LWRES_R_UNEXPECTEDEND if the buffers used for sending queries and 92262706Serwin * receiving replies are too small. 93262706Serwin * 94170222Sdougb * \section lwresutil_see See Also 95262706Serwin * 96170222Sdougb * lwbuffer.c, lwres_gabn.c 97170222Sdougb */ 98170222Sdougb 99135446Strhodes#include <config.h> 100135446Strhodes 101135446Strhodes#include <assert.h> 102135446Strhodes#include <stdlib.h> 103135446Strhodes#include <string.h> 104135446Strhodes#include <unistd.h> 105135446Strhodes 106135446Strhodes#include <lwres/lwbuffer.h> 107135446Strhodes#include <lwres/lwres.h> 108135446Strhodes#include <lwres/result.h> 109135446Strhodes 110135446Strhodes#include "assert_p.h" 111135446Strhodes#include "context_p.h" 112135446Strhodes 113170222Sdougb/*% Parse data. */ 114170222Sdougb/*! 115135446Strhodes * Requires: 116135446Strhodes * 117135446Strhodes * The "current" pointer in "b" points to encoded raw data. 118135446Strhodes * 119135446Strhodes * Ensures: 120135446Strhodes * 121135446Strhodes * The address of the first byte of the data is returned via "p", 122135446Strhodes * and the length is returned via "len". If NULL, they are not 123135446Strhodes * set. 124135446Strhodes * 125135446Strhodes * On return, the current pointer of "b" will point to the character 126135446Strhodes * following the data length and the data. 127135446Strhodes * 128135446Strhodes */ 129135446Strhodeslwres_result_t 130135446Strhodeslwres_data_parse(lwres_buffer_t *b, unsigned char **p, lwres_uint16_t *len) 131135446Strhodes{ 132135446Strhodes lwres_uint16_t datalen; 133135446Strhodes unsigned char *data; 134135446Strhodes 135135446Strhodes REQUIRE(b != NULL); 136135446Strhodes 137135446Strhodes /* 138135446Strhodes * Pull off the length (2 bytes) 139135446Strhodes */ 140135446Strhodes if (!SPACE_REMAINING(b, 2)) 141135446Strhodes return (LWRES_R_UNEXPECTEDEND); 142135446Strhodes datalen = lwres_buffer_getuint16(b); 143135446Strhodes 144135446Strhodes /* 145135446Strhodes * Set the pointer to this string to the right place, then 146135446Strhodes * advance the buffer pointer. 147135446Strhodes */ 148135446Strhodes if (!SPACE_REMAINING(b, datalen)) 149135446Strhodes return (LWRES_R_UNEXPECTEDEND); 150135446Strhodes data = b->base + b->current; 151135446Strhodes lwres_buffer_forward(b, datalen); 152135446Strhodes 153135446Strhodes if (len != NULL) 154135446Strhodes *len = datalen; 155135446Strhodes if (p != NULL) 156135446Strhodes *p = data; 157135446Strhodes 158135446Strhodes return (LWRES_R_SUCCESS); 159135446Strhodes} 160135446Strhodes 161170222Sdougb/*% Retrieves a DNS-encoded string. */ 162170222Sdougb/*! 163135446Strhodes * Requires: 164135446Strhodes * 165135446Strhodes * The "current" pointer in "b" point to an encoded string. 166135446Strhodes * 167135446Strhodes * Ensures: 168135446Strhodes * 169135446Strhodes * The address of the first byte of the string is returned via "c", 170135446Strhodes * and the length is returned via "len". If NULL, they are not 171135446Strhodes * set. 172135446Strhodes * 173135446Strhodes * On return, the current pointer of "b" will point to the character 174135446Strhodes * following the string length, the string, and the trailing NULL. 175135446Strhodes * 176135446Strhodes */ 177135446Strhodeslwres_result_t 178135446Strhodeslwres_string_parse(lwres_buffer_t *b, char **c, lwres_uint16_t *len) 179135446Strhodes{ 180135446Strhodes lwres_uint16_t datalen; 181135446Strhodes char *string; 182135446Strhodes 183135446Strhodes REQUIRE(b != NULL); 184135446Strhodes 185135446Strhodes /* 186135446Strhodes * Pull off the length (2 bytes) 187135446Strhodes */ 188135446Strhodes if (!SPACE_REMAINING(b, 2)) 189135446Strhodes return (LWRES_R_UNEXPECTEDEND); 190135446Strhodes datalen = lwres_buffer_getuint16(b); 191135446Strhodes 192135446Strhodes /* 193135446Strhodes * Set the pointer to this string to the right place, then 194135446Strhodes * advance the buffer pointer. 195135446Strhodes */ 196135446Strhodes if (!SPACE_REMAINING(b, datalen)) 197135446Strhodes return (LWRES_R_UNEXPECTEDEND); 198135446Strhodes string = (char *)b->base + b->current; 199135446Strhodes lwres_buffer_forward(b, datalen); 200135446Strhodes 201135446Strhodes /* 202135446Strhodes * Skip the "must be zero" byte. 203135446Strhodes */ 204135446Strhodes if (!SPACE_REMAINING(b, 1)) 205135446Strhodes return (LWRES_R_UNEXPECTEDEND); 206135446Strhodes if (0 != lwres_buffer_getuint8(b)) 207135446Strhodes return (LWRES_R_FAILURE); 208135446Strhodes 209135446Strhodes if (len != NULL) 210135446Strhodes *len = datalen; 211135446Strhodes if (c != NULL) 212135446Strhodes *c = string; 213135446Strhodes 214135446Strhodes return (LWRES_R_SUCCESS); 215135446Strhodes} 216135446Strhodes 217170222Sdougb/*% Extracts an address from the buffer b. */ 218135446Strhodeslwres_result_t 219135446Strhodeslwres_addr_parse(lwres_buffer_t *b, lwres_addr_t *addr) 220135446Strhodes{ 221135446Strhodes REQUIRE(addr != NULL); 222135446Strhodes 223135446Strhodes if (!SPACE_REMAINING(b, 6)) 224135446Strhodes return (LWRES_R_UNEXPECTEDEND); 225135446Strhodes 226135446Strhodes addr->family = lwres_buffer_getuint32(b); 227135446Strhodes addr->length = lwres_buffer_getuint16(b); 228135446Strhodes 229135446Strhodes if (!SPACE_REMAINING(b, addr->length)) 230135446Strhodes return (LWRES_R_UNEXPECTEDEND); 231135446Strhodes if (addr->length > LWRES_ADDR_MAXLEN) 232135446Strhodes return (LWRES_R_FAILURE); 233135446Strhodes 234135446Strhodes lwres_buffer_getmem(b, addr->address, addr->length); 235135446Strhodes 236135446Strhodes return (LWRES_R_SUCCESS); 237135446Strhodes} 238135446Strhodes 239170222Sdougb/*% Used to perform forward lookups. */ 240135446Strhodeslwres_result_t 241135446Strhodeslwres_getaddrsbyname(lwres_context_t *ctx, const char *name, 242135446Strhodes lwres_uint32_t addrtypes, lwres_gabnresponse_t **structp) 243135446Strhodes{ 244135446Strhodes lwres_gabnrequest_t request; 245135446Strhodes lwres_gabnresponse_t *response; 246135446Strhodes int ret; 247135446Strhodes int recvlen; 248135446Strhodes lwres_buffer_t b_in, b_out; 249135446Strhodes lwres_lwpacket_t pkt; 250135446Strhodes lwres_uint32_t serial; 251135446Strhodes char *buffer; 252135446Strhodes char target_name[1024]; 253135446Strhodes unsigned int target_length; 254135446Strhodes 255135446Strhodes REQUIRE(ctx != NULL); 256135446Strhodes REQUIRE(name != NULL); 257135446Strhodes REQUIRE(addrtypes != 0); 258135446Strhodes REQUIRE(structp != NULL && *structp == NULL); 259135446Strhodes 260135446Strhodes b_in.base = NULL; 261135446Strhodes b_out.base = NULL; 262135446Strhodes response = NULL; 263135446Strhodes buffer = NULL; 264135446Strhodes serial = lwres_context_nextserial(ctx); 265135446Strhodes 266135446Strhodes buffer = CTXMALLOC(LWRES_RECVLENGTH); 267135446Strhodes if (buffer == NULL) { 268135446Strhodes ret = LWRES_R_NOMEMORY; 269135446Strhodes goto out; 270135446Strhodes } 271135446Strhodes 272135446Strhodes target_length = strlen(name); 273135446Strhodes if (target_length >= sizeof(target_name)) 274135446Strhodes return (LWRES_R_FAILURE); 275135446Strhodes strcpy(target_name, name); /* strcpy is safe */ 276135446Strhodes 277135446Strhodes /* 278135446Strhodes * Set up our request and render it to a buffer. 279135446Strhodes */ 280135446Strhodes request.flags = 0; 281135446Strhodes request.addrtypes = addrtypes; 282135446Strhodes request.name = target_name; 283135446Strhodes request.namelen = target_length; 284135446Strhodes pkt.pktflags = 0; 285135446Strhodes pkt.serial = serial; 286135446Strhodes pkt.result = 0; 287135446Strhodes pkt.recvlength = LWRES_RECVLENGTH; 288135446Strhodes 289135446Strhodes again: 290135446Strhodes ret = lwres_gabnrequest_render(ctx, &request, &pkt, &b_out); 291135446Strhodes if (ret != LWRES_R_SUCCESS) 292135446Strhodes goto out; 293135446Strhodes 294135446Strhodes ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer, 295135446Strhodes LWRES_RECVLENGTH, &recvlen); 296135446Strhodes if (ret != LWRES_R_SUCCESS) 297135446Strhodes goto out; 298135446Strhodes 299135446Strhodes lwres_buffer_init(&b_in, buffer, recvlen); 300135446Strhodes b_in.used = recvlen; 301135446Strhodes 302135446Strhodes /* 303135446Strhodes * Parse the packet header. 304135446Strhodes */ 305135446Strhodes ret = lwres_lwpacket_parseheader(&b_in, &pkt); 306135446Strhodes if (ret != LWRES_R_SUCCESS) 307135446Strhodes goto out; 308135446Strhodes 309135446Strhodes /* 310135446Strhodes * Sanity check. 311135446Strhodes */ 312135446Strhodes if (pkt.serial != serial) 313135446Strhodes goto again; 314135446Strhodes if (pkt.opcode != LWRES_OPCODE_GETADDRSBYNAME) 315135446Strhodes goto again; 316135446Strhodes 317135446Strhodes /* 318135446Strhodes * Free what we've transmitted 319135446Strhodes */ 320135446Strhodes CTXFREE(b_out.base, b_out.length); 321135446Strhodes b_out.base = NULL; 322135446Strhodes b_out.length = 0; 323135446Strhodes 324135446Strhodes if (pkt.result != LWRES_R_SUCCESS) { 325135446Strhodes ret = pkt.result; 326135446Strhodes goto out; 327135446Strhodes } 328135446Strhodes 329135446Strhodes /* 330135446Strhodes * Parse the response. 331135446Strhodes */ 332135446Strhodes ret = lwres_gabnresponse_parse(ctx, &b_in, &pkt, &response); 333135446Strhodes if (ret != LWRES_R_SUCCESS) 334135446Strhodes goto out; 335135446Strhodes response->base = buffer; 336135446Strhodes response->baselen = LWRES_RECVLENGTH; 337135446Strhodes buffer = NULL; /* don't free this below */ 338135446Strhodes 339135446Strhodes *structp = response; 340135446Strhodes return (LWRES_R_SUCCESS); 341135446Strhodes 342135446Strhodes out: 343135446Strhodes if (b_out.base != NULL) 344135446Strhodes CTXFREE(b_out.base, b_out.length); 345135446Strhodes if (buffer != NULL) 346135446Strhodes CTXFREE(buffer, LWRES_RECVLENGTH); 347135446Strhodes if (response != NULL) 348135446Strhodes lwres_gabnresponse_free(ctx, &response); 349135446Strhodes 350135446Strhodes return (ret); 351135446Strhodes} 352135446Strhodes 353135446Strhodes 354170222Sdougb/*% Used to perform reverse lookups. */ 355135446Strhodeslwres_result_t 356135446Strhodeslwres_getnamebyaddr(lwres_context_t *ctx, lwres_uint32_t addrtype, 357135446Strhodes lwres_uint16_t addrlen, const unsigned char *addr, 358135446Strhodes lwres_gnbaresponse_t **structp) 359135446Strhodes{ 360135446Strhodes lwres_gnbarequest_t request; 361135446Strhodes lwres_gnbaresponse_t *response; 362135446Strhodes int ret; 363135446Strhodes int recvlen; 364135446Strhodes lwres_buffer_t b_in, b_out; 365135446Strhodes lwres_lwpacket_t pkt; 366135446Strhodes lwres_uint32_t serial; 367135446Strhodes char *buffer; 368135446Strhodes 369135446Strhodes REQUIRE(ctx != NULL); 370135446Strhodes REQUIRE(addrtype != 0); 371135446Strhodes REQUIRE(addrlen != 0); 372135446Strhodes REQUIRE(addr != NULL); 373135446Strhodes REQUIRE(structp != NULL && *structp == NULL); 374135446Strhodes 375135446Strhodes b_in.base = NULL; 376135446Strhodes b_out.base = NULL; 377135446Strhodes response = NULL; 378135446Strhodes buffer = NULL; 379135446Strhodes serial = lwres_context_nextserial(ctx); 380135446Strhodes 381135446Strhodes buffer = CTXMALLOC(LWRES_RECVLENGTH); 382135446Strhodes if (buffer == NULL) { 383135446Strhodes ret = LWRES_R_NOMEMORY; 384135446Strhodes goto out; 385135446Strhodes } 386135446Strhodes 387135446Strhodes /* 388135446Strhodes * Set up our request and render it to a buffer. 389135446Strhodes */ 390135446Strhodes request.flags = 0; 391135446Strhodes request.addr.family = addrtype; 392135446Strhodes request.addr.length = addrlen; 393262706Serwin memmove(request.addr.address, addr, addrlen); 394135446Strhodes pkt.pktflags = 0; 395135446Strhodes pkt.serial = serial; 396135446Strhodes pkt.result = 0; 397135446Strhodes pkt.recvlength = LWRES_RECVLENGTH; 398135446Strhodes 399135446Strhodes again: 400135446Strhodes ret = lwres_gnbarequest_render(ctx, &request, &pkt, &b_out); 401135446Strhodes if (ret != LWRES_R_SUCCESS) 402135446Strhodes goto out; 403135446Strhodes 404135446Strhodes ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer, 405135446Strhodes LWRES_RECVLENGTH, &recvlen); 406135446Strhodes if (ret != LWRES_R_SUCCESS) 407135446Strhodes goto out; 408135446Strhodes 409135446Strhodes lwres_buffer_init(&b_in, buffer, recvlen); 410135446Strhodes b_in.used = recvlen; 411135446Strhodes 412135446Strhodes /* 413135446Strhodes * Parse the packet header. 414135446Strhodes */ 415135446Strhodes ret = lwres_lwpacket_parseheader(&b_in, &pkt); 416135446Strhodes if (ret != LWRES_R_SUCCESS) 417135446Strhodes goto out; 418135446Strhodes 419135446Strhodes /* 420135446Strhodes * Sanity check. 421135446Strhodes */ 422135446Strhodes if (pkt.serial != serial) 423135446Strhodes goto again; 424135446Strhodes if (pkt.opcode != LWRES_OPCODE_GETNAMEBYADDR) 425135446Strhodes goto again; 426135446Strhodes 427135446Strhodes /* 428135446Strhodes * Free what we've transmitted 429135446Strhodes */ 430135446Strhodes CTXFREE(b_out.base, b_out.length); 431135446Strhodes b_out.base = NULL; 432135446Strhodes b_out.length = 0; 433135446Strhodes 434135446Strhodes if (pkt.result != LWRES_R_SUCCESS) { 435135446Strhodes ret = pkt.result; 436135446Strhodes goto out; 437135446Strhodes } 438135446Strhodes 439135446Strhodes /* 440135446Strhodes * Parse the response. 441135446Strhodes */ 442135446Strhodes ret = lwres_gnbaresponse_parse(ctx, &b_in, &pkt, &response); 443135446Strhodes if (ret != LWRES_R_SUCCESS) 444135446Strhodes goto out; 445135446Strhodes response->base = buffer; 446135446Strhodes response->baselen = LWRES_RECVLENGTH; 447135446Strhodes buffer = NULL; /* don't free this below */ 448135446Strhodes 449135446Strhodes *structp = response; 450135446Strhodes return (LWRES_R_SUCCESS); 451135446Strhodes 452135446Strhodes out: 453135446Strhodes if (b_out.base != NULL) 454135446Strhodes CTXFREE(b_out.base, b_out.length); 455135446Strhodes if (buffer != NULL) 456135446Strhodes CTXFREE(buffer, LWRES_RECVLENGTH); 457135446Strhodes if (response != NULL) 458135446Strhodes lwres_gnbaresponse_free(ctx, &response); 459135446Strhodes 460135446Strhodes return (ret); 461135446Strhodes} 462135446Strhodes 463170222Sdougb/*% Get rdata by name. */ 464135446Strhodeslwres_result_t 465135446Strhodeslwres_getrdatabyname(lwres_context_t *ctx, const char *name, 466135446Strhodes lwres_uint16_t rdclass, lwres_uint16_t rdtype, 467135446Strhodes lwres_uint32_t flags, lwres_grbnresponse_t **structp) 468135446Strhodes{ 469135446Strhodes int ret; 470135446Strhodes int recvlen; 471135446Strhodes lwres_buffer_t b_in, b_out; 472135446Strhodes lwres_lwpacket_t pkt; 473135446Strhodes lwres_uint32_t serial; 474135446Strhodes char *buffer; 475135446Strhodes lwres_grbnrequest_t request; 476135446Strhodes lwres_grbnresponse_t *response; 477135446Strhodes char target_name[1024]; 478135446Strhodes unsigned int target_length; 479135446Strhodes 480135446Strhodes REQUIRE(ctx != NULL); 481135446Strhodes REQUIRE(name != NULL); 482135446Strhodes REQUIRE(structp != NULL && *structp == NULL); 483135446Strhodes 484135446Strhodes b_in.base = NULL; 485135446Strhodes b_out.base = NULL; 486135446Strhodes response = NULL; 487135446Strhodes buffer = NULL; 488135446Strhodes serial = lwres_context_nextserial(ctx); 489135446Strhodes 490135446Strhodes buffer = CTXMALLOC(LWRES_RECVLENGTH); 491135446Strhodes if (buffer == NULL) { 492135446Strhodes ret = LWRES_R_NOMEMORY; 493135446Strhodes goto out; 494135446Strhodes } 495135446Strhodes 496135446Strhodes target_length = strlen(name); 497135446Strhodes if (target_length >= sizeof(target_name)) 498135446Strhodes return (LWRES_R_FAILURE); 499135446Strhodes strcpy(target_name, name); /* strcpy is safe */ 500135446Strhodes 501135446Strhodes /* 502135446Strhodes * Set up our request and render it to a buffer. 503135446Strhodes */ 504135446Strhodes request.rdclass = rdclass; 505135446Strhodes request.rdtype = rdtype; 506135446Strhodes request.flags = flags; 507135446Strhodes request.name = target_name; 508135446Strhodes request.namelen = target_length; 509135446Strhodes pkt.pktflags = 0; 510135446Strhodes pkt.serial = serial; 511135446Strhodes pkt.result = 0; 512135446Strhodes pkt.recvlength = LWRES_RECVLENGTH; 513135446Strhodes 514135446Strhodes again: 515135446Strhodes ret = lwres_grbnrequest_render(ctx, &request, &pkt, &b_out); 516135446Strhodes if (ret != LWRES_R_SUCCESS) 517135446Strhodes goto out; 518135446Strhodes 519135446Strhodes ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer, 520135446Strhodes LWRES_RECVLENGTH, &recvlen); 521135446Strhodes if (ret != LWRES_R_SUCCESS) 522135446Strhodes goto out; 523135446Strhodes 524135446Strhodes lwres_buffer_init(&b_in, buffer, recvlen); 525135446Strhodes b_in.used = recvlen; 526135446Strhodes 527135446Strhodes /* 528135446Strhodes * Parse the packet header. 529135446Strhodes */ 530135446Strhodes ret = lwres_lwpacket_parseheader(&b_in, &pkt); 531135446Strhodes if (ret != LWRES_R_SUCCESS) 532135446Strhodes goto out; 533135446Strhodes 534135446Strhodes /* 535135446Strhodes * Sanity check. 536135446Strhodes */ 537135446Strhodes if (pkt.serial != serial) 538135446Strhodes goto again; 539135446Strhodes if (pkt.opcode != LWRES_OPCODE_GETRDATABYNAME) 540135446Strhodes goto again; 541135446Strhodes 542135446Strhodes /* 543135446Strhodes * Free what we've transmitted 544135446Strhodes */ 545135446Strhodes CTXFREE(b_out.base, b_out.length); 546135446Strhodes b_out.base = NULL; 547135446Strhodes b_out.length = 0; 548135446Strhodes 549135446Strhodes if (pkt.result != LWRES_R_SUCCESS) { 550135446Strhodes ret = pkt.result; 551135446Strhodes goto out; 552135446Strhodes } 553135446Strhodes 554135446Strhodes /* 555135446Strhodes * Parse the response. 556135446Strhodes */ 557135446Strhodes ret = lwres_grbnresponse_parse(ctx, &b_in, &pkt, &response); 558135446Strhodes if (ret != LWRES_R_SUCCESS) 559135446Strhodes goto out; 560135446Strhodes response->base = buffer; 561135446Strhodes response->baselen = LWRES_RECVLENGTH; 562135446Strhodes buffer = NULL; /* don't free this below */ 563135446Strhodes 564135446Strhodes *structp = response; 565135446Strhodes return (LWRES_R_SUCCESS); 566135446Strhodes 567135446Strhodes out: 568135446Strhodes if (b_out.base != NULL) 569135446Strhodes CTXFREE(b_out.base, b_out.length); 570135446Strhodes if (buffer != NULL) 571135446Strhodes CTXFREE(buffer, LWRES_RECVLENGTH); 572135446Strhodes if (response != NULL) 573135446Strhodes lwres_grbnresponse_free(ctx, &response); 574135446Strhodes 575135446Strhodes return (ret); 576135446Strhodes} 577