lwresutil.c revision 135446
1/* 2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 2000, 2001 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and 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: lwresutil.c,v 1.29.206.1 2004/03/06 08:15:33 marka Exp $ */ 19 20#include <config.h> 21 22#include <assert.h> 23#include <stdlib.h> 24#include <string.h> 25#include <unistd.h> 26 27#include <lwres/lwbuffer.h> 28#include <lwres/lwres.h> 29#include <lwres/result.h> 30 31#include "assert_p.h" 32#include "context_p.h" 33 34/* 35 * Requires: 36 * 37 * The "current" pointer in "b" points to encoded raw data. 38 * 39 * Ensures: 40 * 41 * The address of the first byte of the data is returned via "p", 42 * and the length is returned via "len". If NULL, they are not 43 * set. 44 * 45 * On return, the current pointer of "b" will point to the character 46 * following the data length and the data. 47 * 48 */ 49lwres_result_t 50lwres_data_parse(lwres_buffer_t *b, unsigned char **p, lwres_uint16_t *len) 51{ 52 lwres_uint16_t datalen; 53 unsigned char *data; 54 55 REQUIRE(b != NULL); 56 57 /* 58 * Pull off the length (2 bytes) 59 */ 60 if (!SPACE_REMAINING(b, 2)) 61 return (LWRES_R_UNEXPECTEDEND); 62 datalen = lwres_buffer_getuint16(b); 63 64 /* 65 * Set the pointer to this string to the right place, then 66 * advance the buffer pointer. 67 */ 68 if (!SPACE_REMAINING(b, datalen)) 69 return (LWRES_R_UNEXPECTEDEND); 70 data = b->base + b->current; 71 lwres_buffer_forward(b, datalen); 72 73 if (len != NULL) 74 *len = datalen; 75 if (p != NULL) 76 *p = data; 77 78 return (LWRES_R_SUCCESS); 79} 80 81/* 82 * Requires: 83 * 84 * The "current" pointer in "b" point to an encoded string. 85 * 86 * Ensures: 87 * 88 * The address of the first byte of the string is returned via "c", 89 * and the length is returned via "len". If NULL, they are not 90 * set. 91 * 92 * On return, the current pointer of "b" will point to the character 93 * following the string length, the string, and the trailing NULL. 94 * 95 */ 96lwres_result_t 97lwres_string_parse(lwres_buffer_t *b, char **c, lwres_uint16_t *len) 98{ 99 lwres_uint16_t datalen; 100 char *string; 101 102 REQUIRE(b != NULL); 103 104 /* 105 * Pull off the length (2 bytes) 106 */ 107 if (!SPACE_REMAINING(b, 2)) 108 return (LWRES_R_UNEXPECTEDEND); 109 datalen = lwres_buffer_getuint16(b); 110 111 /* 112 * Set the pointer to this string to the right place, then 113 * advance the buffer pointer. 114 */ 115 if (!SPACE_REMAINING(b, datalen)) 116 return (LWRES_R_UNEXPECTEDEND); 117 string = (char *)b->base + b->current; 118 lwres_buffer_forward(b, datalen); 119 120 /* 121 * Skip the "must be zero" byte. 122 */ 123 if (!SPACE_REMAINING(b, 1)) 124 return (LWRES_R_UNEXPECTEDEND); 125 if (0 != lwres_buffer_getuint8(b)) 126 return (LWRES_R_FAILURE); 127 128 if (len != NULL) 129 *len = datalen; 130 if (c != NULL) 131 *c = string; 132 133 return (LWRES_R_SUCCESS); 134} 135 136lwres_result_t 137lwres_addr_parse(lwres_buffer_t *b, lwres_addr_t *addr) 138{ 139 REQUIRE(addr != NULL); 140 141 if (!SPACE_REMAINING(b, 6)) 142 return (LWRES_R_UNEXPECTEDEND); 143 144 addr->family = lwres_buffer_getuint32(b); 145 addr->length = lwres_buffer_getuint16(b); 146 147 if (!SPACE_REMAINING(b, addr->length)) 148 return (LWRES_R_UNEXPECTEDEND); 149 if (addr->length > LWRES_ADDR_MAXLEN) 150 return (LWRES_R_FAILURE); 151 152 lwres_buffer_getmem(b, addr->address, addr->length); 153 154 return (LWRES_R_SUCCESS); 155} 156 157lwres_result_t 158lwres_getaddrsbyname(lwres_context_t *ctx, const char *name, 159 lwres_uint32_t addrtypes, lwres_gabnresponse_t **structp) 160{ 161 lwres_gabnrequest_t request; 162 lwres_gabnresponse_t *response; 163 int ret; 164 int recvlen; 165 lwres_buffer_t b_in, b_out; 166 lwres_lwpacket_t pkt; 167 lwres_uint32_t serial; 168 char *buffer; 169 char target_name[1024]; 170 unsigned int target_length; 171 172 REQUIRE(ctx != NULL); 173 REQUIRE(name != NULL); 174 REQUIRE(addrtypes != 0); 175 REQUIRE(structp != NULL && *structp == NULL); 176 177 b_in.base = NULL; 178 b_out.base = NULL; 179 response = NULL; 180 buffer = NULL; 181 serial = lwres_context_nextserial(ctx); 182 183 buffer = CTXMALLOC(LWRES_RECVLENGTH); 184 if (buffer == NULL) { 185 ret = LWRES_R_NOMEMORY; 186 goto out; 187 } 188 189 target_length = strlen(name); 190 if (target_length >= sizeof(target_name)) 191 return (LWRES_R_FAILURE); 192 strcpy(target_name, name); /* strcpy is safe */ 193 194 /* 195 * Set up our request and render it to a buffer. 196 */ 197 request.flags = 0; 198 request.addrtypes = addrtypes; 199 request.name = target_name; 200 request.namelen = target_length; 201 pkt.pktflags = 0; 202 pkt.serial = serial; 203 pkt.result = 0; 204 pkt.recvlength = LWRES_RECVLENGTH; 205 206 again: 207 ret = lwres_gabnrequest_render(ctx, &request, &pkt, &b_out); 208 if (ret != LWRES_R_SUCCESS) 209 goto out; 210 211 ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer, 212 LWRES_RECVLENGTH, &recvlen); 213 if (ret != LWRES_R_SUCCESS) 214 goto out; 215 216 lwres_buffer_init(&b_in, buffer, recvlen); 217 b_in.used = recvlen; 218 219 /* 220 * Parse the packet header. 221 */ 222 ret = lwres_lwpacket_parseheader(&b_in, &pkt); 223 if (ret != LWRES_R_SUCCESS) 224 goto out; 225 226 /* 227 * Sanity check. 228 */ 229 if (pkt.serial != serial) 230 goto again; 231 if (pkt.opcode != LWRES_OPCODE_GETADDRSBYNAME) 232 goto again; 233 234 /* 235 * Free what we've transmitted 236 */ 237 CTXFREE(b_out.base, b_out.length); 238 b_out.base = NULL; 239 b_out.length = 0; 240 241 if (pkt.result != LWRES_R_SUCCESS) { 242 ret = pkt.result; 243 goto out; 244 } 245 246 /* 247 * Parse the response. 248 */ 249 ret = lwres_gabnresponse_parse(ctx, &b_in, &pkt, &response); 250 if (ret != LWRES_R_SUCCESS) 251 goto out; 252 response->base = buffer; 253 response->baselen = LWRES_RECVLENGTH; 254 buffer = NULL; /* don't free this below */ 255 256 *structp = response; 257 return (LWRES_R_SUCCESS); 258 259 out: 260 if (b_out.base != NULL) 261 CTXFREE(b_out.base, b_out.length); 262 if (buffer != NULL) 263 CTXFREE(buffer, LWRES_RECVLENGTH); 264 if (response != NULL) 265 lwres_gabnresponse_free(ctx, &response); 266 267 return (ret); 268} 269 270 271lwres_result_t 272lwres_getnamebyaddr(lwres_context_t *ctx, lwres_uint32_t addrtype, 273 lwres_uint16_t addrlen, const unsigned char *addr, 274 lwres_gnbaresponse_t **structp) 275{ 276 lwres_gnbarequest_t request; 277 lwres_gnbaresponse_t *response; 278 int ret; 279 int recvlen; 280 lwres_buffer_t b_in, b_out; 281 lwres_lwpacket_t pkt; 282 lwres_uint32_t serial; 283 char *buffer; 284 285 REQUIRE(ctx != NULL); 286 REQUIRE(addrtype != 0); 287 REQUIRE(addrlen != 0); 288 REQUIRE(addr != NULL); 289 REQUIRE(structp != NULL && *structp == NULL); 290 291 b_in.base = NULL; 292 b_out.base = NULL; 293 response = NULL; 294 buffer = NULL; 295 serial = lwres_context_nextserial(ctx); 296 297 buffer = CTXMALLOC(LWRES_RECVLENGTH); 298 if (buffer == NULL) { 299 ret = LWRES_R_NOMEMORY; 300 goto out; 301 } 302 303 /* 304 * Set up our request and render it to a buffer. 305 */ 306 request.flags = 0; 307 request.addr.family = addrtype; 308 request.addr.length = addrlen; 309 memcpy(request.addr.address, addr, addrlen); 310 pkt.pktflags = 0; 311 pkt.serial = serial; 312 pkt.result = 0; 313 pkt.recvlength = LWRES_RECVLENGTH; 314 315 again: 316 ret = lwres_gnbarequest_render(ctx, &request, &pkt, &b_out); 317 if (ret != LWRES_R_SUCCESS) 318 goto out; 319 320 ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer, 321 LWRES_RECVLENGTH, &recvlen); 322 if (ret != LWRES_R_SUCCESS) 323 goto out; 324 325 lwres_buffer_init(&b_in, buffer, recvlen); 326 b_in.used = recvlen; 327 328 /* 329 * Parse the packet header. 330 */ 331 ret = lwres_lwpacket_parseheader(&b_in, &pkt); 332 if (ret != LWRES_R_SUCCESS) 333 goto out; 334 335 /* 336 * Sanity check. 337 */ 338 if (pkt.serial != serial) 339 goto again; 340 if (pkt.opcode != LWRES_OPCODE_GETNAMEBYADDR) 341 goto again; 342 343 /* 344 * Free what we've transmitted 345 */ 346 CTXFREE(b_out.base, b_out.length); 347 b_out.base = NULL; 348 b_out.length = 0; 349 350 if (pkt.result != LWRES_R_SUCCESS) { 351 ret = pkt.result; 352 goto out; 353 } 354 355 /* 356 * Parse the response. 357 */ 358 ret = lwres_gnbaresponse_parse(ctx, &b_in, &pkt, &response); 359 if (ret != LWRES_R_SUCCESS) 360 goto out; 361 response->base = buffer; 362 response->baselen = LWRES_RECVLENGTH; 363 buffer = NULL; /* don't free this below */ 364 365 *structp = response; 366 return (LWRES_R_SUCCESS); 367 368 out: 369 if (b_out.base != NULL) 370 CTXFREE(b_out.base, b_out.length); 371 if (buffer != NULL) 372 CTXFREE(buffer, LWRES_RECVLENGTH); 373 if (response != NULL) 374 lwres_gnbaresponse_free(ctx, &response); 375 376 return (ret); 377} 378 379lwres_result_t 380lwres_getrdatabyname(lwres_context_t *ctx, const char *name, 381 lwres_uint16_t rdclass, lwres_uint16_t rdtype, 382 lwres_uint32_t flags, lwres_grbnresponse_t **structp) 383{ 384 int ret; 385 int recvlen; 386 lwres_buffer_t b_in, b_out; 387 lwres_lwpacket_t pkt; 388 lwres_uint32_t serial; 389 char *buffer; 390 lwres_grbnrequest_t request; 391 lwres_grbnresponse_t *response; 392 char target_name[1024]; 393 unsigned int target_length; 394 395 REQUIRE(ctx != NULL); 396 REQUIRE(name != NULL); 397 REQUIRE(structp != NULL && *structp == NULL); 398 399 b_in.base = NULL; 400 b_out.base = NULL; 401 response = NULL; 402 buffer = NULL; 403 serial = lwres_context_nextserial(ctx); 404 405 buffer = CTXMALLOC(LWRES_RECVLENGTH); 406 if (buffer == NULL) { 407 ret = LWRES_R_NOMEMORY; 408 goto out; 409 } 410 411 target_length = strlen(name); 412 if (target_length >= sizeof(target_name)) 413 return (LWRES_R_FAILURE); 414 strcpy(target_name, name); /* strcpy is safe */ 415 416 /* 417 * Set up our request and render it to a buffer. 418 */ 419 request.rdclass = rdclass; 420 request.rdtype = rdtype; 421 request.flags = flags; 422 request.name = target_name; 423 request.namelen = target_length; 424 pkt.pktflags = 0; 425 pkt.serial = serial; 426 pkt.result = 0; 427 pkt.recvlength = LWRES_RECVLENGTH; 428 429 again: 430 ret = lwres_grbnrequest_render(ctx, &request, &pkt, &b_out); 431 if (ret != LWRES_R_SUCCESS) 432 goto out; 433 434 ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer, 435 LWRES_RECVLENGTH, &recvlen); 436 if (ret != LWRES_R_SUCCESS) 437 goto out; 438 439 lwres_buffer_init(&b_in, buffer, recvlen); 440 b_in.used = recvlen; 441 442 /* 443 * Parse the packet header. 444 */ 445 ret = lwres_lwpacket_parseheader(&b_in, &pkt); 446 if (ret != LWRES_R_SUCCESS) 447 goto out; 448 449 /* 450 * Sanity check. 451 */ 452 if (pkt.serial != serial) 453 goto again; 454 if (pkt.opcode != LWRES_OPCODE_GETRDATABYNAME) 455 goto again; 456 457 /* 458 * Free what we've transmitted 459 */ 460 CTXFREE(b_out.base, b_out.length); 461 b_out.base = NULL; 462 b_out.length = 0; 463 464 if (pkt.result != LWRES_R_SUCCESS) { 465 ret = pkt.result; 466 goto out; 467 } 468 469 /* 470 * Parse the response. 471 */ 472 ret = lwres_grbnresponse_parse(ctx, &b_in, &pkt, &response); 473 if (ret != LWRES_R_SUCCESS) 474 goto out; 475 response->base = buffer; 476 response->baselen = LWRES_RECVLENGTH; 477 buffer = NULL; /* don't free this below */ 478 479 *structp = response; 480 return (LWRES_R_SUCCESS); 481 482 out: 483 if (b_out.base != NULL) 484 CTXFREE(b_out.base, b_out.length); 485 if (buffer != NULL) 486 CTXFREE(buffer, LWRES_RECVLENGTH); 487 if (response != NULL) 488 lwres_grbnresponse_free(ctx, &response); 489 490 return (ret); 491} 492