1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7 *
8 * See the COPYRIGHT file distributed with this work for additional
9 * information regarding copyright ownership.
10 */
11
12 /*! \file */
13
14 /**
15 * These are low-level routines for creating and parsing lightweight
16 * resolver no-op request and response messages.
17 *
18 * The no-op message is analogous to a ping packet: a packet is sent to
19 * the resolver daemon and is simply echoed back. The opcode is intended
20 * to allow a client to determine if the server is operational or not.
21 *
22 * There are four main functions for the no-op opcode. One render
23 * function converts a no-op request structure -- lwres_nooprequest_t --
24 * to the lighweight resolver's canonical format. It is complemented by a
25 * parse function that converts a packet in this canonical format to a
26 * no-op request structure. Another render function converts the no-op
27 * response structure -- lwres_noopresponse_t to the canonical format.
28 * This is complemented by a parse function which converts a packet in
29 * canonical format to a no-op response structure.
30 *
31 * These structures are defined in \link lwres.h <lwres/lwres.h.> \endlink They are shown below.
32 *
33 * \code
34 * #define LWRES_OPCODE_NOOP 0x00000000U
35 *
36 * typedef struct {
37 * uint16_t datalength;
38 * unsigned char *data;
39 * } lwres_nooprequest_t;
40 *
41 * typedef struct {
42 * uint16_t datalength;
43 * unsigned char *data;
44 * } lwres_noopresponse_t;
45 * \endcode
46 *
47 * Although the structures have different types, they are identical. This
48 * is because the no-op opcode simply echos whatever data was sent: the
49 * response is therefore identical to the request.
50 *
51 * lwres_nooprequest_render() uses resolver context ctx to convert no-op
52 * request structure req to canonical format. The packet header structure
53 * pkt is initialised and transferred to buffer b. The contents of *req
54 * are then appended to the buffer in canonical format.
55 * lwres_noopresponse_render() performs the same task, except it converts
56 * a no-op response structure lwres_noopresponse_t to the lightweight
57 * resolver's canonical format.
58 *
59 * lwres_nooprequest_parse() uses context ctx to convert the contents of
60 * packet pkt to a lwres_nooprequest_t structure. Buffer b provides space
61 * to be used for storing this structure. When the function succeeds, the
62 * resulting lwres_nooprequest_t is made available through *structp.
63 * lwres_noopresponse_parse() offers the same semantics as
64 * lwres_nooprequest_parse() except it yields a lwres_noopresponse_t
65 * structure.
66 *
67 * lwres_noopresponse_free() and lwres_nooprequest_free() release the
68 * memory in resolver context ctx that was allocated to the
69 * lwres_noopresponse_t or lwres_nooprequest_t structures referenced via
70 * structp.
71 *
72 * \section lwres_noop_return Return Values
73 *
74 * The no-op opcode functions lwres_nooprequest_render(),
75 * lwres_noopresponse_render() lwres_nooprequest_parse() and
76 * lwres_noopresponse_parse() all return #LWRES_R_SUCCESS on success. They
77 * return #LWRES_R_NOMEMORY if memory allocation fails.
78 * #LWRES_R_UNEXPECTEDEND is returned if the available space in the buffer
79 * b is too small to accommodate the packet header or the
80 * lwres_nooprequest_t and lwres_noopresponse_t structures.
81 * lwres_nooprequest_parse() and lwres_noopresponse_parse() will return
82 * #LWRES_R_UNEXPECTEDEND if the buffer is not empty after decoding the
83 * received packet. These functions will return #LWRES_R_FAILURE if
84 * pktflags in the packet header structure #lwres_lwpacket_t indicate that
85 * the packet is not a response to an earlier query.
86 *
87 * \section lwres_noop_see See Also
88 *
89 * lwpacket.c
90 */
91
92 #include <config.h>
93
94 #include <assert.h>
95 #include <inttypes.h>
96 #include <stdlib.h>
97 #include <string.h>
98
99 #include <lwres/lwbuffer.h>
100 #include <lwres/lwpacket.h>
101 #include <lwres/lwres.h>
102 #include <lwres/result.h>
103
104 #include "context_p.h"
105 #include "assert_p.h"
106
107 /*% Uses resolver context ctx to convert no-op request structure req to canonical format. */
108 lwres_result_t
lwres_nooprequest_render(lwres_context_t * ctx,lwres_nooprequest_t * req,lwres_lwpacket_t * pkt,lwres_buffer_t * b)109 lwres_nooprequest_render(lwres_context_t *ctx, lwres_nooprequest_t *req,
110 lwres_lwpacket_t *pkt, lwres_buffer_t *b)
111 {
112 unsigned char *buf;
113 size_t buflen;
114 int ret;
115 size_t payload_length;
116
117 REQUIRE(ctx != NULL);
118 REQUIRE(req != NULL);
119 REQUIRE(pkt != NULL);
120 REQUIRE(b != NULL);
121
122 payload_length = sizeof(uint16_t) + req->datalength;
123
124 buflen = LWRES_LWPACKET_LENGTH + payload_length;
125 buf = CTXMALLOC(buflen);
126 if (buf == NULL)
127 return (LWRES_R_NOMEMORY);
128 lwres_buffer_init(b, buf, (unsigned int)buflen);
129
130 pkt->length = (uint32_t)buflen;
131 pkt->version = LWRES_LWPACKETVERSION_0;
132 pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE;
133 pkt->opcode = LWRES_OPCODE_NOOP;
134 pkt->result = 0;
135 pkt->authtype = 0;
136 pkt->authlength = 0;
137
138 ret = lwres_lwpacket_renderheader(b, pkt);
139 if (ret != LWRES_R_SUCCESS) {
140 lwres_buffer_invalidate(b);
141 CTXFREE(buf, buflen);
142 return (ret);
143 }
144
145 INSIST(SPACE_OK(b, payload_length));
146
147 /*
148 * Put the length and the data. We know this will fit because we
149 * just checked for it.
150 */
151 lwres_buffer_putuint16(b, req->datalength);
152 lwres_buffer_putmem(b, req->data, req->datalength);
153
154 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
155
156 return (LWRES_R_SUCCESS);
157 }
158
159 /*% Converts a no-op response structure lwres_noopresponse_t to the lightweight resolver's canonical format. */
160
161 lwres_result_t
lwres_noopresponse_render(lwres_context_t * ctx,lwres_noopresponse_t * req,lwres_lwpacket_t * pkt,lwres_buffer_t * b)162 lwres_noopresponse_render(lwres_context_t *ctx, lwres_noopresponse_t *req,
163 lwres_lwpacket_t *pkt, lwres_buffer_t *b)
164 {
165 unsigned char *buf;
166 size_t buflen;
167 int ret;
168 size_t payload_length;
169
170 REQUIRE(ctx != NULL);
171 REQUIRE(req != NULL);
172 REQUIRE(pkt != NULL);
173 REQUIRE(b != NULL);
174
175 payload_length = sizeof(uint16_t) + req->datalength;
176
177 buflen = LWRES_LWPACKET_LENGTH + payload_length;
178 buf = CTXMALLOC(buflen);
179 if (buf == NULL)
180 return (LWRES_R_NOMEMORY);
181 lwres_buffer_init(b, buf, (unsigned int)buflen);
182
183 pkt->length = (uint32_t)buflen;
184 pkt->version = LWRES_LWPACKETVERSION_0;
185 pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE;
186 pkt->opcode = LWRES_OPCODE_NOOP;
187 pkt->authtype = 0;
188 pkt->authlength = 0;
189
190 ret = lwres_lwpacket_renderheader(b, pkt);
191 if (ret != LWRES_R_SUCCESS) {
192 lwres_buffer_invalidate(b);
193 CTXFREE(buf, buflen);
194 return (ret);
195 }
196
197 INSIST(SPACE_OK(b, payload_length));
198
199 /*
200 * Put the length and the data. We know this will fit because we
201 * just checked for it.
202 */
203 lwres_buffer_putuint16(b, req->datalength);
204 lwres_buffer_putmem(b, req->data, req->datalength);
205
206 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
207
208 return (LWRES_R_SUCCESS);
209 }
210
211 /*% Uses context ctx to convert the contents of packet pkt to a lwres_nooprequest_t structure. */
212 lwres_result_t
lwres_nooprequest_parse(lwres_context_t * ctx,lwres_buffer_t * b,lwres_lwpacket_t * pkt,lwres_nooprequest_t ** structp)213 lwres_nooprequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
214 lwres_lwpacket_t *pkt, lwres_nooprequest_t **structp)
215 {
216 int ret;
217 lwres_nooprequest_t *req;
218
219 REQUIRE(ctx != NULL);
220 REQUIRE(b != NULL);
221 REQUIRE(pkt != NULL);
222 REQUIRE(structp != NULL && *structp == NULL);
223
224 if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
225 return (LWRES_R_FAILURE);
226
227 req = CTXMALLOC(sizeof(lwres_nooprequest_t));
228 if (req == NULL)
229 return (LWRES_R_NOMEMORY);
230
231 if (!SPACE_REMAINING(b, sizeof(uint16_t))) {
232 ret = LWRES_R_UNEXPECTEDEND;
233 goto out;
234 }
235 req->datalength = lwres_buffer_getuint16(b);
236
237 if (!SPACE_REMAINING(b, req->datalength)) {
238 ret = LWRES_R_UNEXPECTEDEND;
239 goto out;
240 }
241 req->data = b->base + b->current;
242 lwres_buffer_forward(b, req->datalength);
243
244 if (LWRES_BUFFER_REMAINING(b) != 0) {
245 ret = LWRES_R_TRAILINGDATA;
246 goto out;
247 }
248
249 /* success! */
250 *structp = req;
251 return (LWRES_R_SUCCESS);
252
253 /* Error return */
254 out:
255 CTXFREE(req, sizeof(lwres_nooprequest_t));
256 return (ret);
257 }
258
259 /*% Offers the same semantics as lwres_nooprequest_parse() except it yields a lwres_noopresponse_t structure. */
260 lwres_result_t
lwres_noopresponse_parse(lwres_context_t * ctx,lwres_buffer_t * b,lwres_lwpacket_t * pkt,lwres_noopresponse_t ** structp)261 lwres_noopresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
262 lwres_lwpacket_t *pkt, lwres_noopresponse_t **structp)
263 {
264 int ret;
265 lwres_noopresponse_t *req;
266
267 REQUIRE(ctx != NULL);
268 REQUIRE(b != NULL);
269 REQUIRE(pkt != NULL);
270 REQUIRE(structp != NULL && *structp == NULL);
271
272 if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
273 return (LWRES_R_FAILURE);
274
275 req = CTXMALLOC(sizeof(lwres_noopresponse_t));
276 if (req == NULL)
277 return (LWRES_R_NOMEMORY);
278
279 if (!SPACE_REMAINING(b, sizeof(uint16_t))) {
280 ret = LWRES_R_UNEXPECTEDEND;
281 goto out;
282 }
283 req->datalength = lwres_buffer_getuint16(b);
284
285 if (!SPACE_REMAINING(b, req->datalength)) {
286 ret = LWRES_R_UNEXPECTEDEND;
287 goto out;
288 }
289 req->data = b->base + b->current;
290
291 lwres_buffer_forward(b, req->datalength);
292 if (LWRES_BUFFER_REMAINING(b) != 0) {
293 ret = LWRES_R_TRAILINGDATA;
294 goto out;
295 }
296
297 /* success! */
298 *structp = req;
299 return (LWRES_R_SUCCESS);
300
301 /* Error return */
302 out:
303 CTXFREE(req, sizeof(lwres_noopresponse_t));
304 return (ret);
305 }
306
307 /*% Release the memory in resolver context ctx. */
308 void
lwres_noopresponse_free(lwres_context_t * ctx,lwres_noopresponse_t ** structp)309 lwres_noopresponse_free(lwres_context_t *ctx, lwres_noopresponse_t **structp)
310 {
311 lwres_noopresponse_t *noop;
312
313 REQUIRE(ctx != NULL);
314 REQUIRE(structp != NULL && *structp != NULL);
315
316 noop = *structp;
317 *structp = NULL;
318
319 CTXFREE(noop, sizeof(lwres_noopresponse_t));
320 }
321
322 /*% Release the memory in resolver context ctx. */
323 void
lwres_nooprequest_free(lwres_context_t * ctx,lwres_nooprequest_t ** structp)324 lwres_nooprequest_free(lwres_context_t *ctx, lwres_nooprequest_t **structp)
325 {
326 lwres_nooprequest_t *noop;
327
328 REQUIRE(ctx != NULL);
329 REQUIRE(structp != NULL && *structp != NULL);
330
331 noop = *structp;
332 *structp = NULL;
333
334 CTXFREE(noop, sizeof(lwres_nooprequest_t));
335 }
336