1/* 2 * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 2000, 2001 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: lwres_gabn.c,v 1.33 2007/06/19 23:47:22 tbox Exp $ */ 19 20/*! \file lwres_gabn.c 21 These are low-level routines for creating and parsing lightweight 22 resolver name-to-address lookup request and response messages. 23 24 There are four main functions for the getaddrbyname opcode. One render 25 function converts a getaddrbyname request structure -- 26 lwres_gabnrequest_t -- to the lighweight resolver's canonical format. 27 It is complemented by a parse function that converts a packet in this 28 canonical format to a getaddrbyname request structure. Another render 29 function converts the getaddrbyname response structure -- 30 lwres_gabnresponse_t -- to the canonical format. This is complemented 31 by a parse function which converts a packet in canonical format to a 32 getaddrbyname response structure. 33 34 These structures are defined in \link lwres.h <lwres/lwres.h>.\endlink They are shown below. 35 36\code 37#define LWRES_OPCODE_GETADDRSBYNAME 0x00010001U 38 39typedef struct lwres_addr lwres_addr_t; 40typedef LWRES_LIST(lwres_addr_t) lwres_addrlist_t; 41 42typedef struct { 43 lwres_uint32_t flags; 44 lwres_uint32_t addrtypes; 45 lwres_uint16_t namelen; 46 char *name; 47} lwres_gabnrequest_t; 48 49typedef struct { 50 lwres_uint32_t flags; 51 lwres_uint16_t naliases; 52 lwres_uint16_t naddrs; 53 char *realname; 54 char **aliases; 55 lwres_uint16_t realnamelen; 56 lwres_uint16_t *aliaslen; 57 lwres_addrlist_t addrs; 58 void *base; 59 size_t baselen; 60} lwres_gabnresponse_t; 61\endcode 62 63 lwres_gabnrequest_render() uses resolver context ctx to convert 64 getaddrbyname request structure req to canonical format. The packet 65 header structure pkt is initialised and transferred to buffer b. The 66 contents of *req are then appended to the buffer in canonical format. 67 lwres_gabnresponse_render() performs the same task, except it converts 68 a getaddrbyname response structure lwres_gabnresponse_t to the 69 lightweight resolver's canonical format. 70 71 lwres_gabnrequest_parse() uses context ctx to convert the contents of 72 packet pkt to a lwres_gabnrequest_t structure. Buffer b provides space 73 to be used for storing this structure. When the function succeeds, the 74 resulting lwres_gabnrequest_t is made available through *structp. 75 lwres_gabnresponse_parse() offers the same semantics as 76 lwres_gabnrequest_parse() except it yields a lwres_gabnresponse_t 77 structure. 78 79 lwres_gabnresponse_free() and lwres_gabnrequest_free() release the 80 memory in resolver context ctx that was allocated to the 81 lwres_gabnresponse_t or lwres_gabnrequest_t structures referenced via 82 structp. Any memory associated with ancillary buffers and strings for 83 those structures is also discarded. 84 85\section lwres_gabn_return Return Values 86 87 The getaddrbyname opcode functions lwres_gabnrequest_render(), 88 lwres_gabnresponse_render() lwres_gabnrequest_parse() and 89 lwres_gabnresponse_parse() all return #LWRES_R_SUCCESS on success. They 90 return #LWRES_R_NOMEMORY if memory allocation fails. 91 #LWRES_R_UNEXPECTEDEND is returned if the available space in the buffer 92 b is too small to accommodate the packet header or the 93 lwres_gabnrequest_t and lwres_gabnresponse_t structures. 94 lwres_gabnrequest_parse() and lwres_gabnresponse_parse() will return 95 #LWRES_R_UNEXPECTEDEND if the buffer is not empty after decoding the 96 received packet. These functions will return #LWRES_R_FAILURE if 97 pktflags in the packet header structure #lwres_lwpacket_t indicate that 98 the packet is not a response to an earlier query. 99 100\section lwres_gabn_see See Also 101 102 \link lwpacket.c lwres_lwpacket \endlink 103 */ 104 105#include <config.h> 106 107#include <assert.h> 108#include <stdlib.h> 109#include <string.h> 110 111#include <lwres/lwbuffer.h> 112#include <lwres/lwpacket.h> 113#include <lwres/lwres.h> 114#include <lwres/result.h> 115 116#include "context_p.h" 117#include "assert_p.h" 118 119/*% uses resolver context ctx to convert getaddrbyname request structure req to canonical format. */ 120lwres_result_t 121lwres_gabnrequest_render(lwres_context_t *ctx, lwres_gabnrequest_t *req, 122 lwres_lwpacket_t *pkt, lwres_buffer_t *b) 123{ 124 unsigned char *buf; 125 size_t buflen; 126 int ret; 127 size_t payload_length; 128 lwres_uint16_t datalen; 129 130 REQUIRE(ctx != NULL); 131 REQUIRE(req != NULL); 132 REQUIRE(req->name != NULL); 133 REQUIRE(pkt != NULL); 134 REQUIRE(b != NULL); 135 136 datalen = strlen(req->name); 137 138 payload_length = 4 + 4 + 2 + req->namelen + 1; 139 140 buflen = LWRES_LWPACKET_LENGTH + payload_length; 141 buf = CTXMALLOC(buflen); 142 if (buf == NULL) 143 return (LWRES_R_NOMEMORY); 144 145 lwres_buffer_init(b, buf, buflen); 146 147 pkt->length = buflen; 148 pkt->version = LWRES_LWPACKETVERSION_0; 149 pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE; 150 pkt->opcode = LWRES_OPCODE_GETADDRSBYNAME; 151 pkt->result = 0; 152 pkt->authtype = 0; 153 pkt->authlength = 0; 154 155 ret = lwres_lwpacket_renderheader(b, pkt); 156 if (ret != LWRES_R_SUCCESS) { 157 lwres_buffer_invalidate(b); 158 CTXFREE(buf, buflen); 159 return (ret); 160 } 161 162 INSIST(SPACE_OK(b, payload_length)); 163 164 /* 165 * Flags. 166 */ 167 lwres_buffer_putuint32(b, req->flags); 168 169 /* 170 * Address types we'll accept. 171 */ 172 lwres_buffer_putuint32(b, req->addrtypes); 173 174 /* 175 * Put the length and the data. We know this will fit because we 176 * just checked for it. 177 */ 178 lwres_buffer_putuint16(b, datalen); 179 lwres_buffer_putmem(b, (unsigned char *)req->name, datalen); 180 lwres_buffer_putuint8(b, 0); /* trailing NUL */ 181 182 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0); 183 184 return (LWRES_R_SUCCESS); 185} 186/*% converts a getaddrbyname response structure lwres_gabnresponse_t to the lightweight resolver's canonical format. */ 187lwres_result_t 188lwres_gabnresponse_render(lwres_context_t *ctx, lwres_gabnresponse_t *req, 189 lwres_lwpacket_t *pkt, lwres_buffer_t *b) 190{ 191 unsigned char *buf; 192 size_t buflen; 193 int ret; 194 size_t payload_length; 195 lwres_uint16_t datalen; 196 lwres_addr_t *addr; 197 int x; 198 199 REQUIRE(ctx != NULL); 200 REQUIRE(req != NULL); 201 REQUIRE(pkt != NULL); 202 REQUIRE(b != NULL); 203 204 /* naliases, naddrs */ 205 payload_length = 4 + 2 + 2; 206 /* real name encoding */ 207 payload_length += 2 + req->realnamelen + 1; 208 /* each alias */ 209 for (x = 0; x < req->naliases; x++) 210 payload_length += 2 + req->aliaslen[x] + 1; 211 /* each address */ 212 x = 0; 213 addr = LWRES_LIST_HEAD(req->addrs); 214 while (addr != NULL) { 215 payload_length += 4 + 2; 216 payload_length += addr->length; 217 addr = LWRES_LIST_NEXT(addr, link); 218 x++; 219 } 220 INSIST(x == req->naddrs); 221 222 buflen = LWRES_LWPACKET_LENGTH + payload_length; 223 buf = CTXMALLOC(buflen); 224 if (buf == NULL) 225 return (LWRES_R_NOMEMORY); 226 lwres_buffer_init(b, buf, buflen); 227 228 pkt->length = buflen; 229 pkt->version = LWRES_LWPACKETVERSION_0; 230 pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE; 231 pkt->opcode = LWRES_OPCODE_GETADDRSBYNAME; 232 pkt->authtype = 0; 233 pkt->authlength = 0; 234 235 ret = lwres_lwpacket_renderheader(b, pkt); 236 if (ret != LWRES_R_SUCCESS) { 237 lwres_buffer_invalidate(b); 238 CTXFREE(buf, buflen); 239 return (ret); 240 } 241 242 /* 243 * Check space needed here. 244 */ 245 INSIST(SPACE_OK(b, payload_length)); 246 247 /* Flags. */ 248 lwres_buffer_putuint32(b, req->flags); 249 250 /* encode naliases and naddrs */ 251 lwres_buffer_putuint16(b, req->naliases); 252 lwres_buffer_putuint16(b, req->naddrs); 253 254 /* encode the real name */ 255 datalen = req->realnamelen; 256 lwres_buffer_putuint16(b, datalen); 257 lwres_buffer_putmem(b, (unsigned char *)req->realname, datalen); 258 lwres_buffer_putuint8(b, 0); 259 260 /* encode the aliases */ 261 for (x = 0; x < req->naliases; x++) { 262 datalen = req->aliaslen[x]; 263 lwres_buffer_putuint16(b, datalen); 264 lwres_buffer_putmem(b, (unsigned char *)req->aliases[x], 265 datalen); 266 lwres_buffer_putuint8(b, 0); 267 } 268 269 /* encode the addresses */ 270 addr = LWRES_LIST_HEAD(req->addrs); 271 while (addr != NULL) { 272 lwres_buffer_putuint32(b, addr->family); 273 lwres_buffer_putuint16(b, addr->length); 274 lwres_buffer_putmem(b, addr->address, addr->length); 275 addr = LWRES_LIST_NEXT(addr, link); 276 } 277 278 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0); 279 INSIST(LWRES_BUFFER_USEDCOUNT(b) == pkt->length); 280 281 return (LWRES_R_SUCCESS); 282} 283/*% Uses context ctx to convert the contents of packet pkt to a lwres_gabnrequest_t structure. */ 284lwres_result_t 285lwres_gabnrequest_parse(lwres_context_t *ctx, lwres_buffer_t *b, 286 lwres_lwpacket_t *pkt, lwres_gabnrequest_t **structp) 287{ 288 int ret; 289 char *name; 290 lwres_gabnrequest_t *gabn; 291 lwres_uint32_t addrtypes; 292 lwres_uint32_t flags; 293 lwres_uint16_t namelen; 294 295 REQUIRE(ctx != NULL); 296 REQUIRE(pkt != NULL); 297 REQUIRE(b != NULL); 298 REQUIRE(structp != NULL && *structp == NULL); 299 300 if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0) 301 return (LWRES_R_FAILURE); 302 303 if (!SPACE_REMAINING(b, 4 + 4)) 304 return (LWRES_R_UNEXPECTEDEND); 305 306 flags = lwres_buffer_getuint32(b); 307 addrtypes = lwres_buffer_getuint32(b); 308 309 /* 310 * Pull off the name itself 311 */ 312 ret = lwres_string_parse(b, &name, &namelen); 313 if (ret != LWRES_R_SUCCESS) 314 return (ret); 315 316 if (LWRES_BUFFER_REMAINING(b) != 0) 317 return (LWRES_R_TRAILINGDATA); 318 319 gabn = CTXMALLOC(sizeof(lwres_gabnrequest_t)); 320 if (gabn == NULL) 321 return (LWRES_R_NOMEMORY); 322 323 gabn->flags = flags; 324 gabn->addrtypes = addrtypes; 325 gabn->name = name; 326 gabn->namelen = namelen; 327 328 *structp = gabn; 329 return (LWRES_R_SUCCESS); 330} 331 332/*% Offers the same semantics as lwres_gabnrequest_parse() except it yields a lwres_gabnresponse_t structure. */ 333 334lwres_result_t 335lwres_gabnresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b, 336 lwres_lwpacket_t *pkt, lwres_gabnresponse_t **structp) 337{ 338 lwres_result_t ret; 339 unsigned int x; 340 lwres_uint32_t flags; 341 lwres_uint16_t naliases; 342 lwres_uint16_t naddrs; 343 lwres_gabnresponse_t *gabn; 344 lwres_addrlist_t addrlist; 345 lwres_addr_t *addr; 346 347 REQUIRE(ctx != NULL); 348 REQUIRE(pkt != NULL); 349 REQUIRE(b != NULL); 350 REQUIRE(structp != NULL && *structp == NULL); 351 352 gabn = NULL; 353 354 if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0) 355 return (LWRES_R_FAILURE); 356 357 /* 358 * Pull off the name itself 359 */ 360 if (!SPACE_REMAINING(b, 4 + 2 + 2)) 361 return (LWRES_R_UNEXPECTEDEND); 362 flags = lwres_buffer_getuint32(b); 363 naliases = lwres_buffer_getuint16(b); 364 naddrs = lwres_buffer_getuint16(b); 365 366 gabn = CTXMALLOC(sizeof(lwres_gabnresponse_t)); 367 if (gabn == NULL) 368 return (LWRES_R_NOMEMORY); 369 gabn->aliases = NULL; 370 gabn->aliaslen = NULL; 371 LWRES_LIST_INIT(gabn->addrs); 372 gabn->base = NULL; 373 374 gabn->flags = flags; 375 gabn->naliases = naliases; 376 gabn->naddrs = naddrs; 377 378 LWRES_LIST_INIT(addrlist); 379 380 if (naliases > 0) { 381 gabn->aliases = CTXMALLOC(sizeof(char *) * naliases); 382 if (gabn->aliases == NULL) { 383 ret = LWRES_R_NOMEMORY; 384 goto out; 385 } 386 387 gabn->aliaslen = CTXMALLOC(sizeof(lwres_uint16_t) * naliases); 388 if (gabn->aliaslen == NULL) { 389 ret = LWRES_R_NOMEMORY; 390 goto out; 391 } 392 } 393 394 for (x = 0; x < naddrs; x++) { 395 addr = CTXMALLOC(sizeof(lwres_addr_t)); 396 if (addr == NULL) { 397 ret = LWRES_R_NOMEMORY; 398 goto out; 399 } 400 LWRES_LINK_INIT(addr, link); 401 LWRES_LIST_APPEND(addrlist, addr, link); 402 } 403 404 /* 405 * Now, pull off the real name. 406 */ 407 ret = lwres_string_parse(b, &gabn->realname, &gabn->realnamelen); 408 if (ret != LWRES_R_SUCCESS) 409 goto out; 410 411 /* 412 * Parse off the aliases. 413 */ 414 for (x = 0; x < gabn->naliases; x++) { 415 ret = lwres_string_parse(b, &gabn->aliases[x], 416 &gabn->aliaslen[x]); 417 if (ret != LWRES_R_SUCCESS) 418 goto out; 419 } 420 421 /* 422 * Pull off the addresses. We already strung the linked list 423 * up above. 424 */ 425 addr = LWRES_LIST_HEAD(addrlist); 426 for (x = 0; x < gabn->naddrs; x++) { 427 INSIST(addr != NULL); 428 ret = lwres_addr_parse(b, addr); 429 if (ret != LWRES_R_SUCCESS) 430 goto out; 431 addr = LWRES_LIST_NEXT(addr, link); 432 } 433 434 if (LWRES_BUFFER_REMAINING(b) != 0) { 435 ret = LWRES_R_TRAILINGDATA; 436 goto out; 437 } 438 439 gabn->addrs = addrlist; 440 441 *structp = gabn; 442 return (LWRES_R_SUCCESS); 443 444 out: 445 if (gabn != NULL) { 446 if (gabn->aliases != NULL) 447 CTXFREE(gabn->aliases, sizeof(char *) * naliases); 448 if (gabn->aliaslen != NULL) 449 CTXFREE(gabn->aliaslen, 450 sizeof(lwres_uint16_t) * naliases); 451 addr = LWRES_LIST_HEAD(addrlist); 452 while (addr != NULL) { 453 LWRES_LIST_UNLINK(addrlist, addr, link); 454 CTXFREE(addr, sizeof(lwres_addr_t)); 455 addr = LWRES_LIST_HEAD(addrlist); 456 } 457 CTXFREE(gabn, sizeof(lwres_gabnresponse_t)); 458 } 459 460 return (ret); 461} 462 463/*% Release the memory in resolver context ctx that was allocated to the lwres_gabnrequest_t. */ 464void 465lwres_gabnrequest_free(lwres_context_t *ctx, lwres_gabnrequest_t **structp) 466{ 467 lwres_gabnrequest_t *gabn; 468 469 REQUIRE(ctx != NULL); 470 REQUIRE(structp != NULL && *structp != NULL); 471 472 gabn = *structp; 473 *structp = NULL; 474 475 CTXFREE(gabn, sizeof(lwres_gabnrequest_t)); 476} 477 478/*% Release the memory in resolver context ctx that was allocated to the lwres_gabnresponse_t. */ 479void 480lwres_gabnresponse_free(lwres_context_t *ctx, lwres_gabnresponse_t **structp) 481{ 482 lwres_gabnresponse_t *gabn; 483 lwres_addr_t *addr; 484 485 REQUIRE(ctx != NULL); 486 REQUIRE(structp != NULL && *structp != NULL); 487 488 gabn = *structp; 489 *structp = NULL; 490 491 if (gabn->naliases > 0) { 492 CTXFREE(gabn->aliases, sizeof(char *) * gabn->naliases); 493 CTXFREE(gabn->aliaslen, 494 sizeof(lwres_uint16_t) * gabn->naliases); 495 } 496 addr = LWRES_LIST_HEAD(gabn->addrs); 497 while (addr != NULL) { 498 LWRES_LIST_UNLINK(gabn->addrs, addr, link); 499 CTXFREE(addr, sizeof(lwres_addr_t)); 500 addr = LWRES_LIST_HEAD(gabn->addrs); 501 } 502 if (gabn->base != NULL) 503 CTXFREE(gabn->base, gabn->baselen); 504 CTXFREE(gabn, sizeof(lwres_gabnresponse_t)); 505} 506