1/* 2 * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 2000-2002 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_gnba.c,v 1.28 2007/09/24 17:18:25 each Exp $ */ 19 20/*! \file lwres_gnba.c 21 These are low-level routines for creating and parsing lightweight 22 resolver address-to-name lookup request and response messages. 23 24 There are four main functions for the getnamebyaddr opcode. One 25 render function converts a getnamebyaddr request structure -- 26 lwres_gnbarequest_t -- to the lightweight resolver's canonical 27 format. It is complemented by a parse function that converts a 28 packet in this canonical format to a getnamebyaddr request 29 structure. Another render function converts the getnamebyaddr 30 response structure -- lwres_gnbaresponse_t to the canonical format. 31 This is complemented by a parse function which converts a packet in 32 canonical format to a getnamebyaddr response structure. 33 34 These structures are defined in \link lwres.h <lwres/lwres.h.>\endlink They are shown 35 below. 36 37\code 38#define LWRES_OPCODE_GETNAMEBYADDR 0x00010002U 39 40typedef struct { 41 lwres_uint32_t flags; 42 lwres_addr_t addr; 43} lwres_gnbarequest_t; 44 45typedef struct { 46 lwres_uint32_t flags; 47 lwres_uint16_t naliases; 48 char *realname; 49 char **aliases; 50 lwres_uint16_t realnamelen; 51 lwres_uint16_t *aliaslen; 52 void *base; 53 size_t baselen; 54} lwres_gnbaresponse_t; 55\endcode 56 57 lwres_gnbarequest_render() uses resolver context ctx to convert 58 getnamebyaddr request structure req to canonical format. The packet 59 header structure pkt is initialised and transferred to buffer b. 60 The contents of *req are then appended to the buffer in canonical 61 format. lwres_gnbaresponse_render() performs the same task, except 62 it converts a getnamebyaddr response structure lwres_gnbaresponse_t 63 to the lightweight resolver's canonical format. 64 65 lwres_gnbarequest_parse() uses context ctx to convert the contents 66 of packet pkt to a lwres_gnbarequest_t structure. Buffer b provides 67 space to be used for storing this structure. When the function 68 succeeds, the resulting lwres_gnbarequest_t is made available 69 through *structp. lwres_gnbaresponse_parse() offers the same 70semantics as lwres_gnbarequest_parse() except it yields a 71 lwres_gnbaresponse_t structure. 72 73 lwres_gnbaresponse_free() and lwres_gnbarequest_free() release the 74 memory in resolver context ctx that was allocated to the 75 lwres_gnbaresponse_t or lwres_gnbarequest_t structures referenced 76 via structp. Any memory associated with ancillary buffers and 77 strings for those structures is also discarded. 78 79\section lwres_gbna_return Return Values 80 81 The getnamebyaddr opcode functions lwres_gnbarequest_render(), 82 lwres_gnbaresponse_render() lwres_gnbarequest_parse() and 83 lwres_gnbaresponse_parse() all return #LWRES_R_SUCCESS on success. 84 They return #LWRES_R_NOMEMORY if memory allocation fails. 85 #LWRES_R_UNEXPECTEDEND is returned if the available space in the 86 buffer b is too small to accommodate the packet header or the 87 lwres_gnbarequest_t and lwres_gnbaresponse_t structures. 88 lwres_gnbarequest_parse() and lwres_gnbaresponse_parse() will 89 return #LWRES_R_UNEXPECTEDEND if the buffer is not empty after 90 decoding the received packet. These functions will return 91 #LWRES_R_FAILURE if pktflags in the packet header structure 92 #lwres_lwpacket_t indicate that the packet is not a response to an 93 earlier query. 94 95\section lwres_gbna_see See Also 96 97 \link lwpacket.c lwres_packet\endlink 98 99 */ 100 101#include <config.h> 102 103#include <assert.h> 104#include <stdlib.h> 105#include <string.h> 106 107#include <lwres/lwbuffer.h> 108#include <lwres/lwpacket.h> 109#include <lwres/lwres.h> 110#include <lwres/result.h> 111 112#include "context_p.h" 113#include "assert_p.h" 114 115/*% Uses resolver context ctx to convert getnamebyaddr request structure req to canonical format. */ 116lwres_result_t 117lwres_gnbarequest_render(lwres_context_t *ctx, lwres_gnbarequest_t *req, 118 lwres_lwpacket_t *pkt, lwres_buffer_t *b) 119{ 120 unsigned char *buf; 121 size_t buflen; 122 int ret; 123 size_t payload_length; 124 125 REQUIRE(ctx != NULL); 126 REQUIRE(req != NULL); 127 REQUIRE(req->addr.family != 0); 128 REQUIRE(req->addr.length != 0); 129 REQUIRE(pkt != NULL); 130 REQUIRE(b != NULL); 131 132 payload_length = 4 + 4 + 2 + + req->addr.length; 133 134 buflen = LWRES_LWPACKET_LENGTH + payload_length; 135 buf = CTXMALLOC(buflen); 136 if (buf == NULL) 137 return (LWRES_R_NOMEMORY); 138 lwres_buffer_init(b, buf, buflen); 139 140 pkt->length = buflen; 141 pkt->version = LWRES_LWPACKETVERSION_0; 142 pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE; 143 pkt->opcode = LWRES_OPCODE_GETNAMEBYADDR; 144 pkt->result = 0; 145 pkt->authtype = 0; 146 pkt->authlength = 0; 147 148 ret = lwres_lwpacket_renderheader(b, pkt); 149 if (ret != LWRES_R_SUCCESS) { 150 lwres_buffer_invalidate(b); 151 CTXFREE(buf, buflen); 152 return (ret); 153 } 154 155 INSIST(SPACE_OK(b, payload_length)); 156 157 /* 158 * Put the length and the data. We know this will fit because we 159 * just checked for it. 160 */ 161 lwres_buffer_putuint32(b, req->flags); 162 lwres_buffer_putuint32(b, req->addr.family); 163 lwres_buffer_putuint16(b, req->addr.length); 164 lwres_buffer_putmem(b, (unsigned char *)req->addr.address, 165 req->addr.length); 166 167 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0); 168 169 return (LWRES_R_SUCCESS); 170} 171 172/*% Converts a getnamebyaddr response structure lwres_gnbaresponse_t to the lightweight resolver's canonical format. */ 173lwres_result_t 174lwres_gnbaresponse_render(lwres_context_t *ctx, lwres_gnbaresponse_t *req, 175 lwres_lwpacket_t *pkt, lwres_buffer_t *b) 176{ 177 unsigned char *buf; 178 size_t buflen; 179 int ret; 180 size_t payload_length; 181 lwres_uint16_t datalen; 182 int x; 183 184 REQUIRE(ctx != NULL); 185 REQUIRE(req != NULL); 186 REQUIRE(pkt != NULL); 187 REQUIRE(b != NULL); 188 189 /* 190 * Calculate packet size. 191 */ 192 payload_length = 4; /* flags */ 193 payload_length += 2; /* naliases */ 194 payload_length += 2 + req->realnamelen + 1; /* real name encoding */ 195 for (x = 0; x < req->naliases; x++) /* each alias */ 196 payload_length += 2 + req->aliaslen[x] + 1; 197 198 buflen = LWRES_LWPACKET_LENGTH + payload_length; 199 buf = CTXMALLOC(buflen); 200 if (buf == NULL) 201 return (LWRES_R_NOMEMORY); 202 lwres_buffer_init(b, buf, buflen); 203 204 pkt->length = buflen; 205 pkt->version = LWRES_LWPACKETVERSION_0; 206 pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE; 207 pkt->opcode = LWRES_OPCODE_GETNAMEBYADDR; 208 pkt->authtype = 0; 209 pkt->authlength = 0; 210 211 ret = lwres_lwpacket_renderheader(b, pkt); 212 if (ret != LWRES_R_SUCCESS) { 213 lwres_buffer_invalidate(b); 214 CTXFREE(buf, buflen); 215 return (ret); 216 } 217 218 INSIST(SPACE_OK(b, payload_length)); 219 lwres_buffer_putuint32(b, req->flags); 220 221 /* encode naliases */ 222 lwres_buffer_putuint16(b, req->naliases); 223 224 /* encode the real name */ 225 datalen = req->realnamelen; 226 lwres_buffer_putuint16(b, datalen); 227 lwres_buffer_putmem(b, (unsigned char *)req->realname, datalen); 228 lwres_buffer_putuint8(b, 0); 229 230 /* encode the aliases */ 231 for (x = 0; x < req->naliases; x++) { 232 datalen = req->aliaslen[x]; 233 lwres_buffer_putuint16(b, datalen); 234 lwres_buffer_putmem(b, (unsigned char *)req->aliases[x], 235 datalen); 236 lwres_buffer_putuint8(b, 0); 237 } 238 239 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0); 240 241 return (LWRES_R_SUCCESS); 242} 243 244/*% Uses context ctx to convert the contents of packet pkt to a lwres_gnbarequest_t structure. */ 245lwres_result_t 246lwres_gnbarequest_parse(lwres_context_t *ctx, lwres_buffer_t *b, 247 lwres_lwpacket_t *pkt, lwres_gnbarequest_t **structp) 248{ 249 int ret; 250 lwres_gnbarequest_t *gnba; 251 252 REQUIRE(ctx != NULL); 253 REQUIRE(pkt != NULL); 254 REQUIRE(b != NULL); 255 REQUIRE(structp != NULL && *structp == NULL); 256 257 if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0) 258 return (LWRES_R_FAILURE); 259 260 if (!SPACE_REMAINING(b, 4)) 261 return (LWRES_R_UNEXPECTEDEND); 262 263 gnba = CTXMALLOC(sizeof(lwres_gnbarequest_t)); 264 if (gnba == NULL) 265 return (LWRES_R_NOMEMORY); 266 267 gnba->flags = lwres_buffer_getuint32(b); 268 269 ret = lwres_addr_parse(b, &gnba->addr); 270 if (ret != LWRES_R_SUCCESS) 271 goto out; 272 273 if (LWRES_BUFFER_REMAINING(b) != 0) { 274 ret = LWRES_R_TRAILINGDATA; 275 goto out; 276 } 277 278 *structp = gnba; 279 return (LWRES_R_SUCCESS); 280 281 out: 282 if (gnba != NULL) 283 lwres_gnbarequest_free(ctx, &gnba); 284 285 return (ret); 286} 287 288/*% Offers the same semantics as lwres_gnbarequest_parse() except it yields a lwres_gnbaresponse_t structure. */ 289 290lwres_result_t 291lwres_gnbaresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b, 292 lwres_lwpacket_t *pkt, lwres_gnbaresponse_t **structp) 293{ 294 int ret; 295 unsigned int x; 296 lwres_uint32_t flags; 297 lwres_uint16_t naliases; 298 lwres_gnbaresponse_t *gnba; 299 300 REQUIRE(ctx != NULL); 301 REQUIRE(pkt != NULL); 302 REQUIRE(b != NULL); 303 REQUIRE(structp != NULL && *structp == NULL); 304 305 gnba = NULL; 306 307 if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0) 308 return (LWRES_R_FAILURE); 309 310 /* 311 * Pull off flags & naliases 312 */ 313 if (!SPACE_REMAINING(b, 4 + 2)) 314 return (LWRES_R_UNEXPECTEDEND); 315 flags = lwres_buffer_getuint32(b); 316 naliases = lwres_buffer_getuint16(b); 317 318 gnba = CTXMALLOC(sizeof(lwres_gnbaresponse_t)); 319 if (gnba == NULL) 320 return (LWRES_R_NOMEMORY); 321 gnba->base = NULL; 322 gnba->aliases = NULL; 323 gnba->aliaslen = NULL; 324 325 gnba->flags = flags; 326 gnba->naliases = naliases; 327 328 if (naliases > 0) { 329 gnba->aliases = CTXMALLOC(sizeof(char *) * naliases); 330 if (gnba->aliases == NULL) { 331 ret = LWRES_R_NOMEMORY; 332 goto out; 333 } 334 335 gnba->aliaslen = CTXMALLOC(sizeof(lwres_uint16_t) * naliases); 336 if (gnba->aliaslen == NULL) { 337 ret = LWRES_R_NOMEMORY; 338 goto out; 339 } 340 } 341 342 /* 343 * Now, pull off the real name. 344 */ 345 ret = lwres_string_parse(b, &gnba->realname, &gnba->realnamelen); 346 if (ret != LWRES_R_SUCCESS) 347 goto out; 348 349 /* 350 * Parse off the aliases. 351 */ 352 for (x = 0; x < gnba->naliases; x++) { 353 ret = lwres_string_parse(b, &gnba->aliases[x], 354 &gnba->aliaslen[x]); 355 if (ret != LWRES_R_SUCCESS) 356 goto out; 357 } 358 359 if (LWRES_BUFFER_REMAINING(b) != 0) { 360 ret = LWRES_R_TRAILINGDATA; 361 goto out; 362 } 363 364 *structp = gnba; 365 return (LWRES_R_SUCCESS); 366 367 out: 368 if (gnba != NULL) { 369 if (gnba->aliases != NULL) 370 CTXFREE(gnba->aliases, sizeof(char *) * naliases); 371 if (gnba->aliaslen != NULL) 372 CTXFREE(gnba->aliaslen, 373 sizeof(lwres_uint16_t) * naliases); 374 CTXFREE(gnba, sizeof(lwres_gnbaresponse_t)); 375 } 376 377 return (ret); 378} 379 380/*% Release the memory in resolver context ctx that was allocated to the lwres_gnbarequest_t. */ 381void 382lwres_gnbarequest_free(lwres_context_t *ctx, lwres_gnbarequest_t **structp) 383{ 384 lwres_gnbarequest_t *gnba; 385 386 REQUIRE(ctx != NULL); 387 REQUIRE(structp != NULL && *structp != NULL); 388 389 gnba = *structp; 390 *structp = NULL; 391 392 CTXFREE(gnba, sizeof(lwres_gnbarequest_t)); 393} 394 395/*% Release the memory in resolver context ctx that was allocated to the lwres_gnbaresponse_t. */ 396void 397lwres_gnbaresponse_free(lwres_context_t *ctx, lwres_gnbaresponse_t **structp) 398{ 399 lwres_gnbaresponse_t *gnba; 400 401 REQUIRE(ctx != NULL); 402 REQUIRE(structp != NULL && *structp != NULL); 403 404 gnba = *structp; 405 *structp = NULL; 406 407 if (gnba->naliases > 0) { 408 CTXFREE(gnba->aliases, sizeof(char *) * gnba->naliases); 409 CTXFREE(gnba->aliaslen, 410 sizeof(lwres_uint16_t) * gnba->naliases); 411 } 412 if (gnba->base != NULL) 413 CTXFREE(gnba->base, gnba->baselen); 414 CTXFREE(gnba, sizeof(lwres_gnbaresponse_t)); 415} 416