/contrib/bind9/lib/lwres/lwresutil.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 576 lines · 307 code · 77 blank · 192 comment · 107 complexity · f6a18eeeb8fe8c2bdf14aaff1ddf1ab1 MD5 · raw file

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