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