1 1.21 christos /* $NetBSD: message.c,v 1.22 2026/01/29 18:37:49 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1 christos * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 1.1 christos * 6 1.14 christos * SPDX-License-Identifier: MPL-2.0 7 1.14 christos * 8 1.1 christos * This Source Code Form is subject to the terms of the Mozilla Public 9 1.1 christos * License, v. 2.0. If a copy of the MPL was not distributed with this 10 1.11 christos * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 1.1 christos * 12 1.1 christos * See the COPYRIGHT file distributed with this work for additional 13 1.1 christos * information regarding copyright ownership. 14 1.1 christos */ 15 1.1 christos 16 1.1 christos /*! \file */ 17 1.1 christos 18 1.1 christos /*** 19 1.1 christos *** Imports 20 1.1 christos ***/ 21 1.1 christos 22 1.1 christos #include <ctype.h> 23 1.3 christos #include <inttypes.h> 24 1.3 christos #include <stdbool.h> 25 1.1 christos 26 1.19 christos #include <isc/async.h> 27 1.1 christos #include <isc/buffer.h> 28 1.16 christos #include <isc/hash.h> 29 1.19 christos #include <isc/hashmap.h> 30 1.19 christos #include <isc/helper.h> 31 1.19 christos #include <isc/log.h> 32 1.1 christos #include <isc/mem.h> 33 1.17 christos #include <isc/result.h> 34 1.19 christos #include <isc/string.h> 35 1.10 christos #include <isc/utf8.h> 36 1.1 christos #include <isc/util.h> 37 1.19 christos #include <isc/work.h> 38 1.1 christos 39 1.1 christos #include <dns/dnssec.h> 40 1.1 christos #include <dns/keyvalues.h> 41 1.1 christos #include <dns/log.h> 42 1.1 christos #include <dns/masterdump.h> 43 1.1 christos #include <dns/message.h> 44 1.1 christos #include <dns/opcode.h> 45 1.1 christos #include <dns/rcode.h> 46 1.1 christos #include <dns/rdata.h> 47 1.1 christos #include <dns/rdatalist.h> 48 1.1 christos #include <dns/rdataset.h> 49 1.1 christos #include <dns/rdatastruct.h> 50 1.17 christos #include <dns/soa.h> 51 1.1 christos #include <dns/tsig.h> 52 1.1 christos #include <dns/ttl.h> 53 1.1 christos #include <dns/view.h> 54 1.1 christos 55 1.1 christos #ifdef SKAN_MSG_DEBUG 56 1.1 christos static void 57 1.1 christos hexdump(const char *msg, const char *msg2, void *base, size_t len) { 58 1.1 christos unsigned char *p; 59 1.1 christos unsigned int cnt; 60 1.1 christos 61 1.1 christos p = base; 62 1.1 christos cnt = 0; 63 1.1 christos 64 1.19 christos printf("*** %s [%s] (%u bytes @ %p)\n", msg, msg2, (unsigned int)len, 65 1.19 christos base); 66 1.1 christos 67 1.1 christos while (cnt < len) { 68 1.9 christos if (cnt % 16 == 0) { 69 1.1 christos printf("%p: ", p); 70 1.9 christos } else if (cnt % 8 == 0) { 71 1.1 christos printf(" |"); 72 1.9 christos } 73 1.21 christos printf(" %02x %c", *p, isprint(*p) ? *p : ' '); 74 1.1 christos p++; 75 1.1 christos cnt++; 76 1.1 christos 77 1.9 christos if (cnt % 16 == 0) { 78 1.1 christos printf("\n"); 79 1.9 christos } 80 1.1 christos } 81 1.1 christos 82 1.9 christos if (cnt % 16 != 0) { 83 1.1 christos printf("\n"); 84 1.9 christos } 85 1.1 christos } 86 1.9 christos #endif /* ifdef SKAN_MSG_DEBUG */ 87 1.1 christos 88 1.9 christos #define DNS_MESSAGE_OPCODE_MASK 0x7800U 89 1.9 christos #define DNS_MESSAGE_OPCODE_SHIFT 11 90 1.9 christos #define DNS_MESSAGE_RCODE_MASK 0x000fU 91 1.9 christos #define DNS_MESSAGE_FLAG_MASK 0x8ff0U 92 1.9 christos #define DNS_MESSAGE_EDNSRCODE_MASK 0xff000000U 93 1.9 christos #define DNS_MESSAGE_EDNSRCODE_SHIFT 24 94 1.9 christos #define DNS_MESSAGE_EDNSVERSION_MASK 0x00ff0000U 95 1.9 christos #define DNS_MESSAGE_EDNSVERSION_SHIFT 16 96 1.9 christos 97 1.9 christos #define VALID_NAMED_SECTION(s) \ 98 1.9 christos (((s) > DNS_SECTION_ANY) && ((s) < DNS_SECTION_MAX)) 99 1.9 christos #define VALID_SECTION(s) (((s) >= DNS_SECTION_ANY) && ((s) < DNS_SECTION_MAX)) 100 1.9 christos #define ADD_STRING(b, s) \ 101 1.9 christos { \ 102 1.9 christos if (strlen(s) >= isc_buffer_availablelength(b)) { \ 103 1.9 christos result = ISC_R_NOSPACE; \ 104 1.9 christos goto cleanup; \ 105 1.9 christos } else \ 106 1.9 christos isc_buffer_putstr(b, s); \ 107 1.9 christos } 108 1.20 christos #define PUT_YAMLSTR(target, namebuf, len, utfok) \ 109 1.20 christos { \ 110 1.20 christos result = put_yamlstr(target, namebuf, len, utfok); \ 111 1.20 christos if (result != ISC_R_SUCCESS) { \ 112 1.20 christos goto cleanup; \ 113 1.20 christos } \ 114 1.20 christos } 115 1.19 christos #define VALID_NAMED_PSEUDOSECTION(s) \ 116 1.19 christos (((s) > DNS_PSEUDOSECTION_ANY) && ((s) < DNS_PSEUDOSECTION_MAX)) 117 1.9 christos #define VALID_PSEUDOSECTION(s) \ 118 1.9 christos (((s) >= DNS_PSEUDOSECTION_ANY) && ((s) < DNS_PSEUDOSECTION_MAX)) 119 1.1 christos 120 1.1 christos #define OPTOUT(x) (((x)->attributes & DNS_RDATASETATTR_OPTOUT) != 0) 121 1.1 christos 122 1.1 christos /*% 123 1.1 christos * This is the size of each individual scratchpad buffer, and the numbers 124 1.1 christos * of various block allocations used within the server. 125 1.1 christos * XXXMLG These should come from a config setting. 126 1.1 christos */ 127 1.14 christos #define SCRATCHPAD_SIZE 1232 128 1.19 christos #define NAME_FILLCOUNT 1024 129 1.14 christos #define NAME_FREEMAX 8 * NAME_FILLCOUNT 130 1.14 christos #define OFFSET_COUNT 4 131 1.14 christos #define RDATA_COUNT 8 132 1.14 christos #define RDATALIST_COUNT 8 133 1.19 christos #define RDATASET_FILLCOUNT 1024 134 1.14 christos #define RDATASET_FREEMAX 8 * RDATASET_FILLCOUNT 135 1.1 christos 136 1.1 christos /*% 137 1.1 christos * Text representation of the different items, for message_totext 138 1.1 christos * functions. 139 1.1 christos */ 140 1.9 christos static const char *sectiontext[] = { "QUESTION", "ANSWER", "AUTHORITY", 141 1.9 christos "ADDITIONAL" }; 142 1.9 christos 143 1.9 christos static const char *updsectiontext[] = { "ZONE", "PREREQUISITE", "UPDATE", 144 1.9 christos "ADDITIONAL" }; 145 1.9 christos 146 1.9 christos static const char *opcodetext[] = { "QUERY", "IQUERY", "STATUS", 147 1.9 christos "RESERVED3", "NOTIFY", "UPDATE", 148 1.9 christos "RESERVED6", "RESERVED7", "RESERVED8", 149 1.9 christos "RESERVED9", "RESERVED10", "RESERVED11", 150 1.9 christos "RESERVED12", "RESERVED13", "RESERVED14", 151 1.9 christos "RESERVED15" }; 152 1.1 christos 153 1.10 christos static const char *edetext[] = { "Other", 154 1.10 christos "Unsupported DNSKEY Algorithm", 155 1.10 christos "Unsupported DS Digest Type", 156 1.10 christos "Stale Answer", 157 1.10 christos "Forged Answer", 158 1.10 christos "DNSSEC Indeterminate", 159 1.10 christos "DNSSEC Bogus", 160 1.10 christos "Signature Expired", 161 1.10 christos "Signature Not Yet Valid", 162 1.10 christos "DNSKEY Missing", 163 1.10 christos "RRSIGs Missing", 164 1.10 christos "No Zone Key Bit Set", 165 1.10 christos "NSEC Missing", 166 1.10 christos "Cached Error", 167 1.10 christos "Not Ready", 168 1.10 christos "Blocked", 169 1.10 christos "Censored", 170 1.10 christos "Filtered", 171 1.10 christos "Prohibited", 172 1.10 christos "Stale NXDOMAIN Answer", 173 1.10 christos "Not Authoritative", 174 1.10 christos "Not Supported", 175 1.10 christos "No Reachable Authority", 176 1.10 christos "Network Error", 177 1.10 christos "Invalid Data" }; 178 1.10 christos 179 1.1 christos /*% 180 1.1 christos * "helper" type, which consists of a block of some type, and is linkable. 181 1.1 christos * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer 182 1.1 christos * size, or the allocated elements will not be aligned correctly. 183 1.1 christos */ 184 1.1 christos struct dns_msgblock { 185 1.9 christos unsigned int count; 186 1.9 christos unsigned int remaining; 187 1.9 christos ISC_LINK(dns_msgblock_t) link; 188 1.1 christos }; /* dynamically sized */ 189 1.1 christos 190 1.14 christos static dns_msgblock_t * 191 1.1 christos msgblock_allocate(isc_mem_t *, unsigned int, unsigned int); 192 1.1 christos 193 1.1 christos #define msgblock_get(block, type) \ 194 1.1 christos ((type *)msgblock_internalget(block, sizeof(type))) 195 1.1 christos 196 1.19 christos /* 197 1.19 christos * A context type to pass information when checking a message signature 198 1.19 christos * asynchronously. 199 1.19 christos */ 200 1.19 christos typedef struct checksig_ctx { 201 1.19 christos isc_loop_t *loop; 202 1.19 christos dns_message_t *msg; 203 1.19 christos dns_view_t *view; 204 1.19 christos dns_message_cb_t cb; 205 1.19 christos void *cbarg; 206 1.19 christos isc_result_t result; 207 1.19 christos } checksig_ctx_t; 208 1.19 christos 209 1.19 christos /* 210 1.19 christos * This function differs from public dns_message_puttemprdataset() that it 211 1.19 christos * requires the *rdatasetp to be associated, and it will disassociate and 212 1.19 christos * put it back to the memory pool. 213 1.19 christos */ 214 1.19 christos static void 215 1.19 christos dns__message_putassociatedrdataset(dns_message_t *msg, 216 1.19 christos dns_rdataset_t **rdatasetp); 217 1.19 christos 218 1.14 christos static void * 219 1.1 christos msgblock_internalget(dns_msgblock_t *, unsigned int); 220 1.1 christos 221 1.14 christos static void 222 1.1 christos msgblock_reset(dns_msgblock_t *); 223 1.1 christos 224 1.14 christos static void 225 1.1 christos msgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int); 226 1.1 christos 227 1.1 christos static void 228 1.1 christos logfmtpacket(dns_message_t *message, const char *description, 229 1.1 christos const isc_sockaddr_t *address, isc_logcategory_t *category, 230 1.1 christos isc_logmodule_t *module, const dns_master_style_t *style, 231 1.1 christos int level, isc_mem_t *mctx); 232 1.1 christos 233 1.1 christos /* 234 1.1 christos * Allocate a new dns_msgblock_t, and return a pointer to it. If no memory 235 1.1 christos * is free, return NULL. 236 1.1 christos */ 237 1.14 christos static dns_msgblock_t * 238 1.1 christos msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type, 239 1.9 christos unsigned int count) { 240 1.1 christos dns_msgblock_t *block; 241 1.1 christos unsigned int length; 242 1.1 christos 243 1.1 christos length = sizeof(dns_msgblock_t) + (sizeof_type * count); 244 1.1 christos 245 1.1 christos block = isc_mem_get(mctx, length); 246 1.1 christos 247 1.1 christos block->count = count; 248 1.1 christos block->remaining = count; 249 1.1 christos 250 1.1 christos ISC_LINK_INIT(block, link); 251 1.1 christos 252 1.19 christos return block; 253 1.1 christos } 254 1.1 christos 255 1.1 christos /* 256 1.1 christos * Return an element from the msgblock. If no more are available, return 257 1.1 christos * NULL. 258 1.1 christos */ 259 1.14 christos static void * 260 1.1 christos msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) { 261 1.1 christos void *ptr; 262 1.1 christos 263 1.9 christos if (block == NULL || block->remaining == 0) { 264 1.19 christos return NULL; 265 1.9 christos } 266 1.1 christos 267 1.1 christos block->remaining--; 268 1.1 christos 269 1.9 christos ptr = (((unsigned char *)block) + sizeof(dns_msgblock_t) + 270 1.9 christos (sizeof_type * block->remaining)); 271 1.1 christos 272 1.19 christos return ptr; 273 1.1 christos } 274 1.1 christos 275 1.14 christos static void 276 1.1 christos msgblock_reset(dns_msgblock_t *block) { 277 1.1 christos block->remaining = block->count; 278 1.1 christos } 279 1.1 christos 280 1.1 christos /* 281 1.1 christos * Release memory associated with a message block. 282 1.1 christos */ 283 1.14 christos static void 284 1.9 christos msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, 285 1.9 christos unsigned int sizeof_type) { 286 1.1 christos unsigned int length; 287 1.1 christos 288 1.1 christos length = sizeof(dns_msgblock_t) + (sizeof_type * block->count); 289 1.1 christos 290 1.1 christos isc_mem_put(mctx, block, length); 291 1.1 christos } 292 1.1 christos 293 1.1 christos /* 294 1.1 christos * Allocate a new dynamic buffer, and attach it to this message as the 295 1.1 christos * "current" buffer. (which is always the last on the list, for our 296 1.1 christos * uses) 297 1.1 christos */ 298 1.14 christos static isc_result_t 299 1.1 christos newbuffer(dns_message_t *msg, unsigned int size) { 300 1.1 christos isc_buffer_t *dynbuf; 301 1.1 christos 302 1.1 christos dynbuf = NULL; 303 1.9 christos isc_buffer_allocate(msg->mctx, &dynbuf, size); 304 1.1 christos 305 1.1 christos ISC_LIST_APPEND(msg->scratchpad, dynbuf, link); 306 1.19 christos return ISC_R_SUCCESS; 307 1.1 christos } 308 1.1 christos 309 1.14 christos static isc_buffer_t * 310 1.1 christos currentbuffer(dns_message_t *msg) { 311 1.1 christos isc_buffer_t *dynbuf; 312 1.1 christos 313 1.1 christos dynbuf = ISC_LIST_TAIL(msg->scratchpad); 314 1.1 christos INSIST(dynbuf != NULL); 315 1.1 christos 316 1.19 christos return dynbuf; 317 1.1 christos } 318 1.1 christos 319 1.14 christos static void 320 1.1 christos releaserdata(dns_message_t *msg, dns_rdata_t *rdata) { 321 1.1 christos ISC_LIST_PREPEND(msg->freerdata, rdata, link); 322 1.1 christos } 323 1.1 christos 324 1.14 christos static dns_rdata_t * 325 1.1 christos newrdata(dns_message_t *msg) { 326 1.1 christos dns_msgblock_t *msgblock; 327 1.1 christos dns_rdata_t *rdata; 328 1.1 christos 329 1.1 christos rdata = ISC_LIST_HEAD(msg->freerdata); 330 1.1 christos if (rdata != NULL) { 331 1.1 christos ISC_LIST_UNLINK(msg->freerdata, rdata, link); 332 1.19 christos return rdata; 333 1.1 christos } 334 1.1 christos 335 1.1 christos msgblock = ISC_LIST_TAIL(msg->rdatas); 336 1.1 christos rdata = msgblock_get(msgblock, dns_rdata_t); 337 1.1 christos if (rdata == NULL) { 338 1.1 christos msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t), 339 1.1 christos RDATA_COUNT); 340 1.1 christos ISC_LIST_APPEND(msg->rdatas, msgblock, link); 341 1.1 christos 342 1.1 christos rdata = msgblock_get(msgblock, dns_rdata_t); 343 1.1 christos } 344 1.1 christos 345 1.1 christos dns_rdata_init(rdata); 346 1.19 christos return rdata; 347 1.1 christos } 348 1.1 christos 349 1.14 christos static void 350 1.1 christos releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) { 351 1.1 christos ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link); 352 1.1 christos } 353 1.1 christos 354 1.14 christos static dns_rdatalist_t * 355 1.1 christos newrdatalist(dns_message_t *msg) { 356 1.1 christos dns_msgblock_t *msgblock; 357 1.1 christos dns_rdatalist_t *rdatalist; 358 1.1 christos 359 1.1 christos rdatalist = ISC_LIST_HEAD(msg->freerdatalist); 360 1.1 christos if (rdatalist != NULL) { 361 1.1 christos ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link); 362 1.1 christos goto out; 363 1.1 christos } 364 1.1 christos 365 1.1 christos msgblock = ISC_LIST_TAIL(msg->rdatalists); 366 1.1 christos rdatalist = msgblock_get(msgblock, dns_rdatalist_t); 367 1.1 christos if (rdatalist == NULL) { 368 1.9 christos msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdatalist_t), 369 1.1 christos RDATALIST_COUNT); 370 1.1 christos ISC_LIST_APPEND(msg->rdatalists, msgblock, link); 371 1.1 christos 372 1.1 christos rdatalist = msgblock_get(msgblock, dns_rdatalist_t); 373 1.1 christos } 374 1.9 christos out: 375 1.17 christos dns_rdatalist_init(rdatalist); 376 1.19 christos return rdatalist; 377 1.1 christos } 378 1.1 christos 379 1.14 christos static dns_offsets_t * 380 1.1 christos newoffsets(dns_message_t *msg) { 381 1.1 christos dns_msgblock_t *msgblock; 382 1.1 christos dns_offsets_t *offsets; 383 1.1 christos 384 1.1 christos msgblock = ISC_LIST_TAIL(msg->offsets); 385 1.1 christos offsets = msgblock_get(msgblock, dns_offsets_t); 386 1.1 christos if (offsets == NULL) { 387 1.9 christos msgblock = msgblock_allocate(msg->mctx, sizeof(dns_offsets_t), 388 1.1 christos OFFSET_COUNT); 389 1.1 christos ISC_LIST_APPEND(msg->offsets, msgblock, link); 390 1.1 christos 391 1.1 christos offsets = msgblock_get(msgblock, dns_offsets_t); 392 1.1 christos } 393 1.1 christos 394 1.19 christos return offsets; 395 1.1 christos } 396 1.1 christos 397 1.14 christos static void 398 1.1 christos msginitheader(dns_message_t *m) { 399 1.1 christos m->id = 0; 400 1.1 christos m->flags = 0; 401 1.1 christos m->rcode = 0; 402 1.1 christos m->opcode = 0; 403 1.1 christos m->rdclass = 0; 404 1.1 christos } 405 1.1 christos 406 1.14 christos static void 407 1.1 christos msginitprivate(dns_message_t *m) { 408 1.1 christos unsigned int i; 409 1.1 christos 410 1.1 christos for (i = 0; i < DNS_SECTION_MAX; i++) { 411 1.1 christos m->cursors[i] = NULL; 412 1.1 christos m->counts[i] = 0; 413 1.1 christos } 414 1.1 christos m->opt = NULL; 415 1.1 christos m->sig0 = NULL; 416 1.1 christos m->sig0name = NULL; 417 1.1 christos m->tsig = NULL; 418 1.1 christos m->tsigname = NULL; 419 1.9 christos m->state = DNS_SECTION_ANY; /* indicate nothing parsed or rendered */ 420 1.1 christos m->opt_reserved = 0; 421 1.1 christos m->sig_reserved = 0; 422 1.1 christos m->reserved = 0; 423 1.1 christos m->padding = 0; 424 1.1 christos m->padding_off = 0; 425 1.1 christos m->buffer = NULL; 426 1.1 christos } 427 1.1 christos 428 1.14 christos static void 429 1.1 christos msginittsig(dns_message_t *m) { 430 1.1 christos m->tsigstatus = dns_rcode_noerror; 431 1.1 christos m->querytsigstatus = dns_rcode_noerror; 432 1.1 christos m->tsigkey = NULL; 433 1.1 christos m->tsigctx = NULL; 434 1.1 christos m->sigstart = -1; 435 1.1 christos m->sig0key = NULL; 436 1.1 christos m->sig0status = dns_rcode_noerror; 437 1.1 christos m->timeadjust = 0; 438 1.1 christos } 439 1.1 christos 440 1.1 christos /* 441 1.1 christos * Init elements to default state. Used both when allocating a new element 442 1.1 christos * and when resetting one. 443 1.1 christos */ 444 1.14 christos static void 445 1.1 christos msginit(dns_message_t *m) { 446 1.1 christos msginitheader(m); 447 1.1 christos msginitprivate(m); 448 1.1 christos msginittsig(m); 449 1.1 christos m->header_ok = 0; 450 1.1 christos m->question_ok = 0; 451 1.1 christos m->tcp_continuation = 0; 452 1.1 christos m->verified_sig = 0; 453 1.1 christos m->verify_attempted = 0; 454 1.1 christos m->order = NULL; 455 1.1 christos m->order_arg.env = NULL; 456 1.1 christos m->order_arg.acl = NULL; 457 1.1 christos m->order_arg.element = NULL; 458 1.1 christos m->query.base = NULL; 459 1.1 christos m->query.length = 0; 460 1.1 christos m->free_query = 0; 461 1.1 christos m->saved.base = NULL; 462 1.1 christos m->saved.length = 0; 463 1.1 christos m->free_saved = 0; 464 1.1 christos m->cc_ok = 0; 465 1.1 christos m->cc_bad = 0; 466 1.1 christos m->tkey = 0; 467 1.1 christos m->rdclass_set = 0; 468 1.22 christos m->has_dname = 0; 469 1.1 christos m->querytsig = NULL; 470 1.9 christos m->indent.string = "\t"; 471 1.9 christos m->indent.count = 0; 472 1.1 christos } 473 1.1 christos 474 1.14 christos static void 475 1.19 christos msgresetname(dns_message_t *msg, dns_name_t *name) { 476 1.19 christos dns_rdataset_t *rds = NULL, *next_rds = NULL; 477 1.19 christos 478 1.22 christos ISC_LIST_FOREACH_SAFE(name->list, rds, link, next_rds) { 479 1.19 christos ISC_LIST_UNLINK(name->list, rds, link); 480 1.19 christos 481 1.19 christos dns__message_putassociatedrdataset(msg, &rds); 482 1.19 christos } 483 1.19 christos } 484 1.19 christos 485 1.19 christos static void 486 1.1 christos msgresetnames(dns_message_t *msg, unsigned int first_section) { 487 1.19 christos /* Clean up name lists. */ 488 1.19 christos for (size_t i = first_section; i < DNS_SECTION_MAX; i++) { 489 1.19 christos dns_name_t *name = NULL, *next_name = NULL; 490 1.1 christos 491 1.22 christos ISC_LIST_FOREACH_SAFE(msg->sections[i], name, link, next_name) { 492 1.1 christos ISC_LIST_UNLINK(msg->sections[i], name, link); 493 1.1 christos 494 1.19 christos msgresetname(msg, name); 495 1.19 christos 496 1.13 christos dns_message_puttempname(msg, &name); 497 1.1 christos } 498 1.1 christos } 499 1.1 christos } 500 1.1 christos 501 1.1 christos static void 502 1.9 christos msgresetopt(dns_message_t *msg) { 503 1.1 christos if (msg->opt != NULL) { 504 1.1 christos if (msg->opt_reserved > 0) { 505 1.1 christos dns_message_renderrelease(msg, msg->opt_reserved); 506 1.1 christos msg->opt_reserved = 0; 507 1.1 christos } 508 1.19 christos dns__message_putassociatedrdataset(msg, &msg->opt); 509 1.1 christos msg->opt = NULL; 510 1.1 christos msg->cc_ok = 0; 511 1.1 christos msg->cc_bad = 0; 512 1.1 christos } 513 1.1 christos } 514 1.1 christos 515 1.1 christos static void 516 1.3 christos msgresetsigs(dns_message_t *msg, bool replying) { 517 1.1 christos if (msg->sig_reserved > 0) { 518 1.1 christos dns_message_renderrelease(msg, msg->sig_reserved); 519 1.1 christos msg->sig_reserved = 0; 520 1.1 christos } 521 1.1 christos if (msg->tsig != NULL) { 522 1.1 christos INSIST(dns_rdataset_isassociated(msg->tsig)); 523 1.1 christos INSIST(msg->namepool != NULL); 524 1.1 christos if (replying) { 525 1.1 christos INSIST(msg->querytsig == NULL); 526 1.1 christos msg->querytsig = msg->tsig; 527 1.1 christos } else { 528 1.19 christos dns__message_putassociatedrdataset(msg, &msg->tsig); 529 1.1 christos if (msg->querytsig != NULL) { 530 1.19 christos dns__message_putassociatedrdataset( 531 1.19 christos msg, &msg->querytsig); 532 1.1 christos } 533 1.1 christos } 534 1.13 christos dns_message_puttempname(msg, &msg->tsigname); 535 1.1 christos msg->tsig = NULL; 536 1.1 christos } else if (msg->querytsig != NULL && !replying) { 537 1.19 christos dns__message_putassociatedrdataset(msg, &msg->querytsig); 538 1.1 christos msg->querytsig = NULL; 539 1.1 christos } 540 1.1 christos if (msg->sig0 != NULL) { 541 1.19 christos dns__message_putassociatedrdataset(msg, &msg->sig0); 542 1.1 christos msg->sig0 = NULL; 543 1.17 christos } 544 1.17 christos if (msg->sig0name != NULL) { 545 1.17 christos dns_message_puttempname(msg, &msg->sig0name); 546 1.1 christos } 547 1.1 christos } 548 1.1 christos 549 1.1 christos /* 550 1.1 christos * Free all but one (or everything) for this message. This is used by 551 1.11 christos * both dns_message_reset() and dns__message_destroy(). 552 1.1 christos */ 553 1.1 christos static void 554 1.3 christos msgreset(dns_message_t *msg, bool everything) { 555 1.19 christos dns_msgblock_t *msgblock = NULL, *next_msgblock = NULL; 556 1.19 christos isc_buffer_t *dynbuf = NULL, *next_dynbuf = NULL; 557 1.19 christos dns_rdata_t *rdata = NULL; 558 1.19 christos dns_rdatalist_t *rdatalist = NULL; 559 1.1 christos 560 1.1 christos msgresetnames(msg, 0); 561 1.1 christos msgresetopt(msg); 562 1.3 christos msgresetsigs(msg, false); 563 1.1 christos 564 1.1 christos /* 565 1.1 christos * Clean up linked lists. 566 1.1 christos */ 567 1.1 christos 568 1.1 christos /* 569 1.1 christos * Run through the free lists, and just unlink anything found there. 570 1.1 christos * The memory isn't lost since these are part of message blocks we 571 1.1 christos * have allocated. 572 1.1 christos */ 573 1.1 christos rdata = ISC_LIST_HEAD(msg->freerdata); 574 1.1 christos while (rdata != NULL) { 575 1.1 christos ISC_LIST_UNLINK(msg->freerdata, rdata, link); 576 1.1 christos rdata = ISC_LIST_HEAD(msg->freerdata); 577 1.1 christos } 578 1.1 christos rdatalist = ISC_LIST_HEAD(msg->freerdatalist); 579 1.1 christos while (rdatalist != NULL) { 580 1.1 christos ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link); 581 1.1 christos rdatalist = ISC_LIST_HEAD(msg->freerdatalist); 582 1.1 christos } 583 1.1 christos 584 1.1 christos dynbuf = ISC_LIST_HEAD(msg->scratchpad); 585 1.1 christos INSIST(dynbuf != NULL); 586 1.1 christos if (!everything) { 587 1.1 christos isc_buffer_clear(dynbuf); 588 1.1 christos dynbuf = ISC_LIST_NEXT(dynbuf, link); 589 1.1 christos } 590 1.1 christos while (dynbuf != NULL) { 591 1.1 christos next_dynbuf = ISC_LIST_NEXT(dynbuf, link); 592 1.1 christos ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link); 593 1.1 christos isc_buffer_free(&dynbuf); 594 1.1 christos dynbuf = next_dynbuf; 595 1.1 christos } 596 1.1 christos 597 1.1 christos msgblock = ISC_LIST_HEAD(msg->rdatas); 598 1.1 christos if (!everything && msgblock != NULL) { 599 1.1 christos msgblock_reset(msgblock); 600 1.1 christos msgblock = ISC_LIST_NEXT(msgblock, link); 601 1.1 christos } 602 1.1 christos while (msgblock != NULL) { 603 1.1 christos next_msgblock = ISC_LIST_NEXT(msgblock, link); 604 1.1 christos ISC_LIST_UNLINK(msg->rdatas, msgblock, link); 605 1.1 christos msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t)); 606 1.1 christos msgblock = next_msgblock; 607 1.1 christos } 608 1.1 christos 609 1.1 christos /* 610 1.1 christos * rdatalists could be empty. 611 1.1 christos */ 612 1.1 christos 613 1.1 christos msgblock = ISC_LIST_HEAD(msg->rdatalists); 614 1.1 christos if (!everything && msgblock != NULL) { 615 1.1 christos msgblock_reset(msgblock); 616 1.1 christos msgblock = ISC_LIST_NEXT(msgblock, link); 617 1.1 christos } 618 1.1 christos while (msgblock != NULL) { 619 1.1 christos next_msgblock = ISC_LIST_NEXT(msgblock, link); 620 1.1 christos ISC_LIST_UNLINK(msg->rdatalists, msgblock, link); 621 1.1 christos msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t)); 622 1.1 christos msgblock = next_msgblock; 623 1.1 christos } 624 1.1 christos 625 1.1 christos msgblock = ISC_LIST_HEAD(msg->offsets); 626 1.1 christos if (!everything && msgblock != NULL) { 627 1.1 christos msgblock_reset(msgblock); 628 1.1 christos msgblock = ISC_LIST_NEXT(msgblock, link); 629 1.1 christos } 630 1.1 christos while (msgblock != NULL) { 631 1.1 christos next_msgblock = ISC_LIST_NEXT(msgblock, link); 632 1.1 christos ISC_LIST_UNLINK(msg->offsets, msgblock, link); 633 1.1 christos msgblock_free(msg->mctx, msgblock, sizeof(dns_offsets_t)); 634 1.1 christos msgblock = next_msgblock; 635 1.1 christos } 636 1.1 christos 637 1.1 christos if (msg->tsigkey != NULL) { 638 1.1 christos dns_tsigkey_detach(&msg->tsigkey); 639 1.1 christos msg->tsigkey = NULL; 640 1.1 christos } 641 1.1 christos 642 1.9 christos if (msg->tsigctx != NULL) { 643 1.1 christos dst_context_destroy(&msg->tsigctx); 644 1.9 christos } 645 1.1 christos 646 1.1 christos if (msg->query.base != NULL) { 647 1.9 christos if (msg->free_query != 0) { 648 1.1 christos isc_mem_put(msg->mctx, msg->query.base, 649 1.1 christos msg->query.length); 650 1.9 christos } 651 1.1 christos msg->query.base = NULL; 652 1.1 christos msg->query.length = 0; 653 1.1 christos } 654 1.1 christos 655 1.1 christos if (msg->saved.base != NULL) { 656 1.9 christos if (msg->free_saved != 0) { 657 1.1 christos isc_mem_put(msg->mctx, msg->saved.base, 658 1.1 christos msg->saved.length); 659 1.9 christos } 660 1.1 christos msg->saved.base = NULL; 661 1.1 christos msg->saved.length = 0; 662 1.1 christos } 663 1.1 christos 664 1.1 christos /* 665 1.1 christos * cleanup the buffer cleanup list 666 1.1 christos */ 667 1.1 christos dynbuf = ISC_LIST_HEAD(msg->cleanup); 668 1.1 christos while (dynbuf != NULL) { 669 1.1 christos next_dynbuf = ISC_LIST_NEXT(dynbuf, link); 670 1.1 christos ISC_LIST_UNLINK(msg->cleanup, dynbuf, link); 671 1.1 christos isc_buffer_free(&dynbuf); 672 1.1 christos dynbuf = next_dynbuf; 673 1.1 christos } 674 1.1 christos 675 1.17 christos if (msg->order_arg.env != NULL) { 676 1.17 christos dns_aclenv_detach(&msg->order_arg.env); 677 1.17 christos } 678 1.17 christos if (msg->order_arg.acl != NULL) { 679 1.17 christos dns_acl_detach(&msg->order_arg.acl); 680 1.17 christos } 681 1.17 christos 682 1.1 christos /* 683 1.1 christos * Set other bits to normal default values. 684 1.1 christos */ 685 1.9 christos if (!everything) { 686 1.1 christos msginit(msg); 687 1.9 christos } 688 1.1 christos } 689 1.1 christos 690 1.1 christos static unsigned int 691 1.1 christos spacefortsig(dns_tsigkey_t *key, int otherlen) { 692 1.20 christos isc_region_t r1 = { 0 }, r2 = { 0 }; 693 1.20 christos unsigned int x = 0; 694 1.1 christos 695 1.1 christos /* 696 1.20 christos * The space required for a TSIG record is: 697 1.1 christos * 698 1.1 christos * n1 bytes for the name 699 1.1 christos * 2 bytes for the type 700 1.1 christos * 2 bytes for the class 701 1.1 christos * 4 bytes for the ttl 702 1.1 christos * 2 bytes for the rdlength 703 1.1 christos * n2 bytes for the algorithm name 704 1.1 christos * 6 bytes for the time signed 705 1.1 christos * 2 bytes for the fudge 706 1.1 christos * 2 bytes for the MAC size 707 1.1 christos * x bytes for the MAC 708 1.1 christos * 2 bytes for the original id 709 1.1 christos * 2 bytes for the error 710 1.1 christos * 2 bytes for the other data length 711 1.1 christos * y bytes for the other data (at most) 712 1.1 christos * --------------------------------- 713 1.1 christos * 26 + n1 + n2 + x + y bytes 714 1.1 christos */ 715 1.1 christos 716 1.19 christos dns_name_toregion(key->name, &r1); 717 1.20 christos if (key->alg != DST_ALG_UNKNOWN) { 718 1.20 christos dns_name_toregion(dns_tsigkey_algorithm(key), &r2); 719 1.20 christos } 720 1.20 christos if (key->key != NULL) { 721 1.20 christos isc_result_t result = dst_key_sigsize(key->key, &x); 722 1.9 christos if (result != ISC_R_SUCCESS) { 723 1.1 christos x = 0; 724 1.9 christos } 725 1.1 christos } 726 1.19 christos return 26 + r1.length + r2.length + x + otherlen; 727 1.1 christos } 728 1.1 christos 729 1.11 christos void 730 1.19 christos dns_message_create(isc_mem_t *mctx, isc_mempool_t *namepool, 731 1.19 christos isc_mempool_t *rdspool, dns_message_intent_t intent, 732 1.19 christos dns_message_t **msgp) { 733 1.1 christos REQUIRE(mctx != NULL); 734 1.1 christos REQUIRE(msgp != NULL); 735 1.1 christos REQUIRE(*msgp == NULL); 736 1.9 christos REQUIRE(intent == DNS_MESSAGE_INTENTPARSE || 737 1.9 christos intent == DNS_MESSAGE_INTENTRENDER); 738 1.19 christos REQUIRE((namepool != NULL && rdspool != NULL) || 739 1.19 christos (namepool == NULL && rdspool == NULL)); 740 1.1 christos 741 1.19 christos dns_message_t *msg = isc_mem_get(mctx, sizeof(dns_message_t)); 742 1.19 christos *msg = (dns_message_t){ 743 1.19 christos .from_to_wire = intent, 744 1.19 christos .references = ISC_REFCOUNT_INITIALIZER(1), 745 1.19 christos .scratchpad = ISC_LIST_INITIALIZER, 746 1.19 christos .cleanup = ISC_LIST_INITIALIZER, 747 1.19 christos .rdatas = ISC_LIST_INITIALIZER, 748 1.19 christos .rdatalists = ISC_LIST_INITIALIZER, 749 1.19 christos .offsets = ISC_LIST_INITIALIZER, 750 1.19 christos .freerdata = ISC_LIST_INITIALIZER, 751 1.19 christos .freerdatalist = ISC_LIST_INITIALIZER, 752 1.19 christos .magic = DNS_MESSAGE_MAGIC, 753 1.19 christos .namepool = namepool, 754 1.19 christos .rdspool = rdspool, 755 1.19 christos .free_pools = (namepool == NULL && rdspool == NULL), 756 1.19 christos }; 757 1.19 christos 758 1.19 christos isc_mem_attach(mctx, &msg->mctx); 759 1.1 christos 760 1.19 christos if (msg->free_pools) { 761 1.19 christos dns_message_createpools(mctx, &msg->namepool, &msg->rdspool); 762 1.9 christos } 763 1.1 christos 764 1.19 christos msginit(msg); 765 1.19 christos 766 1.19 christos for (size_t i = 0; i < DNS_SECTION_MAX; i++) { 767 1.19 christos ISC_LIST_INIT(msg->sections[i]); 768 1.19 christos } 769 1.1 christos 770 1.19 christos isc_buffer_t *dynbuf = NULL; 771 1.9 christos isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE); 772 1.19 christos ISC_LIST_APPEND(msg->scratchpad, dynbuf, link); 773 1.11 christos 774 1.19 christos *msgp = msg; 775 1.1 christos } 776 1.1 christos 777 1.1 christos void 778 1.19 christos dns_message_reset(dns_message_t *msg, dns_message_intent_t intent) { 779 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 780 1.9 christos REQUIRE(intent == DNS_MESSAGE_INTENTPARSE || 781 1.9 christos intent == DNS_MESSAGE_INTENTRENDER); 782 1.1 christos 783 1.3 christos msgreset(msg, false); 784 1.1 christos msg->from_to_wire = intent; 785 1.1 christos } 786 1.1 christos 787 1.11 christos static void 788 1.11 christos dns__message_destroy(dns_message_t *msg) { 789 1.11 christos REQUIRE(msg != NULL); 790 1.11 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 791 1.1 christos 792 1.3 christos msgreset(msg, true); 793 1.19 christos 794 1.1 christos msg->magic = 0; 795 1.1 christos 796 1.19 christos if (msg->free_pools) { 797 1.19 christos dns_message_destroypools(&msg->namepool, &msg->rdspool); 798 1.19 christos } 799 1.11 christos 800 1.19 christos isc_mem_putanddetach(&msg->mctx, msg, sizeof(dns_message_t)); 801 1.11 christos } 802 1.11 christos 803 1.19 christos #if DNS_MESSAGE_TRACE 804 1.19 christos ISC_REFCOUNT_TRACE_IMPL(dns_message, dns__message_destroy); 805 1.19 christos #else 806 1.19 christos ISC_REFCOUNT_IMPL(dns_message, dns__message_destroy); 807 1.19 christos #endif 808 1.11 christos 809 1.19 christos static bool 810 1.19 christos name_match(void *node, const void *key) { 811 1.19 christos return dns_name_equal(node, key); 812 1.16 christos } 813 1.16 christos 814 1.16 christos static isc_result_t 815 1.1 christos findname(dns_name_t **foundname, const dns_name_t *target, 816 1.9 christos dns_namelist_t *section) { 817 1.19 christos dns_name_t *name = NULL; 818 1.1 christos 819 1.22 christos ISC_LIST_FOREACH_REV(*section, name, link) { 820 1.19 christos if (dns_name_equal(name, target)) { 821 1.9 christos if (foundname != NULL) { 822 1.19 christos *foundname = name; 823 1.9 christos } 824 1.19 christos return ISC_R_SUCCESS; 825 1.1 christos } 826 1.1 christos } 827 1.1 christos 828 1.19 christos return ISC_R_NOTFOUND; 829 1.19 christos } 830 1.19 christos 831 1.19 christos static uint32_t 832 1.19 christos rds_hash(dns_rdataset_t *rds) { 833 1.19 christos isc_hash32_t state; 834 1.19 christos 835 1.19 christos isc_hash32_init(&state); 836 1.19 christos isc_hash32_hash(&state, &rds->rdclass, sizeof(rds->rdclass), true); 837 1.19 christos isc_hash32_hash(&state, &rds->type, sizeof(rds->type), true); 838 1.19 christos isc_hash32_hash(&state, &rds->covers, sizeof(rds->covers), true); 839 1.19 christos 840 1.19 christos return isc_hash32_finalize(&state); 841 1.1 christos } 842 1.1 christos 843 1.19 christos static bool 844 1.19 christos rds_match(void *node, const void *key0) { 845 1.19 christos const dns_rdataset_t *rds = node; 846 1.19 christos const dns_rdataset_t *key = key0; 847 1.1 christos 848 1.19 christos return rds->rdclass == key->rdclass && rds->type == key->type && 849 1.19 christos rds->covers == key->covers; 850 1.1 christos } 851 1.1 christos 852 1.1 christos isc_result_t 853 1.1 christos dns_message_findtype(const dns_name_t *name, dns_rdatatype_t type, 854 1.19 christos dns_rdatatype_t covers, dns_rdataset_t **rdatasetp) { 855 1.19 christos dns_rdataset_t *rds = NULL; 856 1.1 christos 857 1.1 christos REQUIRE(name != NULL); 858 1.19 christos REQUIRE(rdatasetp == NULL || *rdatasetp == NULL); 859 1.19 christos 860 1.22 christos ISC_LIST_FOREACH_REV(name->list, rds, link) { 861 1.19 christos if (rds->type == type && rds->covers == covers) { 862 1.19 christos SET_IF_NOT_NULL(rdatasetp, rds); 863 1.1 christos 864 1.19 christos return ISC_R_SUCCESS; 865 1.1 christos } 866 1.1 christos } 867 1.1 christos 868 1.19 christos return ISC_R_NOTFOUND; 869 1.1 christos } 870 1.1 christos 871 1.1 christos /* 872 1.1 christos * Read a name from buffer "source". 873 1.1 christos */ 874 1.1 christos static isc_result_t 875 1.1 christos getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg, 876 1.19 christos dns_decompress_t dctx) { 877 1.1 christos isc_buffer_t *scratch; 878 1.1 christos isc_result_t result; 879 1.1 christos unsigned int tries; 880 1.1 christos 881 1.1 christos scratch = currentbuffer(msg); 882 1.1 christos 883 1.1 christos /* 884 1.1 christos * First try: use current buffer. 885 1.1 christos * Second try: allocate a new buffer and use that. 886 1.1 christos */ 887 1.1 christos tries = 0; 888 1.1 christos while (tries < 2) { 889 1.19 christos result = dns_name_fromwire(name, source, dctx, scratch); 890 1.1 christos 891 1.1 christos if (result == ISC_R_NOSPACE) { 892 1.1 christos tries++; 893 1.1 christos 894 1.1 christos result = newbuffer(msg, SCRATCHPAD_SIZE); 895 1.9 christos if (result != ISC_R_SUCCESS) { 896 1.19 christos return result; 897 1.9 christos } 898 1.1 christos 899 1.1 christos scratch = currentbuffer(msg); 900 1.1 christos dns_name_reset(name); 901 1.1 christos } else { 902 1.19 christos return result; 903 1.1 christos } 904 1.1 christos } 905 1.1 christos 906 1.14 christos UNREACHABLE(); 907 1.1 christos } 908 1.1 christos 909 1.1 christos static isc_result_t 910 1.19 christos getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx, 911 1.1 christos dns_rdataclass_t rdclass, dns_rdatatype_t rdtype, 912 1.9 christos unsigned int rdatalen, dns_rdata_t *rdata) { 913 1.1 christos isc_buffer_t *scratch; 914 1.1 christos isc_result_t result; 915 1.1 christos unsigned int tries; 916 1.1 christos unsigned int trysize; 917 1.1 christos 918 1.1 christos scratch = currentbuffer(msg); 919 1.1 christos 920 1.1 christos isc_buffer_setactive(source, rdatalen); 921 1.1 christos 922 1.1 christos /* 923 1.1 christos * First try: use current buffer. 924 1.1 christos * Second try: allocate a new buffer of size 925 1.1 christos * max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen) 926 1.1 christos * (the data will fit if it was not more than 50% compressed) 927 1.1 christos * Subsequent tries: double buffer size on each try. 928 1.1 christos */ 929 1.1 christos tries = 0; 930 1.1 christos trysize = 0; 931 1.1 christos /* XXX possibly change this to a while (tries < 2) loop */ 932 1.1 christos for (;;) { 933 1.9 christos result = dns_rdata_fromwire(rdata, rdclass, rdtype, source, 934 1.19 christos dctx, scratch); 935 1.1 christos 936 1.1 christos if (result == ISC_R_NOSPACE) { 937 1.1 christos if (tries == 0) { 938 1.1 christos trysize = 2 * rdatalen; 939 1.9 christos if (trysize < SCRATCHPAD_SIZE) { 940 1.1 christos trysize = SCRATCHPAD_SIZE; 941 1.9 christos } 942 1.1 christos } else { 943 1.1 christos INSIST(trysize != 0); 944 1.9 christos if (trysize >= 65535) { 945 1.19 christos return ISC_R_NOSPACE; 946 1.9 christos } 947 1.9 christos /* XXX DNS_R_RRTOOLONG? */ 948 1.1 christos trysize *= 2; 949 1.1 christos } 950 1.1 christos tries++; 951 1.1 christos result = newbuffer(msg, trysize); 952 1.9 christos if (result != ISC_R_SUCCESS) { 953 1.19 christos return result; 954 1.9 christos } 955 1.1 christos 956 1.1 christos scratch = currentbuffer(msg); 957 1.1 christos } else { 958 1.19 christos return result; 959 1.1 christos } 960 1.1 christos } 961 1.1 christos } 962 1.1 christos 963 1.9 christos #define DO_ERROR(r) \ 964 1.9 christos do { \ 965 1.9 christos if (best_effort) { \ 966 1.9 christos seen_problem = true; \ 967 1.9 christos } else { \ 968 1.9 christos result = r; \ 969 1.9 christos goto cleanup; \ 970 1.9 christos } \ 971 1.12 rillig } while (0) 972 1.1 christos 973 1.16 christos static void 974 1.16 christos cleanup_name_hashmaps(dns_namelist_t *section) { 975 1.16 christos dns_name_t *name = NULL; 976 1.22 christos ISC_LIST_FOREACH(*section, name, link) { 977 1.19 christos if (name->hashmap != NULL) { 978 1.19 christos isc_hashmap_destroy(&name->hashmap); 979 1.16 christos } 980 1.16 christos } 981 1.16 christos } 982 1.16 christos 983 1.1 christos static isc_result_t 984 1.19 christos getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx, 985 1.9 christos unsigned int options) { 986 1.1 christos isc_region_t r; 987 1.1 christos unsigned int count; 988 1.13 christos dns_name_t *name = NULL; 989 1.19 christos dns_name_t *found_name = NULL; 990 1.13 christos dns_rdataset_t *rdataset = NULL; 991 1.13 christos dns_rdatalist_t *rdatalist = NULL; 992 1.16 christos isc_result_t result = ISC_R_SUCCESS; 993 1.1 christos dns_rdatatype_t rdtype; 994 1.1 christos dns_rdataclass_t rdclass; 995 1.13 christos dns_namelist_t *section = &msg->sections[DNS_SECTION_QUESTION]; 996 1.13 christos bool best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0); 997 1.13 christos bool seen_problem = false; 998 1.13 christos bool free_name = false; 999 1.19 christos bool free_hashmaps = false; 1000 1.19 christos isc_hashmap_t *name_map = NULL; 1001 1.16 christos 1002 1.16 christos if (msg->counts[DNS_SECTION_QUESTION] > 1) { 1003 1.19 christos isc_hashmap_create(msg->mctx, 1, &name_map); 1004 1.16 christos } 1005 1.1 christos 1006 1.1 christos for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) { 1007 1.13 christos name = NULL; 1008 1.19 christos dns_message_gettempname(msg, &name); 1009 1.13 christos name->offsets = (unsigned char *)newoffsets(msg); 1010 1.3 christos free_name = true; 1011 1.1 christos 1012 1.1 christos /* 1013 1.1 christos * Parse the name out of this packet. 1014 1.1 christos */ 1015 1.1 christos isc_buffer_remainingregion(source, &r); 1016 1.1 christos isc_buffer_setactive(source, r.length); 1017 1.1 christos result = getname(name, source, msg, dctx); 1018 1.9 christos if (result != ISC_R_SUCCESS) { 1019 1.1 christos goto cleanup; 1020 1.9 christos } 1021 1.1 christos 1022 1.16 christos /* If there is only one QNAME, skip the duplicity checks */ 1023 1.16 christos if (name_map == NULL) { 1024 1.16 christos result = ISC_R_SUCCESS; 1025 1.16 christos goto skip_name_check; 1026 1.16 christos } 1027 1.16 christos 1028 1.1 christos /* 1029 1.1 christos * Run through the section, looking to see if this name 1030 1.1 christos * is already there. If it is found, put back the allocated 1031 1.1 christos * name since we no longer need it, and set our name pointer 1032 1.1 christos * to point to the name we found. 1033 1.1 christos */ 1034 1.19 christos result = isc_hashmap_add(name_map, dns_name_hash(name), 1035 1.19 christos name_match, name, name, 1036 1.19 christos (void **)&found_name); 1037 1.1 christos 1038 1.1 christos /* 1039 1.1 christos * If it is the first name in the section, accept it. 1040 1.1 christos * 1041 1.1 christos * If it is not, but is not the same as the name already 1042 1.1 christos * in the question section, append to the section. Note that 1043 1.1 christos * here in the question section this is illegal, so return 1044 1.1 christos * FORMERR. In the future, check the opcode to see if 1045 1.1 christos * this should be legal or not. In either case we no longer 1046 1.1 christos * need this name pointer. 1047 1.1 christos */ 1048 1.16 christos skip_name_check: 1049 1.16 christos switch (result) { 1050 1.16 christos case ISC_R_SUCCESS: 1051 1.9 christos if (!ISC_LIST_EMPTY(*section)) { 1052 1.1 christos DO_ERROR(DNS_R_FORMERR); 1053 1.9 christos } 1054 1.1 christos ISC_LIST_APPEND(*section, name, link); 1055 1.16 christos break; 1056 1.16 christos case ISC_R_EXISTS: 1057 1.13 christos dns_message_puttempname(msg, &name); 1058 1.19 christos name = found_name; 1059 1.19 christos found_name = NULL; 1060 1.16 christos break; 1061 1.16 christos default: 1062 1.16 christos UNREACHABLE(); 1063 1.1 christos } 1064 1.1 christos 1065 1.16 christos free_name = false; 1066 1.16 christos 1067 1.1 christos /* 1068 1.1 christos * Get type and class. 1069 1.1 christos */ 1070 1.1 christos isc_buffer_remainingregion(source, &r); 1071 1.1 christos if (r.length < 4) { 1072 1.1 christos result = ISC_R_UNEXPECTEDEND; 1073 1.1 christos goto cleanup; 1074 1.1 christos } 1075 1.1 christos rdtype = isc_buffer_getuint16(source); 1076 1.1 christos rdclass = isc_buffer_getuint16(source); 1077 1.1 christos 1078 1.1 christos /* 1079 1.1 christos * If this class is different than the one we already read, 1080 1.1 christos * this is an error. 1081 1.1 christos */ 1082 1.1 christos if (msg->rdclass_set == 0) { 1083 1.1 christos msg->rdclass = rdclass; 1084 1.1 christos msg->rdclass_set = 1; 1085 1.9 christos } else if (msg->rdclass != rdclass) { 1086 1.1 christos DO_ERROR(DNS_R_FORMERR); 1087 1.9 christos } 1088 1.1 christos 1089 1.1 christos /* 1090 1.1 christos * Is this a TKEY query? 1091 1.1 christos */ 1092 1.9 christos if (rdtype == dns_rdatatype_tkey) { 1093 1.1 christos msg->tkey = 1; 1094 1.9 christos } 1095 1.1 christos 1096 1.1 christos /* 1097 1.1 christos * Allocate a new rdatalist. 1098 1.1 christos */ 1099 1.1 christos rdatalist = newrdatalist(msg); 1100 1.19 christos rdatalist->type = rdtype; 1101 1.19 christos rdatalist->rdclass = rdclass; 1102 1.19 christos rdatalist->covers = 0; 1103 1.1 christos 1104 1.1 christos /* 1105 1.1 christos * Convert rdatalist to rdataset, and attach the latter to 1106 1.1 christos * the name. 1107 1.1 christos */ 1108 1.19 christos dns_message_gettemprdataset(msg, &rdataset); 1109 1.19 christos dns_rdatalist_tordataset(rdatalist, rdataset); 1110 1.16 christos 1111 1.16 christos rdataset->attributes |= DNS_RDATASETATTR_QUESTION; 1112 1.16 christos 1113 1.16 christos /* 1114 1.16 christos * Skip the duplicity check for first rdataset 1115 1.16 christos */ 1116 1.16 christos if (ISC_LIST_EMPTY(name->list)) { 1117 1.16 christos result = ISC_R_SUCCESS; 1118 1.16 christos goto skip_rds_check; 1119 1.9 christos } 1120 1.1 christos 1121 1.16 christos /* 1122 1.16 christos * Can't ask the same question twice. 1123 1.16 christos */ 1124 1.19 christos if (name->hashmap == NULL) { 1125 1.19 christos isc_hashmap_create(msg->mctx, 1, &name->hashmap); 1126 1.19 christos free_hashmaps = true; 1127 1.16 christos 1128 1.16 christos INSIST(ISC_LIST_HEAD(name->list) == 1129 1.16 christos ISC_LIST_TAIL(name->list)); 1130 1.16 christos 1131 1.16 christos dns_rdataset_t *old_rdataset = 1132 1.16 christos ISC_LIST_HEAD(name->list); 1133 1.16 christos 1134 1.19 christos result = isc_hashmap_add( 1135 1.19 christos name->hashmap, rds_hash(old_rdataset), 1136 1.19 christos rds_match, old_rdataset, old_rdataset, NULL); 1137 1.16 christos 1138 1.16 christos INSIST(result == ISC_R_SUCCESS); 1139 1.16 christos } 1140 1.19 christos result = isc_hashmap_add(name->hashmap, rds_hash(rdataset), 1141 1.19 christos rds_match, rdataset, rdataset, NULL); 1142 1.17 christos if (result == ISC_R_EXISTS) { 1143 1.17 christos DO_ERROR(DNS_R_FORMERR); 1144 1.17 christos } 1145 1.17 christos 1146 1.16 christos skip_rds_check: 1147 1.1 christos ISC_LIST_APPEND(name->list, rdataset, link); 1148 1.16 christos 1149 1.1 christos rdataset = NULL; 1150 1.1 christos } 1151 1.1 christos 1152 1.9 christos if (seen_problem) { 1153 1.18 christos /* XXX test coverage */ 1154 1.16 christos result = DNS_R_RECOVERABLE; 1155 1.9 christos } 1156 1.1 christos 1157 1.9 christos cleanup: 1158 1.1 christos if (rdataset != NULL) { 1159 1.16 christos if (dns_rdataset_isassociated(rdataset)) { 1160 1.16 christos dns_rdataset_disassociate(rdataset); 1161 1.16 christos } 1162 1.19 christos dns_message_puttemprdataset(msg, &rdataset); 1163 1.1 christos } 1164 1.19 christos 1165 1.9 christos if (free_name) { 1166 1.13 christos dns_message_puttempname(msg, &name); 1167 1.9 christos } 1168 1.1 christos 1169 1.19 christos if (free_hashmaps) { 1170 1.16 christos cleanup_name_hashmaps(section); 1171 1.16 christos } 1172 1.16 christos 1173 1.16 christos if (name_map != NULL) { 1174 1.19 christos isc_hashmap_destroy(&name_map); 1175 1.16 christos } 1176 1.16 christos 1177 1.19 christos return result; 1178 1.1 christos } 1179 1.1 christos 1180 1.3 christos static bool 1181 1.1 christos update(dns_section_t section, dns_rdataclass_t rdclass) { 1182 1.9 christos if (section == DNS_SECTION_PREREQUISITE) { 1183 1.19 christos return rdclass == dns_rdataclass_any || 1184 1.19 christos rdclass == dns_rdataclass_none; 1185 1.9 christos } 1186 1.9 christos if (section == DNS_SECTION_UPDATE) { 1187 1.19 christos return rdclass == dns_rdataclass_any; 1188 1.9 christos } 1189 1.19 christos return false; 1190 1.1 christos } 1191 1.1 christos 1192 1.1 christos static isc_result_t 1193 1.19 christos getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx, 1194 1.9 christos dns_section_t sectionid, unsigned int options) { 1195 1.1 christos isc_region_t r; 1196 1.1 christos unsigned int count, rdatalen; 1197 1.1 christos dns_name_t *name = NULL; 1198 1.19 christos dns_name_t *found_name = NULL; 1199 1.2 christos dns_rdataset_t *rdataset = NULL; 1200 1.16 christos dns_rdataset_t *found_rdataset = NULL; 1201 1.13 christos dns_rdatalist_t *rdatalist = NULL; 1202 1.16 christos isc_result_t result = ISC_R_SUCCESS; 1203 1.1 christos dns_rdatatype_t rdtype, covers; 1204 1.1 christos dns_rdataclass_t rdclass; 1205 1.13 christos dns_rdata_t *rdata = NULL; 1206 1.1 christos dns_ttl_t ttl; 1207 1.13 christos dns_namelist_t *section = &msg->sections[sectionid]; 1208 1.16 christos bool free_name = false, seen_problem = false; 1209 1.19 christos bool free_hashmaps = false; 1210 1.13 christos bool preserve_order = ((options & DNS_MESSAGEPARSE_PRESERVEORDER) != 0); 1211 1.13 christos bool best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0); 1212 1.5 christos bool isedns, issigzero, istsig; 1213 1.19 christos isc_hashmap_t *name_map = NULL; 1214 1.16 christos 1215 1.16 christos if (msg->counts[sectionid] > 1) { 1216 1.19 christos isc_hashmap_create(msg->mctx, 1, &name_map); 1217 1.16 christos } 1218 1.3 christos 1219 1.1 christos for (count = 0; count < msg->counts[sectionid]; count++) { 1220 1.1 christos int recstart = source->current; 1221 1.3 christos bool skip_name_search, skip_type_search; 1222 1.1 christos 1223 1.3 christos skip_name_search = false; 1224 1.3 christos skip_type_search = false; 1225 1.5 christos isedns = false; 1226 1.5 christos issigzero = false; 1227 1.5 christos istsig = false; 1228 1.16 christos found_rdataset = NULL; 1229 1.1 christos 1230 1.13 christos name = NULL; 1231 1.19 christos dns_message_gettempname(msg, &name); 1232 1.13 christos name->offsets = (unsigned char *)newoffsets(msg); 1233 1.3 christos free_name = true; 1234 1.1 christos 1235 1.1 christos /* 1236 1.1 christos * Parse the name out of this packet. 1237 1.1 christos */ 1238 1.1 christos isc_buffer_remainingregion(source, &r); 1239 1.1 christos isc_buffer_setactive(source, r.length); 1240 1.1 christos result = getname(name, source, msg, dctx); 1241 1.9 christos if (result != ISC_R_SUCCESS) { 1242 1.1 christos goto cleanup; 1243 1.9 christos } 1244 1.1 christos 1245 1.1 christos /* 1246 1.1 christos * Get type, class, ttl, and rdatalen. Verify that at least 1247 1.1 christos * rdatalen bytes remain. (Some of this is deferred to 1248 1.1 christos * later.) 1249 1.1 christos */ 1250 1.1 christos isc_buffer_remainingregion(source, &r); 1251 1.1 christos if (r.length < 2 + 2 + 4 + 2) { 1252 1.1 christos result = ISC_R_UNEXPECTEDEND; 1253 1.1 christos goto cleanup; 1254 1.1 christos } 1255 1.1 christos rdtype = isc_buffer_getuint16(source); 1256 1.1 christos rdclass = isc_buffer_getuint16(source); 1257 1.1 christos 1258 1.1 christos /* 1259 1.1 christos * If there was no question section, we may not yet have 1260 1.1 christos * established a class. Do so now. 1261 1.1 christos */ 1262 1.1 christos if (msg->rdclass_set == 0 && 1263 1.9 christos rdtype != dns_rdatatype_opt && /* class is UDP SIZE */ 1264 1.9 christos rdtype != dns_rdatatype_tsig && /* class is ANY */ 1265 1.16 christos rdtype != dns_rdatatype_tkey) /* class is undefined */ 1266 1.16 christos { 1267 1.1 christos msg->rdclass = rdclass; 1268 1.1 christos msg->rdclass_set = 1; 1269 1.1 christos } 1270 1.1 christos 1271 1.1 christos /* 1272 1.1 christos * If this class is different than the one in the question 1273 1.1 christos * section, bail. 1274 1.1 christos */ 1275 1.9 christos if (msg->opcode != dns_opcode_update && 1276 1.9 christos rdtype != dns_rdatatype_tsig && 1277 1.9 christos rdtype != dns_rdatatype_opt && 1278 1.9 christos rdtype != dns_rdatatype_key && /* in a TKEY query */ 1279 1.9 christos rdtype != dns_rdatatype_sig && /* SIG(0) */ 1280 1.9 christos rdtype != dns_rdatatype_tkey && /* Win2000 TKEY */ 1281 1.9 christos msg->rdclass != dns_rdataclass_any && 1282 1.9 christos msg->rdclass != rdclass) 1283 1.9 christos { 1284 1.1 christos DO_ERROR(DNS_R_FORMERR); 1285 1.9 christos } 1286 1.1 christos 1287 1.1 christos /* 1288 1.1 christos * If this is not a TKEY query/response then the KEY 1289 1.1 christos * record's class needs to match. 1290 1.1 christos */ 1291 1.1 christos if (msg->opcode != dns_opcode_update && !msg->tkey && 1292 1.1 christos rdtype == dns_rdatatype_key && 1293 1.1 christos msg->rdclass != dns_rdataclass_any && 1294 1.1 christos msg->rdclass != rdclass) 1295 1.9 christos { 1296 1.1 christos DO_ERROR(DNS_R_FORMERR); 1297 1.9 christos } 1298 1.1 christos 1299 1.1 christos /* 1300 1.1 christos * Special type handling for TSIG, OPT, and TKEY. 1301 1.1 christos */ 1302 1.1 christos if (rdtype == dns_rdatatype_tsig) { 1303 1.1 christos /* 1304 1.1 christos * If it is a tsig, verify that it is in the 1305 1.1 christos * additional data section. 1306 1.1 christos */ 1307 1.1 christos if (sectionid != DNS_SECTION_ADDITIONAL || 1308 1.1 christos rdclass != dns_rdataclass_any || 1309 1.9 christos count != msg->counts[sectionid] - 1) 1310 1.9 christos { 1311 1.1 christos DO_ERROR(DNS_R_BADTSIG); 1312 1.5 christos } else { 1313 1.5 christos skip_name_search = true; 1314 1.5 christos skip_type_search = true; 1315 1.5 christos istsig = true; 1316 1.5 christos } 1317 1.1 christos } else if (rdtype == dns_rdatatype_opt) { 1318 1.1 christos /* 1319 1.1 christos * The name of an OPT record must be ".", it 1320 1.1 christos * must be in the additional data section, and 1321 1.1 christos * it must be the first OPT we've seen. 1322 1.1 christos */ 1323 1.1 christos if (!dns_name_equal(dns_rootname, name) || 1324 1.1 christos sectionid != DNS_SECTION_ADDITIONAL || 1325 1.9 christos msg->opt != NULL) 1326 1.9 christos { 1327 1.1 christos DO_ERROR(DNS_R_FORMERR); 1328 1.5 christos } else { 1329 1.5 christos skip_name_search = true; 1330 1.5 christos skip_type_search = true; 1331 1.5 christos isedns = true; 1332 1.5 christos } 1333 1.1 christos } else if (rdtype == dns_rdatatype_tkey) { 1334 1.1 christos /* 1335 1.1 christos * A TKEY must be in the additional section if this 1336 1.1 christos * is a query, and the answer section if this is a 1337 1.1 christos * response. Unless it's a Win2000 client. 1338 1.1 christos * 1339 1.1 christos * Its class is ignored. 1340 1.1 christos */ 1341 1.1 christos dns_section_t tkeysection; 1342 1.1 christos 1343 1.9 christos if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0) { 1344 1.1 christos tkeysection = DNS_SECTION_ADDITIONAL; 1345 1.9 christos } else { 1346 1.1 christos tkeysection = DNS_SECTION_ANSWER; 1347 1.9 christos } 1348 1.1 christos if (sectionid != tkeysection && 1349 1.15 christos sectionid != DNS_SECTION_ANSWER) 1350 1.15 christos { 1351 1.1 christos DO_ERROR(DNS_R_FORMERR); 1352 1.9 christos } 1353 1.1 christos } 1354 1.1 christos 1355 1.1 christos /* 1356 1.1 christos * ... now get ttl and rdatalen, and check buffer. 1357 1.1 christos */ 1358 1.1 christos ttl = isc_buffer_getuint32(source); 1359 1.1 christos rdatalen = isc_buffer_getuint16(source); 1360 1.1 christos r.length -= (2 + 2 + 4 + 2); 1361 1.1 christos if (r.length < rdatalen) { 1362 1.1 christos result = ISC_R_UNEXPECTEDEND; 1363 1.1 christos goto cleanup; 1364 1.1 christos } 1365 1.1 christos 1366 1.1 christos /* 1367 1.1 christos * Read the rdata from the wire format. Interpret the 1368 1.1 christos * rdata according to its actual class, even if it had a 1369 1.1 christos * DynDNS meta-class in the packet (unless this is a TSIG). 1370 1.1 christos * Then put the meta-class back into the finished rdata. 1371 1.1 christos */ 1372 1.1 christos rdata = newrdata(msg); 1373 1.1 christos if (msg->opcode == dns_opcode_update && 1374 1.15 christos update(sectionid, rdclass)) 1375 1.15 christos { 1376 1.1 christos if (rdatalen != 0) { 1377 1.1 christos result = DNS_R_FORMERR; 1378 1.1 christos goto cleanup; 1379 1.1 christos } 1380 1.1 christos /* 1381 1.1 christos * When the rdata is empty, the data pointer is 1382 1.1 christos * never dereferenced, but it must still be non-NULL. 1383 1.1 christos * Casting 1 rather than "" avoids warnings about 1384 1.1 christos * discarding the const attribute of a string, 1385 1.1 christos * for compilers that would warn about such things. 1386 1.1 christos */ 1387 1.1 christos rdata->data = (unsigned char *)1; 1388 1.1 christos rdata->length = 0; 1389 1.1 christos rdata->rdclass = rdclass; 1390 1.1 christos rdata->type = rdtype; 1391 1.1 christos rdata->flags = DNS_RDATA_UPDATE; 1392 1.1 christos result = ISC_R_SUCCESS; 1393 1.1 christos } else if (rdclass == dns_rdataclass_none && 1394 1.1 christos msg->opcode == dns_opcode_update && 1395 1.9 christos sectionid == DNS_SECTION_UPDATE) 1396 1.9 christos { 1397 1.1 christos result = getrdata(source, msg, dctx, msg->rdclass, 1398 1.1 christos rdtype, rdatalen, rdata); 1399 1.9 christos } else { 1400 1.9 christos result = getrdata(source, msg, dctx, rdclass, rdtype, 1401 1.9 christos rdatalen, rdata); 1402 1.9 christos } 1403 1.9 christos if (result != ISC_R_SUCCESS) { 1404 1.1 christos goto cleanup; 1405 1.9 christos } 1406 1.1 christos rdata->rdclass = rdclass; 1407 1.9 christos if (rdtype == dns_rdatatype_rrsig && rdata->flags == 0) { 1408 1.1 christos covers = dns_rdata_covers(rdata); 1409 1.9 christos if (covers == 0) { 1410 1.1 christos DO_ERROR(DNS_R_FORMERR); 1411 1.9 christos } 1412 1.1 christos } else if (rdtype == dns_rdatatype_sig /* SIG(0) */ && 1413 1.15 christos rdata->flags == 0) 1414 1.15 christos { 1415 1.1 christos covers = dns_rdata_covers(rdata); 1416 1.1 christos if (covers == 0) { 1417 1.1 christos if (sectionid != DNS_SECTION_ADDITIONAL || 1418 1.17 christos count != msg->counts[sectionid] - 1 || 1419 1.17 christos !dns_name_equal(name, dns_rootname)) 1420 1.15 christos { 1421 1.1 christos DO_ERROR(DNS_R_BADSIG0); 1422 1.5 christos } else { 1423 1.5 christos skip_name_search = true; 1424 1.5 christos skip_type_search = true; 1425 1.5 christos issigzero = true; 1426 1.5 christos } 1427 1.1 christos } else { 1428 1.1 christos if (msg->rdclass != dns_rdataclass_any && 1429 1.15 christos msg->rdclass != rdclass) 1430 1.15 christos { 1431 1.18 christos /* XXX test coverage */ 1432 1.1 christos DO_ERROR(DNS_R_FORMERR); 1433 1.9 christos } 1434 1.1 christos } 1435 1.9 christos } else { 1436 1.1 christos covers = 0; 1437 1.9 christos } 1438 1.1 christos 1439 1.1 christos /* 1440 1.1 christos * Check the ownername of NSEC3 records 1441 1.1 christos */ 1442 1.1 christos if (rdtype == dns_rdatatype_nsec3 && 1443 1.9 christos !dns_rdata_checkowner(name, msg->rdclass, rdtype, false)) 1444 1.9 christos { 1445 1.1 christos result = DNS_R_BADOWNERNAME; 1446 1.1 christos goto cleanup; 1447 1.1 christos } 1448 1.1 christos 1449 1.1 christos /* 1450 1.1 christos * If we are doing a dynamic update or this is a meta-type, 1451 1.1 christos * don't bother searching for a name, just append this one 1452 1.1 christos * to the end of the message. 1453 1.1 christos */ 1454 1.1 christos if (preserve_order || msg->opcode == dns_opcode_update || 1455 1.15 christos skip_name_search) 1456 1.15 christos { 1457 1.5 christos if (!isedns && !istsig && !issigzero) { 1458 1.1 christos ISC_LIST_APPEND(*section, name, link); 1459 1.3 christos free_name = false; 1460 1.1 christos } 1461 1.1 christos } else { 1462 1.16 christos if (name_map == NULL) { 1463 1.16 christos result = ISC_R_SUCCESS; 1464 1.16 christos goto skip_name_check; 1465 1.16 christos } 1466 1.16 christos 1467 1.1 christos /* 1468 1.1 christos * Run through the section, looking to see if this name 1469 1.1 christos * is already there. If it is found, put back the 1470 1.1 christos * allocated name since we no longer need it, and set 1471 1.1 christos * our name pointer to point to the name we found. 1472 1.1 christos */ 1473 1.19 christos result = isc_hashmap_add(name_map, dns_name_hash(name), 1474 1.19 christos name_match, name, name, 1475 1.19 christos (void **)&found_name); 1476 1.1 christos 1477 1.1 christos /* 1478 1.1 christos * If it is a new name, append to the section. 1479 1.1 christos */ 1480 1.16 christos skip_name_check: 1481 1.16 christos switch (result) { 1482 1.16 christos case ISC_R_SUCCESS: 1483 1.16 christos ISC_LIST_APPEND(*section, name, link); 1484 1.16 christos break; 1485 1.16 christos case ISC_R_EXISTS: 1486 1.13 christos dns_message_puttempname(msg, &name); 1487 1.19 christos name = found_name; 1488 1.19 christos found_name = NULL; 1489 1.16 christos break; 1490 1.16 christos default: 1491 1.16 christos UNREACHABLE(); 1492 1.1 christos } 1493 1.3 christos free_name = false; 1494 1.1 christos } 1495 1.1 christos 1496 1.16 christos rdatalist = newrdatalist(msg); 1497 1.16 christos rdatalist->type = rdtype; 1498 1.16 christos rdatalist->covers = covers; 1499 1.16 christos rdatalist->rdclass = rdclass; 1500 1.16 christos rdatalist->ttl = ttl; 1501 1.16 christos 1502 1.17 christos dns_message_gettemprdataset(msg, &rdataset); 1503 1.19 christos dns_rdatalist_tordataset(rdatalist, rdataset); 1504 1.16 christos dns_rdataset_setownercase(rdataset, name); 1505 1.16 christos rdatalist = NULL; 1506 1.16 christos 1507 1.1 christos /* 1508 1.1 christos * Search name for the particular type and class. 1509 1.1 christos * Skip this stage if in update mode or this is a meta-type. 1510 1.1 christos */ 1511 1.16 christos if (isedns || istsig || issigzero) { 1512 1.16 christos /* Skip adding the rdataset to the tables */ 1513 1.16 christos } else if (preserve_order || msg->opcode == dns_opcode_update || 1514 1.16 christos skip_type_search) 1515 1.15 christos { 1516 1.16 christos result = ISC_R_SUCCESS; 1517 1.16 christos 1518 1.16 christos ISC_LIST_APPEND(name->list, rdataset, link); 1519 1.9 christos } else { 1520 1.1 christos /* 1521 1.1 christos * If this is a type that can only occur in 1522 1.1 christos * the question section, fail. 1523 1.1 christos */ 1524 1.9 christos if (dns_rdatatype_questiononly(rdtype)) { 1525 1.1 christos DO_ERROR(DNS_R_FORMERR); 1526 1.9 christos } 1527 1.1 christos 1528 1.16 christos if (ISC_LIST_EMPTY(name->list)) { 1529 1.16 christos result = ISC_R_SUCCESS; 1530 1.16 christos goto skip_rds_check; 1531 1.16 christos } 1532 1.16 christos 1533 1.19 christos if (name->hashmap == NULL) { 1534 1.19 christos isc_hashmap_create(msg->mctx, 1, 1535 1.19 christos &name->hashmap); 1536 1.19 christos free_hashmaps = true; 1537 1.16 christos 1538 1.16 christos INSIST(ISC_LIST_HEAD(name->list) == 1539 1.16 christos ISC_LIST_TAIL(name->list)); 1540 1.16 christos 1541 1.16 christos dns_rdataset_t *old_rdataset = 1542 1.16 christos ISC_LIST_HEAD(name->list); 1543 1.16 christos 1544 1.19 christos result = isc_hashmap_add( 1545 1.19 christos name->hashmap, rds_hash(old_rdataset), 1546 1.19 christos rds_match, old_rdataset, old_rdataset, 1547 1.19 christos NULL); 1548 1.16 christos 1549 1.16 christos INSIST(result == ISC_R_SUCCESS); 1550 1.16 christos } 1551 1.19 christos 1552 1.19 christos result = isc_hashmap_add( 1553 1.19 christos name->hashmap, rds_hash(rdataset), rds_match, 1554 1.19 christos rdataset, rdataset, (void **)&found_rdataset); 1555 1.16 christos 1556 1.16 christos /* 1557 1.16 christos * If we found an rdataset that matches, we need to 1558 1.16 christos * append this rdata to that set. If we did not, we 1559 1.16 christos * need to create a new rdatalist, store the important 1560 1.16 christos * bits there, convert it to an rdataset, and link the 1561 1.16 christos * latter to the name. Yuck. When appending, make 1562 1.16 christos * certain that the type isn't a singleton type, such as 1563 1.16 christos * SOA or CNAME. 1564 1.16 christos * 1565 1.16 christos * Note that this check will be bypassed when preserving 1566 1.16 christos * order, the opcode is an update, or the type search is 1567 1.16 christos * skipped. 1568 1.16 christos */ 1569 1.16 christos skip_rds_check: 1570 1.16 christos switch (result) { 1571 1.16 christos case ISC_R_EXISTS: 1572 1.16 christos /* Free the rdataset we used as the key */ 1573 1.19 christos dns__message_putassociatedrdataset(msg, 1574 1.19 christos &rdataset); 1575 1.16 christos result = ISC_R_SUCCESS; 1576 1.16 christos rdataset = found_rdataset; 1577 1.16 christos 1578 1.16 christos if (!dns_rdatatype_issingleton(rdtype)) { 1579 1.16 christos break; 1580 1.16 christos } 1581 1.1 christos 1582 1.1 christos dns_rdatalist_fromrdataset(rdataset, 1583 1.1 christos &rdatalist); 1584 1.16 christos dns_rdata_t *first = 1585 1.16 christos ISC_LIST_HEAD(rdatalist->rdata); 1586 1.1 christos INSIST(first != NULL); 1587 1.9 christos if (dns_rdata_compare(rdata, first) != 0) { 1588 1.1 christos DO_ERROR(DNS_R_FORMERR); 1589 1.9 christos } 1590 1.16 christos break; 1591 1.16 christos case ISC_R_SUCCESS: 1592 1.1 christos ISC_LIST_APPEND(name->list, rdataset, link); 1593 1.16 christos break; 1594 1.16 christos default: 1595 1.16 christos UNREACHABLE(); 1596 1.1 christos } 1597 1.1 christos } 1598 1.1 christos 1599 1.1 christos /* 1600 1.1 christos * Minimize TTLs. 1601 1.1 christos * 1602 1.1 christos * Section 5.2 of RFC2181 says we should drop 1603 1.1 christos * nonauthoritative rrsets where the TTLs differ, but we 1604 1.1 christos * currently treat them the as if they were authoritative and 1605 1.1 christos * minimize them. 1606 1.1 christos */ 1607 1.1 christos if (ttl != rdataset->ttl) { 1608 1.1 christos rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED; 1609 1.9 christos if (ttl < rdataset->ttl) { 1610 1.1 christos rdataset->ttl = ttl; 1611 1.9 christos } 1612 1.1 christos } 1613 1.1 christos 1614 1.1 christos /* Append this rdata to the rdataset. */ 1615 1.1 christos dns_rdatalist_fromrdataset(rdataset, &rdatalist); 1616 1.1 christos ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 1617 1.1 christos 1618 1.1 christos /* 1619 1.1 christos * If this is an OPT, SIG(0) or TSIG record, remember it. 1620 1.1 christos * Also, set the extended rcode for TSIG. 1621 1.1 christos * 1622 1.1 christos * Note msg->opt, msg->sig0 and msg->tsig will only be 1623 1.1 christos * already set if best-effort parsing is enabled otherwise 1624 1.1 christos * there will only be at most one of each. 1625 1.1 christos */ 1626 1.5 christos if (isedns) { 1627 1.1 christos dns_rcode_t ercode; 1628 1.1 christos 1629 1.1 christos msg->opt = rdataset; 1630 1.13 christos ercode = (dns_rcode_t)((msg->opt->ttl & 1631 1.13 christos DNS_MESSAGE_EDNSRCODE_MASK) >> 1632 1.13 christos 20); 1633 1.1 christos msg->rcode |= ercode; 1634 1.13 christos dns_message_puttempname(msg, &name); 1635 1.3 christos free_name = false; 1636 1.5 christos } else if (issigzero) { 1637 1.1 christos msg->sig0 = rdataset; 1638 1.1 christos msg->sig0name = name; 1639 1.5 christos msg->sigstart = recstart; 1640 1.3 christos free_name = false; 1641 1.5 christos } else if (istsig) { 1642 1.1 christos msg->tsig = rdataset; 1643 1.1 christos msg->tsigname = name; 1644 1.5 christos msg->sigstart = recstart; 1645 1.5 christos /* 1646 1.5 christos * Windows doesn't like TSIG names to be compressed. 1647 1.5 christos */ 1648 1.19 christos msg->tsigname->attributes.nocompress = true; 1649 1.3 christos free_name = false; 1650 1.22 christos } else if (rdtype == dns_rdatatype_dname && 1651 1.22 christos sectionid == DNS_SECTION_ANSWER && 1652 1.22 christos msg->opcode == dns_opcode_query) 1653 1.22 christos { 1654 1.22 christos msg->has_dname = 1; 1655 1.1 christos } 1656 1.16 christos rdataset = NULL; 1657 1.1 christos 1658 1.1 christos if (seen_problem) { 1659 1.9 christos if (free_name) { 1660 1.18 christos /* XXX test coverage */ 1661 1.13 christos dns_message_puttempname(msg, &name); 1662 1.9 christos } 1663 1.16 christos free_name = false; 1664 1.1 christos } 1665 1.10 christos INSIST(!free_name); 1666 1.1 christos } 1667 1.1 christos 1668 1.9 christos if (seen_problem) { 1669 1.16 christos result = DNS_R_RECOVERABLE; 1670 1.9 christos } 1671 1.1 christos 1672 1.9 christos cleanup: 1673 1.16 christos if (rdataset != NULL && rdataset != found_rdataset) { 1674 1.19 christos dns__message_putassociatedrdataset(msg, &rdataset); 1675 1.16 christos } 1676 1.9 christos if (free_name) { 1677 1.13 christos dns_message_puttempname(msg, &name); 1678 1.9 christos } 1679 1.16 christos 1680 1.19 christos if (free_hashmaps) { 1681 1.16 christos cleanup_name_hashmaps(section); 1682 1.16 christos } 1683 1.16 christos 1684 1.16 christos if (name_map != NULL) { 1685 1.19 christos isc_hashmap_destroy(&name_map); 1686 1.9 christos } 1687 1.1 christos 1688 1.19 christos return result; 1689 1.1 christos } 1690 1.1 christos 1691 1.1 christos isc_result_t 1692 1.1 christos dns_message_parse(dns_message_t *msg, isc_buffer_t *source, 1693 1.9 christos unsigned int options) { 1694 1.1 christos isc_region_t r; 1695 1.1 christos dns_decompress_t dctx; 1696 1.1 christos isc_result_t ret; 1697 1.3 christos uint16_t tmpflags; 1698 1.1 christos isc_buffer_t origsource; 1699 1.3 christos bool seen_problem; 1700 1.3 christos bool ignore_tc; 1701 1.1 christos 1702 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 1703 1.1 christos REQUIRE(source != NULL); 1704 1.1 christos REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE); 1705 1.1 christos 1706 1.3 christos seen_problem = false; 1707 1.3 christos ignore_tc = ((options & DNS_MESSAGEPARSE_IGNORETRUNCATION) != 0); 1708 1.1 christos 1709 1.1 christos origsource = *source; 1710 1.1 christos 1711 1.1 christos msg->header_ok = 0; 1712 1.1 christos msg->question_ok = 0; 1713 1.1 christos 1714 1.11 christos if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0) { 1715 1.11 christos isc_buffer_usedregion(&origsource, &msg->saved); 1716 1.11 christos } else { 1717 1.11 christos msg->saved.length = isc_buffer_usedlength(&origsource); 1718 1.11 christos msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length); 1719 1.11 christos memmove(msg->saved.base, isc_buffer_base(&origsource), 1720 1.11 christos msg->saved.length); 1721 1.11 christos msg->free_saved = 1; 1722 1.11 christos } 1723 1.11 christos 1724 1.1 christos isc_buffer_remainingregion(source, &r); 1725 1.9 christos if (r.length < DNS_MESSAGE_HEADERLEN) { 1726 1.19 christos return ISC_R_UNEXPECTEDEND; 1727 1.9 christos } 1728 1.1 christos 1729 1.1 christos msg->id = isc_buffer_getuint16(source); 1730 1.1 christos tmpflags = isc_buffer_getuint16(source); 1731 1.9 christos msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK) >> 1732 1.9 christos DNS_MESSAGE_OPCODE_SHIFT); 1733 1.1 christos msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK); 1734 1.1 christos msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK); 1735 1.1 christos msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source); 1736 1.1 christos msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source); 1737 1.1 christos msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source); 1738 1.1 christos msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source); 1739 1.1 christos 1740 1.1 christos msg->header_ok = 1; 1741 1.1 christos msg->state = DNS_SECTION_QUESTION; 1742 1.1 christos 1743 1.19 christos dctx = DNS_DECOMPRESS_ALWAYS; 1744 1.1 christos 1745 1.19 christos ret = getquestions(source, msg, dctx, options); 1746 1.1 christos 1747 1.9 christos if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) { 1748 1.1 christos goto truncated; 1749 1.9 christos } 1750 1.1 christos if (ret == DNS_R_RECOVERABLE) { 1751 1.3 christos seen_problem = true; 1752 1.1 christos ret = ISC_R_SUCCESS; 1753 1.1 christos } 1754 1.9 christos if (ret != ISC_R_SUCCESS) { 1755 1.19 christos return ret; 1756 1.9 christos } 1757 1.1 christos msg->question_ok = 1; 1758 1.1 christos 1759 1.19 christos ret = getsection(source, msg, dctx, DNS_SECTION_ANSWER, options); 1760 1.9 christos if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) { 1761 1.1 christos goto truncated; 1762 1.9 christos } 1763 1.1 christos if (ret == DNS_R_RECOVERABLE) { 1764 1.3 christos seen_problem = true; 1765 1.1 christos ret = ISC_R_SUCCESS; 1766 1.1 christos } 1767 1.9 christos if (ret != ISC_R_SUCCESS) { 1768 1.19 christos return ret; 1769 1.9 christos } 1770 1.1 christos 1771 1.19 christos ret = getsection(source, msg, dctx, DNS_SECTION_AUTHORITY, options); 1772 1.9 christos if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) { 1773 1.1 christos goto truncated; 1774 1.9 christos } 1775 1.1 christos if (ret == DNS_R_RECOVERABLE) { 1776 1.3 christos seen_problem = true; 1777 1.1 christos ret = ISC_R_SUCCESS; 1778 1.1 christos } 1779 1.9 christos if (ret != ISC_R_SUCCESS) { 1780 1.19 christos return ret; 1781 1.9 christos } 1782 1.1 christos 1783 1.19 christos ret = getsection(source, msg, dctx, DNS_SECTION_ADDITIONAL, options); 1784 1.9 christos if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) { 1785 1.1 christos goto truncated; 1786 1.9 christos } 1787 1.1 christos if (ret == DNS_R_RECOVERABLE) { 1788 1.3 christos seen_problem = true; 1789 1.1 christos ret = ISC_R_SUCCESS; 1790 1.1 christos } 1791 1.9 christos if (ret != ISC_R_SUCCESS) { 1792 1.19 christos return ret; 1793 1.9 christos } 1794 1.1 christos 1795 1.1 christos isc_buffer_remainingregion(source, &r); 1796 1.1 christos if (r.length != 0) { 1797 1.1 christos isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1798 1.1 christos DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3), 1799 1.1 christos "message has %u byte(s) of trailing garbage", 1800 1.1 christos r.length); 1801 1.1 christos } 1802 1.1 christos 1803 1.9 christos truncated: 1804 1.1 christos 1805 1.9 christos if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) { 1806 1.19 christos return DNS_R_RECOVERABLE; 1807 1.9 christos } 1808 1.10 christos if (seen_problem) { 1809 1.19 christos return DNS_R_RECOVERABLE; 1810 1.9 christos } 1811 1.19 christos return ISC_R_SUCCESS; 1812 1.1 christos } 1813 1.1 christos 1814 1.1 christos isc_result_t 1815 1.1 christos dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx, 1816 1.9 christos isc_buffer_t *buffer) { 1817 1.1 christos isc_region_t r; 1818 1.1 christos 1819 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 1820 1.1 christos REQUIRE(buffer != NULL); 1821 1.17 christos REQUIRE(isc_buffer_length(buffer) < 65536); 1822 1.1 christos REQUIRE(msg->buffer == NULL); 1823 1.1 christos REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 1824 1.1 christos 1825 1.1 christos msg->cctx = cctx; 1826 1.1 christos 1827 1.1 christos /* 1828 1.1 christos * Erase the contents of this buffer. 1829 1.1 christos */ 1830 1.1 christos isc_buffer_clear(buffer); 1831 1.1 christos 1832 1.1 christos /* 1833 1.1 christos * Make certain there is enough for at least the header in this 1834 1.1 christos * buffer. 1835 1.1 christos */ 1836 1.1 christos isc_buffer_availableregion(buffer, &r); 1837 1.9 christos if (r.length < DNS_MESSAGE_HEADERLEN) { 1838 1.19 christos return ISC_R_NOSPACE; 1839 1.9 christos } 1840 1.1 christos 1841 1.9 christos if (r.length - DNS_MESSAGE_HEADERLEN < msg->reserved) { 1842 1.19 christos return ISC_R_NOSPACE; 1843 1.9 christos } 1844 1.1 christos 1845 1.1 christos /* 1846 1.1 christos * Reserve enough space for the header in this buffer. 1847 1.1 christos */ 1848 1.1 christos isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN); 1849 1.1 christos 1850 1.1 christos msg->buffer = buffer; 1851 1.1 christos 1852 1.19 christos return ISC_R_SUCCESS; 1853 1.1 christos } 1854 1.1 christos 1855 1.1 christos isc_result_t 1856 1.1 christos dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) { 1857 1.1 christos isc_region_t r, rn; 1858 1.1 christos 1859 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 1860 1.1 christos REQUIRE(buffer != NULL); 1861 1.1 christos REQUIRE(msg->buffer != NULL); 1862 1.1 christos 1863 1.1 christos /* 1864 1.1 christos * Ensure that the new buffer is empty, and has enough space to 1865 1.1 christos * hold the current contents. 1866 1.1 christos */ 1867 1.1 christos isc_buffer_clear(buffer); 1868 1.1 christos 1869 1.1 christos isc_buffer_availableregion(buffer, &rn); 1870 1.1 christos isc_buffer_usedregion(msg->buffer, &r); 1871 1.1 christos REQUIRE(rn.length > r.length); 1872 1.1 christos 1873 1.1 christos /* 1874 1.1 christos * Copy the contents from the old to the new buffer. 1875 1.1 christos */ 1876 1.1 christos isc_buffer_add(buffer, r.length); 1877 1.1 christos memmove(rn.base, r.base, r.length); 1878 1.1 christos 1879 1.1 christos msg->buffer = buffer; 1880 1.1 christos 1881 1.19 christos return ISC_R_SUCCESS; 1882 1.1 christos } 1883 1.1 christos 1884 1.1 christos void 1885 1.1 christos dns_message_renderrelease(dns_message_t *msg, unsigned int space) { 1886 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 1887 1.1 christos REQUIRE(space <= msg->reserved); 1888 1.1 christos 1889 1.1 christos msg->reserved -= space; 1890 1.1 christos } 1891 1.1 christos 1892 1.1 christos isc_result_t 1893 1.1 christos dns_message_renderreserve(dns_message_t *msg, unsigned int space) { 1894 1.1 christos isc_region_t r; 1895 1.1 christos 1896 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 1897 1.1 christos 1898 1.1 christos if (msg->buffer != NULL) { 1899 1.1 christos isc_buffer_availableregion(msg->buffer, &r); 1900 1.9 christos if (r.length < (space + msg->reserved)) { 1901 1.19 christos return ISC_R_NOSPACE; 1902 1.9 christos } 1903 1.1 christos } 1904 1.1 christos 1905 1.1 christos msg->reserved += space; 1906 1.1 christos 1907 1.19 christos return ISC_R_SUCCESS; 1908 1.1 christos } 1909 1.1 christos 1910 1.14 christos static bool 1911 1.1 christos wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) { 1912 1.1 christos int pass_needed; 1913 1.1 christos 1914 1.1 christos /* 1915 1.1 christos * If we are not rendering class IN, this ordering is bogus. 1916 1.1 christos */ 1917 1.9 christos if (rds->rdclass != dns_rdataclass_in) { 1918 1.19 christos return false; 1919 1.9 christos } 1920 1.1 christos 1921 1.1 christos switch (rds->type) { 1922 1.1 christos case dns_rdatatype_a: 1923 1.1 christos case dns_rdatatype_aaaa: 1924 1.9 christos if (preferred_glue == rds->type) { 1925 1.1 christos pass_needed = 4; 1926 1.9 christos } else { 1927 1.1 christos pass_needed = 3; 1928 1.9 christos } 1929 1.1 christos break; 1930 1.1 christos case dns_rdatatype_rrsig: 1931 1.1 christos case dns_rdatatype_dnskey: 1932 1.1 christos pass_needed = 2; 1933 1.1 christos break; 1934 1.1 christos default: 1935 1.1 christos pass_needed = 1; 1936 1.1 christos } 1937 1.1 christos 1938 1.9 christos if (pass_needed >= pass) { 1939 1.19 christos return false; 1940 1.9 christos } 1941 1.1 christos 1942 1.19 christos return true; 1943 1.1 christos } 1944 1.1 christos 1945 1.1 christos static isc_result_t 1946 1.1 christos renderset(dns_rdataset_t *rdataset, const dns_name_t *owner_name, 1947 1.9 christos dns_compress_t *cctx, isc_buffer_t *target, unsigned int reserved, 1948 1.9 christos unsigned int options, unsigned int *countp) { 1949 1.1 christos isc_result_t result; 1950 1.1 christos 1951 1.1 christos /* 1952 1.1 christos * Shrink the space in the buffer by the reserved amount. 1953 1.1 christos */ 1954 1.9 christos if (target->length - target->used < reserved) { 1955 1.19 christos return ISC_R_NOSPACE; 1956 1.9 christos } 1957 1.1 christos 1958 1.1 christos target->length -= reserved; 1959 1.9 christos result = dns_rdataset_towire(rdataset, owner_name, cctx, target, 1960 1.9 christos options, countp); 1961 1.1 christos target->length += reserved; 1962 1.1 christos 1963 1.19 christos return result; 1964 1.1 christos } 1965 1.1 christos 1966 1.1 christos static void 1967 1.1 christos maybe_clear_ad(dns_message_t *msg, dns_section_t sectionid) { 1968 1.1 christos if (msg->counts[sectionid] == 0 && 1969 1.1 christos (sectionid == DNS_SECTION_ANSWER || 1970 1.1 christos (sectionid == DNS_SECTION_AUTHORITY && 1971 1.1 christos msg->counts[DNS_SECTION_ANSWER] == 0))) 1972 1.9 christos { 1973 1.1 christos msg->flags &= ~DNS_MESSAGEFLAG_AD; 1974 1.9 christos } 1975 1.1 christos } 1976 1.1 christos 1977 1.17 christos static void 1978 1.17 christos update_min_section_ttl(dns_message_t *restrict msg, 1979 1.17 christos const dns_section_t sectionid, 1980 1.17 christos dns_rdataset_t *restrict rdataset) { 1981 1.17 christos if (!msg->minttl[sectionid].is_set || 1982 1.17 christos rdataset->ttl < msg->minttl[sectionid].ttl) 1983 1.17 christos { 1984 1.17 christos msg->minttl[sectionid].is_set = true; 1985 1.17 christos msg->minttl[sectionid].ttl = rdataset->ttl; 1986 1.17 christos } 1987 1.17 christos } 1988 1.17 christos 1989 1.1 christos isc_result_t 1990 1.1 christos dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid, 1991 1.9 christos unsigned int options) { 1992 1.1 christos dns_namelist_t *section; 1993 1.1 christos dns_name_t *name, *next_name; 1994 1.1 christos dns_rdataset_t *rdataset, *next_rdataset; 1995 1.1 christos unsigned int count, total; 1996 1.1 christos isc_result_t result; 1997 1.1 christos isc_buffer_t st; /* for rollbacks */ 1998 1.1 christos int pass; 1999 1.3 christos bool partial = false; 2000 1.1 christos unsigned int rd_options; 2001 1.1 christos dns_rdatatype_t preferred_glue = 0; 2002 1.1 christos 2003 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2004 1.1 christos REQUIRE(msg->buffer != NULL); 2005 1.1 christos REQUIRE(VALID_NAMED_SECTION(sectionid)); 2006 1.1 christos 2007 1.1 christos section = &msg->sections[sectionid]; 2008 1.1 christos 2009 1.9 christos if ((sectionid == DNS_SECTION_ADDITIONAL) && 2010 1.9 christos (options & DNS_MESSAGERENDER_ORDERED) == 0) 2011 1.9 christos { 2012 1.1 christos if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) { 2013 1.1 christos preferred_glue = dns_rdatatype_a; 2014 1.1 christos pass = 4; 2015 1.1 christos } else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) { 2016 1.1 christos preferred_glue = dns_rdatatype_aaaa; 2017 1.1 christos pass = 4; 2018 1.9 christos } else { 2019 1.1 christos pass = 3; 2020 1.9 christos } 2021 1.9 christos } else { 2022 1.1 christos pass = 1; 2023 1.9 christos } 2024 1.1 christos 2025 1.9 christos if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0) { 2026 1.1 christos rd_options = 0; 2027 1.9 christos } else { 2028 1.1 christos rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC; 2029 1.9 christos } 2030 1.1 christos 2031 1.1 christos /* 2032 1.1 christos * Shrink the space in the buffer by the reserved amount. 2033 1.1 christos */ 2034 1.9 christos if (msg->buffer->length - msg->buffer->used < msg->reserved) { 2035 1.19 christos return ISC_R_NOSPACE; 2036 1.9 christos } 2037 1.1 christos msg->buffer->length -= msg->reserved; 2038 1.1 christos 2039 1.1 christos total = 0; 2040 1.9 christos if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0) { 2041 1.3 christos partial = true; 2042 1.9 christos } 2043 1.1 christos 2044 1.1 christos /* 2045 1.1 christos * Render required glue first. Set TC if it won't fit. 2046 1.1 christos */ 2047 1.1 christos name = ISC_LIST_HEAD(*section); 2048 1.1 christos if (name != NULL) { 2049 1.1 christos rdataset = ISC_LIST_HEAD(name->list); 2050 1.1 christos if (rdataset != NULL && 2051 1.9 christos (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 2052 1.9 christos 0 && 2053 1.9 christos (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) 2054 1.9 christos { 2055 1.1 christos const void *order_arg = &msg->order_arg; 2056 1.1 christos st = *(msg->buffer); 2057 1.1 christos count = 0; 2058 1.9 christos if (partial) { 2059 1.9 christos result = dns_rdataset_towirepartial( 2060 1.9 christos rdataset, name, msg->cctx, msg->buffer, 2061 1.9 christos msg->order, order_arg, rd_options, 2062 1.9 christos &count, NULL); 2063 1.9 christos } else { 2064 1.9 christos result = dns_rdataset_towiresorted( 2065 1.9 christos rdataset, name, msg->cctx, msg->buffer, 2066 1.9 christos msg->order, order_arg, rd_options, 2067 1.9 christos &count); 2068 1.9 christos } 2069 1.1 christos total += count; 2070 1.1 christos if (partial && result == ISC_R_NOSPACE) { 2071 1.1 christos msg->flags |= DNS_MESSAGEFLAG_TC; 2072 1.1 christos msg->buffer->length += msg->reserved; 2073 1.1 christos msg->counts[sectionid] += total; 2074 1.19 christos return result; 2075 1.1 christos } 2076 1.9 christos if (result == ISC_R_NOSPACE) { 2077 1.1 christos msg->flags |= DNS_MESSAGEFLAG_TC; 2078 1.9 christos } 2079 1.1 christos if (result != ISC_R_SUCCESS) { 2080 1.19 christos dns_compress_rollback(msg->cctx, st.used); 2081 1.9 christos *(msg->buffer) = st; /* rollback */ 2082 1.1 christos msg->buffer->length += msg->reserved; 2083 1.1 christos msg->counts[sectionid] += total; 2084 1.19 christos return result; 2085 1.1 christos } 2086 1.17 christos 2087 1.17 christos update_min_section_ttl(msg, sectionid, rdataset); 2088 1.17 christos 2089 1.1 christos rdataset->attributes |= DNS_RDATASETATTR_RENDERED; 2090 1.1 christos } 2091 1.1 christos } 2092 1.1 christos 2093 1.1 christos do { 2094 1.1 christos name = ISC_LIST_HEAD(*section); 2095 1.1 christos if (name == NULL) { 2096 1.1 christos msg->buffer->length += msg->reserved; 2097 1.1 christos msg->counts[sectionid] += total; 2098 1.19 christos return ISC_R_SUCCESS; 2099 1.1 christos } 2100 1.1 christos 2101 1.1 christos while (name != NULL) { 2102 1.1 christos next_name = ISC_LIST_NEXT(name, link); 2103 1.1 christos 2104 1.1 christos rdataset = ISC_LIST_HEAD(name->list); 2105 1.1 christos while (rdataset != NULL) { 2106 1.1 christos next_rdataset = ISC_LIST_NEXT(rdataset, link); 2107 1.1 christos 2108 1.1 christos if ((rdataset->attributes & 2109 1.15 christos DNS_RDATASETATTR_RENDERED) != 0) 2110 1.15 christos { 2111 1.1 christos goto next; 2112 1.9 christos } 2113 1.1 christos 2114 1.9 christos if (((options & DNS_MESSAGERENDER_ORDERED) == 2115 1.9 christos 0) && 2116 1.9 christos (sectionid == DNS_SECTION_ADDITIONAL) && 2117 1.9 christos wrong_priority(rdataset, pass, 2118 1.9 christos preferred_glue)) 2119 1.9 christos { 2120 1.1 christos goto next; 2121 1.9 christos } 2122 1.1 christos 2123 1.1 christos st = *(msg->buffer); 2124 1.1 christos 2125 1.1 christos count = 0; 2126 1.9 christos if (partial) { 2127 1.1 christos result = dns_rdataset_towirepartial( 2128 1.9 christos rdataset, name, msg->cctx, 2129 1.9 christos msg->buffer, msg->order, 2130 1.9 christos &msg->order_arg, rd_options, 2131 1.9 christos &count, NULL); 2132 1.9 christos } else { 2133 1.1 christos result = dns_rdataset_towiresorted( 2134 1.9 christos rdataset, name, msg->cctx, 2135 1.9 christos msg->buffer, msg->order, 2136 1.9 christos &msg->order_arg, rd_options, 2137 1.9 christos &count); 2138 1.9 christos } 2139 1.1 christos 2140 1.1 christos total += count; 2141 1.1 christos 2142 1.1 christos /* 2143 1.1 christos * If out of space, record stats on what we 2144 1.1 christos * rendered so far, and return that status. 2145 1.1 christos * 2146 1.1 christos * XXXMLG Need to change this when 2147 1.1 christos * dns_rdataset_towire() can render partial 2148 1.1 christos * sets starting at some arbitrary point in the 2149 1.1 christos * set. This will include setting a bit in the 2150 1.1 christos * rdataset to indicate that a partial 2151 1.1 christos * rendering was done, and some state saved 2152 1.1 christos * somewhere (probably in the message struct) 2153 1.1 christos * to indicate where to continue from. 2154 1.1 christos */ 2155 1.1 christos if (partial && result == ISC_R_NOSPACE) { 2156 1.1 christos msg->buffer->length += msg->reserved; 2157 1.1 christos msg->counts[sectionid] += total; 2158 1.19 christos return result; 2159 1.1 christos } 2160 1.1 christos if (result != ISC_R_SUCCESS) { 2161 1.1 christos INSIST(st.used < 65536); 2162 1.9 christos dns_compress_rollback( 2163 1.9 christos msg->cctx, (uint16_t)st.used); 2164 1.9 christos *(msg->buffer) = st; /* rollback */ 2165 1.1 christos msg->buffer->length += msg->reserved; 2166 1.1 christos msg->counts[sectionid] += total; 2167 1.1 christos maybe_clear_ad(msg, sectionid); 2168 1.19 christos return result; 2169 1.1 christos } 2170 1.1 christos 2171 1.1 christos /* 2172 1.1 christos * If we have rendered non-validated data, 2173 1.1 christos * ensure that the AD bit is not set. 2174 1.1 christos */ 2175 1.1 christos if (rdataset->trust != dns_trust_secure && 2176 1.1 christos (sectionid == DNS_SECTION_ANSWER || 2177 1.1 christos sectionid == DNS_SECTION_AUTHORITY)) 2178 1.9 christos { 2179 1.1 christos msg->flags &= ~DNS_MESSAGEFLAG_AD; 2180 1.9 christos } 2181 1.9 christos if (OPTOUT(rdataset)) { 2182 1.1 christos msg->flags &= ~DNS_MESSAGEFLAG_AD; 2183 1.9 christos } 2184 1.1 christos 2185 1.17 christos update_min_section_ttl(msg, sectionid, 2186 1.17 christos rdataset); 2187 1.17 christos 2188 1.1 christos rdataset->attributes |= 2189 1.1 christos DNS_RDATASETATTR_RENDERED; 2190 1.1 christos 2191 1.1 christos next: 2192 1.1 christos rdataset = next_rdataset; 2193 1.1 christos } 2194 1.1 christos 2195 1.1 christos name = next_name; 2196 1.1 christos } 2197 1.1 christos } while (--pass != 0); 2198 1.1 christos 2199 1.1 christos msg->buffer->length += msg->reserved; 2200 1.1 christos msg->counts[sectionid] += total; 2201 1.1 christos 2202 1.19 christos return ISC_R_SUCCESS; 2203 1.1 christos } 2204 1.1 christos 2205 1.1 christos void 2206 1.1 christos dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) { 2207 1.3 christos uint16_t tmp; 2208 1.1 christos isc_region_t r; 2209 1.1 christos 2210 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2211 1.21 christos REQUIRE(msg->buffer != NULL); 2212 1.1 christos REQUIRE(target != NULL); 2213 1.1 christos 2214 1.1 christos isc_buffer_availableregion(target, &r); 2215 1.1 christos REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN); 2216 1.1 christos 2217 1.1 christos isc_buffer_putuint16(target, msg->id); 2218 1.1 christos 2219 1.9 christos tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT) & 2220 1.9 christos DNS_MESSAGE_OPCODE_MASK); 2221 1.1 christos tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK); 2222 1.1 christos tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK); 2223 1.1 christos 2224 1.9 christos INSIST(msg->counts[DNS_SECTION_QUESTION] < 65536 && 2225 1.9 christos msg->counts[DNS_SECTION_ANSWER] < 65536 && 2226 1.1 christos msg->counts[DNS_SECTION_AUTHORITY] < 65536 && 2227 1.1 christos msg->counts[DNS_SECTION_ADDITIONAL] < 65536); 2228 1.1 christos 2229 1.1 christos isc_buffer_putuint16(target, tmp); 2230 1.1 christos isc_buffer_putuint16(target, 2231 1.9 christos (uint16_t)msg->counts[DNS_SECTION_QUESTION]); 2232 1.9 christos isc_buffer_putuint16(target, (uint16_t)msg->counts[DNS_SECTION_ANSWER]); 2233 1.1 christos isc_buffer_putuint16(target, 2234 1.9 christos (uint16_t)msg->counts[DNS_SECTION_AUTHORITY]); 2235 1.1 christos isc_buffer_putuint16(target, 2236 1.9 christos (uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]); 2237 1.1 christos } 2238 1.1 christos 2239 1.1 christos isc_result_t 2240 1.1 christos dns_message_renderend(dns_message_t *msg) { 2241 1.1 christos isc_buffer_t tmpbuf; 2242 1.1 christos isc_region_t r; 2243 1.1 christos int result; 2244 1.1 christos unsigned int count; 2245 1.1 christos 2246 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2247 1.1 christos REQUIRE(msg->buffer != NULL); 2248 1.1 christos 2249 1.1 christos if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) { 2250 1.1 christos /* 2251 1.1 christos * We have an extended rcode but are not using EDNS. 2252 1.1 christos */ 2253 1.19 christos return DNS_R_FORMERR; 2254 1.1 christos } 2255 1.1 christos 2256 1.1 christos /* 2257 1.1 christos * If we're adding a OPT, TSIG or SIG(0) to a truncated message, 2258 1.1 christos * clear all rdatasets from the message except for the question 2259 1.1 christos * before adding the OPT, TSIG or SIG(0). If the question doesn't 2260 1.1 christos * fit, don't include it. 2261 1.1 christos */ 2262 1.1 christos if ((msg->tsigkey != NULL || msg->sig0key != NULL || msg->opt) && 2263 1.1 christos (msg->flags & DNS_MESSAGEFLAG_TC) != 0) 2264 1.1 christos { 2265 1.1 christos isc_buffer_t *buf; 2266 1.1 christos 2267 1.1 christos msgresetnames(msg, DNS_SECTION_ANSWER); 2268 1.1 christos buf = msg->buffer; 2269 1.1 christos dns_message_renderreset(msg); 2270 1.1 christos msg->buffer = buf; 2271 1.1 christos isc_buffer_clear(msg->buffer); 2272 1.1 christos isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN); 2273 1.1 christos dns_compress_rollback(msg->cctx, 0); 2274 1.1 christos result = dns_message_rendersection(msg, DNS_SECTION_QUESTION, 2275 1.1 christos 0); 2276 1.9 christos if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE) { 2277 1.19 christos return result; 2278 1.9 christos } 2279 1.1 christos } 2280 1.1 christos 2281 1.1 christos /* 2282 1.1 christos * If we've got an OPT record, render it. 2283 1.1 christos */ 2284 1.1 christos if (msg->opt != NULL) { 2285 1.1 christos dns_message_renderrelease(msg, msg->opt_reserved); 2286 1.1 christos msg->opt_reserved = 0; 2287 1.1 christos /* 2288 1.11 christos * Set the extended rcode. Cast msg->rcode to dns_ttl_t 2289 1.11 christos * so that we do a unsigned shift. 2290 1.1 christos */ 2291 1.1 christos msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK; 2292 1.11 christos msg->opt->ttl |= (((dns_ttl_t)(msg->rcode) << 20) & 2293 1.1 christos DNS_MESSAGE_EDNSRCODE_MASK); 2294 1.1 christos /* 2295 1.1 christos * Render. 2296 1.1 christos */ 2297 1.1 christos count = 0; 2298 1.1 christos result = renderset(msg->opt, dns_rootname, msg->cctx, 2299 1.1 christos msg->buffer, msg->reserved, 0, &count); 2300 1.1 christos msg->counts[DNS_SECTION_ADDITIONAL] += count; 2301 1.9 christos if (result != ISC_R_SUCCESS) { 2302 1.19 christos return result; 2303 1.9 christos } 2304 1.1 christos } 2305 1.1 christos 2306 1.1 christos /* 2307 1.1 christos * Deal with EDNS padding. 2308 1.1 christos * 2309 1.1 christos * padding_off is the length of the OPT with the 0-length PAD 2310 1.1 christos * at the end. 2311 1.1 christos */ 2312 1.1 christos if (msg->padding_off > 0) { 2313 1.1 christos unsigned char *cp = isc_buffer_used(msg->buffer); 2314 1.1 christos unsigned int used, remaining; 2315 1.3 christos uint16_t len, padsize = 0; 2316 1.1 christos 2317 1.1 christos /* Check PAD */ 2318 1.9 christos if ((cp[-4] != 0) || (cp[-3] != DNS_OPT_PAD) || (cp[-2] != 0) || 2319 1.15 christos (cp[-1] != 0)) 2320 1.15 christos { 2321 1.19 christos return ISC_R_UNEXPECTED; 2322 1.9 christos } 2323 1.1 christos 2324 1.1 christos /* 2325 1.1 christos * Zero-fill the PAD to the computed size; 2326 1.1 christos * patch PAD length and OPT rdlength 2327 1.1 christos */ 2328 1.1 christos 2329 1.1 christos /* Aligned used length + reserved to padding block */ 2330 1.1 christos used = isc_buffer_usedlength(msg->buffer); 2331 1.1 christos if (msg->padding != 0) { 2332 1.9 christos padsize = ((uint16_t)used + msg->reserved) % 2333 1.9 christos msg->padding; 2334 1.1 christos } 2335 1.1 christos if (padsize != 0) { 2336 1.1 christos padsize = msg->padding - padsize; 2337 1.1 christos } 2338 1.1 christos /* Stay below the available length */ 2339 1.1 christos remaining = isc_buffer_availablelength(msg->buffer); 2340 1.9 christos if (padsize > remaining) { 2341 1.1 christos padsize = remaining; 2342 1.9 christos } 2343 1.1 christos 2344 1.1 christos isc_buffer_add(msg->buffer, padsize); 2345 1.1 christos memset(cp, 0, padsize); 2346 1.1 christos cp[-2] = (unsigned char)((padsize & 0xff00U) >> 8); 2347 1.1 christos cp[-1] = (unsigned char)(padsize & 0x00ffU); 2348 1.1 christos cp -= msg->padding_off; 2349 1.3 christos len = ((uint16_t)(cp[-2])) << 8; 2350 1.3 christos len |= ((uint16_t)(cp[-1])); 2351 1.1 christos len += padsize; 2352 1.1 christos cp[-2] = (unsigned char)((len & 0xff00U) >> 8); 2353 1.1 christos cp[-1] = (unsigned char)(len & 0x00ffU); 2354 1.1 christos } 2355 1.1 christos 2356 1.1 christos /* 2357 1.1 christos * If we're adding a TSIG record, generate and render it. 2358 1.1 christos */ 2359 1.1 christos if (msg->tsigkey != NULL) { 2360 1.1 christos dns_message_renderrelease(msg, msg->sig_reserved); 2361 1.1 christos msg->sig_reserved = 0; 2362 1.1 christos result = dns_tsig_sign(msg); 2363 1.9 christos if (result != ISC_R_SUCCESS) { 2364 1.19 christos return result; 2365 1.9 christos } 2366 1.1 christos count = 0; 2367 1.1 christos result = renderset(msg->tsig, msg->tsigname, msg->cctx, 2368 1.1 christos msg->buffer, msg->reserved, 0, &count); 2369 1.1 christos msg->counts[DNS_SECTION_ADDITIONAL] += count; 2370 1.9 christos if (result != ISC_R_SUCCESS) { 2371 1.19 christos return result; 2372 1.9 christos } 2373 1.1 christos } 2374 1.1 christos 2375 1.1 christos /* 2376 1.1 christos * If we're adding a SIG(0) record, generate and render it. 2377 1.1 christos */ 2378 1.1 christos if (msg->sig0key != NULL) { 2379 1.1 christos dns_message_renderrelease(msg, msg->sig_reserved); 2380 1.1 christos msg->sig_reserved = 0; 2381 1.1 christos result = dns_dnssec_signmessage(msg, msg->sig0key); 2382 1.9 christos if (result != ISC_R_SUCCESS) { 2383 1.19 christos return result; 2384 1.9 christos } 2385 1.1 christos count = 0; 2386 1.1 christos /* 2387 1.1 christos * Note: dns_rootname is used here, not msg->sig0name, since 2388 1.1 christos * the owner name of a SIG(0) is irrelevant, and will not 2389 1.1 christos * be set in a message being rendered. 2390 1.1 christos */ 2391 1.1 christos result = renderset(msg->sig0, dns_rootname, msg->cctx, 2392 1.1 christos msg->buffer, msg->reserved, 0, &count); 2393 1.1 christos msg->counts[DNS_SECTION_ADDITIONAL] += count; 2394 1.9 christos if (result != ISC_R_SUCCESS) { 2395 1.19 christos return result; 2396 1.9 christos } 2397 1.1 christos } 2398 1.1 christos 2399 1.1 christos isc_buffer_usedregion(msg->buffer, &r); 2400 1.1 christos isc_buffer_init(&tmpbuf, r.base, r.length); 2401 1.1 christos 2402 1.1 christos dns_message_renderheader(msg, &tmpbuf); 2403 1.1 christos 2404 1.9 christos msg->buffer = NULL; /* forget about this buffer only on success XXX */ 2405 1.1 christos 2406 1.19 christos return ISC_R_SUCCESS; 2407 1.1 christos } 2408 1.1 christos 2409 1.1 christos void 2410 1.1 christos dns_message_renderreset(dns_message_t *msg) { 2411 1.1 christos /* 2412 1.1 christos * Reset the message so that it may be rendered again. 2413 1.1 christos */ 2414 1.1 christos 2415 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2416 1.1 christos REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 2417 1.1 christos 2418 1.1 christos msg->buffer = NULL; 2419 1.1 christos 2420 1.19 christos for (size_t i = 0; i < DNS_SECTION_MAX; i++) { 2421 1.19 christos dns_name_t *name = NULL; 2422 1.19 christos 2423 1.1 christos msg->cursors[i] = NULL; 2424 1.1 christos msg->counts[i] = 0; 2425 1.22 christos ISC_LIST_FOREACH(msg->sections[i], name, link) { 2426 1.19 christos dns_rdataset_t *rds = NULL; 2427 1.22 christos ISC_LIST_FOREACH(name->list, rds, link) { 2428 1.1 christos rds->attributes &= ~DNS_RDATASETATTR_RENDERED; 2429 1.1 christos } 2430 1.1 christos } 2431 1.1 christos } 2432 1.9 christos if (msg->tsigname != NULL) { 2433 1.1 christos dns_message_puttempname(msg, &msg->tsigname); 2434 1.9 christos } 2435 1.1 christos if (msg->tsig != NULL) { 2436 1.19 christos dns__message_putassociatedrdataset(msg, &msg->tsig); 2437 1.1 christos } 2438 1.17 christos if (msg->sig0name != NULL) { 2439 1.17 christos dns_message_puttempname(msg, &msg->sig0name); 2440 1.17 christos } 2441 1.1 christos if (msg->sig0 != NULL) { 2442 1.19 christos dns__message_putassociatedrdataset(msg, &msg->sig0); 2443 1.1 christos } 2444 1.1 christos } 2445 1.1 christos 2446 1.1 christos isc_result_t 2447 1.1 christos dns_message_firstname(dns_message_t *msg, dns_section_t section) { 2448 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2449 1.1 christos REQUIRE(VALID_NAMED_SECTION(section)); 2450 1.1 christos 2451 1.1 christos msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]); 2452 1.1 christos 2453 1.9 christos if (msg->cursors[section] == NULL) { 2454 1.19 christos return ISC_R_NOMORE; 2455 1.9 christos } 2456 1.1 christos 2457 1.19 christos return ISC_R_SUCCESS; 2458 1.1 christos } 2459 1.1 christos 2460 1.1 christos isc_result_t 2461 1.1 christos dns_message_nextname(dns_message_t *msg, dns_section_t section) { 2462 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2463 1.1 christos REQUIRE(VALID_NAMED_SECTION(section)); 2464 1.1 christos REQUIRE(msg->cursors[section] != NULL); 2465 1.1 christos 2466 1.1 christos msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link); 2467 1.1 christos 2468 1.9 christos if (msg->cursors[section] == NULL) { 2469 1.19 christos return ISC_R_NOMORE; 2470 1.9 christos } 2471 1.1 christos 2472 1.19 christos return ISC_R_SUCCESS; 2473 1.1 christos } 2474 1.1 christos 2475 1.1 christos void 2476 1.1 christos dns_message_currentname(dns_message_t *msg, dns_section_t section, 2477 1.9 christos dns_name_t **name) { 2478 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2479 1.1 christos REQUIRE(VALID_NAMED_SECTION(section)); 2480 1.1 christos REQUIRE(name != NULL && *name == NULL); 2481 1.1 christos REQUIRE(msg->cursors[section] != NULL); 2482 1.1 christos 2483 1.1 christos *name = msg->cursors[section]; 2484 1.1 christos } 2485 1.1 christos 2486 1.1 christos isc_result_t 2487 1.1 christos dns_message_findname(dns_message_t *msg, dns_section_t section, 2488 1.1 christos const dns_name_t *target, dns_rdatatype_t type, 2489 1.1 christos dns_rdatatype_t covers, dns_name_t **name, 2490 1.9 christos dns_rdataset_t **rdataset) { 2491 1.16 christos dns_name_t *foundname = NULL; 2492 1.1 christos isc_result_t result; 2493 1.1 christos 2494 1.1 christos /* 2495 1.1 christos * XXX These requirements are probably too intensive, especially 2496 1.1 christos * where things can be NULL, but as they are they ensure that if 2497 1.1 christos * something is NON-NULL, indicating that the caller expects it 2498 1.1 christos * to be filled in, that we can in fact fill it in. 2499 1.1 christos */ 2500 1.1 christos REQUIRE(msg != NULL); 2501 1.19 christos REQUIRE(VALID_NAMED_SECTION(section)); 2502 1.1 christos REQUIRE(target != NULL); 2503 1.1 christos REQUIRE(name == NULL || *name == NULL); 2504 1.1 christos 2505 1.1 christos if (type == dns_rdatatype_any) { 2506 1.1 christos REQUIRE(rdataset == NULL); 2507 1.1 christos } else { 2508 1.1 christos REQUIRE(rdataset == NULL || *rdataset == NULL); 2509 1.1 christos } 2510 1.1 christos 2511 1.9 christos result = findname(&foundname, target, &msg->sections[section]); 2512 1.1 christos 2513 1.9 christos if (result == ISC_R_NOTFOUND) { 2514 1.19 christos return DNS_R_NXDOMAIN; 2515 1.9 christos } else if (result != ISC_R_SUCCESS) { 2516 1.19 christos return result; 2517 1.9 christos } 2518 1.1 christos 2519 1.20 christos SET_IF_NOT_NULL(name, foundname); 2520 1.1 christos 2521 1.1 christos /* 2522 1.1 christos * And now look for the type. 2523 1.1 christos */ 2524 1.17 christos if (type == dns_rdatatype_any) { 2525 1.19 christos return ISC_R_SUCCESS; 2526 1.9 christos } 2527 1.1 christos 2528 1.1 christos result = dns_message_findtype(foundname, type, covers, rdataset); 2529 1.9 christos if (result == ISC_R_NOTFOUND) { 2530 1.19 christos return DNS_R_NXRRSET; 2531 1.9 christos } 2532 1.1 christos 2533 1.19 christos return result; 2534 1.1 christos } 2535 1.1 christos 2536 1.1 christos void 2537 1.1 christos dns_message_addname(dns_message_t *msg, dns_name_t *name, 2538 1.9 christos dns_section_t section) { 2539 1.1 christos REQUIRE(msg != NULL); 2540 1.1 christos REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 2541 1.21 christos REQUIRE(dns_name_isabsolute(name)); 2542 1.1 christos REQUIRE(VALID_NAMED_SECTION(section)); 2543 1.1 christos 2544 1.1 christos ISC_LIST_APPEND(msg->sections[section], name, link); 2545 1.1 christos } 2546 1.1 christos 2547 1.1 christos void 2548 1.1 christos dns_message_removename(dns_message_t *msg, dns_name_t *name, 2549 1.9 christos dns_section_t section) { 2550 1.1 christos REQUIRE(msg != NULL); 2551 1.1 christos REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 2552 1.21 christos REQUIRE(dns_name_isabsolute(name)); 2553 1.1 christos REQUIRE(VALID_NAMED_SECTION(section)); 2554 1.1 christos 2555 1.1 christos ISC_LIST_UNLINK(msg->sections[section], name, link); 2556 1.1 christos } 2557 1.1 christos 2558 1.19 christos void 2559 1.1 christos dns_message_gettempname(dns_message_t *msg, dns_name_t **item) { 2560 1.13 christos dns_fixedname_t *fn = NULL; 2561 1.1 christos 2562 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2563 1.1 christos REQUIRE(item != NULL && *item == NULL); 2564 1.1 christos 2565 1.13 christos fn = isc_mempool_get(msg->namepool); 2566 1.13 christos *item = dns_fixedname_initname(fn); 2567 1.1 christos } 2568 1.1 christos 2569 1.19 christos void 2570 1.1 christos dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) { 2571 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2572 1.1 christos REQUIRE(item != NULL && *item == NULL); 2573 1.1 christos 2574 1.1 christos *item = newrdata(msg); 2575 1.1 christos } 2576 1.1 christos 2577 1.19 christos void 2578 1.1 christos dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) { 2579 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2580 1.1 christos REQUIRE(item != NULL && *item == NULL); 2581 1.1 christos 2582 1.1 christos *item = isc_mempool_get(msg->rdspool); 2583 1.1 christos dns_rdataset_init(*item); 2584 1.1 christos } 2585 1.1 christos 2586 1.19 christos void 2587 1.1 christos dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) { 2588 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2589 1.1 christos REQUIRE(item != NULL && *item == NULL); 2590 1.1 christos 2591 1.1 christos *item = newrdatalist(msg); 2592 1.1 christos } 2593 1.1 christos 2594 1.1 christos void 2595 1.1 christos dns_message_puttempname(dns_message_t *msg, dns_name_t **itemp) { 2596 1.13 christos dns_name_t *item = NULL; 2597 1.1 christos 2598 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2599 1.1 christos REQUIRE(itemp != NULL && *itemp != NULL); 2600 1.13 christos 2601 1.1 christos item = *itemp; 2602 1.9 christos *itemp = NULL; 2603 1.13 christos 2604 1.1 christos REQUIRE(!ISC_LINK_LINKED(item, link)); 2605 1.1 christos REQUIRE(ISC_LIST_HEAD(item->list) == NULL); 2606 1.1 christos 2607 1.19 christos if (item->hashmap != NULL) { 2608 1.19 christos isc_hashmap_destroy(&item->hashmap); 2609 1.16 christos } 2610 1.16 christos 2611 1.13 christos /* 2612 1.13 christos * we need to check this in case dns_name_dup() was used. 2613 1.13 christos */ 2614 1.9 christos if (dns_name_dynamic(item)) { 2615 1.1 christos dns_name_free(item, msg->mctx); 2616 1.9 christos } 2617 1.13 christos 2618 1.13 christos /* 2619 1.13 christos * 'name' is the first field in dns_fixedname_t, so putting 2620 1.13 christos * back the address of name is the same as putting back 2621 1.13 christos * the fixedname. 2622 1.13 christos */ 2623 1.1 christos isc_mempool_put(msg->namepool, item); 2624 1.1 christos } 2625 1.1 christos 2626 1.1 christos void 2627 1.1 christos dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) { 2628 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2629 1.1 christos REQUIRE(item != NULL && *item != NULL); 2630 1.1 christos 2631 1.1 christos releaserdata(msg, *item); 2632 1.1 christos *item = NULL; 2633 1.1 christos } 2634 1.1 christos 2635 1.19 christos static void 2636 1.19 christos dns__message_putassociatedrdataset(dns_message_t *msg, dns_rdataset_t **item) { 2637 1.19 christos dns_rdataset_disassociate(*item); 2638 1.19 christos dns_message_puttemprdataset(msg, item); 2639 1.19 christos } 2640 1.19 christos 2641 1.1 christos void 2642 1.1 christos dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) { 2643 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2644 1.1 christos REQUIRE(item != NULL && *item != NULL); 2645 1.1 christos 2646 1.1 christos REQUIRE(!dns_rdataset_isassociated(*item)); 2647 1.1 christos isc_mempool_put(msg->rdspool, *item); 2648 1.1 christos *item = NULL; 2649 1.1 christos } 2650 1.1 christos 2651 1.1 christos void 2652 1.1 christos dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) { 2653 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2654 1.1 christos REQUIRE(item != NULL && *item != NULL); 2655 1.1 christos 2656 1.1 christos releaserdatalist(msg, *item); 2657 1.1 christos *item = NULL; 2658 1.1 christos } 2659 1.1 christos 2660 1.1 christos isc_result_t 2661 1.1 christos dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp, 2662 1.9 christos unsigned int *flagsp) { 2663 1.1 christos isc_region_t r; 2664 1.1 christos isc_buffer_t buffer; 2665 1.1 christos dns_messageid_t id; 2666 1.1 christos unsigned int flags; 2667 1.1 christos 2668 1.1 christos REQUIRE(source != NULL); 2669 1.1 christos 2670 1.1 christos buffer = *source; 2671 1.1 christos 2672 1.1 christos isc_buffer_remainingregion(&buffer, &r); 2673 1.9 christos if (r.length < DNS_MESSAGE_HEADERLEN) { 2674 1.19 christos return ISC_R_UNEXPECTEDEND; 2675 1.9 christos } 2676 1.1 christos 2677 1.1 christos id = isc_buffer_getuint16(&buffer); 2678 1.1 christos flags = isc_buffer_getuint16(&buffer); 2679 1.1 christos flags &= DNS_MESSAGE_FLAG_MASK; 2680 1.1 christos 2681 1.19 christos SET_IF_NOT_NULL(flagsp, flags); 2682 1.19 christos SET_IF_NOT_NULL(idp, id); 2683 1.1 christos 2684 1.19 christos return ISC_R_SUCCESS; 2685 1.1 christos } 2686 1.1 christos 2687 1.1 christos isc_result_t 2688 1.3 christos dns_message_reply(dns_message_t *msg, bool want_question_section) { 2689 1.1 christos unsigned int clear_from; 2690 1.1 christos isc_result_t result; 2691 1.1 christos 2692 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2693 1.1 christos REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0); 2694 1.1 christos 2695 1.9 christos if (!msg->header_ok) { 2696 1.19 christos return DNS_R_FORMERR; 2697 1.9 christos } 2698 1.9 christos if (msg->opcode != dns_opcode_query && msg->opcode != dns_opcode_notify) 2699 1.9 christos { 2700 1.3 christos want_question_section = false; 2701 1.9 christos } 2702 1.9 christos if (msg->opcode == dns_opcode_update) { 2703 1.1 christos clear_from = DNS_SECTION_PREREQUISITE; 2704 1.9 christos } else if (want_question_section) { 2705 1.9 christos if (!msg->question_ok) { 2706 1.19 christos return DNS_R_FORMERR; 2707 1.9 christos } 2708 1.1 christos clear_from = DNS_SECTION_ANSWER; 2709 1.9 christos } else { 2710 1.1 christos clear_from = DNS_SECTION_QUESTION; 2711 1.9 christos } 2712 1.1 christos msg->from_to_wire = DNS_MESSAGE_INTENTRENDER; 2713 1.1 christos msgresetnames(msg, clear_from); 2714 1.1 christos msgresetopt(msg); 2715 1.3 christos msgresetsigs(msg, true); 2716 1.1 christos msginitprivate(msg); 2717 1.1 christos /* 2718 1.1 christos * We now clear most flags and then set QR, ensuring that the 2719 1.1 christos * reply's flags will be in a reasonable state. 2720 1.1 christos */ 2721 1.9 christos if (msg->opcode == dns_opcode_query) { 2722 1.1 christos msg->flags &= DNS_MESSAGE_REPLYPRESERVE; 2723 1.9 christos } else { 2724 1.1 christos msg->flags = 0; 2725 1.9 christos } 2726 1.1 christos msg->flags |= DNS_MESSAGEFLAG_QR; 2727 1.1 christos 2728 1.1 christos /* 2729 1.1 christos * This saves the query TSIG status, if the query was signed, and 2730 1.1 christos * reserves space in the reply for the TSIG. 2731 1.1 christos */ 2732 1.1 christos if (msg->tsigkey != NULL) { 2733 1.1 christos unsigned int otherlen = 0; 2734 1.1 christos msg->querytsigstatus = msg->tsigstatus; 2735 1.1 christos msg->tsigstatus = dns_rcode_noerror; 2736 1.9 christos if (msg->querytsigstatus == dns_tsigerror_badtime) { 2737 1.1 christos otherlen = 6; 2738 1.9 christos } 2739 1.1 christos msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen); 2740 1.1 christos result = dns_message_renderreserve(msg, msg->sig_reserved); 2741 1.1 christos if (result != ISC_R_SUCCESS) { 2742 1.1 christos msg->sig_reserved = 0; 2743 1.19 christos return result; 2744 1.1 christos } 2745 1.1 christos } 2746 1.1 christos if (msg->saved.base != NULL) { 2747 1.1 christos msg->query.base = msg->saved.base; 2748 1.1 christos msg->query.length = msg->saved.length; 2749 1.1 christos msg->free_query = msg->free_saved; 2750 1.1 christos msg->saved.base = NULL; 2751 1.1 christos msg->saved.length = 0; 2752 1.1 christos msg->free_saved = 0; 2753 1.1 christos } 2754 1.1 christos 2755 1.19 christos return ISC_R_SUCCESS; 2756 1.1 christos } 2757 1.1 christos 2758 1.1 christos dns_rdataset_t * 2759 1.1 christos dns_message_getopt(dns_message_t *msg) { 2760 1.1 christos /* 2761 1.1 christos * Get the OPT record for 'msg'. 2762 1.1 christos */ 2763 1.1 christos 2764 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2765 1.1 christos 2766 1.19 christos return msg->opt; 2767 1.1 christos } 2768 1.1 christos 2769 1.1 christos isc_result_t 2770 1.1 christos dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) { 2771 1.1 christos isc_result_t result; 2772 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT; 2773 1.1 christos 2774 1.1 christos /* 2775 1.1 christos * Set the OPT record for 'msg'. 2776 1.1 christos */ 2777 1.1 christos 2778 1.1 christos /* 2779 1.1 christos * The space required for an OPT record is: 2780 1.1 christos * 2781 1.1 christos * 1 byte for the name 2782 1.1 christos * 2 bytes for the type 2783 1.1 christos * 2 bytes for the class 2784 1.1 christos * 4 bytes for the ttl 2785 1.1 christos * 2 bytes for the rdata length 2786 1.1 christos * --------------------------------- 2787 1.1 christos * 11 bytes 2788 1.1 christos * 2789 1.1 christos * plus the length of the rdata. 2790 1.1 christos */ 2791 1.1 christos 2792 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2793 1.19 christos REQUIRE(opt == NULL || DNS_RDATASET_VALID(opt)); 2794 1.19 christos REQUIRE(opt == NULL || opt->type == dns_rdatatype_opt); 2795 1.1 christos REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 2796 1.1 christos REQUIRE(msg->state == DNS_SECTION_ANY); 2797 1.1 christos 2798 1.1 christos msgresetopt(msg); 2799 1.1 christos 2800 1.19 christos if (opt == NULL) { 2801 1.19 christos return ISC_R_SUCCESS; 2802 1.19 christos } 2803 1.19 christos 2804 1.1 christos result = dns_rdataset_first(opt); 2805 1.9 christos if (result != ISC_R_SUCCESS) { 2806 1.1 christos goto cleanup; 2807 1.9 christos } 2808 1.1 christos dns_rdataset_current(opt, &rdata); 2809 1.1 christos msg->opt_reserved = 11 + rdata.length; 2810 1.1 christos result = dns_message_renderreserve(msg, msg->opt_reserved); 2811 1.1 christos if (result != ISC_R_SUCCESS) { 2812 1.1 christos msg->opt_reserved = 0; 2813 1.1 christos goto cleanup; 2814 1.1 christos } 2815 1.1 christos 2816 1.1 christos msg->opt = opt; 2817 1.1 christos 2818 1.19 christos return ISC_R_SUCCESS; 2819 1.1 christos 2820 1.9 christos cleanup: 2821 1.19 christos dns__message_putassociatedrdataset(msg, &opt); 2822 1.19 christos return result; 2823 1.1 christos } 2824 1.1 christos 2825 1.1 christos dns_rdataset_t * 2826 1.1 christos dns_message_gettsig(dns_message_t *msg, const dns_name_t **owner) { 2827 1.1 christos /* 2828 1.1 christos * Get the TSIG record and owner for 'msg'. 2829 1.1 christos */ 2830 1.1 christos 2831 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2832 1.1 christos REQUIRE(owner == NULL || *owner == NULL); 2833 1.1 christos 2834 1.19 christos SET_IF_NOT_NULL(owner, msg->tsigname); 2835 1.19 christos return msg->tsig; 2836 1.1 christos } 2837 1.1 christos 2838 1.1 christos isc_result_t 2839 1.1 christos dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) { 2840 1.1 christos isc_result_t result; 2841 1.1 christos 2842 1.1 christos /* 2843 1.1 christos * Set the TSIG key for 'msg' 2844 1.1 christos */ 2845 1.1 christos 2846 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2847 1.1 christos 2848 1.1 christos if (key == NULL && msg->tsigkey != NULL) { 2849 1.1 christos if (msg->sig_reserved != 0) { 2850 1.1 christos dns_message_renderrelease(msg, msg->sig_reserved); 2851 1.1 christos msg->sig_reserved = 0; 2852 1.1 christos } 2853 1.1 christos dns_tsigkey_detach(&msg->tsigkey); 2854 1.1 christos } 2855 1.1 christos if (key != NULL) { 2856 1.1 christos REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL); 2857 1.1 christos dns_tsigkey_attach(key, &msg->tsigkey); 2858 1.1 christos if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) { 2859 1.1 christos msg->sig_reserved = spacefortsig(msg->tsigkey, 0); 2860 1.1 christos result = dns_message_renderreserve(msg, 2861 1.1 christos msg->sig_reserved); 2862 1.1 christos if (result != ISC_R_SUCCESS) { 2863 1.1 christos dns_tsigkey_detach(&msg->tsigkey); 2864 1.1 christos msg->sig_reserved = 0; 2865 1.19 christos return result; 2866 1.1 christos } 2867 1.1 christos } 2868 1.1 christos } 2869 1.19 christos return ISC_R_SUCCESS; 2870 1.1 christos } 2871 1.1 christos 2872 1.1 christos dns_tsigkey_t * 2873 1.1 christos dns_message_gettsigkey(dns_message_t *msg) { 2874 1.1 christos /* 2875 1.1 christos * Get the TSIG key for 'msg' 2876 1.1 christos */ 2877 1.1 christos 2878 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2879 1.1 christos 2880 1.19 christos return msg->tsigkey; 2881 1.1 christos } 2882 1.1 christos 2883 1.19 christos void 2884 1.1 christos dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) { 2885 1.1 christos dns_rdata_t *rdata = NULL; 2886 1.1 christos dns_rdatalist_t *list = NULL; 2887 1.1 christos dns_rdataset_t *set = NULL; 2888 1.1 christos isc_buffer_t *buf = NULL; 2889 1.1 christos isc_region_t r; 2890 1.1 christos 2891 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2892 1.1 christos REQUIRE(msg->querytsig == NULL); 2893 1.1 christos 2894 1.9 christos if (querytsig == NULL) { 2895 1.19 christos return; 2896 1.9 christos } 2897 1.1 christos 2898 1.19 christos dns_message_gettemprdata(msg, &rdata); 2899 1.1 christos 2900 1.19 christos dns_message_gettemprdatalist(msg, &list); 2901 1.19 christos dns_message_gettemprdataset(msg, &set); 2902 1.1 christos 2903 1.1 christos isc_buffer_usedregion(querytsig, &r); 2904 1.9 christos isc_buffer_allocate(msg->mctx, &buf, r.length); 2905 1.1 christos isc_buffer_putmem(buf, r.base, r.length); 2906 1.1 christos isc_buffer_usedregion(buf, &r); 2907 1.1 christos dns_rdata_init(rdata); 2908 1.1 christos dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r); 2909 1.1 christos dns_message_takebuffer(msg, &buf); 2910 1.1 christos ISC_LIST_APPEND(list->rdata, rdata, link); 2911 1.19 christos dns_rdatalist_tordataset(list, set); 2912 1.1 christos 2913 1.1 christos msg->querytsig = set; 2914 1.1 christos } 2915 1.1 christos 2916 1.1 christos isc_result_t 2917 1.1 christos dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx, 2918 1.1 christos isc_buffer_t **querytsig) { 2919 1.1 christos isc_result_t result; 2920 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT; 2921 1.1 christos isc_region_t r; 2922 1.1 christos 2923 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2924 1.1 christos REQUIRE(mctx != NULL); 2925 1.1 christos REQUIRE(querytsig != NULL && *querytsig == NULL); 2926 1.1 christos 2927 1.9 christos if (msg->tsig == NULL) { 2928 1.19 christos return ISC_R_SUCCESS; 2929 1.9 christos } 2930 1.1 christos 2931 1.1 christos result = dns_rdataset_first(msg->tsig); 2932 1.9 christos if (result != ISC_R_SUCCESS) { 2933 1.19 christos return result; 2934 1.9 christos } 2935 1.1 christos dns_rdataset_current(msg->tsig, &rdata); 2936 1.1 christos dns_rdata_toregion(&rdata, &r); 2937 1.1 christos 2938 1.9 christos isc_buffer_allocate(mctx, querytsig, r.length); 2939 1.1 christos isc_buffer_putmem(*querytsig, r.base, r.length); 2940 1.19 christos return ISC_R_SUCCESS; 2941 1.1 christos } 2942 1.1 christos 2943 1.1 christos dns_rdataset_t * 2944 1.1 christos dns_message_getsig0(dns_message_t *msg, const dns_name_t **owner) { 2945 1.1 christos /* 2946 1.1 christos * Get the SIG(0) record for 'msg'. 2947 1.1 christos */ 2948 1.1 christos 2949 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2950 1.1 christos REQUIRE(owner == NULL || *owner == NULL); 2951 1.1 christos 2952 1.1 christos if (msg->sig0 != NULL && owner != NULL) { 2953 1.1 christos /* If dns_message_getsig0 is called on a rendered message 2954 1.1 christos * after the SIG(0) has been applied, we need to return the 2955 1.1 christos * root name, not NULL. 2956 1.1 christos */ 2957 1.9 christos if (msg->sig0name == NULL) { 2958 1.1 christos *owner = dns_rootname; 2959 1.9 christos } else { 2960 1.1 christos *owner = msg->sig0name; 2961 1.9 christos } 2962 1.1 christos } 2963 1.19 christos return msg->sig0; 2964 1.1 christos } 2965 1.1 christos 2966 1.1 christos isc_result_t 2967 1.1 christos dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) { 2968 1.1 christos isc_region_t r; 2969 1.1 christos unsigned int x; 2970 1.1 christos isc_result_t result; 2971 1.1 christos 2972 1.1 christos /* 2973 1.1 christos * Set the SIG(0) key for 'msg' 2974 1.1 christos */ 2975 1.1 christos 2976 1.1 christos /* 2977 1.1 christos * The space required for an SIG(0) record is: 2978 1.1 christos * 2979 1.1 christos * 1 byte for the name 2980 1.1 christos * 2 bytes for the type 2981 1.1 christos * 2 bytes for the class 2982 1.1 christos * 4 bytes for the ttl 2983 1.1 christos * 2 bytes for the type covered 2984 1.1 christos * 1 byte for the algorithm 2985 1.1 christos * 1 bytes for the labels 2986 1.1 christos * 4 bytes for the original ttl 2987 1.1 christos * 4 bytes for the signature expiration 2988 1.1 christos * 4 bytes for the signature inception 2989 1.1 christos * 2 bytes for the key tag 2990 1.1 christos * n bytes for the signer's name 2991 1.1 christos * x bytes for the signature 2992 1.1 christos * --------------------------------- 2993 1.1 christos * 27 + n + x bytes 2994 1.1 christos */ 2995 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 2996 1.1 christos REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 2997 1.1 christos REQUIRE(msg->state == DNS_SECTION_ANY); 2998 1.1 christos 2999 1.1 christos if (key != NULL) { 3000 1.1 christos REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL); 3001 1.1 christos dns_name_toregion(dst_key_name(key), &r); 3002 1.1 christos result = dst_key_sigsize(key, &x); 3003 1.1 christos if (result != ISC_R_SUCCESS) { 3004 1.1 christos msg->sig_reserved = 0; 3005 1.19 christos return result; 3006 1.1 christos } 3007 1.1 christos msg->sig_reserved = 27 + r.length + x; 3008 1.1 christos result = dns_message_renderreserve(msg, msg->sig_reserved); 3009 1.1 christos if (result != ISC_R_SUCCESS) { 3010 1.1 christos msg->sig_reserved = 0; 3011 1.19 christos return result; 3012 1.1 christos } 3013 1.1 christos msg->sig0key = key; 3014 1.1 christos } 3015 1.19 christos return ISC_R_SUCCESS; 3016 1.1 christos } 3017 1.1 christos 3018 1.1 christos dst_key_t * 3019 1.1 christos dns_message_getsig0key(dns_message_t *msg) { 3020 1.1 christos /* 3021 1.1 christos * Get the SIG(0) key for 'msg' 3022 1.1 christos */ 3023 1.1 christos 3024 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 3025 1.1 christos 3026 1.19 christos return msg->sig0key; 3027 1.1 christos } 3028 1.1 christos 3029 1.1 christos void 3030 1.1 christos dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) { 3031 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 3032 1.1 christos REQUIRE(buffer != NULL); 3033 1.1 christos REQUIRE(ISC_BUFFER_VALID(*buffer)); 3034 1.1 christos 3035 1.1 christos ISC_LIST_APPEND(msg->cleanup, *buffer, link); 3036 1.1 christos *buffer = NULL; 3037 1.1 christos } 3038 1.1 christos 3039 1.1 christos isc_result_t 3040 1.1 christos dns_message_signer(dns_message_t *msg, dns_name_t *signer) { 3041 1.1 christos isc_result_t result = ISC_R_SUCCESS; 3042 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT; 3043 1.1 christos 3044 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 3045 1.1 christos REQUIRE(signer != NULL); 3046 1.1 christos REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE); 3047 1.1 christos 3048 1.9 christos if (msg->tsig == NULL && msg->sig0 == NULL) { 3049 1.19 christos return ISC_R_NOTFOUND; 3050 1.9 christos } 3051 1.1 christos 3052 1.9 christos if (msg->verify_attempted == 0) { 3053 1.19 christos return DNS_R_NOTVERIFIEDYET; 3054 1.9 christos } 3055 1.1 christos 3056 1.1 christos if (!dns_name_hasbuffer(signer)) { 3057 1.1 christos isc_buffer_t *dynbuf = NULL; 3058 1.9 christos isc_buffer_allocate(msg->mctx, &dynbuf, 512); 3059 1.1 christos dns_name_setbuffer(signer, dynbuf); 3060 1.1 christos dns_message_takebuffer(msg, &dynbuf); 3061 1.1 christos } 3062 1.1 christos 3063 1.1 christos if (msg->sig0 != NULL) { 3064 1.1 christos dns_rdata_sig_t sig; 3065 1.1 christos 3066 1.1 christos result = dns_rdataset_first(msg->sig0); 3067 1.1 christos INSIST(result == ISC_R_SUCCESS); 3068 1.1 christos dns_rdataset_current(msg->sig0, &rdata); 3069 1.1 christos 3070 1.1 christos result = dns_rdata_tostruct(&rdata, &sig, NULL); 3071 1.9 christos if (result != ISC_R_SUCCESS) { 3072 1.19 christos return result; 3073 1.9 christos } 3074 1.1 christos 3075 1.9 christos if (msg->verified_sig && msg->sig0status == dns_rcode_noerror) { 3076 1.1 christos result = ISC_R_SUCCESS; 3077 1.9 christos } else { 3078 1.1 christos result = DNS_R_SIGINVALID; 3079 1.9 christos } 3080 1.1 christos dns_name_clone(&sig.signer, signer); 3081 1.1 christos dns_rdata_freestruct(&sig); 3082 1.1 christos } else { 3083 1.8 christos const dns_name_t *identity; 3084 1.1 christos dns_rdata_any_tsig_t tsig; 3085 1.1 christos 3086 1.1 christos result = dns_rdataset_first(msg->tsig); 3087 1.1 christos INSIST(result == ISC_R_SUCCESS); 3088 1.1 christos dns_rdataset_current(msg->tsig, &rdata); 3089 1.1 christos 3090 1.1 christos result = dns_rdata_tostruct(&rdata, &tsig, NULL); 3091 1.1 christos INSIST(result == ISC_R_SUCCESS); 3092 1.9 christos if (msg->verified_sig && msg->tsigstatus == dns_rcode_noerror && 3093 1.1 christos tsig.error == dns_rcode_noerror) 3094 1.1 christos { 3095 1.1 christos result = ISC_R_SUCCESS; 3096 1.1 christos } else if ((!msg->verified_sig) || 3097 1.15 christos (msg->tsigstatus != dns_rcode_noerror)) 3098 1.15 christos { 3099 1.1 christos result = DNS_R_TSIGVERIFYFAILURE; 3100 1.1 christos } else { 3101 1.1 christos INSIST(tsig.error != dns_rcode_noerror); 3102 1.1 christos result = DNS_R_TSIGERRORSET; 3103 1.1 christos } 3104 1.1 christos dns_rdata_freestruct(&tsig); 3105 1.1 christos 3106 1.1 christos if (msg->tsigkey == NULL) { 3107 1.1 christos /* 3108 1.1 christos * If msg->tsigstatus & tsig.error are both 3109 1.1 christos * dns_rcode_noerror, the message must have been 3110 1.1 christos * verified, which means msg->tsigkey will be 3111 1.1 christos * non-NULL. 3112 1.1 christos */ 3113 1.1 christos INSIST(result != ISC_R_SUCCESS); 3114 1.1 christos } else { 3115 1.1 christos identity = dns_tsigkey_identity(msg->tsigkey); 3116 1.1 christos if (identity == NULL) { 3117 1.9 christos if (result == ISC_R_SUCCESS) { 3118 1.1 christos result = DNS_R_NOIDENTITY; 3119 1.9 christos } 3120 1.19 christos identity = msg->tsigkey->name; 3121 1.1 christos } 3122 1.1 christos dns_name_clone(identity, signer); 3123 1.1 christos } 3124 1.1 christos } 3125 1.1 christos 3126 1.19 christos return result; 3127 1.1 christos } 3128 1.1 christos 3129 1.1 christos void 3130 1.1 christos dns_message_resetsig(dns_message_t *msg) { 3131 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 3132 1.1 christos msg->verified_sig = 0; 3133 1.1 christos msg->verify_attempted = 0; 3134 1.1 christos msg->tsigstatus = dns_rcode_noerror; 3135 1.1 christos msg->sig0status = dns_rcode_noerror; 3136 1.1 christos msg->timeadjust = 0; 3137 1.1 christos if (msg->tsigkey != NULL) { 3138 1.1 christos dns_tsigkey_detach(&msg->tsigkey); 3139 1.1 christos msg->tsigkey = NULL; 3140 1.1 christos } 3141 1.1 christos } 3142 1.1 christos 3143 1.1 christos #ifdef SKAN_MSG_DEBUG 3144 1.1 christos void 3145 1.1 christos dns_message_dumpsig(dns_message_t *msg, char *txt1) { 3146 1.1 christos dns_rdata_t querytsigrdata = DNS_RDATA_INIT; 3147 1.1 christos dns_rdata_any_tsig_t querytsig; 3148 1.1 christos isc_result_t result; 3149 1.1 christos 3150 1.1 christos if (msg->tsig != NULL) { 3151 1.1 christos result = dns_rdataset_first(msg->tsig); 3152 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS); 3153 1.1 christos dns_rdataset_current(msg->tsig, &querytsigrdata); 3154 1.1 christos result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL); 3155 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS); 3156 1.9 christos hexdump(txt1, "TSIG", querytsig.signature, querytsig.siglen); 3157 1.1 christos } 3158 1.1 christos 3159 1.1 christos if (msg->querytsig != NULL) { 3160 1.1 christos result = dns_rdataset_first(msg->querytsig); 3161 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS); 3162 1.1 christos dns_rdataset_current(msg->querytsig, &querytsigrdata); 3163 1.1 christos result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL); 3164 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS); 3165 1.1 christos hexdump(txt1, "QUERYTSIG", querytsig.signature, 3166 1.1 christos querytsig.siglen); 3167 1.1 christos } 3168 1.1 christos } 3169 1.9 christos #endif /* ifdef SKAN_MSG_DEBUG */ 3170 1.1 christos 3171 1.19 christos static void 3172 1.19 christos checksig_done(void *arg); 3173 1.19 christos 3174 1.19 christos static void 3175 1.19 christos checksig_run(void *arg) { 3176 1.19 christos checksig_ctx_t *chsigctx = arg; 3177 1.19 christos 3178 1.19 christos chsigctx->result = dns_message_checksig(chsigctx->msg, chsigctx->view); 3179 1.19 christos 3180 1.19 christos isc_async_run(chsigctx->loop, checksig_done, chsigctx); 3181 1.19 christos } 3182 1.19 christos 3183 1.19 christos static void 3184 1.19 christos checksig_done(void *arg) { 3185 1.19 christos checksig_ctx_t *chsigctx = arg; 3186 1.19 christos dns_message_t *msg = chsigctx->msg; 3187 1.19 christos 3188 1.19 christos chsigctx->cb(chsigctx->cbarg, chsigctx->result); 3189 1.19 christos 3190 1.19 christos dns_view_detach(&chsigctx->view); 3191 1.19 christos isc_loop_detach(&chsigctx->loop); 3192 1.19 christos isc_mem_put(msg->mctx, chsigctx, sizeof(*chsigctx)); 3193 1.19 christos dns_message_detach(&msg); 3194 1.19 christos } 3195 1.19 christos 3196 1.19 christos isc_result_t 3197 1.19 christos dns_message_checksig_async(dns_message_t *msg, dns_view_t *view, 3198 1.19 christos isc_loop_t *loop, dns_message_cb_t cb, void *cbarg) { 3199 1.19 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 3200 1.19 christos REQUIRE(view != NULL); 3201 1.19 christos REQUIRE(loop != NULL); 3202 1.19 christos REQUIRE(cb != NULL); 3203 1.19 christos 3204 1.19 christos checksig_ctx_t *chsigctx = isc_mem_get(msg->mctx, sizeof(*chsigctx)); 3205 1.19 christos *chsigctx = (checksig_ctx_t){ 3206 1.19 christos .cb = cb, 3207 1.19 christos .cbarg = cbarg, 3208 1.19 christos .result = ISC_R_UNSET, 3209 1.19 christos .loop = isc_loop_ref(loop), 3210 1.19 christos }; 3211 1.19 christos dns_message_attach(msg, &chsigctx->msg); 3212 1.19 christos dns_view_attach(view, &chsigctx->view); 3213 1.19 christos 3214 1.19 christos dns_message_clonebuffer(msg); 3215 1.19 christos isc_helper_run(loop, checksig_run, chsigctx); 3216 1.19 christos 3217 1.19 christos return DNS_R_WAIT; 3218 1.19 christos } 3219 1.19 christos 3220 1.1 christos isc_result_t 3221 1.1 christos dns_message_checksig(dns_message_t *msg, dns_view_t *view) { 3222 1.19 christos isc_buffer_t b, msgb; 3223 1.1 christos 3224 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 3225 1.1 christos 3226 1.19 christos if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL) { 3227 1.19 christos return ISC_R_SUCCESS; 3228 1.9 christos } 3229 1.1 christos 3230 1.1 christos INSIST(msg->saved.base != NULL); 3231 1.1 christos isc_buffer_init(&msgb, msg->saved.base, msg->saved.length); 3232 1.1 christos isc_buffer_add(&msgb, msg->saved.length); 3233 1.19 christos if (msg->tsigkey != NULL || msg->tsig != NULL) { 3234 1.1 christos #ifdef SKAN_MSG_DEBUG 3235 1.19 christos dns_message_dumpsig(msg, "dns_message_checksig#1"); 3236 1.9 christos #endif /* ifdef SKAN_MSG_DEBUG */ 3237 1.19 christos if (view != NULL) { 3238 1.19 christos return dns_view_checksig(view, &msgb, msg); 3239 1.19 christos } else { 3240 1.19 christos return dns_tsig_verify(&msgb, msg, NULL, NULL); 3241 1.19 christos } 3242 1.1 christos } else { 3243 1.19 christos dns_rdata_t rdata = DNS_RDATA_INIT; 3244 1.19 christos dns_rdata_sig_t sig; 3245 1.19 christos dns_rdataset_t keyset; 3246 1.19 christos isc_result_t result; 3247 1.20 christos uint32_t key_checks, message_checks; 3248 1.19 christos 3249 1.19 christos result = dns_rdataset_first(msg->sig0); 3250 1.19 christos INSIST(result == ISC_R_SUCCESS); 3251 1.19 christos dns_rdataset_current(msg->sig0, &rdata); 3252 1.19 christos 3253 1.19 christos /* 3254 1.19 christos * This can occur when the message is a dynamic update, since 3255 1.19 christos * the rdata length checking is relaxed. This should not 3256 1.19 christos * happen in a well-formed message, since the SIG(0) is only 3257 1.19 christos * looked for in the additional section, and the dynamic update 3258 1.19 christos * meta-records are in the prerequisite and update sections. 3259 1.19 christos */ 3260 1.19 christos if (rdata.length == 0) { 3261 1.19 christos return ISC_R_UNEXPECTEDEND; 3262 1.19 christos } 3263 1.19 christos 3264 1.19 christos result = dns_rdata_tostruct(&rdata, &sig, NULL); 3265 1.19 christos if (result != ISC_R_SUCCESS) { 3266 1.19 christos return result; 3267 1.19 christos } 3268 1.19 christos 3269 1.19 christos dns_rdataset_init(&keyset); 3270 1.19 christos if (view == NULL) { 3271 1.19 christos result = DNS_R_KEYUNAUTHORIZED; 3272 1.19 christos goto freesig; 3273 1.19 christos } 3274 1.19 christos result = dns_view_simplefind(view, &sig.signer, 3275 1.19 christos dns_rdatatype_key /* SIG(0) */, 0, 3276 1.19 christos 0, false, &keyset, NULL); 3277 1.19 christos 3278 1.19 christos if (result != ISC_R_SUCCESS) { 3279 1.19 christos result = DNS_R_KEYUNAUTHORIZED; 3280 1.19 christos goto freesig; 3281 1.19 christos } else if (keyset.trust < dns_trust_ultimate) { 3282 1.19 christos result = DNS_R_KEYUNAUTHORIZED; 3283 1.19 christos goto freesig; 3284 1.19 christos } 3285 1.19 christos result = dns_rdataset_first(&keyset); 3286 1.19 christos INSIST(result == ISC_R_SUCCESS); 3287 1.19 christos 3288 1.20 christos /* 3289 1.20 christos * In order to protect from a possible DoS attack, this function 3290 1.20 christos * supports limitations on how many keyid checks and how many 3291 1.20 christos * key checks (message verifications using a matched key) are 3292 1.20 christos * going to be allowed. 3293 1.20 christos */ 3294 1.20 christos const uint32_t max_key_checks = 3295 1.20 christos view->sig0key_checks_limit > 0 3296 1.20 christos ? view->sig0key_checks_limit 3297 1.20 christos : UINT32_MAX; 3298 1.20 christos const uint32_t max_message_checks = 3299 1.20 christos view->sig0message_checks_limit > 0 3300 1.20 christos ? view->sig0message_checks_limit 3301 1.20 christos : UINT32_MAX; 3302 1.20 christos 3303 1.20 christos for (key_checks = 0, message_checks = 0; 3304 1.20 christos result == ISC_R_SUCCESS && key_checks < max_key_checks && 3305 1.20 christos message_checks < max_message_checks; 3306 1.20 christos key_checks++, result = dns_rdataset_next(&keyset)) 3307 1.19 christos { 3308 1.19 christos dst_key_t *key = NULL; 3309 1.19 christos 3310 1.19 christos dns_rdata_reset(&rdata); 3311 1.19 christos dns_rdataset_current(&keyset, &rdata); 3312 1.19 christos isc_buffer_init(&b, rdata.data, rdata.length); 3313 1.19 christos isc_buffer_add(&b, rdata.length); 3314 1.19 christos 3315 1.19 christos result = dst_key_fromdns(&sig.signer, rdata.rdclass, &b, 3316 1.19 christos view->mctx, &key); 3317 1.19 christos if (result != ISC_R_SUCCESS) { 3318 1.19 christos continue; 3319 1.19 christos } 3320 1.19 christos if (dst_key_alg(key) != sig.algorithm || 3321 1.19 christos dst_key_id(key) != sig.keyid || 3322 1.19 christos !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC || 3323 1.19 christos dst_key_proto(key) == DNS_KEYPROTO_ANY)) 3324 1.19 christos { 3325 1.19 christos dst_key_free(&key); 3326 1.19 christos continue; 3327 1.19 christos } 3328 1.19 christos result = dns_dnssec_verifymessage(&msgb, msg, key); 3329 1.19 christos dst_key_free(&key); 3330 1.19 christos if (result == ISC_R_SUCCESS) { 3331 1.19 christos break; 3332 1.19 christos } 3333 1.20 christos message_checks++; 3334 1.19 christos } 3335 1.20 christos if (result == ISC_R_NOMORE) { 3336 1.20 christos result = DNS_R_KEYUNAUTHORIZED; 3337 1.20 christos } else if (key_checks == max_key_checks) { 3338 1.20 christos isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 3339 1.20 christos DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3), 3340 1.20 christos "sig0key-checks-limit reached when " 3341 1.20 christos "trying to check a message signature"); 3342 1.20 christos result = DNS_R_KEYUNAUTHORIZED; 3343 1.20 christos } else if (message_checks == max_message_checks) { 3344 1.20 christos isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 3345 1.20 christos DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3), 3346 1.20 christos "sig0message-checks-limit reached when " 3347 1.20 christos "trying to check a message signature"); 3348 1.19 christos result = DNS_R_KEYUNAUTHORIZED; 3349 1.19 christos } 3350 1.19 christos 3351 1.19 christos freesig: 3352 1.19 christos if (dns_rdataset_isassociated(&keyset)) { 3353 1.19 christos dns_rdataset_disassociate(&keyset); 3354 1.19 christos } 3355 1.19 christos dns_rdata_freestruct(&sig); 3356 1.19 christos return result; 3357 1.1 christos } 3358 1.1 christos } 3359 1.1 christos 3360 1.9 christos #define INDENT(sp) \ 3361 1.9 christos do { \ 3362 1.9 christos unsigned int __i; \ 3363 1.9 christos dns_masterstyle_flags_t __flags = dns_master_styleflags(sp); \ 3364 1.9 christos if ((__flags & DNS_STYLEFLAG_INDENT) == 0ULL && \ 3365 1.9 christos (__flags & DNS_STYLEFLAG_YAML) == 0ULL) \ 3366 1.19 christos { \ 3367 1.9 christos break; \ 3368 1.19 christos } \ 3369 1.9 christos for (__i = 0; __i < msg->indent.count; __i++) { \ 3370 1.9 christos ADD_STRING(target, msg->indent.string); \ 3371 1.9 christos } \ 3372 1.12 rillig } while (0) 3373 1.1 christos 3374 1.1 christos isc_result_t 3375 1.1 christos dns_message_sectiontotext(dns_message_t *msg, dns_section_t section, 3376 1.1 christos const dns_master_style_t *style, 3377 1.9 christos dns_messagetextflag_t flags, isc_buffer_t *target) { 3378 1.19 christos dns_name_t empty_name; 3379 1.1 christos isc_result_t result = ISC_R_SUCCESS; 3380 1.3 christos bool seensoa = false; 3381 1.9 christos size_t saved_count; 3382 1.1 christos dns_masterstyle_flags_t sflags; 3383 1.1 christos 3384 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 3385 1.1 christos REQUIRE(target != NULL); 3386 1.19 christos REQUIRE(VALID_NAMED_SECTION(section)); 3387 1.1 christos 3388 1.9 christos saved_count = msg->indent.count; 3389 1.9 christos 3390 1.9 christos if (ISC_LIST_EMPTY(msg->sections[section])) { 3391 1.1 christos goto cleanup; 3392 1.9 christos } 3393 1.1 christos 3394 1.9 christos sflags = dns_master_styleflags(style); 3395 1.1 christos 3396 1.1 christos INDENT(style); 3397 1.1 christos if ((sflags & DNS_STYLEFLAG_YAML) != 0) { 3398 1.1 christos if (msg->opcode != dns_opcode_update) { 3399 1.1 christos ADD_STRING(target, sectiontext[section]); 3400 1.1 christos } else { 3401 1.1 christos ADD_STRING(target, updsectiontext[section]); 3402 1.1 christos } 3403 1.1 christos ADD_STRING(target, "_SECTION:\n"); 3404 1.1 christos } else if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) { 3405 1.1 christos ADD_STRING(target, ";; "); 3406 1.1 christos if (msg->opcode != dns_opcode_update) { 3407 1.1 christos ADD_STRING(target, sectiontext[section]); 3408 1.1 christos } else { 3409 1.1 christos ADD_STRING(target, updsectiontext[section]); 3410 1.1 christos } 3411 1.1 christos ADD_STRING(target, " SECTION:\n"); 3412 1.1 christos } 3413 1.1 christos 3414 1.1 christos dns_name_init(&empty_name, NULL); 3415 1.1 christos result = dns_message_firstname(msg, section); 3416 1.1 christos if (result != ISC_R_SUCCESS) { 3417 1.1 christos goto cleanup; 3418 1.1 christos } 3419 1.1 christos if ((sflags & DNS_STYLEFLAG_YAML) != 0) { 3420 1.9 christos msg->indent.count++; 3421 1.1 christos } 3422 1.1 christos do { 3423 1.19 christos dns_name_t *name = NULL; 3424 1.1 christos dns_message_currentname(msg, section, &name); 3425 1.19 christos 3426 1.19 christos dns_rdataset_t *rds = NULL; 3427 1.22 christos ISC_LIST_FOREACH(name->list, rds, link) { 3428 1.1 christos if (section == DNS_SECTION_ANSWER && 3429 1.19 christos rds->type == dns_rdatatype_soa) 3430 1.15 christos { 3431 1.1 christos if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0) 3432 1.9 christos { 3433 1.1 christos continue; 3434 1.9 christos } 3435 1.1 christos if (seensoa && 3436 1.15 christos (flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0) 3437 1.15 christos { 3438 1.1 christos continue; 3439 1.9 christos } 3440 1.3 christos seensoa = true; 3441 1.1 christos } 3442 1.1 christos if (section == DNS_SECTION_QUESTION) { 3443 1.1 christos INDENT(style); 3444 1.18 christos if ((sflags & DNS_STYLEFLAG_YAML) == 0) { 3445 1.1 christos ADD_STRING(target, ";"); 3446 1.1 christos } 3447 1.9 christos result = dns_master_questiontotext( 3448 1.19 christos name, rds, style, target); 3449 1.1 christos } else { 3450 1.9 christos result = dns_master_rdatasettotext( 3451 1.19 christos name, rds, style, &msg->indent, target); 3452 1.1 christos } 3453 1.9 christos if (result != ISC_R_SUCCESS) { 3454 1.1 christos goto cleanup; 3455 1.9 christos } 3456 1.1 christos } 3457 1.1 christos result = dns_message_nextname(msg, section); 3458 1.1 christos } while (result == ISC_R_SUCCESS); 3459 1.1 christos if ((sflags & DNS_STYLEFLAG_YAML) != 0) { 3460 1.9 christos msg->indent.count--; 3461 1.1 christos } 3462 1.1 christos if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 && 3463 1.1 christos (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0 && 3464 1.1 christos (sflags & DNS_STYLEFLAG_YAML) == 0) 3465 1.1 christos { 3466 1.1 christos INDENT(style); 3467 1.1 christos ADD_STRING(target, "\n"); 3468 1.1 christos } 3469 1.9 christos if (result == ISC_R_NOMORE) { 3470 1.1 christos result = ISC_R_SUCCESS; 3471 1.9 christos } 3472 1.1 christos 3473 1.9 christos cleanup: 3474 1.9 christos msg->indent.count = saved_count; 3475 1.19 christos return result; 3476 1.1 christos } 3477 1.1 christos 3478 1.1 christos static isc_result_t 3479 1.1 christos render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) { 3480 1.1 christos int i; 3481 1.19 christos char addr[16] = { 0 }, addr_text[64]; 3482 1.3 christos uint16_t family; 3483 1.3 christos uint8_t addrlen, addrbytes, scopelen; 3484 1.1 christos isc_result_t result; 3485 1.1 christos 3486 1.1 christos /* 3487 1.1 christos * Note: This routine needs to handle malformed ECS options. 3488 1.1 christos */ 3489 1.1 christos 3490 1.9 christos if (isc_buffer_remaininglength(ecsbuf) < 4) { 3491 1.19 christos return DNS_R_OPTERR; 3492 1.9 christos } 3493 1.1 christos family = isc_buffer_getuint16(ecsbuf); 3494 1.1 christos addrlen = isc_buffer_getuint8(ecsbuf); 3495 1.1 christos scopelen = isc_buffer_getuint8(ecsbuf); 3496 1.1 christos 3497 1.1 christos addrbytes = (addrlen + 7) / 8; 3498 1.9 christos if (isc_buffer_remaininglength(ecsbuf) < addrbytes) { 3499 1.19 christos return DNS_R_OPTERR; 3500 1.9 christos } 3501 1.1 christos 3502 1.9 christos if (addrbytes > sizeof(addr)) { 3503 1.19 christos return DNS_R_OPTERR; 3504 1.9 christos } 3505 1.1 christos 3506 1.9 christos for (i = 0; i < addrbytes; i++) { 3507 1.1 christos addr[i] = isc_buffer_getuint8(ecsbuf); 3508 1.9 christos } 3509 1.1 christos 3510 1.1 christos switch (family) { 3511 1.1 christos case 0: 3512 1.9 christos if (addrlen != 0U || scopelen != 0U) { 3513 1.19 christos return DNS_R_OPTERR; 3514 1.9 christos } 3515 1.1 christos strlcpy(addr_text, "0", sizeof(addr_text)); 3516 1.1 christos break; 3517 1.1 christos case 1: 3518 1.9 christos if (addrlen > 32 || scopelen > 32) { 3519 1.19 christos return DNS_R_OPTERR; 3520 1.9 christos } 3521 1.1 christos inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text)); 3522 1.1 christos break; 3523 1.1 christos case 2: 3524 1.9 christos if (addrlen > 128 || scopelen > 128) { 3525 1.19 christos return DNS_R_OPTERR; 3526 1.9 christos } 3527 1.1 christos inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text)); 3528 1.1 christos break; 3529 1.1 christos default: 3530 1.19 christos return DNS_R_OPTERR; 3531 1.1 christos } 3532 1.1 christos 3533 1.9 christos ADD_STRING(target, " "); 3534 1.1 christos ADD_STRING(target, addr_text); 3535 1.1 christos snprintf(addr_text, sizeof(addr_text), "/%d/%d", addrlen, scopelen); 3536 1.1 christos ADD_STRING(target, addr_text); 3537 1.1 christos 3538 1.1 christos result = ISC_R_SUCCESS; 3539 1.1 christos 3540 1.9 christos cleanup: 3541 1.19 christos return result; 3542 1.1 christos } 3543 1.1 christos 3544 1.7 christos static isc_result_t 3545 1.20 christos render_llq(isc_buffer_t *optbuf, dns_message_t *msg, 3546 1.20 christos const dns_master_style_t *style, isc_buffer_t *target) { 3547 1.7 christos char buf[sizeof("18446744073709551615")]; /* 2^64-1 */ 3548 1.7 christos isc_result_t result = ISC_R_SUCCESS; 3549 1.7 christos uint32_t u; 3550 1.7 christos uint64_t q; 3551 1.20 christos const char *sep1 = " ", *sep2 = ", "; 3552 1.20 christos size_t count = msg->indent.count; 3553 1.20 christos bool yaml = false; 3554 1.20 christos 3555 1.20 christos if ((dns_master_styleflags(style) & DNS_STYLEFLAG_YAML) != 0) { 3556 1.20 christos sep1 = sep2 = "\n"; 3557 1.20 christos msg->indent.count++; 3558 1.20 christos yaml = true; 3559 1.20 christos } 3560 1.7 christos 3561 1.7 christos u = isc_buffer_getuint16(optbuf); 3562 1.20 christos ADD_STRING(target, sep1); 3563 1.20 christos INDENT(style); 3564 1.20 christos if (yaml) { 3565 1.20 christos ADD_STRING(target, "LLQ-VERSION: "); 3566 1.20 christos } else { 3567 1.20 christos ADD_STRING(target, "Version: "); 3568 1.20 christos } 3569 1.7 christos snprintf(buf, sizeof(buf), "%u", u); 3570 1.7 christos ADD_STRING(target, buf); 3571 1.7 christos 3572 1.7 christos u = isc_buffer_getuint16(optbuf); 3573 1.20 christos ADD_STRING(target, sep2); 3574 1.20 christos INDENT(style); 3575 1.20 christos if (yaml) { 3576 1.20 christos ADD_STRING(target, "LLQ-OPCODE: "); 3577 1.20 christos } else { 3578 1.20 christos ADD_STRING(target, "Opcode: "); 3579 1.20 christos } 3580 1.7 christos snprintf(buf, sizeof(buf), "%u", u); 3581 1.7 christos ADD_STRING(target, buf); 3582 1.7 christos 3583 1.7 christos u = isc_buffer_getuint16(optbuf); 3584 1.20 christos ADD_STRING(target, sep2); 3585 1.20 christos INDENT(style); 3586 1.20 christos if (yaml) { 3587 1.20 christos ADD_STRING(target, "LLQ-ERROR: "); 3588 1.20 christos } else { 3589 1.20 christos ADD_STRING(target, "Error: "); 3590 1.20 christos } 3591 1.7 christos snprintf(buf, sizeof(buf), "%u", u); 3592 1.7 christos ADD_STRING(target, buf); 3593 1.7 christos 3594 1.7 christos q = isc_buffer_getuint32(optbuf); 3595 1.7 christos q <<= 32; 3596 1.7 christos q |= isc_buffer_getuint32(optbuf); 3597 1.20 christos ADD_STRING(target, sep2); 3598 1.20 christos INDENT(style); 3599 1.20 christos if (yaml) { 3600 1.20 christos ADD_STRING(target, "LLQ-ID: "); 3601 1.20 christos } else { 3602 1.20 christos ADD_STRING(target, "Identifier: "); 3603 1.20 christos } 3604 1.7 christos snprintf(buf, sizeof(buf), "%" PRIu64, q); 3605 1.7 christos ADD_STRING(target, buf); 3606 1.7 christos 3607 1.7 christos u = isc_buffer_getuint32(optbuf); 3608 1.20 christos ADD_STRING(target, sep2); 3609 1.20 christos INDENT(style); 3610 1.20 christos if (yaml) { 3611 1.20 christos ADD_STRING(target, "LLQ-LEASE: "); 3612 1.20 christos } else { 3613 1.20 christos ADD_STRING(target, "Lifetime: "); 3614 1.20 christos } 3615 1.7 christos snprintf(buf, sizeof(buf), "%u", u); 3616 1.7 christos ADD_STRING(target, buf); 3617 1.20 christos 3618 1.9 christos cleanup: 3619 1.20 christos msg->indent.count = count; 3620 1.19 christos return result; 3621 1.7 christos } 3622 1.1 christos 3623 1.1 christos static isc_result_t 3624 1.20 christos put_yamlstr(isc_buffer_t *target, unsigned char *namebuf, size_t len, 3625 1.20 christos bool utfok) { 3626 1.20 christos isc_result_t result = ISC_R_SUCCESS; 3627 1.20 christos 3628 1.20 christos for (size_t i = 0; i < len; i++) { 3629 1.20 christos if (isprint(namebuf[i]) || (utfok && namebuf[i] > 127)) { 3630 1.20 christos if (namebuf[i] == '\\' || namebuf[i] == '"') { 3631 1.20 christos ADD_STRING(target, "\\"); 3632 1.20 christos } 3633 1.20 christos if (isc_buffer_availablelength(target) < 1) { 3634 1.20 christos return ISC_R_NOSPACE; 3635 1.20 christos } 3636 1.20 christos isc_buffer_putmem(target, &namebuf[i], 1); 3637 1.20 christos } else { 3638 1.20 christos ADD_STRING(target, "."); 3639 1.20 christos } 3640 1.20 christos } 3641 1.20 christos cleanup: 3642 1.20 christos return result; 3643 1.20 christos } 3644 1.20 christos 3645 1.20 christos static isc_result_t 3646 1.20 christos render_nameopt(isc_buffer_t *optbuf, bool yaml, isc_buffer_t *target) { 3647 1.20 christos dns_decompress_t dctx = DNS_DECOMPRESS_NEVER; 3648 1.20 christos dns_fixedname_t fixed; 3649 1.20 christos dns_name_t *name = dns_fixedname_initname(&fixed); 3650 1.20 christos char namebuf[DNS_NAME_FORMATSIZE]; 3651 1.20 christos isc_result_t result; 3652 1.20 christos 3653 1.20 christos result = dns_name_fromwire(name, optbuf, dctx, NULL); 3654 1.20 christos if (result == ISC_R_SUCCESS && isc_buffer_activelength(optbuf) == 0) { 3655 1.20 christos dns_name_format(name, namebuf, sizeof(namebuf)); 3656 1.20 christos ADD_STRING(target, " \""); 3657 1.20 christos if (yaml) { 3658 1.20 christos PUT_YAMLSTR(target, (unsigned char *)namebuf, 3659 1.20 christos strlen(namebuf), false); 3660 1.20 christos } else { 3661 1.20 christos ADD_STRING(target, namebuf); 3662 1.20 christos } 3663 1.20 christos ADD_STRING(target, "\""); 3664 1.20 christos return result; 3665 1.20 christos } 3666 1.20 christos result = ISC_R_FAILURE; 3667 1.20 christos cleanup: 3668 1.20 christos return result; 3669 1.20 christos } 3670 1.20 christos 3671 1.20 christos static const char *option_names[] = { 3672 1.20 christos [DNS_OPT_LLQ] = "LLQ", 3673 1.20 christos [DNS_OPT_UL] = "UPDATE-LEASE", 3674 1.20 christos [DNS_OPT_NSID] = "NSID", 3675 1.20 christos [DNS_OPT_DAU] = "DAU", 3676 1.20 christos [DNS_OPT_DHU] = "DHU", 3677 1.20 christos [DNS_OPT_N3U] = "N3U", 3678 1.20 christos [DNS_OPT_CLIENT_SUBNET] = "CLIENT-SUBNET", 3679 1.20 christos [DNS_OPT_EXPIRE] = "EXPIRE", 3680 1.20 christos [DNS_OPT_COOKIE] = "COOKIE", 3681 1.20 christos [DNS_OPT_TCP_KEEPALIVE] = "TCP-KEEPALIVE", 3682 1.20 christos [DNS_OPT_PAD] = "PADDING", 3683 1.20 christos [DNS_OPT_CHAIN] = "CHAIN", 3684 1.20 christos [DNS_OPT_KEY_TAG] = "KEY-TAG", 3685 1.20 christos [DNS_OPT_EDE] = "EDE", 3686 1.20 christos [DNS_OPT_CLIENT_TAG] = "CLIENT-TAG", 3687 1.20 christos [DNS_OPT_SERVER_TAG] = "SERVER-TAG", 3688 1.20 christos [DNS_OPT_REPORT_CHANNEL] = "Report-Channel", 3689 1.20 christos [DNS_OPT_ZONEVERSION] = "ZONEVERSION", 3690 1.20 christos }; 3691 1.20 christos 3692 1.20 christos static isc_result_t 3693 1.9 christos dns_message_pseudosectiontoyaml(dns_message_t *msg, dns_pseudosection_t section, 3694 1.1 christos const dns_master_style_t *style, 3695 1.1 christos dns_messagetextflag_t flags, 3696 1.9 christos isc_buffer_t *target) { 3697 1.1 christos dns_rdataset_t *ps = NULL; 3698 1.1 christos const dns_name_t *name = NULL; 3699 1.1 christos isc_result_t result = ISC_R_SUCCESS; 3700 1.19 christos char buf[sizeof("/1234567890")]; 3701 1.3 christos uint32_t mbz; 3702 1.1 christos dns_rdata_t rdata; 3703 1.1 christos isc_buffer_t optbuf; 3704 1.3 christos uint16_t optcode, optlen; 3705 1.9 christos size_t saved_count; 3706 1.20 christos unsigned char *optdata = NULL; 3707 1.10 christos unsigned int indent; 3708 1.20 christos isc_buffer_t ecsbuf; 3709 1.1 christos 3710 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 3711 1.1 christos REQUIRE(target != NULL); 3712 1.19 christos REQUIRE(VALID_NAMED_PSEUDOSECTION(section)); 3713 1.1 christos 3714 1.9 christos saved_count = msg->indent.count; 3715 1.9 christos 3716 1.1 christos switch (section) { 3717 1.1 christos case DNS_PSEUDOSECTION_OPT: 3718 1.1 christos ps = dns_message_getopt(msg); 3719 1.1 christos if (ps == NULL) { 3720 1.1 christos goto cleanup; 3721 1.1 christos } 3722 1.1 christos 3723 1.1 christos INDENT(style); 3724 1.1 christos ADD_STRING(target, "OPT_PSEUDOSECTION:\n"); 3725 1.9 christos msg->indent.count++; 3726 1.1 christos 3727 1.1 christos INDENT(style); 3728 1.1 christos ADD_STRING(target, "EDNS:\n"); 3729 1.10 christos indent = ++msg->indent.count; 3730 1.1 christos 3731 1.1 christos INDENT(style); 3732 1.1 christos ADD_STRING(target, "version: "); 3733 1.1 christos snprintf(buf, sizeof(buf), "%u", 3734 1.1 christos (unsigned int)((ps->ttl & 0x00ff0000) >> 16)); 3735 1.1 christos ADD_STRING(target, buf); 3736 1.1 christos ADD_STRING(target, "\n"); 3737 1.1 christos INDENT(style); 3738 1.1 christos ADD_STRING(target, "flags:"); 3739 1.9 christos if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0) { 3740 1.1 christos ADD_STRING(target, " do"); 3741 1.9 christos } 3742 1.21 christos if ((ps->ttl & DNS_MESSAGEEXTFLAG_CO) != 0) { 3743 1.21 christos ADD_STRING(target, " co"); 3744 1.21 christos } 3745 1.1 christos ADD_STRING(target, "\n"); 3746 1.1 christos mbz = ps->ttl & 0xffff; 3747 1.21 christos /* Exclude Known Flags. */ 3748 1.21 christos mbz &= ~(DNS_MESSAGEEXTFLAG_DO | DNS_MESSAGEEXTFLAG_CO); 3749 1.1 christos if (mbz != 0) { 3750 1.1 christos INDENT(style); 3751 1.1 christos ADD_STRING(target, "MBZ: "); 3752 1.1 christos snprintf(buf, sizeof(buf), "0x%.4x", mbz); 3753 1.1 christos ADD_STRING(target, buf); 3754 1.1 christos ADD_STRING(target, "\n"); 3755 1.1 christos } 3756 1.1 christos INDENT(style); 3757 1.1 christos ADD_STRING(target, "udp: "); 3758 1.1 christos snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass); 3759 1.1 christos ADD_STRING(target, buf); 3760 1.1 christos result = dns_rdataset_first(ps); 3761 1.1 christos if (result != ISC_R_SUCCESS) { 3762 1.1 christos result = ISC_R_SUCCESS; 3763 1.1 christos goto cleanup; 3764 1.1 christos } 3765 1.1 christos 3766 1.1 christos /* 3767 1.1 christos * Print EDNS info, if any. 3768 1.1 christos * 3769 1.1 christos * WARNING: The option contents may be malformed as 3770 1.10 christos * dig +ednsopt=value:<content> does not perform validity 3771 1.1 christos * checking. 3772 1.1 christos */ 3773 1.1 christos dns_rdata_init(&rdata); 3774 1.1 christos dns_rdataset_current(ps, &rdata); 3775 1.1 christos 3776 1.1 christos isc_buffer_init(&optbuf, rdata.data, rdata.length); 3777 1.1 christos isc_buffer_add(&optbuf, rdata.length); 3778 1.1 christos while (isc_buffer_remaininglength(&optbuf) != 0) { 3779 1.10 christos bool extra_text = false; 3780 1.20 christos const char *option_name = NULL; 3781 1.20 christos 3782 1.10 christos msg->indent.count = indent; 3783 1.1 christos INSIST(isc_buffer_remaininglength(&optbuf) >= 4U); 3784 1.1 christos optcode = isc_buffer_getuint16(&optbuf); 3785 1.1 christos optlen = isc_buffer_getuint16(&optbuf); 3786 1.1 christos INSIST(isc_buffer_remaininglength(&optbuf) >= optlen); 3787 1.1 christos 3788 1.20 christos INDENT(style); 3789 1.20 christos if (optcode < ARRAY_SIZE(option_names)) { 3790 1.20 christos option_name = option_names[optcode]; 3791 1.20 christos } 3792 1.20 christos if (option_name != NULL) { 3793 1.20 christos ADD_STRING(target, option_names[optcode]) 3794 1.20 christos } else { 3795 1.20 christos snprintf(buf, sizeof(buf), "OPT=%u", optcode); 3796 1.20 christos ADD_STRING(target, buf); 3797 1.20 christos } 3798 1.20 christos ADD_STRING(target, ":"); 3799 1.20 christos 3800 1.20 christos switch (optcode) { 3801 1.20 christos case DNS_OPT_LLQ: 3802 1.7 christos if (optlen == 18U) { 3803 1.20 christos result = render_llq(&optbuf, msg, style, 3804 1.20 christos target); 3805 1.7 christos if (result != ISC_R_SUCCESS) { 3806 1.7 christos goto cleanup; 3807 1.7 christos } 3808 1.7 christos ADD_STRING(target, "\n"); 3809 1.7 christos continue; 3810 1.7 christos } 3811 1.20 christos break; 3812 1.20 christos case DNS_OPT_UL: 3813 1.19 christos if (optlen == 4U || optlen == 8U) { 3814 1.19 christos uint32_t secs, key = 0; 3815 1.20 christos msg->indent.count++; 3816 1.20 christos 3817 1.19 christos secs = isc_buffer_getuint32(&optbuf); 3818 1.20 christos ADD_STRING(target, "\n"); 3819 1.20 christos INDENT(style); 3820 1.20 christos ADD_STRING(target, "LEASE:"); 3821 1.19 christos snprintf(buf, sizeof(buf), " %u", secs); 3822 1.19 christos ADD_STRING(target, buf); 3823 1.20 christos 3824 1.20 christos ADD_STRING(target, " # "); 3825 1.19 christos result = dns_ttl_totext(secs, true, 3826 1.19 christos true, target); 3827 1.19 christos if (result != ISC_R_SUCCESS) { 3828 1.19 christos goto cleanup; 3829 1.19 christos } 3830 1.20 christos ADD_STRING(target, "\n"); 3831 1.20 christos 3832 1.19 christos if (optlen == 8U) { 3833 1.20 christos key = isc_buffer_getuint32( 3834 1.20 christos &optbuf); 3835 1.20 christos INDENT(style); 3836 1.20 christos ADD_STRING(target, 3837 1.20 christos "KEY-LEASE:"); 3838 1.20 christos snprintf(buf, sizeof(buf), 3839 1.20 christos " %u", key); 3840 1.20 christos ADD_STRING(target, buf); 3841 1.20 christos 3842 1.20 christos ADD_STRING(target, " # "); 3843 1.19 christos result = dns_ttl_totext( 3844 1.19 christos key, true, true, 3845 1.19 christos target); 3846 1.19 christos if (result != ISC_R_SUCCESS) { 3847 1.19 christos goto cleanup; 3848 1.19 christos } 3849 1.20 christos ADD_STRING(target, "\n"); 3850 1.19 christos } 3851 1.19 christos continue; 3852 1.19 christos } 3853 1.20 christos break; 3854 1.20 christos case DNS_OPT_CLIENT_SUBNET: 3855 1.1 christos isc_buffer_init(&ecsbuf, 3856 1.1 christos isc_buffer_current(&optbuf), 3857 1.1 christos optlen); 3858 1.1 christos isc_buffer_add(&ecsbuf, optlen); 3859 1.1 christos result = render_ecs(&ecsbuf, target); 3860 1.9 christos if (result == ISC_R_NOSPACE) { 3861 1.1 christos goto cleanup; 3862 1.9 christos } 3863 1.1 christos if (result == ISC_R_SUCCESS) { 3864 1.1 christos isc_buffer_forward(&optbuf, optlen); 3865 1.1 christos ADD_STRING(target, "\n"); 3866 1.1 christos continue; 3867 1.1 christos } 3868 1.1 christos ADD_STRING(target, "\n"); 3869 1.20 christos break; 3870 1.20 christos case DNS_OPT_EXPIRE: 3871 1.1 christos if (optlen == 4) { 3872 1.3 christos uint32_t secs; 3873 1.1 christos secs = isc_buffer_getuint32(&optbuf); 3874 1.9 christos snprintf(buf, sizeof(buf), " %u", secs); 3875 1.1 christos ADD_STRING(target, buf); 3876 1.20 christos ADD_STRING(target, " # "); 3877 1.9 christos result = dns_ttl_totext(secs, true, 3878 1.9 christos true, target); 3879 1.9 christos if (result != ISC_R_SUCCESS) { 3880 1.1 christos goto cleanup; 3881 1.9 christos } 3882 1.20 christos ADD_STRING(target, "\n"); 3883 1.1 christos continue; 3884 1.1 christos } 3885 1.20 christos break; 3886 1.20 christos case DNS_OPT_TCP_KEEPALIVE: 3887 1.9 christos if (optlen == 2) { 3888 1.9 christos unsigned int dsecs; 3889 1.9 christos dsecs = isc_buffer_getuint16(&optbuf); 3890 1.20 christos snprintf(buf, sizeof(buf), " %u.%u", 3891 1.9 christos dsecs / 10U, dsecs % 10U); 3892 1.9 christos ADD_STRING(target, buf); 3893 1.9 christos ADD_STRING(target, " secs\n"); 3894 1.9 christos continue; 3895 1.9 christos } 3896 1.20 christos break; 3897 1.20 christos case DNS_OPT_CHAIN: 3898 1.20 christos case DNS_OPT_REPORT_CHANNEL: 3899 1.20 christos if (optlen > 0U) { 3900 1.20 christos isc_buffer_t sb = optbuf; 3901 1.20 christos isc_buffer_setactive(&optbuf, optlen); 3902 1.20 christos result = render_nameopt(&optbuf, true, 3903 1.20 christos target); 3904 1.20 christos if (result == ISC_R_SUCCESS) { 3905 1.20 christos ADD_STRING(target, "\n"); 3906 1.20 christos continue; 3907 1.20 christos } 3908 1.20 christos optbuf = sb; 3909 1.20 christos } 3910 1.20 christos break; 3911 1.20 christos case DNS_OPT_KEY_TAG: 3912 1.1 christos if (optlen > 0U && (optlen % 2U) == 0U) { 3913 1.20 christos const char *sep = " ["; 3914 1.1 christos while (optlen > 0U) { 3915 1.20 christos uint16_t id = 3916 1.20 christos isc_buffer_getuint16( 3917 1.20 christos &optbuf); 3918 1.9 christos snprintf(buf, sizeof(buf), 3919 1.9 christos "%s %u", sep, id); 3920 1.9 christos ADD_STRING(target, buf); 3921 1.9 christos sep = ","; 3922 1.9 christos optlen -= 2; 3923 1.1 christos } 3924 1.20 christos ADD_STRING(target, " ]\n"); 3925 1.1 christos continue; 3926 1.1 christos } 3927 1.20 christos break; 3928 1.20 christos case DNS_OPT_EDE: 3929 1.10 christos if (optlen >= 2U) { 3930 1.10 christos uint16_t ede; 3931 1.10 christos ADD_STRING(target, "\n"); 3932 1.10 christos msg->indent.count++; 3933 1.10 christos INDENT(style); 3934 1.10 christos ADD_STRING(target, "INFO-CODE:"); 3935 1.10 christos ede = isc_buffer_getuint16(&optbuf); 3936 1.10 christos snprintf(buf, sizeof(buf), " %u", ede); 3937 1.10 christos ADD_STRING(target, buf); 3938 1.10 christos if (ede < ARRAY_SIZE(edetext)) { 3939 1.10 christos ADD_STRING(target, " ("); 3940 1.10 christos ADD_STRING(target, 3941 1.10 christos edetext[ede]); 3942 1.10 christos ADD_STRING(target, ")"); 3943 1.10 christos } 3944 1.10 christos ADD_STRING(target, "\n"); 3945 1.10 christos optlen -= 2; 3946 1.10 christos if (optlen != 0) { 3947 1.10 christos INDENT(style); 3948 1.10 christos ADD_STRING(target, 3949 1.10 christos "EXTRA-TEXT:"); 3950 1.10 christos extra_text = true; 3951 1.10 christos } 3952 1.10 christos } 3953 1.20 christos break; 3954 1.20 christos case DNS_OPT_CLIENT_TAG: 3955 1.20 christos case DNS_OPT_SERVER_TAG: 3956 1.6 christos if (optlen == 2U) { 3957 1.20 christos uint16_t id = 3958 1.20 christos isc_buffer_getuint16(&optbuf); 3959 1.9 christos snprintf(buf, sizeof(buf), " %u\n", id); 3960 1.6 christos ADD_STRING(target, buf); 3961 1.6 christos continue; 3962 1.6 christos } 3963 1.20 christos break; 3964 1.20 christos case DNS_OPT_COOKIE: 3965 1.20 christos if (optlen == 8 || 3966 1.20 christos (optlen >= 16 && optlen < 40)) 3967 1.20 christos { 3968 1.20 christos size_t i; 3969 1.20 christos 3970 1.20 christos msg->indent.count++; 3971 1.20 christos optdata = isc_buffer_current(&optbuf); 3972 1.20 christos 3973 1.20 christos ADD_STRING(target, "\n"); 3974 1.20 christos INDENT(style); 3975 1.20 christos ADD_STRING(target, "CLIENT: "); 3976 1.20 christos for (i = 0; i < 8; i++) { 3977 1.20 christos snprintf(buf, sizeof(buf), 3978 1.20 christos "%02x", optdata[i]); 3979 1.20 christos ADD_STRING(target, buf); 3980 1.20 christos } 3981 1.20 christos ADD_STRING(target, "\n"); 3982 1.20 christos 3983 1.20 christos if (optlen >= 16) { 3984 1.20 christos INDENT(style); 3985 1.20 christos ADD_STRING(target, "SERVER: "); 3986 1.20 christos for (; i < optlen; i++) { 3987 1.20 christos snprintf(buf, 3988 1.20 christos sizeof(buf), 3989 1.20 christos "%02x", 3990 1.20 christos optdata[i]); 3991 1.20 christos ADD_STRING(target, buf); 3992 1.20 christos } 3993 1.20 christos ADD_STRING(target, "\n"); 3994 1.20 christos } 3995 1.20 christos 3996 1.20 christos /* 3997 1.20 christos * Valid server cookie? 3998 1.20 christos */ 3999 1.20 christos if (msg->cc_ok && optlen >= 16) { 4000 1.20 christos INDENT(style); 4001 1.20 christos ADD_STRING(target, 4002 1.20 christos "STATUS: good\n"); 4003 1.20 christos } 4004 1.20 christos /* 4005 1.20 christos * Server cookie is not valid but 4006 1.20 christos * we had our cookie echoed back. 4007 1.20 christos */ 4008 1.20 christos if (msg->cc_ok && optlen < 16) { 4009 1.20 christos INDENT(style); 4010 1.20 christos ADD_STRING(target, 4011 1.20 christos "STATUS: echoed\n"); 4012 1.20 christos } 4013 1.20 christos /* 4014 1.20 christos * We didn't get our cookie echoed 4015 1.20 christos * back. 4016 1.20 christos */ 4017 1.20 christos if (msg->cc_bad) { 4018 1.20 christos INDENT(style); 4019 1.20 christos ADD_STRING(target, 4020 1.20 christos "STATUS: bad\n)"); 4021 1.20 christos } 4022 1.20 christos isc_buffer_forward(&optbuf, optlen); 4023 1.6 christos continue; 4024 1.6 christos } 4025 1.20 christos break; 4026 1.20 christos default: 4027 1.20 christos break; 4028 1.1 christos } 4029 1.1 christos 4030 1.1 christos if (optlen != 0) { 4031 1.1 christos int i; 4032 1.10 christos bool utf8ok = false; 4033 1.9 christos 4034 1.9 christos ADD_STRING(target, " "); 4035 1.1 christos 4036 1.1 christos optdata = isc_buffer_current(&optbuf); 4037 1.10 christos if (extra_text) { 4038 1.10 christos utf8ok = isc_utf8_valid(optdata, 4039 1.10 christos optlen); 4040 1.10 christos } 4041 1.10 christos if (!utf8ok) { 4042 1.10 christos for (i = 0; i < optlen; i++) { 4043 1.10 christos const char *sep; 4044 1.10 christos switch (optcode) { 4045 1.10 christos case DNS_OPT_COOKIE: 4046 1.10 christos sep = ""; 4047 1.10 christos break; 4048 1.10 christos default: 4049 1.10 christos sep = " "; 4050 1.10 christos break; 4051 1.10 christos } 4052 1.10 christos snprintf(buf, sizeof(buf), 4053 1.10 christos "%02x%s", optdata[i], 4054 1.10 christos sep); 4055 1.10 christos ADD_STRING(target, buf); 4056 1.1 christos } 4057 1.1 christos } 4058 1.1 christos 4059 1.1 christos isc_buffer_forward(&optbuf, optlen); 4060 1.1 christos 4061 1.20 christos if (optcode == DNS_OPT_COOKIE || 4062 1.20 christos optcode == DNS_OPT_CLIENT_SUBNET) 4063 1.20 christos { 4064 1.1 christos ADD_STRING(target, "\n"); 4065 1.1 christos continue; 4066 1.1 christos } 4067 1.1 christos 4068 1.1 christos /* 4069 1.1 christos * For non-COOKIE options, add a printable 4070 1.1 christos * version 4071 1.1 christos */ 4072 1.10 christos if (!extra_text) { 4073 1.10 christos ADD_STRING(target, "(\""); 4074 1.10 christos } else { 4075 1.10 christos ADD_STRING(target, "\""); 4076 1.10 christos } 4077 1.20 christos PUT_YAMLSTR(target, optdata, optlen, utf8ok); 4078 1.10 christos if (!extra_text) { 4079 1.10 christos ADD_STRING(target, "\")"); 4080 1.10 christos } else { 4081 1.10 christos ADD_STRING(target, "\""); 4082 1.10 christos } 4083 1.1 christos } 4084 1.1 christos ADD_STRING(target, "\n"); 4085 1.1 christos } 4086 1.10 christos msg->indent.count = indent; 4087 1.1 christos result = ISC_R_SUCCESS; 4088 1.1 christos goto cleanup; 4089 1.1 christos case DNS_PSEUDOSECTION_TSIG: 4090 1.1 christos ps = dns_message_gettsig(msg, &name); 4091 1.1 christos if (ps == NULL) { 4092 1.1 christos result = ISC_R_SUCCESS; 4093 1.1 christos goto cleanup; 4094 1.1 christos } 4095 1.1 christos INDENT(style); 4096 1.1 christos ADD_STRING(target, "TSIG_PSEUDOSECTION:\n"); 4097 1.9 christos result = dns_master_rdatasettotext(name, ps, style, 4098 1.9 christos &msg->indent, target); 4099 1.1 christos ADD_STRING(target, "\n"); 4100 1.1 christos goto cleanup; 4101 1.1 christos case DNS_PSEUDOSECTION_SIG0: 4102 1.1 christos ps = dns_message_getsig0(msg, &name); 4103 1.1 christos if (ps == NULL) { 4104 1.1 christos result = ISC_R_SUCCESS; 4105 1.1 christos goto cleanup; 4106 1.1 christos } 4107 1.1 christos INDENT(style); 4108 1.1 christos ADD_STRING(target, "SIG0_PSEUDOSECTION:\n"); 4109 1.9 christos result = dns_master_rdatasettotext(name, ps, style, 4110 1.9 christos &msg->indent, target); 4111 1.1 christos if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 && 4112 1.1 christos (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 4113 1.9 christos { 4114 1.1 christos ADD_STRING(target, "\n"); 4115 1.9 christos } 4116 1.1 christos goto cleanup; 4117 1.1 christos } 4118 1.1 christos 4119 1.1 christos result = ISC_R_UNEXPECTED; 4120 1.1 christos 4121 1.9 christos cleanup: 4122 1.9 christos msg->indent.count = saved_count; 4123 1.19 christos return result; 4124 1.1 christos } 4125 1.1 christos 4126 1.1 christos isc_result_t 4127 1.9 christos dns_message_pseudosectiontotext(dns_message_t *msg, dns_pseudosection_t section, 4128 1.1 christos const dns_master_style_t *style, 4129 1.1 christos dns_messagetextflag_t flags, 4130 1.9 christos isc_buffer_t *target) { 4131 1.1 christos dns_rdataset_t *ps = NULL; 4132 1.1 christos const dns_name_t *name = NULL; 4133 1.1 christos isc_result_t result; 4134 1.1 christos char buf[sizeof(" (65000 bytes)")]; 4135 1.3 christos uint32_t mbz; 4136 1.1 christos dns_rdata_t rdata; 4137 1.1 christos isc_buffer_t optbuf; 4138 1.3 christos uint16_t optcode, optlen; 4139 1.20 christos unsigned char *optdata = NULL; 4140 1.20 christos isc_buffer_t ecsbuf; 4141 1.1 christos 4142 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 4143 1.1 christos REQUIRE(target != NULL); 4144 1.19 christos REQUIRE(VALID_NAMED_PSEUDOSECTION(section)); 4145 1.1 christos 4146 1.9 christos if ((dns_master_styleflags(style) & DNS_STYLEFLAG_YAML) != 0) { 4147 1.19 christos return dns_message_pseudosectiontoyaml(msg, section, style, 4148 1.19 christos flags, target); 4149 1.9 christos } 4150 1.9 christos 4151 1.1 christos switch (section) { 4152 1.1 christos case DNS_PSEUDOSECTION_OPT: 4153 1.1 christos ps = dns_message_getopt(msg); 4154 1.9 christos if (ps == NULL) { 4155 1.19 christos return ISC_R_SUCCESS; 4156 1.9 christos } 4157 1.1 christos if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) { 4158 1.1 christos INDENT(style); 4159 1.1 christos ADD_STRING(target, ";; OPT PSEUDOSECTION:\n"); 4160 1.1 christos } 4161 1.1 christos 4162 1.1 christos INDENT(style); 4163 1.1 christos ADD_STRING(target, "; EDNS: version: "); 4164 1.1 christos snprintf(buf, sizeof(buf), "%u", 4165 1.1 christos (unsigned int)((ps->ttl & 0x00ff0000) >> 16)); 4166 1.1 christos ADD_STRING(target, buf); 4167 1.1 christos ADD_STRING(target, ", flags:"); 4168 1.9 christos if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0) { 4169 1.1 christos ADD_STRING(target, " do"); 4170 1.9 christos } 4171 1.21 christos if ((ps->ttl & DNS_MESSAGEEXTFLAG_CO) != 0) { 4172 1.21 christos ADD_STRING(target, " co"); 4173 1.21 christos } 4174 1.1 christos mbz = ps->ttl & 0xffff; 4175 1.21 christos /* Exclude Known Flags. */ 4176 1.21 christos mbz &= ~(DNS_MESSAGEEXTFLAG_DO | DNS_MESSAGEEXTFLAG_CO); 4177 1.1 christos if (mbz != 0) { 4178 1.1 christos ADD_STRING(target, "; MBZ: "); 4179 1.1 christos snprintf(buf, sizeof(buf), "0x%.4x", mbz); 4180 1.1 christos ADD_STRING(target, buf); 4181 1.1 christos ADD_STRING(target, ", udp: "); 4182 1.9 christos } else { 4183 1.1 christos ADD_STRING(target, "; udp: "); 4184 1.9 christos } 4185 1.1 christos snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass); 4186 1.1 christos ADD_STRING(target, buf); 4187 1.1 christos 4188 1.1 christos result = dns_rdataset_first(ps); 4189 1.9 christos if (result != ISC_R_SUCCESS) { 4190 1.19 christos return ISC_R_SUCCESS; 4191 1.9 christos } 4192 1.1 christos 4193 1.1 christos /* 4194 1.1 christos * Print EDNS info, if any. 4195 1.1 christos * 4196 1.1 christos * WARNING: The option contents may be malformed as 4197 1.1 christos * dig +ednsopt=value:<content> does no validity 4198 1.1 christos * checking. 4199 1.1 christos */ 4200 1.1 christos dns_rdata_init(&rdata); 4201 1.1 christos dns_rdataset_current(ps, &rdata); 4202 1.1 christos 4203 1.1 christos isc_buffer_init(&optbuf, rdata.data, rdata.length); 4204 1.1 christos isc_buffer_add(&optbuf, rdata.length); 4205 1.1 christos while (isc_buffer_remaininglength(&optbuf) != 0) { 4206 1.20 christos const char *option_name = NULL; 4207 1.20 christos 4208 1.1 christos INSIST(isc_buffer_remaininglength(&optbuf) >= 4U); 4209 1.1 christos optcode = isc_buffer_getuint16(&optbuf); 4210 1.1 christos optlen = isc_buffer_getuint16(&optbuf); 4211 1.1 christos 4212 1.1 christos INSIST(isc_buffer_remaininglength(&optbuf) >= optlen); 4213 1.1 christos 4214 1.1 christos INDENT(style); 4215 1.20 christos ADD_STRING(target, "; "); 4216 1.20 christos if (optcode < ARRAY_SIZE(option_names)) { 4217 1.20 christos option_name = option_names[optcode]; 4218 1.20 christos } 4219 1.20 christos if (option_name != NULL) { 4220 1.20 christos ADD_STRING(target, option_names[optcode]) 4221 1.20 christos } else { 4222 1.20 christos snprintf(buf, sizeof(buf), "OPT=%u", optcode); 4223 1.20 christos ADD_STRING(target, buf); 4224 1.20 christos } 4225 1.20 christos ADD_STRING(target, ":"); 4226 1.1 christos 4227 1.20 christos switch (optcode) { 4228 1.20 christos case DNS_OPT_LLQ: 4229 1.7 christos if (optlen == 18U) { 4230 1.20 christos result = render_llq(&optbuf, msg, style, 4231 1.20 christos target); 4232 1.7 christos if (result != ISC_R_SUCCESS) { 4233 1.19 christos return result; 4234 1.7 christos } 4235 1.7 christos ADD_STRING(target, "\n"); 4236 1.7 christos continue; 4237 1.7 christos } 4238 1.20 christos break; 4239 1.20 christos case DNS_OPT_UL: 4240 1.19 christos if (optlen == 4U || optlen == 8U) { 4241 1.19 christos uint32_t secs, key = 0; 4242 1.19 christos secs = isc_buffer_getuint32(&optbuf); 4243 1.19 christos snprintf(buf, sizeof(buf), " %u", secs); 4244 1.19 christos ADD_STRING(target, buf); 4245 1.19 christos if (optlen == 8U) { 4246 1.19 christos key = isc_buffer_getuint32( 4247 1.19 christos &optbuf); 4248 1.19 christos snprintf(buf, sizeof(buf), 4249 1.19 christos "/%u", key); 4250 1.19 christos ADD_STRING(target, buf); 4251 1.19 christos } 4252 1.19 christos ADD_STRING(target, " ("); 4253 1.19 christos result = dns_ttl_totext(secs, true, 4254 1.19 christos true, target); 4255 1.19 christos if (result != ISC_R_SUCCESS) { 4256 1.19 christos goto cleanup; 4257 1.19 christos } 4258 1.19 christos if (optlen == 8U) { 4259 1.19 christos ADD_STRING(target, "/"); 4260 1.19 christos result = dns_ttl_totext( 4261 1.19 christos key, true, true, 4262 1.19 christos target); 4263 1.19 christos if (result != ISC_R_SUCCESS) { 4264 1.19 christos goto cleanup; 4265 1.19 christos } 4266 1.19 christos } 4267 1.19 christos ADD_STRING(target, ")\n"); 4268 1.19 christos continue; 4269 1.19 christos } 4270 1.20 christos break; 4271 1.20 christos case DNS_OPT_CLIENT_SUBNET: 4272 1.1 christos isc_buffer_init(&ecsbuf, 4273 1.1 christos isc_buffer_current(&optbuf), 4274 1.1 christos optlen); 4275 1.1 christos isc_buffer_add(&ecsbuf, optlen); 4276 1.1 christos result = render_ecs(&ecsbuf, target); 4277 1.9 christos if (result == ISC_R_NOSPACE) { 4278 1.19 christos return result; 4279 1.9 christos } 4280 1.1 christos if (result == ISC_R_SUCCESS) { 4281 1.1 christos isc_buffer_forward(&optbuf, optlen); 4282 1.1 christos ADD_STRING(target, "\n"); 4283 1.1 christos continue; 4284 1.1 christos } 4285 1.20 christos break; 4286 1.20 christos case DNS_OPT_EXPIRE: 4287 1.1 christos if (optlen == 4) { 4288 1.3 christos uint32_t secs; 4289 1.1 christos secs = isc_buffer_getuint32(&optbuf); 4290 1.9 christos snprintf(buf, sizeof(buf), " %u", secs); 4291 1.1 christos ADD_STRING(target, buf); 4292 1.1 christos ADD_STRING(target, " ("); 4293 1.9 christos result = dns_ttl_totext(secs, true, 4294 1.9 christos true, target); 4295 1.9 christos if (result != ISC_R_SUCCESS) { 4296 1.19 christos return result; 4297 1.9 christos } 4298 1.1 christos ADD_STRING(target, ")\n"); 4299 1.1 christos continue; 4300 1.1 christos } 4301 1.20 christos break; 4302 1.20 christos case DNS_OPT_TCP_KEEPALIVE: 4303 1.1 christos if (optlen == 2) { 4304 1.1 christos unsigned int dsecs; 4305 1.1 christos dsecs = isc_buffer_getuint16(&optbuf); 4306 1.1 christos snprintf(buf, sizeof(buf), " %u.%u", 4307 1.1 christos dsecs / 10U, dsecs % 10U); 4308 1.1 christos ADD_STRING(target, buf); 4309 1.1 christos ADD_STRING(target, " secs\n"); 4310 1.1 christos continue; 4311 1.1 christos } 4312 1.20 christos break; 4313 1.20 christos case DNS_OPT_PAD: 4314 1.1 christos if (optlen > 0U) { 4315 1.1 christos snprintf(buf, sizeof(buf), 4316 1.1 christos " (%u bytes)", optlen); 4317 1.1 christos ADD_STRING(target, buf); 4318 1.1 christos isc_buffer_forward(&optbuf, optlen); 4319 1.1 christos } 4320 1.1 christos ADD_STRING(target, "\n"); 4321 1.1 christos continue; 4322 1.20 christos case DNS_OPT_CHAIN: 4323 1.20 christos case DNS_OPT_REPORT_CHANNEL: 4324 1.20 christos if (optlen > 0U) { 4325 1.20 christos isc_buffer_t sb = optbuf; 4326 1.20 christos isc_buffer_setactive(&optbuf, optlen); 4327 1.20 christos result = render_nameopt(&optbuf, false, 4328 1.20 christos target); 4329 1.20 christos if (result == ISC_R_SUCCESS) { 4330 1.20 christos ADD_STRING(target, "\n"); 4331 1.20 christos continue; 4332 1.20 christos } 4333 1.20 christos optbuf = sb; 4334 1.20 christos } 4335 1.20 christos ADD_STRING(target, "\n"); 4336 1.20 christos break; 4337 1.20 christos case DNS_OPT_KEY_TAG: 4338 1.1 christos if (optlen > 0U && (optlen % 2U) == 0U) { 4339 1.9 christos const char *sep = ""; 4340 1.1 christos while (optlen > 0U) { 4341 1.20 christos uint16_t id = 4342 1.20 christos isc_buffer_getuint16( 4343 1.20 christos &optbuf); 4344 1.9 christos snprintf(buf, sizeof(buf), 4345 1.9 christos "%s %u", sep, id); 4346 1.9 christos ADD_STRING(target, buf); 4347 1.9 christos sep = ","; 4348 1.9 christos optlen -= 2; 4349 1.1 christos } 4350 1.1 christos ADD_STRING(target, "\n"); 4351 1.1 christos continue; 4352 1.1 christos } 4353 1.20 christos break; 4354 1.20 christos case DNS_OPT_EDE: 4355 1.10 christos if (optlen >= 2U) { 4356 1.10 christos uint16_t ede; 4357 1.10 christos ede = isc_buffer_getuint16(&optbuf); 4358 1.10 christos snprintf(buf, sizeof(buf), " %u", ede); 4359 1.10 christos ADD_STRING(target, buf); 4360 1.10 christos if (ede < ARRAY_SIZE(edetext)) { 4361 1.10 christos ADD_STRING(target, " ("); 4362 1.10 christos ADD_STRING(target, 4363 1.10 christos edetext[ede]); 4364 1.10 christos ADD_STRING(target, ")"); 4365 1.10 christos } 4366 1.10 christos optlen -= 2; 4367 1.10 christos if (optlen != 0) { 4368 1.10 christos ADD_STRING(target, ":"); 4369 1.10 christos } 4370 1.10 christos } else if (optlen == 1U) { 4371 1.10 christos /* Malformed */ 4372 1.10 christos optdata = isc_buffer_current(&optbuf); 4373 1.10 christos snprintf(buf, sizeof(buf), 4374 1.10 christos " %02x (\"%c\")\n", optdata[0], 4375 1.10 christos isprint(optdata[0]) 4376 1.10 christos ? optdata[0] 4377 1.10 christos : '.'); 4378 1.10 christos isc_buffer_forward(&optbuf, optlen); 4379 1.10 christos ADD_STRING(target, buf); 4380 1.10 christos continue; 4381 1.10 christos } 4382 1.20 christos break; 4383 1.20 christos case DNS_OPT_CLIENT_TAG: 4384 1.20 christos case DNS_OPT_SERVER_TAG: 4385 1.6 christos if (optlen == 2U) { 4386 1.20 christos uint16_t id = 4387 1.20 christos isc_buffer_getuint16(&optbuf); 4388 1.9 christos snprintf(buf, sizeof(buf), " %u\n", id); 4389 1.6 christos ADD_STRING(target, buf); 4390 1.6 christos continue; 4391 1.6 christos } 4392 1.20 christos break; 4393 1.20 christos default: 4394 1.20 christos break; 4395 1.1 christos } 4396 1.1 christos 4397 1.1 christos if (optlen != 0) { 4398 1.1 christos int i; 4399 1.10 christos bool utf8ok = false; 4400 1.9 christos 4401 1.9 christos ADD_STRING(target, " "); 4402 1.1 christos 4403 1.1 christos optdata = isc_buffer_current(&optbuf); 4404 1.10 christos if (optcode == DNS_OPT_EDE) { 4405 1.10 christos utf8ok = isc_utf8_valid(optdata, 4406 1.10 christos optlen); 4407 1.10 christos } 4408 1.10 christos if (!utf8ok) { 4409 1.10 christos for (i = 0; i < optlen; i++) { 4410 1.10 christos const char *sep; 4411 1.10 christos switch (optcode) { 4412 1.10 christos case DNS_OPT_COOKIE: 4413 1.10 christos sep = ""; 4414 1.10 christos break; 4415 1.10 christos default: 4416 1.10 christos sep = " "; 4417 1.10 christos break; 4418 1.10 christos } 4419 1.10 christos snprintf(buf, sizeof(buf), 4420 1.10 christos "%02x%s", optdata[i], 4421 1.10 christos sep); 4422 1.10 christos ADD_STRING(target, buf); 4423 1.1 christos } 4424 1.1 christos } 4425 1.1 christos 4426 1.1 christos isc_buffer_forward(&optbuf, optlen); 4427 1.1 christos 4428 1.1 christos if (optcode == DNS_OPT_COOKIE) { 4429 1.1 christos /* 4430 1.1 christos * Valid server cookie? 4431 1.1 christos */ 4432 1.9 christos if (msg->cc_ok && optlen >= 16) { 4433 1.1 christos ADD_STRING(target, " (good)"); 4434 1.9 christos } 4435 1.1 christos /* 4436 1.1 christos * Server cookie is not valid but 4437 1.1 christos * we had our cookie echoed back. 4438 1.1 christos */ 4439 1.9 christos if (msg->cc_ok && optlen < 16) { 4440 1.1 christos ADD_STRING(target, " (echoed)"); 4441 1.9 christos } 4442 1.1 christos /* 4443 1.1 christos * We didn't get our cookie echoed 4444 1.1 christos * back. 4445 1.1 christos */ 4446 1.9 christos if (msg->cc_bad) { 4447 1.1 christos ADD_STRING(target, " (bad)"); 4448 1.9 christos } 4449 1.1 christos ADD_STRING(target, "\n"); 4450 1.1 christos continue; 4451 1.1 christos } 4452 1.1 christos 4453 1.1 christos if (optcode == DNS_OPT_CLIENT_SUBNET) { 4454 1.1 christos ADD_STRING(target, "\n"); 4455 1.1 christos continue; 4456 1.1 christos } 4457 1.1 christos 4458 1.1 christos /* 4459 1.1 christos * For non-COOKIE options, add a printable 4460 1.10 christos * version. 4461 1.1 christos */ 4462 1.10 christos if (optcode != DNS_OPT_EDE) { 4463 1.10 christos ADD_STRING(target, "(\""); 4464 1.10 christos } else { 4465 1.10 christos ADD_STRING(target, "("); 4466 1.10 christos } 4467 1.1 christos if (isc_buffer_availablelength(target) < optlen) 4468 1.9 christos { 4469 1.19 christos return ISC_R_NOSPACE; 4470 1.9 christos } 4471 1.1 christos for (i = 0; i < optlen; i++) { 4472 1.10 christos if (isprint(optdata[i]) || 4473 1.15 christos (utf8ok && optdata[i] > 127)) 4474 1.15 christos { 4475 1.9 christos isc_buffer_putmem( 4476 1.9 christos target, &optdata[i], 1); 4477 1.9 christos } else { 4478 1.1 christos isc_buffer_putstr(target, "."); 4479 1.9 christos } 4480 1.1 christos } 4481 1.10 christos if (optcode != DNS_OPT_EDE) { 4482 1.10 christos ADD_STRING(target, "\")"); 4483 1.10 christos } else { 4484 1.10 christos ADD_STRING(target, ")"); 4485 1.10 christos } 4486 1.1 christos } 4487 1.1 christos ADD_STRING(target, "\n"); 4488 1.1 christos } 4489 1.19 christos return ISC_R_SUCCESS; 4490 1.1 christos case DNS_PSEUDOSECTION_TSIG: 4491 1.1 christos ps = dns_message_gettsig(msg, &name); 4492 1.9 christos if (ps == NULL) { 4493 1.19 christos return ISC_R_SUCCESS; 4494 1.9 christos } 4495 1.1 christos INDENT(style); 4496 1.9 christos if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) { 4497 1.1 christos ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n"); 4498 1.9 christos } 4499 1.9 christos result = dns_master_rdatasettotext(name, ps, style, 4500 1.9 christos &msg->indent, target); 4501 1.1 christos if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 && 4502 1.1 christos (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 4503 1.9 christos { 4504 1.1 christos ADD_STRING(target, "\n"); 4505 1.9 christos } 4506 1.19 christos return result; 4507 1.1 christos case DNS_PSEUDOSECTION_SIG0: 4508 1.1 christos ps = dns_message_getsig0(msg, &name); 4509 1.9 christos if (ps == NULL) { 4510 1.19 christos return ISC_R_SUCCESS; 4511 1.9 christos } 4512 1.1 christos INDENT(style); 4513 1.9 christos if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) { 4514 1.1 christos ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n"); 4515 1.9 christos } 4516 1.9 christos result = dns_master_rdatasettotext(name, ps, style, 4517 1.9 christos &msg->indent, target); 4518 1.1 christos if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 && 4519 1.1 christos (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 4520 1.9 christos { 4521 1.1 christos ADD_STRING(target, "\n"); 4522 1.9 christos } 4523 1.19 christos return result; 4524 1.1 christos } 4525 1.1 christos result = ISC_R_UNEXPECTED; 4526 1.9 christos cleanup: 4527 1.19 christos return result; 4528 1.1 christos } 4529 1.1 christos 4530 1.1 christos isc_result_t 4531 1.9 christos dns_message_headertotext(dns_message_t *msg, const dns_master_style_t *style, 4532 1.9 christos dns_messagetextflag_t flags, isc_buffer_t *target) { 4533 1.1 christos char buf[sizeof("1234567890")]; 4534 1.1 christos isc_result_t result; 4535 1.1 christos 4536 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 4537 1.1 christos REQUIRE(target != NULL); 4538 1.1 christos 4539 1.9 christos if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) != 0) { 4540 1.19 christos return ISC_R_SUCCESS; 4541 1.9 christos } 4542 1.9 christos 4543 1.9 christos if (dns_master_styleflags(style) & DNS_STYLEFLAG_YAML) { 4544 1.1 christos INDENT(style); 4545 1.1 christos ADD_STRING(target, "opcode: "); 4546 1.1 christos ADD_STRING(target, opcodetext[msg->opcode]); 4547 1.1 christos ADD_STRING(target, "\n"); 4548 1.1 christos INDENT(style); 4549 1.1 christos ADD_STRING(target, "status: "); 4550 1.1 christos result = dns_rcode_totext(msg->rcode, target); 4551 1.9 christos if (result != ISC_R_SUCCESS) { 4552 1.19 christos return result; 4553 1.9 christos } 4554 1.1 christos ADD_STRING(target, "\n"); 4555 1.1 christos INDENT(style); 4556 1.1 christos ADD_STRING(target, "id: "); 4557 1.9 christos snprintf(buf, sizeof(buf), "%u", msg->id); 4558 1.1 christos ADD_STRING(target, buf); 4559 1.1 christos ADD_STRING(target, "\n"); 4560 1.1 christos INDENT(style); 4561 1.1 christos ADD_STRING(target, "flags:"); 4562 1.9 christos if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) { 4563 1.1 christos ADD_STRING(target, " qr"); 4564 1.9 christos } 4565 1.9 christos if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) { 4566 1.1 christos ADD_STRING(target, " aa"); 4567 1.9 christos } 4568 1.9 christos if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) { 4569 1.1 christos ADD_STRING(target, " tc"); 4570 1.9 christos } 4571 1.9 christos if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) { 4572 1.1 christos ADD_STRING(target, " rd"); 4573 1.9 christos } 4574 1.9 christos if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) { 4575 1.1 christos ADD_STRING(target, " ra"); 4576 1.9 christos } 4577 1.9 christos if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) { 4578 1.1 christos ADD_STRING(target, " ad"); 4579 1.9 christos } 4580 1.9 christos if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) { 4581 1.1 christos ADD_STRING(target, " cd"); 4582 1.9 christos } 4583 1.1 christos ADD_STRING(target, "\n"); 4584 1.1 christos /* 4585 1.1 christos * The final unnamed flag must be zero. 4586 1.1 christos */ 4587 1.1 christos if ((msg->flags & 0x0040U) != 0) { 4588 1.1 christos INDENT(style); 4589 1.1 christos ADD_STRING(target, "MBZ: 0x4"); 4590 1.1 christos ADD_STRING(target, "\n"); 4591 1.1 christos } 4592 1.1 christos if (msg->opcode != dns_opcode_update) { 4593 1.1 christos INDENT(style); 4594 1.1 christos ADD_STRING(target, "QUESTION: "); 4595 1.1 christos } else { 4596 1.14 christos INDENT(style); 4597 1.1 christos ADD_STRING(target, "ZONE: "); 4598 1.1 christos } 4599 1.1 christos snprintf(buf, sizeof(buf), "%1u", 4600 1.1 christos msg->counts[DNS_SECTION_QUESTION]); 4601 1.1 christos ADD_STRING(target, buf); 4602 1.1 christos ADD_STRING(target, "\n"); 4603 1.1 christos if (msg->opcode != dns_opcode_update) { 4604 1.1 christos INDENT(style); 4605 1.1 christos ADD_STRING(target, "ANSWER: "); 4606 1.1 christos } else { 4607 1.1 christos INDENT(style); 4608 1.1 christos ADD_STRING(target, "PREREQ: "); 4609 1.1 christos } 4610 1.1 christos snprintf(buf, sizeof(buf), "%1u", 4611 1.1 christos msg->counts[DNS_SECTION_ANSWER]); 4612 1.1 christos ADD_STRING(target, buf); 4613 1.1 christos ADD_STRING(target, "\n"); 4614 1.1 christos if (msg->opcode != dns_opcode_update) { 4615 1.1 christos INDENT(style); 4616 1.1 christos ADD_STRING(target, "AUTHORITY: "); 4617 1.1 christos } else { 4618 1.1 christos INDENT(style); 4619 1.1 christos ADD_STRING(target, "UPDATE: "); 4620 1.1 christos } 4621 1.1 christos snprintf(buf, sizeof(buf), "%1u", 4622 1.9 christos msg->counts[DNS_SECTION_AUTHORITY]); 4623 1.1 christos ADD_STRING(target, buf); 4624 1.1 christos ADD_STRING(target, "\n"); 4625 1.1 christos INDENT(style); 4626 1.1 christos ADD_STRING(target, "ADDITIONAL: "); 4627 1.1 christos snprintf(buf, sizeof(buf), "%1u", 4628 1.9 christos msg->counts[DNS_SECTION_ADDITIONAL]); 4629 1.1 christos ADD_STRING(target, buf); 4630 1.1 christos ADD_STRING(target, "\n"); 4631 1.9 christos } else { 4632 1.1 christos INDENT(style); 4633 1.1 christos ADD_STRING(target, ";; ->>HEADER<<- opcode: "); 4634 1.1 christos ADD_STRING(target, opcodetext[msg->opcode]); 4635 1.1 christos ADD_STRING(target, ", status: "); 4636 1.1 christos result = dns_rcode_totext(msg->rcode, target); 4637 1.9 christos if (result != ISC_R_SUCCESS) { 4638 1.19 christos return result; 4639 1.9 christos } 4640 1.1 christos ADD_STRING(target, ", id: "); 4641 1.1 christos snprintf(buf, sizeof(buf), "%6u", msg->id); 4642 1.1 christos ADD_STRING(target, buf); 4643 1.1 christos ADD_STRING(target, "\n"); 4644 1.1 christos INDENT(style); 4645 1.1 christos ADD_STRING(target, ";; flags:"); 4646 1.9 christos if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) { 4647 1.1 christos ADD_STRING(target, " qr"); 4648 1.9 christos } 4649 1.9 christos if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) { 4650 1.1 christos ADD_STRING(target, " aa"); 4651 1.9 christos } 4652 1.9 christos if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) { 4653 1.1 christos ADD_STRING(target, " tc"); 4654 1.9 christos } 4655 1.9 christos if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) { 4656 1.1 christos ADD_STRING(target, " rd"); 4657 1.9 christos } 4658 1.9 christos if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) { 4659 1.1 christos ADD_STRING(target, " ra"); 4660 1.9 christos } 4661 1.9 christos if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) { 4662 1.1 christos ADD_STRING(target, " ad"); 4663 1.9 christos } 4664 1.9 christos if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) { 4665 1.1 christos ADD_STRING(target, " cd"); 4666 1.9 christos } 4667 1.1 christos /* 4668 1.1 christos * The final unnamed flag must be zero. 4669 1.1 christos */ 4670 1.1 christos if ((msg->flags & 0x0040U) != 0) { 4671 1.1 christos INDENT(style); 4672 1.1 christos ADD_STRING(target, "; MBZ: 0x4"); 4673 1.1 christos } 4674 1.1 christos if (msg->opcode != dns_opcode_update) { 4675 1.1 christos INDENT(style); 4676 1.1 christos ADD_STRING(target, "; QUESTION: "); 4677 1.1 christos } else { 4678 1.1 christos INDENT(style); 4679 1.1 christos ADD_STRING(target, "; ZONE: "); 4680 1.1 christos } 4681 1.1 christos snprintf(buf, sizeof(buf), "%1u", 4682 1.1 christos msg->counts[DNS_SECTION_QUESTION]); 4683 1.1 christos ADD_STRING(target, buf); 4684 1.1 christos if (msg->opcode != dns_opcode_update) { 4685 1.1 christos ADD_STRING(target, ", ANSWER: "); 4686 1.1 christos } else { 4687 1.1 christos ADD_STRING(target, ", PREREQ: "); 4688 1.1 christos } 4689 1.1 christos snprintf(buf, sizeof(buf), "%1u", 4690 1.1 christos msg->counts[DNS_SECTION_ANSWER]); 4691 1.1 christos ADD_STRING(target, buf); 4692 1.1 christos if (msg->opcode != dns_opcode_update) { 4693 1.1 christos ADD_STRING(target, ", AUTHORITY: "); 4694 1.1 christos } else { 4695 1.1 christos ADD_STRING(target, ", UPDATE: "); 4696 1.1 christos } 4697 1.1 christos snprintf(buf, sizeof(buf), "%1u", 4698 1.9 christos msg->counts[DNS_SECTION_AUTHORITY]); 4699 1.1 christos ADD_STRING(target, buf); 4700 1.1 christos ADD_STRING(target, ", ADDITIONAL: "); 4701 1.1 christos snprintf(buf, sizeof(buf), "%1u", 4702 1.9 christos msg->counts[DNS_SECTION_ADDITIONAL]); 4703 1.1 christos ADD_STRING(target, buf); 4704 1.1 christos ADD_STRING(target, "\n"); 4705 1.1 christos } 4706 1.9 christos 4707 1.9 christos cleanup: 4708 1.19 christos return result; 4709 1.9 christos } 4710 1.9 christos 4711 1.9 christos isc_result_t 4712 1.9 christos dns_message_totext(dns_message_t *msg, const dns_master_style_t *style, 4713 1.9 christos dns_messagetextflag_t flags, isc_buffer_t *target) { 4714 1.9 christos isc_result_t result; 4715 1.9 christos 4716 1.9 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 4717 1.9 christos REQUIRE(target != NULL); 4718 1.9 christos 4719 1.9 christos result = dns_message_headertotext(msg, style, flags, target); 4720 1.9 christos if (result != ISC_R_SUCCESS) { 4721 1.19 christos return result; 4722 1.9 christos } 4723 1.9 christos 4724 1.9 christos result = dns_message_pseudosectiontotext(msg, DNS_PSEUDOSECTION_OPT, 4725 1.1 christos style, flags, target); 4726 1.9 christos if (result != ISC_R_SUCCESS) { 4727 1.19 christos return result; 4728 1.9 christos } 4729 1.1 christos 4730 1.9 christos result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION, style, 4731 1.9 christos flags, target); 4732 1.9 christos if (result != ISC_R_SUCCESS) { 4733 1.19 christos return result; 4734 1.9 christos } 4735 1.9 christos 4736 1.9 christos result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER, style, 4737 1.9 christos flags, target); 4738 1.9 christos if (result != ISC_R_SUCCESS) { 4739 1.19 christos return result; 4740 1.9 christos } 4741 1.9 christos 4742 1.9 christos result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY, style, 4743 1.9 christos flags, target); 4744 1.9 christos if (result != ISC_R_SUCCESS) { 4745 1.19 christos return result; 4746 1.9 christos } 4747 1.9 christos 4748 1.9 christos result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL, style, 4749 1.9 christos flags, target); 4750 1.9 christos if (result != ISC_R_SUCCESS) { 4751 1.19 christos return result; 4752 1.9 christos } 4753 1.1 christos 4754 1.9 christos result = dns_message_pseudosectiontotext(msg, DNS_PSEUDOSECTION_TSIG, 4755 1.1 christos style, flags, target); 4756 1.9 christos if (result != ISC_R_SUCCESS) { 4757 1.19 christos return result; 4758 1.9 christos } 4759 1.1 christos 4760 1.9 christos result = dns_message_pseudosectiontotext(msg, DNS_PSEUDOSECTION_SIG0, 4761 1.1 christos style, flags, target); 4762 1.19 christos return result; 4763 1.1 christos } 4764 1.1 christos 4765 1.1 christos isc_region_t * 4766 1.1 christos dns_message_getrawmessage(dns_message_t *msg) { 4767 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 4768 1.19 christos return &msg->saved; 4769 1.1 christos } 4770 1.1 christos 4771 1.1 christos void 4772 1.1 christos dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order, 4773 1.17 christos dns_aclenv_t *env, dns_acl_t *acl, 4774 1.9 christos const dns_aclelement_t *elem) { 4775 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 4776 1.1 christos REQUIRE((order == NULL) == (env == NULL)); 4777 1.1 christos REQUIRE(env == NULL || (acl != NULL || elem != NULL)); 4778 1.1 christos 4779 1.1 christos msg->order = order; 4780 1.17 christos if (env != NULL) { 4781 1.17 christos dns_aclenv_attach(env, &msg->order_arg.env); 4782 1.17 christos } 4783 1.17 christos if (acl != NULL) { 4784 1.17 christos dns_acl_attach(acl, &msg->order_arg.acl); 4785 1.17 christos } 4786 1.1 christos msg->order_arg.element = elem; 4787 1.1 christos } 4788 1.1 christos 4789 1.1 christos void 4790 1.1 christos dns_message_settimeadjust(dns_message_t *msg, int timeadjust) { 4791 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 4792 1.1 christos msg->timeadjust = timeadjust; 4793 1.1 christos } 4794 1.1 christos 4795 1.1 christos int 4796 1.1 christos dns_message_gettimeadjust(dns_message_t *msg) { 4797 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 4798 1.19 christos return msg->timeadjust; 4799 1.1 christos } 4800 1.1 christos 4801 1.1 christos isc_result_t 4802 1.1 christos dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) { 4803 1.1 christos REQUIRE(opcode < 16); 4804 1.1 christos 4805 1.9 christos if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode])) { 4806 1.19 christos return ISC_R_NOSPACE; 4807 1.9 christos } 4808 1.1 christos isc_buffer_putstr(target, opcodetext[opcode]); 4809 1.19 christos return ISC_R_SUCCESS; 4810 1.1 christos } 4811 1.1 christos 4812 1.1 christos void 4813 1.9 christos dns_message_logpacket(dns_message_t *message, const char *description, 4814 1.9 christos const isc_sockaddr_t *address, 4815 1.1 christos isc_logcategory_t *category, isc_logmodule_t *module, 4816 1.9 christos int level, isc_mem_t *mctx) { 4817 1.1 christos REQUIRE(address != NULL); 4818 1.1 christos 4819 1.1 christos logfmtpacket(message, description, address, category, module, 4820 1.1 christos &dns_master_style_debug, level, mctx); 4821 1.1 christos } 4822 1.1 christos 4823 1.1 christos void 4824 1.9 christos dns_message_logfmtpacket(dns_message_t *message, const char *description, 4825 1.3 christos const isc_sockaddr_t *address, 4826 1.1 christos isc_logcategory_t *category, isc_logmodule_t *module, 4827 1.1 christos const dns_master_style_t *style, int level, 4828 1.9 christos isc_mem_t *mctx) { 4829 1.1 christos REQUIRE(address != NULL); 4830 1.1 christos 4831 1.1 christos logfmtpacket(message, description, address, category, module, style, 4832 1.1 christos level, mctx); 4833 1.1 christos } 4834 1.1 christos 4835 1.1 christos static void 4836 1.1 christos logfmtpacket(dns_message_t *message, const char *description, 4837 1.1 christos const isc_sockaddr_t *address, isc_logcategory_t *category, 4838 1.1 christos isc_logmodule_t *module, const dns_master_style_t *style, 4839 1.9 christos int level, isc_mem_t *mctx) { 4840 1.1 christos char addrbuf[ISC_SOCKADDR_FORMATSIZE] = { 0 }; 4841 1.1 christos const char *newline = "\n"; 4842 1.1 christos const char *space = " "; 4843 1.1 christos isc_buffer_t buffer; 4844 1.1 christos char *buf = NULL; 4845 1.1 christos int len = 1024; 4846 1.1 christos isc_result_t result; 4847 1.1 christos 4848 1.9 christos if (!isc_log_wouldlog(dns_lctx, level)) { 4849 1.1 christos return; 4850 1.9 christos } 4851 1.1 christos 4852 1.1 christos /* 4853 1.1 christos * Note that these are multiline debug messages. We want a newline 4854 1.1 christos * to appear in the log after each message. 4855 1.1 christos */ 4856 1.1 christos 4857 1.9 christos if (address != NULL) { 4858 1.1 christos isc_sockaddr_format(address, addrbuf, sizeof(addrbuf)); 4859 1.9 christos } else { 4860 1.1 christos newline = space = ""; 4861 1.9 christos } 4862 1.1 christos 4863 1.1 christos do { 4864 1.1 christos buf = isc_mem_get(mctx, len); 4865 1.1 christos isc_buffer_init(&buffer, buf, len); 4866 1.1 christos result = dns_message_totext(message, style, 0, &buffer); 4867 1.1 christos if (result == ISC_R_NOSPACE) { 4868 1.1 christos isc_mem_put(mctx, buf, len); 4869 1.1 christos len += 1024; 4870 1.9 christos } else if (result == ISC_R_SUCCESS) { 4871 1.1 christos isc_log_write(dns_lctx, category, module, level, 4872 1.1 christos "%s%s%s%s%.*s", description, space, 4873 1.1 christos addrbuf, newline, 4874 1.9 christos (int)isc_buffer_usedlength(&buffer), buf); 4875 1.9 christos } 4876 1.1 christos } while (result == ISC_R_NOSPACE); 4877 1.1 christos 4878 1.9 christos if (buf != NULL) { 4879 1.1 christos isc_mem_put(mctx, buf, len); 4880 1.9 christos } 4881 1.1 christos } 4882 1.1 christos 4883 1.1 christos isc_result_t 4884 1.1 christos dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp, 4885 1.9 christos unsigned int version, uint16_t udpsize, unsigned int flags, 4886 1.9 christos dns_ednsopt_t *ednsopts, size_t count) { 4887 1.1 christos dns_rdataset_t *rdataset = NULL; 4888 1.1 christos dns_rdatalist_t *rdatalist = NULL; 4889 1.1 christos dns_rdata_t *rdata = NULL; 4890 1.1 christos isc_result_t result; 4891 1.1 christos unsigned int len = 0, i; 4892 1.1 christos 4893 1.1 christos REQUIRE(DNS_MESSAGE_VALID(message)); 4894 1.1 christos REQUIRE(rdatasetp != NULL && *rdatasetp == NULL); 4895 1.1 christos 4896 1.19 christos dns_message_gettemprdatalist(message, &rdatalist); 4897 1.19 christos dns_message_gettemprdata(message, &rdata); 4898 1.19 christos dns_message_gettemprdataset(message, &rdataset); 4899 1.1 christos 4900 1.1 christos rdatalist->type = dns_rdatatype_opt; 4901 1.1 christos 4902 1.1 christos /* 4903 1.1 christos * Set Maximum UDP buffer size. 4904 1.1 christos */ 4905 1.1 christos rdatalist->rdclass = udpsize; 4906 1.1 christos 4907 1.1 christos /* 4908 1.1 christos * Set EXTENDED-RCODE and Z to 0. 4909 1.1 christos */ 4910 1.1 christos rdatalist->ttl = (version << 16); 4911 1.1 christos rdatalist->ttl |= (flags & 0xffff); 4912 1.1 christos 4913 1.1 christos /* 4914 1.1 christos * Set EDNS options if applicable 4915 1.1 christos */ 4916 1.1 christos if (count != 0U) { 4917 1.1 christos isc_buffer_t *buf = NULL; 4918 1.3 christos bool seenpad = false; 4919 1.9 christos for (i = 0; i < count; i++) { 4920 1.1 christos len += ednsopts[i].length + 4; 4921 1.9 christos } 4922 1.1 christos 4923 1.1 christos if (len > 0xffffU) { 4924 1.1 christos result = ISC_R_NOSPACE; 4925 1.1 christos goto cleanup; 4926 1.1 christos } 4927 1.1 christos 4928 1.9 christos isc_buffer_allocate(message->mctx, &buf, len); 4929 1.1 christos 4930 1.9 christos for (i = 0; i < count; i++) { 4931 1.1 christos if (ednsopts[i].code == DNS_OPT_PAD && 4932 1.15 christos ednsopts[i].length == 0U && !seenpad) 4933 1.15 christos { 4934 1.3 christos seenpad = true; 4935 1.1 christos continue; 4936 1.1 christos } 4937 1.1 christos isc_buffer_putuint16(buf, ednsopts[i].code); 4938 1.1 christos isc_buffer_putuint16(buf, ednsopts[i].length); 4939 1.1 christos if (ednsopts[i].length != 0) { 4940 1.1 christos isc_buffer_putmem(buf, ednsopts[i].value, 4941 1.1 christos ednsopts[i].length); 4942 1.1 christos } 4943 1.1 christos } 4944 1.1 christos 4945 1.1 christos /* Padding must be the final option */ 4946 1.1 christos if (seenpad) { 4947 1.1 christos isc_buffer_putuint16(buf, DNS_OPT_PAD); 4948 1.1 christos isc_buffer_putuint16(buf, 0); 4949 1.1 christos } 4950 1.1 christos rdata->data = isc_buffer_base(buf); 4951 1.1 christos rdata->length = len; 4952 1.1 christos dns_message_takebuffer(message, &buf); 4953 1.9 christos if (seenpad) { 4954 1.1 christos message->padding_off = len; 4955 1.9 christos } 4956 1.1 christos } else { 4957 1.1 christos rdata->data = NULL; 4958 1.1 christos rdata->length = 0; 4959 1.1 christos } 4960 1.1 christos 4961 1.1 christos rdata->rdclass = rdatalist->rdclass; 4962 1.1 christos rdata->type = rdatalist->type; 4963 1.1 christos rdata->flags = 0; 4964 1.1 christos 4965 1.1 christos ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 4966 1.19 christos dns_rdatalist_tordataset(rdatalist, rdataset); 4967 1.1 christos 4968 1.1 christos *rdatasetp = rdataset; 4969 1.19 christos return ISC_R_SUCCESS; 4970 1.1 christos 4971 1.9 christos cleanup: 4972 1.19 christos dns_message_puttemprdata(message, &rdata); 4973 1.19 christos dns_message_puttemprdataset(message, &rdataset); 4974 1.19 christos dns_message_puttemprdatalist(message, &rdatalist); 4975 1.19 christos return result; 4976 1.1 christos } 4977 1.1 christos 4978 1.1 christos void 4979 1.1 christos dns_message_setclass(dns_message_t *msg, dns_rdataclass_t rdclass) { 4980 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 4981 1.1 christos REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE); 4982 1.1 christos REQUIRE(msg->state == DNS_SECTION_ANY); 4983 1.1 christos REQUIRE(msg->rdclass_set == 0); 4984 1.1 christos 4985 1.1 christos msg->rdclass = rdclass; 4986 1.1 christos msg->rdclass_set = 1; 4987 1.1 christos } 4988 1.1 christos 4989 1.1 christos void 4990 1.3 christos dns_message_setpadding(dns_message_t *msg, uint16_t padding) { 4991 1.1 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 4992 1.1 christos 4993 1.1 christos /* Avoid silly large padding */ 4994 1.9 christos if (padding > 512) { 4995 1.1 christos padding = 512; 4996 1.9 christos } 4997 1.1 christos msg->padding = padding; 4998 1.1 christos } 4999 1.11 christos 5000 1.11 christos void 5001 1.11 christos dns_message_clonebuffer(dns_message_t *msg) { 5002 1.11 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 5003 1.11 christos 5004 1.11 christos if (msg->free_saved == 0 && msg->saved.base != NULL) { 5005 1.11 christos msg->saved.base = 5006 1.11 christos memmove(isc_mem_get(msg->mctx, msg->saved.length), 5007 1.11 christos msg->saved.base, msg->saved.length); 5008 1.11 christos msg->free_saved = 1; 5009 1.11 christos } 5010 1.11 christos if (msg->free_query == 0 && msg->query.base != NULL) { 5011 1.11 christos msg->query.base = 5012 1.11 christos memmove(isc_mem_get(msg->mctx, msg->query.length), 5013 1.11 christos msg->query.base, msg->query.length); 5014 1.11 christos msg->free_query = 1; 5015 1.11 christos } 5016 1.11 christos } 5017 1.17 christos 5018 1.17 christos static isc_result_t 5019 1.19 christos rdataset_soa_min(dns_rdataset_t *rds, dns_ttl_t *ttlp) { 5020 1.19 christos isc_result_t result; 5021 1.19 christos /* loop over the rdatas */ 5022 1.19 christos for (result = dns_rdataset_first(rds); result == ISC_R_SUCCESS; 5023 1.19 christos result = dns_rdataset_next(rds)) 5024 1.19 christos { 5025 1.19 christos dns_name_t tmp; 5026 1.19 christos isc_region_t r = { 0 }; 5027 1.19 christos dns_rdata_t rdata = DNS_RDATA_INIT; 5028 1.19 christos 5029 1.19 christos dns_rdataset_current(rds, &rdata); 5030 1.19 christos 5031 1.19 christos switch (rdata.type) { 5032 1.19 christos case dns_rdatatype_soa: 5033 1.19 christos /* SOA rdataset */ 5034 1.19 christos break; 5035 1.19 christos case dns_rdatatype_none: 5036 1.19 christos /* 5037 1.19 christos * Negative cache rdataset: we need 5038 1.19 christos * to inspect the rdata to determine 5039 1.19 christos * whether it's an SOA. 5040 1.19 christos */ 5041 1.19 christos dns_rdata_toregion(&rdata, &r); 5042 1.19 christos dns_name_init(&tmp, NULL); 5043 1.19 christos dns_name_fromregion(&tmp, &r); 5044 1.19 christos isc_region_consume(&r, tmp.length); 5045 1.19 christos if (r.length < 2) { 5046 1.19 christos continue; 5047 1.19 christos } 5048 1.19 christos rdata.type = r.base[0] << 8 | r.base[1]; 5049 1.19 christos if (rdata.type != dns_rdatatype_soa) { 5050 1.19 christos continue; 5051 1.19 christos } 5052 1.19 christos break; 5053 1.19 christos default: 5054 1.19 christos continue; 5055 1.19 christos } 5056 1.19 christos 5057 1.19 christos if (rdata.type == dns_rdatatype_soa) { 5058 1.19 christos *ttlp = ISC_MIN(rds->ttl, dns_soa_getminimum(&rdata)); 5059 1.19 christos return ISC_R_SUCCESS; 5060 1.19 christos } 5061 1.19 christos } 5062 1.19 christos 5063 1.19 christos return ISC_R_NOTFOUND; 5064 1.19 christos } 5065 1.19 christos 5066 1.19 christos static isc_result_t 5067 1.19 christos message_authority_soa_min(dns_message_t *msg, dns_ttl_t *ttlp) { 5068 1.17 christos isc_result_t result; 5069 1.17 christos 5070 1.17 christos if (msg->counts[DNS_SECTION_AUTHORITY] == 0) { 5071 1.19 christos return ISC_R_NOTFOUND; 5072 1.17 christos } 5073 1.17 christos 5074 1.17 christos for (result = dns_message_firstname(msg, DNS_SECTION_AUTHORITY); 5075 1.17 christos result == ISC_R_SUCCESS; 5076 1.17 christos result = dns_message_nextname(msg, DNS_SECTION_AUTHORITY)) 5077 1.17 christos { 5078 1.19 christos dns_name_t *name = NULL; 5079 1.17 christos dns_message_currentname(msg, DNS_SECTION_AUTHORITY, &name); 5080 1.17 christos 5081 1.19 christos dns_rdataset_t *rds = NULL; 5082 1.22 christos ISC_LIST_FOREACH(name->list, rds, link) { 5083 1.19 christos if ((rds->attributes & DNS_RDATASETATTR_RENDERED) == 0) 5084 1.17 christos { 5085 1.17 christos continue; 5086 1.17 christos } 5087 1.17 christos 5088 1.19 christos result = rdataset_soa_min(rds, ttlp); 5089 1.19 christos if (result == ISC_R_SUCCESS) { 5090 1.19 christos return ISC_R_SUCCESS; 5091 1.17 christos } 5092 1.17 christos } 5093 1.17 christos } 5094 1.17 christos 5095 1.19 christos return ISC_R_NOTFOUND; 5096 1.17 christos } 5097 1.17 christos 5098 1.17 christos isc_result_t 5099 1.17 christos dns_message_minttl(dns_message_t *msg, const dns_section_t sectionid, 5100 1.17 christos dns_ttl_t *pttl) { 5101 1.17 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 5102 1.17 christos REQUIRE(pttl != NULL); 5103 1.17 christos 5104 1.17 christos if (!msg->minttl[sectionid].is_set) { 5105 1.19 christos return ISC_R_NOTFOUND; 5106 1.17 christos } 5107 1.17 christos 5108 1.17 christos *pttl = msg->minttl[sectionid].ttl; 5109 1.19 christos return ISC_R_SUCCESS; 5110 1.17 christos } 5111 1.17 christos 5112 1.17 christos isc_result_t 5113 1.17 christos dns_message_response_minttl(dns_message_t *msg, dns_ttl_t *pttl) { 5114 1.17 christos isc_result_t result; 5115 1.17 christos 5116 1.17 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 5117 1.17 christos REQUIRE(pttl != NULL); 5118 1.17 christos 5119 1.17 christos result = dns_message_minttl(msg, DNS_SECTION_ANSWER, pttl); 5120 1.17 christos if (result != ISC_R_SUCCESS) { 5121 1.19 christos return message_authority_soa_min(msg, pttl); 5122 1.17 christos } 5123 1.17 christos 5124 1.19 christos return ISC_R_SUCCESS; 5125 1.19 christos } 5126 1.19 christos 5127 1.19 christos void 5128 1.19 christos dns_message_createpools(isc_mem_t *mctx, isc_mempool_t **namepoolp, 5129 1.19 christos isc_mempool_t **rdspoolp) { 5130 1.19 christos REQUIRE(mctx != NULL); 5131 1.19 christos REQUIRE(namepoolp != NULL && *namepoolp == NULL); 5132 1.19 christos REQUIRE(rdspoolp != NULL && *rdspoolp == NULL); 5133 1.19 christos 5134 1.19 christos isc_mempool_create(mctx, sizeof(dns_fixedname_t), namepoolp); 5135 1.19 christos isc_mempool_setfillcount(*namepoolp, NAME_FILLCOUNT); 5136 1.19 christos isc_mempool_setfreemax(*namepoolp, NAME_FREEMAX); 5137 1.19 christos isc_mempool_setname(*namepoolp, "dns_fixedname_pool"); 5138 1.19 christos 5139 1.19 christos isc_mempool_create(mctx, sizeof(dns_rdataset_t), rdspoolp); 5140 1.19 christos isc_mempool_setfillcount(*rdspoolp, RDATASET_FILLCOUNT); 5141 1.19 christos isc_mempool_setfreemax(*rdspoolp, RDATASET_FREEMAX); 5142 1.19 christos isc_mempool_setname(*rdspoolp, "dns_rdataset_pool"); 5143 1.19 christos } 5144 1.19 christos 5145 1.19 christos void 5146 1.19 christos dns_message_destroypools(isc_mempool_t **namepoolp, isc_mempool_t **rdspoolp) { 5147 1.19 christos REQUIRE(namepoolp != NULL && *namepoolp != NULL); 5148 1.19 christos REQUIRE(rdspoolp != NULL && *rdspoolp != NULL); 5149 1.19 christos 5150 1.19 christos ENSURE(isc_mempool_getallocated(*namepoolp) == 0); 5151 1.19 christos ENSURE(isc_mempool_getallocated(*rdspoolp) == 0); 5152 1.19 christos 5153 1.19 christos isc_mempool_destroy(rdspoolp); 5154 1.19 christos isc_mempool_destroy(namepoolp); 5155 1.17 christos } 5156 1.22 christos 5157 1.22 christos bool 5158 1.22 christos dns_message_hasdname(dns_message_t *msg) { 5159 1.22 christos REQUIRE(DNS_MESSAGE_VALID(msg)); 5160 1.22 christos return msg->has_dname; 5161 1.22 christos } 5162