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