1 /* MIT License 2 * 3 * Copyright (c) 2023 Brad House 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a copy 6 * of this software and associated documentation files (the "Software"), to deal 7 * in the Software without restriction, including without limitation the rights 8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 * copies of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 * SPDX-License-Identifier: MIT 25 */ 26 #ifndef __ARES__BUF_H 27 #define __ARES__BUF_H 28 29 /*! \addtogroup ares__buf Safe Data Builder and buffer 30 * 31 * This is a buffer building and parsing framework with a focus on security over 32 * performance. All data to be read from the buffer will perform explicit length 33 * validation and return a success/fail result. There are also various helpers 34 * for writing data to the buffer which dynamically grows. 35 * 36 * All operations that fetch or consume data from the buffer will move forward 37 * the internal pointer, thus marking the data as processed which may no longer 38 * be accessible after certain operations (such as append). 39 * 40 * The helpers for this object are meant to be added as needed. If you can't 41 * find it, write it! 42 * 43 * @{ 44 */ 45 struct ares__buf; 46 47 /*! Opaque data type for generic hash table implementation */ 48 typedef struct ares__buf ares__buf_t; 49 50 /*! Create a new buffer object that dynamically allocates buffers for data. 51 * 52 * \return initialized buffer object or NULL if out of memory. 53 */ 54 ares__buf_t *ares__buf_create(void); 55 56 /*! Create a new buffer object that uses a user-provided data pointer. The 57 * data provided will not be manipulated, and cannot be appended to. This 58 * is strictly used for parsing. 59 * 60 * \param[in] data Data to provide to buffer, must not be NULL. 61 * \param[in] data_len Size of buffer provided, must be > 0 62 * 63 * \return initialized buffer object or NULL if out of memory or misuse. 64 */ 65 ares__buf_t *ares__buf_create_const(const unsigned char *data, size_t data_len); 66 67 68 /*! Destroy an initialized buffer object. 69 * 70 * \param[in] buf Initialized buf object 71 */ 72 void ares__buf_destroy(ares__buf_t *buf); 73 74 75 /*! Append multiple bytes to a dynamic buffer object 76 * 77 * \param[in] buf Initialized buffer object 78 * \param[in] data Data to copy to buffer object 79 * \param[in] data_len Length of data to copy to buffer object. 80 * \return ARES_SUCCESS or one of the c-ares error codes 81 */ 82 ares_status_t ares__buf_append(ares__buf_t *buf, const unsigned char *data, 83 size_t data_len); 84 85 /*! Append a single byte to the dynamic buffer object 86 * 87 * \param[in] buf Initialized buffer object 88 * \param[in] byte Single byte to append to buffer object. 89 * \return ARES_SUCCESS or one of the c-ares error codes 90 */ 91 ares_status_t ares__buf_append_byte(ares__buf_t *buf, unsigned char byte); 92 93 /*! Append a null-terminated string to the dynamic buffer object 94 * 95 * \param[in] buf Initialized buffer object 96 * \param[in] str String to append to buffer object. 97 * \return ARES_SUCCESS or one of the c-ares error codes 98 */ 99 ares_status_t ares__buf_append_str(ares__buf_t *buf, const char *str); 100 101 /*! Append a 16bit Big Endian number to the buffer. 102 * 103 * \param[in] buf Initialized buffer object 104 * \param[out] u16 16bit integer 105 * \return ARES_SUCCESS or one of the c-ares error codes 106 */ 107 ares_status_t ares__buf_append_be16(ares__buf_t *buf, unsigned short u16); 108 109 /*! Append a 32bit Big Endian number to the buffer. 110 * 111 * \param[in] buf Initialized buffer object 112 * \param[out] u32 32bit integer 113 * \return ARES_SUCCESS or one of the c-ares error codes 114 */ 115 ares_status_t ares__buf_append_be32(ares__buf_t *buf, unsigned int u32); 116 117 /*! Append a number in ASCII decimal form. 118 * 119 * \param[in] buf Initialized buffer object 120 * \param[in] num Number to print 121 * \param[in] len Length to output, use 0 for no padding 122 * \return ARES_SUCCESS on success 123 */ 124 ares_status_t ares__buf_append_num_dec(ares__buf_t *buf, size_t num, 125 size_t len); 126 127 /*! Append a number in ASCII hexadecimal form. 128 * 129 * \param[in] buf Initialized buffer object 130 * \param[in] num Number to print 131 * \param[in] len Length to output, use 0 for no padding 132 * \return ARES_SUCCESS on success 133 */ 134 ares_status_t ares__buf_append_num_hex(ares__buf_t *buf, size_t num, 135 size_t len); 136 137 /*! Sets the current buffer length. This *may* be used if there is a need to 138 * override a prior position in the buffer, such as if there is a length 139 * prefix that isn't easily predictable, and you must go back and overwrite 140 * that position. 141 * 142 * Only valid on non-const buffers. Length provided must not exceed current 143 * allocated buffer size, but otherwise there are very few protections on 144 * this function. Use cautiously. 145 * 146 * \param[in] buf Initialized buffer object 147 * \param[in] len Length to set 148 * \return ARES_SUCCESS or one of the c-ares error codes 149 */ 150 ares_status_t ares__buf_set_length(ares__buf_t *buf, size_t len); 151 152 153 /*! Start a dynamic append operation that returns a buffer suitable for 154 * writing. A desired minimum length is passed in, and the actual allocated 155 * buffer size is returned which may be greater than the requested size. 156 * No operation other than ares__buf_append_finish() is allowed on the 157 * buffer after this request. 158 * 159 * \param[in] buf Initialized buffer object 160 * \param[in,out] len Desired non-zero length passed in, actual buffer size 161 * returned. 162 * \return Pointer to writable buffer or NULL on failure (usage, out of mem) 163 */ 164 unsigned char *ares__buf_append_start(ares__buf_t *buf, size_t *len); 165 166 /*! Finish a dynamic append operation. Called after 167 * ares__buf_append_start() once desired data is written. 168 * 169 * \param[in] buf Initialized buffer object. 170 * \param[in] len Length of data written. May be zero to terminate 171 * operation. Must not be greater than returned from 172 * ares__buf_append_start(). 173 */ 174 void ares__buf_append_finish(ares__buf_t *buf, size_t len); 175 176 /*! Write the data provided to the buffer in a hexdump format. 177 * 178 * \param[in] buf Initialized buffer object. 179 * \param[in] data Data to hex dump 180 * \param[in] data_len Length of data to hexdump 181 * \return ARES_SUCCESS on success. 182 */ 183 ares_status_t ares__buf_hexdump(ares__buf_t *buf, const unsigned char *data, 184 size_t len); 185 186 /*! Clean up ares__buf_t and return allocated pointer to unprocessed data. It 187 * is the responsibility of the caller to ares_free() the returned buffer. 188 * The passed in buf parameter is invalidated by this call. 189 * 190 * \param[in] buf Initialized buffer object. Can not be a "const" buffer. 191 * \param[out] len Length of data returned 192 * \return pointer to unprocessed data (may be zero length) or NULL on error. 193 */ 194 unsigned char *ares__buf_finish_bin(ares__buf_t *buf, size_t *len); 195 196 /*! Clean up ares__buf_t and return allocated pointer to unprocessed data and 197 * return it as a string (null terminated). It is the responsibility of the 198 * caller to ares_free() the returned buffer. The passed in buf parameter is 199 * invalidated by this call. 200 * 201 * This function in no way validates the data in this buffer is actually 202 * a string, that characters are printable, or that there aren't multiple 203 * NULL terminators. It is assumed that the caller will either validate that 204 * themselves or has built this buffer with only a valid character set. 205 * 206 * \param[in] buf Initialized buffer object. Can not be a "const" buffer. 207 * \param[out] len Optional. Length of data returned, or NULL if not needed. 208 * \return pointer to unprocessed data or NULL on error. 209 */ 210 char *ares__buf_finish_str(ares__buf_t *buf, size_t *len); 211 212 /*! Tag a position to save in the buffer in case parsing needs to rollback, 213 * such as if insufficient data is available, but more data may be added in 214 * the future. Only a single tag can be set per buffer object. Setting a 215 * tag will override any pre-existing tag. 216 * 217 * \param[in] buf Initialized buffer object 218 */ 219 void ares__buf_tag(ares__buf_t *buf); 220 221 /*! Rollback to a tagged position. Will automatically clear the tag. 222 * 223 * \param[in] buf Initialized buffer object 224 * \return ARES_SUCCESS or one of the c-ares error codes 225 */ 226 ares_status_t ares__buf_tag_rollback(ares__buf_t *buf); 227 228 /*! Clear the tagged position without rolling back. You should do this any 229 * time a tag is no longer needed as future append operations can reclaim 230 * buffer space. 231 * 232 * \param[in] buf Initialized buffer object 233 * \return ARES_SUCCESS or one of the c-ares error codes 234 */ 235 ares_status_t ares__buf_tag_clear(ares__buf_t *buf); 236 237 /*! Fetch the buffer and length of data starting from the tagged position up 238 * to the _current_ position. It will not unset the tagged position. The 239 * data may be invalidated by any future ares__buf_*() calls. 240 * 241 * \param[in] buf Initialized buffer object 242 * \param[out] len Length between tag and current offset in buffer 243 * \return NULL on failure (such as no tag), otherwise pointer to start of 244 * buffer 245 */ 246 const unsigned char *ares__buf_tag_fetch(const ares__buf_t *buf, size_t *len); 247 248 /*! Get the length of the current tag offset to the current position. 249 * 250 * \param[in] buf Initialized buffer object 251 * \return length 252 */ 253 size_t ares__buf_tag_length(const ares__buf_t *buf); 254 255 /*! Fetch the bytes starting from the tagged position up to the _current_ 256 * position using the provided buffer. It will not unset the tagged position. 257 * 258 * \param[in] buf Initialized buffer object 259 * \param[in,out] bytes Buffer to hold data 260 * \param[in,out] len On input, buffer size, on output, bytes place in 261 * buffer. 262 * \return ARES_SUCCESS if fetched, ARES_EFORMERR if insufficient buffer size 263 */ 264 ares_status_t ares__buf_tag_fetch_bytes(const ares__buf_t *buf, 265 unsigned char *bytes, size_t *len); 266 267 /*! Fetch the bytes starting from the tagged position up to the _current_ 268 * position as a NULL-terminated string using the provided buffer. The data 269 * is validated to be ASCII-printable data. It will not unset the tagged 270 * poition. 271 * 272 * \param[in] buf Initialized buffer object 273 * \param[in,out] str Buffer to hold data 274 * \param[in] len On input, buffer size, on output, bytes place in 275 * buffer. 276 * \return ARES_SUCCESS if fetched, ARES_EFORMERR if insufficient buffer size, 277 * ARES_EBADSTR if not printable ASCII 278 */ 279 ares_status_t ares__buf_tag_fetch_string(const ares__buf_t *buf, char *str, 280 size_t len); 281 282 /*! Consume the given number of bytes without reading them. 283 * 284 * \param[in] buf Initialized buffer object 285 * \param[in] len Length to consume 286 * \return ARES_SUCCESS or one of the c-ares error codes 287 */ 288 ares_status_t ares__buf_consume(ares__buf_t *buf, size_t len); 289 290 /*! Fetch a 16bit Big Endian number from the buffer. 291 * 292 * \param[in] buf Initialized buffer object 293 * \param[out] u16 Buffer to hold 16bit integer 294 * \return ARES_SUCCESS or one of the c-ares error codes 295 */ 296 ares_status_t ares__buf_fetch_be16(ares__buf_t *buf, unsigned short *u16); 297 298 /*! Fetch a 32bit Big Endian number from the buffer. 299 * 300 * \param[in] buf Initialized buffer object 301 * \param[out] u32 Buffer to hold 32bit integer 302 * \return ARES_SUCCESS or one of the c-ares error codes 303 */ 304 ares_status_t ares__buf_fetch_be32(ares__buf_t *buf, unsigned int *u32); 305 306 307 /*! Fetch the requested number of bytes into the provided buffer 308 * 309 * \param[in] buf Initialized buffer object 310 * \param[out] bytes Buffer to hold data 311 * \param[in] len Requested number of bytes (must be > 0) 312 * \return ARES_SUCCESS or one of the c-ares error codes 313 */ 314 ares_status_t ares__buf_fetch_bytes(ares__buf_t *buf, unsigned char *bytes, 315 size_t len); 316 317 318 /*! Fetch the requested number of bytes and return a new buffer that must be 319 * ares_free()'d by the caller. 320 * 321 * \param[in] buf Initialized buffer object 322 * \param[in] len Requested number of bytes (must be > 0) 323 * \param[in] null_term Even though this is considered binary data, the user 324 * knows it may be a vald string, so add a null 325 * terminator. 326 * \param[out] bytes Pointer passed by reference. Will be allocated. 327 * \return ARES_SUCCESS or one of the c-ares error codes 328 */ 329 ares_status_t ares__buf_fetch_bytes_dup(ares__buf_t *buf, size_t len, 330 ares_bool_t null_term, 331 unsigned char **bytes); 332 333 /*! Fetch the requested number of bytes and place them into the provided 334 * dest buffer object. 335 * 336 * \param[in] buf Initialized buffer object 337 * \param[out] dest Buffer object to append bytes. 338 * \param[in] len Requested number of bytes (must be > 0) 339 * \return ARES_SUCCESS or one of the c-ares error codes 340 */ 341 ares_status_t ares__buf_fetch_bytes_into_buf(ares__buf_t *buf, 342 ares__buf_t *dest, size_t len); 343 344 /*! Fetch the requested number of bytes and return a new buffer that must be 345 * ares_free()'d by the caller. The returned buffer is a null terminated 346 * string. 347 * 348 * \param[in] buf Initialized buffer object 349 * \param[in] len Requested number of bytes (must be > 0) 350 * \param[out] str Pointer passed by reference. Will be allocated. 351 * \return ARES_SUCCESS or one of the c-ares error codes 352 */ 353 ares_status_t ares__buf_fetch_str_dup(ares__buf_t *buf, size_t len, char **str); 354 355 /*! Consume whitespace characters (0x09, 0x0B, 0x0C, 0x0D, 0x20, and optionally 356 * 0x0A). 357 * 358 * \param[in] buf Initialized buffer object 359 * \param[in] include_linefeed ARES_TRUE to include consuming 0x0A, 360 * ARES_FALSE otherwise. 361 * \return number of whitespace characters consumed 362 */ 363 size_t ares__buf_consume_whitespace(ares__buf_t *buf, 364 ares_bool_t include_linefeed); 365 366 367 /*! Consume any non-whitespace character (anything other than 0x09, 0x0B, 0x0C, 368 * 0x0D, 0x20, and 0x0A). 369 * 370 * \param[in] buf Initialized buffer object 371 * \return number of characters consumed 372 */ 373 size_t ares__buf_consume_nonwhitespace(ares__buf_t *buf); 374 375 376 /*! Consume until a character in the character set provided is reached 377 * 378 * \param[in] buf Initialized buffer object 379 * \param[in] charset character set 380 * \param[in] len length of character set 381 * \param[in] require_charset require we find a character from the charset. 382 * if ARES_FALSE it will simply consume the 383 * rest of the buffer. If ARES_TRUE will return 384 * 0 if not found. 385 * \return number of characters consumed 386 */ 387 size_t ares__buf_consume_until_charset(ares__buf_t *buf, 388 const unsigned char *charset, size_t len, 389 ares_bool_t require_charset); 390 391 392 /*! Consume while the characters match the characters in the provided set. 393 * 394 * \param[in] buf Initialized buffer object 395 * \param[in] charset character set 396 * \param[in] len length of character set 397 * \return number of characters consumed 398 */ 399 size_t ares__buf_consume_charset(ares__buf_t *buf, const unsigned char *charset, 400 size_t len); 401 402 403 /*! Consume from the current position until the end of the line, and optionally 404 * the end of line character (0x0A) itself. 405 * 406 * \param[in] buf Initialized buffer object 407 * \param[in] include_linefeed ARES_TRUE to include consuming 0x0A, 408 * ARES_FALSE otherwise. 409 * \return number of characters consumed 410 */ 411 size_t ares__buf_consume_line(ares__buf_t *buf, ares_bool_t include_linefeed); 412 413 typedef enum { 414 /*! No flags */ 415 ARES_BUF_SPLIT_NONE = 0, 416 /*! The delimiter will be the first character in the buffer, except the 417 * first buffer since the start doesn't have a delimiter 418 */ 419 ARES_BUF_SPLIT_DONT_CONSUME_DELIMS = 1 << 0, 420 /*! Allow blank sections, by default blank sections are not emitted. If using 421 * ARES_BUF_SPLIT_DONT_CONSUME_DELIMS, the delimiter is not counted as part 422 * of the section */ 423 ARES_BUF_SPLIT_ALLOW_BLANK = 1 << 1, 424 /*! Remove duplicate entries */ 425 ARES_BUF_SPLIT_NO_DUPLICATES = 1 << 2, 426 /*! Perform case-insensitive matching when comparing values */ 427 ARES_BUF_SPLIT_CASE_INSENSITIVE = 1 << 3 428 } ares__buf_split_t; 429 430 /*! Split the provided buffer into multiple sub-buffers stored in the variable 431 * pointed to by the linked list. The sub buffers are const buffers pointing 432 * into the buf provided. 433 * 434 * \param[in] buf Initialized buffer object 435 * \param[in] delims Possible delimiters 436 * \param[in] delims_len Length of possible delimiters 437 * \param[in] flags One more more flags 438 * \param[out] list Result. Depending on flags, this may be a 439 * valid list with no elements. Use 440 * ares__llist_destroy() to free the memory which 441 * will also free the contained ares__buf_t 442 * objects. 443 * \return ARES_SUCCESS on success, or error like ARES_ENOMEM. 444 */ 445 ares_status_t ares__buf_split(ares__buf_t *buf, const unsigned char *delims, 446 size_t delims_len, ares__buf_split_t flags, 447 ares__llist_t **list); 448 449 450 /*! Check the unprocessed buffer to see if it begins with the sequence of 451 * characters provided. 452 * 453 * \param[in] buf Initialized buffer object 454 * \param[in] data Bytes of data to compare. 455 * \param[in] data_len Length of data to compare. 456 * \return ARES_TRUE on match, ARES_FALSE otherwise. 457 */ 458 ares_bool_t ares__buf_begins_with(const ares__buf_t *buf, 459 const unsigned char *data, size_t data_len); 460 461 462 /*! Size of unprocessed remaining data length 463 * 464 * \param[in] buf Initialized buffer object 465 * \return length remaining 466 */ 467 size_t ares__buf_len(const ares__buf_t *buf); 468 469 /*! Retrieve a pointer to the currently unprocessed data. Generally this isn't 470 * recommended to be used in practice. The returned pointer may be invalidated 471 * by any future ares__buf_*() calls. 472 * 473 * \param[in] buf Initialized buffer object 474 * \param[out] len Length of available data 475 * \return Pointer to buffer of unprocessed data 476 */ 477 const unsigned char *ares__buf_peek(const ares__buf_t *buf, size_t *len); 478 479 480 /*! Wipe any processed data from the beginning of the buffer. This will 481 * move any remaining data to the front of the internally allocated buffer. 482 * 483 * Can not be used on const buffer objects. 484 * 485 * Typically not needed to call, as any new append operation will automatically 486 * call this function if there is insufficient space to append the data in 487 * order to try to avoid another memory allocation. 488 * 489 * It may be useful to call in order to ensure the current message being 490 * processed is in the beginning of the buffer if there is an intent to use 491 * ares__buf_set_position() and ares__buf_get_position() as may be necessary 492 * when processing DNS compressed names. 493 * 494 * If there is an active tag, it will NOT clear the tag, it will use the tag 495 * as the start of the unprocessed data rather than the current offset. If 496 * a prior tag is no longer needed, may be wise to call ares__buf_tag_clear(). 497 * 498 * \param[in] buf Initialized buffer object 499 */ 500 void ares__buf_reclaim(ares__buf_t *buf); 501 502 /*! Set the current offset within the internal buffer. 503 * 504 * Typically this should not be used, if possible, use the ares__buf_tag*() 505 * operations instead. 506 * 507 * One exception is DNS name compression which may backwards reference to 508 * an index in the message. It may be necessary in such a case to call 509 * ares__buf_reclaim() if using a dynamic (non-const) buffer before processing 510 * such a message. 511 * 512 * \param[in] buf Initialized buffer object 513 * \param[in] idx Index to set position 514 * \return ARES_SUCCESS if valid index 515 */ 516 ares_status_t ares__buf_set_position(ares__buf_t *buf, size_t idx); 517 518 /*! Get the current offset within the internal buffer. 519 * 520 * Typically this should not be used, if possible, use the ares__buf_tag*() 521 * operations instead. 522 * 523 * This can be used to get the current position, useful for saving if a 524 * jump via ares__buf_set_position() is performed and need to restore the 525 * current position for future operations. 526 * 527 * \param[in] buf Initialized buffer object 528 * \return index of current position 529 */ 530 size_t ares__buf_get_position(const ares__buf_t *buf); 531 532 /*! Parse a character-string as defined in RFC1035, as a null-terminated 533 * string. 534 * 535 * \param[in] buf initialized buffer object 536 * \param[in] remaining_len maximum length that should be used for parsing 537 * the string, this is often less than the remaining 538 * buffer and is based on the RR record length. 539 * \param[out] str Pointer passed by reference to be filled in with 540 * allocated string of the parsed that must be 541 * ares_free()'d by the caller. 542 * \param[in] allow_multiple ARES_TRUE if it should attempt to parse multiple 543 * strings back to back, and will concatenate in 544 * the returned str. 545 * \return ARES_SUCCESS on success 546 */ 547 ares_status_t ares__buf_parse_dns_str(ares__buf_t *buf, size_t remaining_len, 548 char **name, ares_bool_t allow_multiple); 549 550 /*! Parse a character-string as defined in RFC1035, as binary, however for 551 * convenience this does guarantee a NULL terminator (that is not included 552 * in the returned length). 553 * 554 * \param[in] buf initialized buffer object 555 * \param[in] remaining_len maximum length that should be used for parsing 556 * the string, this is often less than the remaining 557 * buffer and is based on the RR record length. 558 * \param[out] bin Pointer passed by reference to be filled in with 559 * allocated string of the parsed that must be 560 * ares_free()'d by the caller. 561 * \param[out] bin_len Length of returned string. 562 * \param[in] allow_multiple ARES_TRUE if it should attempt to parse multiple 563 * strings back to back, and will concatenate in 564 * the returned str. 565 * \return ARES_SUCCESS on success 566 */ 567 ares_status_t ares__buf_parse_dns_binstr(ares__buf_t *buf, size_t remaining_len, 568 unsigned char **bin, size_t *bin_len, 569 ares_bool_t allow_multiple); 570 /*! @} */ 571 572 #endif /* __ARES__BUF_H */ 573