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