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