/contrib/bind9/lib/lwres/lwres_noop.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 342 lines · 175 code · 54 blank · 113 comment · 54 complexity · 760ffe5d9c4ade5df21731cad8615d76 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: lwres_noop.c,v 1.19 2007/06/19 23:47:22 tbox Exp $ */
  18. /*! \file */
  19. /**
  20. * These are low-level routines for creating and parsing lightweight
  21. * resolver no-op request and response messages.
  22. *
  23. * The no-op message is analogous to a ping packet: a packet is sent to
  24. * the resolver daemon and is simply echoed back. The opcode is intended
  25. * to allow a client to determine if the server is operational or not.
  26. *
  27. * There are four main functions for the no-op opcode. One render
  28. * function converts a no-op request structure -- lwres_nooprequest_t --
  29. * to the lighweight resolver's canonical format. It is complemented by a
  30. * parse function that converts a packet in this canonical format to a
  31. * no-op request structure. Another render function converts the no-op
  32. * response structure -- lwres_noopresponse_t to the canonical format.
  33. * This is complemented by a parse function which converts a packet in
  34. * canonical format to a no-op 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_NOOP 0x00000000U
  40. *
  41. * typedef struct {
  42. * lwres_uint16_t datalength;
  43. * unsigned char *data;
  44. * } lwres_nooprequest_t;
  45. *
  46. * typedef struct {
  47. * lwres_uint16_t datalength;
  48. * unsigned char *data;
  49. * } lwres_noopresponse_t;
  50. * \endcode
  51. *
  52. * Although the structures have different types, they are identical. This
  53. * is because the no-op opcode simply echos whatever data was sent: the
  54. * response is therefore identical to the request.
  55. *
  56. * lwres_nooprequest_render() uses resolver context ctx to convert no-op
  57. * request structure req to canonical format. The packet header structure
  58. * pkt is initialised and transferred to buffer b. The contents of *req
  59. * are then appended to the buffer in canonical format.
  60. * lwres_noopresponse_render() performs the same task, except it converts
  61. * a no-op response structure lwres_noopresponse_t to the lightweight
  62. * resolver's canonical format.
  63. *
  64. * lwres_nooprequest_parse() uses context ctx to convert the contents of
  65. * packet pkt to a lwres_nooprequest_t structure. Buffer b provides space
  66. * to be used for storing this structure. When the function succeeds, the
  67. * resulting lwres_nooprequest_t is made available through *structp.
  68. * lwres_noopresponse_parse() offers the same semantics as
  69. * lwres_nooprequest_parse() except it yields a lwres_noopresponse_t
  70. * structure.
  71. *
  72. * lwres_noopresponse_free() and lwres_nooprequest_free() release the
  73. * memory in resolver context ctx that was allocated to the
  74. * lwres_noopresponse_t or lwres_nooprequest_t structures referenced via
  75. * structp.
  76. *
  77. * \section lwres_noop_return Return Values
  78. *
  79. * The no-op opcode functions lwres_nooprequest_render(),
  80. * lwres_noopresponse_render() lwres_nooprequest_parse() and
  81. * lwres_noopresponse_parse() all return #LWRES_R_SUCCESS on success. They
  82. * return #LWRES_R_NOMEMORY if memory allocation fails.
  83. * #LWRES_R_UNEXPECTEDEND is returned if the available space in the buffer
  84. * b is too small to accommodate the packet header or the
  85. * lwres_nooprequest_t and lwres_noopresponse_t structures.
  86. * lwres_nooprequest_parse() and lwres_noopresponse_parse() will return
  87. * #LWRES_R_UNEXPECTEDEND if the buffer is not empty after decoding the
  88. * received packet. These functions will return #LWRES_R_FAILURE if
  89. * pktflags in the packet header structure #lwres_lwpacket_t indicate that
  90. * the packet is not a response to an earlier query.
  91. *
  92. * \section lwres_noop_see See Also
  93. *
  94. * lwpacket.c
  95. */
  96. #include <config.h>
  97. #include <assert.h>
  98. #include <stdlib.h>
  99. #include <string.h>
  100. #include <lwres/lwbuffer.h>
  101. #include <lwres/lwpacket.h>
  102. #include <lwres/lwres.h>
  103. #include <lwres/result.h>
  104. #include "context_p.h"
  105. #include "assert_p.h"
  106. /*% Uses resolver context ctx to convert no-op request structure req to canonical format. */
  107. lwres_result_t
  108. lwres_nooprequest_render(lwres_context_t *ctx, lwres_nooprequest_t *req,
  109. lwres_lwpacket_t *pkt, lwres_buffer_t *b)
  110. {
  111. unsigned char *buf;
  112. size_t buflen;
  113. int ret;
  114. size_t payload_length;
  115. REQUIRE(ctx != NULL);
  116. REQUIRE(req != NULL);
  117. REQUIRE(pkt != NULL);
  118. REQUIRE(b != NULL);
  119. payload_length = sizeof(lwres_uint16_t) + req->datalength;
  120. buflen = LWRES_LWPACKET_LENGTH + payload_length;
  121. buf = CTXMALLOC(buflen);
  122. if (buf == NULL)
  123. return (LWRES_R_NOMEMORY);
  124. lwres_buffer_init(b, buf, buflen);
  125. pkt->length = buflen;
  126. pkt->version = LWRES_LWPACKETVERSION_0;
  127. pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE;
  128. pkt->opcode = LWRES_OPCODE_NOOP;
  129. pkt->result = 0;
  130. pkt->authtype = 0;
  131. pkt->authlength = 0;
  132. ret = lwres_lwpacket_renderheader(b, pkt);
  133. if (ret != LWRES_R_SUCCESS) {
  134. lwres_buffer_invalidate(b);
  135. CTXFREE(buf, buflen);
  136. return (ret);
  137. }
  138. INSIST(SPACE_OK(b, payload_length));
  139. /*
  140. * Put the length and the data. We know this will fit because we
  141. * just checked for it.
  142. */
  143. lwres_buffer_putuint16(b, req->datalength);
  144. lwres_buffer_putmem(b, req->data, req->datalength);
  145. INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
  146. return (LWRES_R_SUCCESS);
  147. }
  148. /*% Converts a no-op response structure lwres_noopresponse_t to the lightweight resolver's canonical format. */
  149. lwres_result_t
  150. lwres_noopresponse_render(lwres_context_t *ctx, lwres_noopresponse_t *req,
  151. lwres_lwpacket_t *pkt, lwres_buffer_t *b)
  152. {
  153. unsigned char *buf;
  154. size_t buflen;
  155. int ret;
  156. size_t payload_length;
  157. REQUIRE(ctx != NULL);
  158. REQUIRE(req != NULL);
  159. REQUIRE(pkt != NULL);
  160. REQUIRE(b != NULL);
  161. payload_length = sizeof(lwres_uint16_t) + req->datalength;
  162. buflen = LWRES_LWPACKET_LENGTH + payload_length;
  163. buf = CTXMALLOC(buflen);
  164. if (buf == NULL)
  165. return (LWRES_R_NOMEMORY);
  166. lwres_buffer_init(b, buf, buflen);
  167. pkt->length = buflen;
  168. pkt->version = LWRES_LWPACKETVERSION_0;
  169. pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE;
  170. pkt->opcode = LWRES_OPCODE_NOOP;
  171. pkt->authtype = 0;
  172. pkt->authlength = 0;
  173. ret = lwres_lwpacket_renderheader(b, pkt);
  174. if (ret != LWRES_R_SUCCESS) {
  175. lwres_buffer_invalidate(b);
  176. CTXFREE(buf, buflen);
  177. return (ret);
  178. }
  179. INSIST(SPACE_OK(b, payload_length));
  180. /*
  181. * Put the length and the data. We know this will fit because we
  182. * just checked for it.
  183. */
  184. lwres_buffer_putuint16(b, req->datalength);
  185. lwres_buffer_putmem(b, req->data, req->datalength);
  186. INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
  187. return (LWRES_R_SUCCESS);
  188. }
  189. /*% Uses context ctx to convert the contents of packet pkt to a lwres_nooprequest_t structure. */
  190. lwres_result_t
  191. lwres_nooprequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
  192. lwres_lwpacket_t *pkt, lwres_nooprequest_t **structp)
  193. {
  194. int ret;
  195. lwres_nooprequest_t *req;
  196. REQUIRE(ctx != NULL);
  197. REQUIRE(b != NULL);
  198. REQUIRE(pkt != NULL);
  199. REQUIRE(structp != NULL && *structp == NULL);
  200. if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
  201. return (LWRES_R_FAILURE);
  202. req = CTXMALLOC(sizeof(lwres_nooprequest_t));
  203. if (req == NULL)
  204. return (LWRES_R_NOMEMORY);
  205. if (!SPACE_REMAINING(b, sizeof(lwres_uint16_t))) {
  206. ret = LWRES_R_UNEXPECTEDEND;
  207. goto out;
  208. }
  209. req->datalength = lwres_buffer_getuint16(b);
  210. if (!SPACE_REMAINING(b, req->datalength)) {
  211. ret = LWRES_R_UNEXPECTEDEND;
  212. goto out;
  213. }
  214. req->data = b->base + b->current;
  215. lwres_buffer_forward(b, req->datalength);
  216. if (LWRES_BUFFER_REMAINING(b) != 0) {
  217. ret = LWRES_R_TRAILINGDATA;
  218. goto out;
  219. }
  220. /* success! */
  221. *structp = req;
  222. return (LWRES_R_SUCCESS);
  223. /* Error return */
  224. out:
  225. CTXFREE(req, sizeof(lwres_nooprequest_t));
  226. return (ret);
  227. }
  228. /*% Offers the same semantics as lwres_nooprequest_parse() except it yields a lwres_noopresponse_t structure. */
  229. lwres_result_t
  230. lwres_noopresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
  231. lwres_lwpacket_t *pkt, lwres_noopresponse_t **structp)
  232. {
  233. int ret;
  234. lwres_noopresponse_t *req;
  235. REQUIRE(ctx != NULL);
  236. REQUIRE(b != NULL);
  237. REQUIRE(pkt != NULL);
  238. REQUIRE(structp != NULL && *structp == NULL);
  239. if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
  240. return (LWRES_R_FAILURE);
  241. req = CTXMALLOC(sizeof(lwres_noopresponse_t));
  242. if (req == NULL)
  243. return (LWRES_R_NOMEMORY);
  244. if (!SPACE_REMAINING(b, sizeof(lwres_uint16_t))) {
  245. ret = LWRES_R_UNEXPECTEDEND;
  246. goto out;
  247. }
  248. req->datalength = lwres_buffer_getuint16(b);
  249. if (!SPACE_REMAINING(b, req->datalength)) {
  250. ret = LWRES_R_UNEXPECTEDEND;
  251. goto out;
  252. }
  253. req->data = b->base + b->current;
  254. lwres_buffer_forward(b, req->datalength);
  255. if (LWRES_BUFFER_REMAINING(b) != 0) {
  256. ret = LWRES_R_TRAILINGDATA;
  257. goto out;
  258. }
  259. /* success! */
  260. *structp = req;
  261. return (LWRES_R_SUCCESS);
  262. /* Error return */
  263. out:
  264. CTXFREE(req, sizeof(lwres_noopresponse_t));
  265. return (ret);
  266. }
  267. /*% Release the memory in resolver context ctx. */
  268. void
  269. lwres_noopresponse_free(lwres_context_t *ctx, lwres_noopresponse_t **structp)
  270. {
  271. lwres_noopresponse_t *noop;
  272. REQUIRE(ctx != NULL);
  273. REQUIRE(structp != NULL && *structp != NULL);
  274. noop = *structp;
  275. *structp = NULL;
  276. CTXFREE(noop, sizeof(lwres_noopresponse_t));
  277. }
  278. /*% Release the memory in resolver context ctx. */
  279. void
  280. lwres_nooprequest_free(lwres_context_t *ctx, lwres_nooprequest_t **structp)
  281. {
  282. lwres_nooprequest_t *noop;
  283. REQUIRE(ctx != NULL);
  284. REQUIRE(structp != NULL && *structp != NULL);
  285. noop = *structp;
  286. *structp = NULL;
  287. CTXFREE(noop, sizeof(lwres_nooprequest_t));
  288. }