message.c revision 218384
1135446Strhodes/* 2218384Sdougb * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1999-2003 Internet Software Consortium. 4135446Strhodes * 5174187Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18218384Sdougb/* $Id: message.c,v 1.245.50.7 2010-06-03 05:29:03 marka Exp $ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes/*** 23135446Strhodes *** Imports 24135446Strhodes ***/ 25135446Strhodes 26135446Strhodes#include <config.h> 27193149Sdougb#include <ctype.h> 28135446Strhodes 29135446Strhodes#include <isc/buffer.h> 30135446Strhodes#include <isc/mem.h> 31135446Strhodes#include <isc/print.h> 32135446Strhodes#include <isc/string.h> /* Required for HP/UX (and others?) */ 33135446Strhodes#include <isc/util.h> 34135446Strhodes 35135446Strhodes#include <dns/dnssec.h> 36135446Strhodes#include <dns/keyvalues.h> 37135446Strhodes#include <dns/log.h> 38135446Strhodes#include <dns/masterdump.h> 39135446Strhodes#include <dns/message.h> 40135446Strhodes#include <dns/opcode.h> 41135446Strhodes#include <dns/rdata.h> 42135446Strhodes#include <dns/rdatalist.h> 43135446Strhodes#include <dns/rdataset.h> 44135446Strhodes#include <dns/rdatastruct.h> 45135446Strhodes#include <dns/result.h> 46135446Strhodes#include <dns/tsig.h> 47135446Strhodes#include <dns/view.h> 48135446Strhodes 49193149Sdougb#ifdef SKAN_MSG_DEBUG 50193149Sdougbstatic void 51193149Sdougbhexdump(const char *msg, const char *msg2, void *base, size_t len) { 52193149Sdougb unsigned char *p; 53193149Sdougb unsigned int cnt; 54193149Sdougb 55193149Sdougb p = base; 56193149Sdougb cnt = 0; 57193149Sdougb 58193149Sdougb printf("*** %s [%s] (%u bytes @ %p)\n", msg, msg2, len, base); 59193149Sdougb 60193149Sdougb while (cnt < len) { 61193149Sdougb if (cnt % 16 == 0) 62193149Sdougb printf("%p: ", p); 63193149Sdougb else if (cnt % 8 == 0) 64193149Sdougb printf(" |"); 65193149Sdougb printf(" %02x %c", *p, (isprint(*p) ? *p : ' ')); 66193149Sdougb p++; 67193149Sdougb cnt++; 68193149Sdougb 69193149Sdougb if (cnt % 16 == 0) 70193149Sdougb printf("\n"); 71193149Sdougb } 72193149Sdougb 73193149Sdougb if (cnt % 16 != 0) 74193149Sdougb printf("\n"); 75193149Sdougb} 76193149Sdougb#endif 77193149Sdougb 78135446Strhodes#define DNS_MESSAGE_OPCODE_MASK 0x7800U 79135446Strhodes#define DNS_MESSAGE_OPCODE_SHIFT 11 80135446Strhodes#define DNS_MESSAGE_RCODE_MASK 0x000fU 81135446Strhodes#define DNS_MESSAGE_FLAG_MASK 0x8ff0U 82135446Strhodes#define DNS_MESSAGE_EDNSRCODE_MASK 0xff000000U 83135446Strhodes#define DNS_MESSAGE_EDNSRCODE_SHIFT 24 84135446Strhodes#define DNS_MESSAGE_EDNSVERSION_MASK 0x00ff0000U 85135446Strhodes#define DNS_MESSAGE_EDNSVERSION_SHIFT 16 86135446Strhodes 87135446Strhodes#define VALID_NAMED_SECTION(s) (((s) > DNS_SECTION_ANY) \ 88135446Strhodes && ((s) < DNS_SECTION_MAX)) 89135446Strhodes#define VALID_SECTION(s) (((s) >= DNS_SECTION_ANY) \ 90135446Strhodes && ((s) < DNS_SECTION_MAX)) 91135446Strhodes#define ADD_STRING(b, s) {if (strlen(s) >= \ 92135446Strhodes isc_buffer_availablelength(b)) \ 93135446Strhodes return(ISC_R_NOSPACE); else \ 94135446Strhodes isc_buffer_putstr(b, s);} 95135446Strhodes#define VALID_PSEUDOSECTION(s) (((s) >= DNS_PSEUDOSECTION_ANY) \ 96135446Strhodes && ((s) < DNS_PSEUDOSECTION_MAX)) 97135446Strhodes 98193149Sdougb#define OPTOUT(x) (((x)->attributes & DNS_RDATASETATTR_OPTOUT) != 0) 99193149Sdougb 100170222Sdougb/*% 101135446Strhodes * This is the size of each individual scratchpad buffer, and the numbers 102135446Strhodes * of various block allocations used within the server. 103135446Strhodes * XXXMLG These should come from a config setting. 104135446Strhodes */ 105135446Strhodes#define SCRATCHPAD_SIZE 512 106135446Strhodes#define NAME_COUNT 8 107135446Strhodes#define OFFSET_COUNT 4 108135446Strhodes#define RDATA_COUNT 8 109135446Strhodes#define RDATALIST_COUNT 8 110135446Strhodes#define RDATASET_COUNT RDATALIST_COUNT 111135446Strhodes 112170222Sdougb/*% 113135446Strhodes * Text representation of the different items, for message_totext 114135446Strhodes * functions. 115135446Strhodes */ 116135446Strhodesstatic const char *sectiontext[] = { 117135446Strhodes "QUESTION", 118135446Strhodes "ANSWER", 119135446Strhodes "AUTHORITY", 120135446Strhodes "ADDITIONAL" 121135446Strhodes}; 122135446Strhodes 123135446Strhodesstatic const char *updsectiontext[] = { 124135446Strhodes "ZONE", 125135446Strhodes "PREREQUISITE", 126135446Strhodes "UPDATE", 127135446Strhodes "ADDITIONAL" 128135446Strhodes}; 129135446Strhodes 130135446Strhodesstatic const char *opcodetext[] = { 131135446Strhodes "QUERY", 132135446Strhodes "IQUERY", 133135446Strhodes "STATUS", 134135446Strhodes "RESERVED3", 135135446Strhodes "NOTIFY", 136135446Strhodes "UPDATE", 137135446Strhodes "RESERVED6", 138135446Strhodes "RESERVED7", 139135446Strhodes "RESERVED8", 140135446Strhodes "RESERVED9", 141135446Strhodes "RESERVED10", 142135446Strhodes "RESERVED11", 143135446Strhodes "RESERVED12", 144135446Strhodes "RESERVED13", 145135446Strhodes "RESERVED14", 146135446Strhodes "RESERVED15" 147135446Strhodes}; 148135446Strhodes 149135446Strhodesstatic const char *rcodetext[] = { 150135446Strhodes "NOERROR", 151135446Strhodes "FORMERR", 152135446Strhodes "SERVFAIL", 153135446Strhodes "NXDOMAIN", 154135446Strhodes "NOTIMP", 155135446Strhodes "REFUSED", 156135446Strhodes "YXDOMAIN", 157135446Strhodes "YXRRSET", 158135446Strhodes "NXRRSET", 159135446Strhodes "NOTAUTH", 160135446Strhodes "NOTZONE", 161135446Strhodes "RESERVED11", 162135446Strhodes "RESERVED12", 163135446Strhodes "RESERVED13", 164135446Strhodes "RESERVED14", 165135446Strhodes "RESERVED15", 166135446Strhodes "BADVERS" 167135446Strhodes}; 168135446Strhodes 169135446Strhodes 170170222Sdougb/*% 171135446Strhodes * "helper" type, which consists of a block of some type, and is linkable. 172135446Strhodes * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer 173193149Sdougb * size, or the allocated elements will not be aligned correctly. 174135446Strhodes */ 175135446Strhodesstruct dns_msgblock { 176135446Strhodes unsigned int count; 177135446Strhodes unsigned int remaining; 178135446Strhodes ISC_LINK(dns_msgblock_t) link; 179135446Strhodes}; /* dynamically sized */ 180135446Strhodes 181135446Strhodesstatic inline dns_msgblock_t * 182135446Strhodesmsgblock_allocate(isc_mem_t *, unsigned int, unsigned int); 183135446Strhodes 184135446Strhodes#define msgblock_get(block, type) \ 185135446Strhodes ((type *)msgblock_internalget(block, sizeof(type))) 186135446Strhodes 187135446Strhodesstatic inline void * 188135446Strhodesmsgblock_internalget(dns_msgblock_t *, unsigned int); 189135446Strhodes 190135446Strhodesstatic inline void 191135446Strhodesmsgblock_reset(dns_msgblock_t *); 192135446Strhodes 193135446Strhodesstatic inline void 194135446Strhodesmsgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int); 195135446Strhodes 196135446Strhodes/* 197135446Strhodes * Allocate a new dns_msgblock_t, and return a pointer to it. If no memory 198135446Strhodes * is free, return NULL. 199135446Strhodes */ 200135446Strhodesstatic inline dns_msgblock_t * 201135446Strhodesmsgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type, 202135446Strhodes unsigned int count) 203135446Strhodes{ 204135446Strhodes dns_msgblock_t *block; 205135446Strhodes unsigned int length; 206135446Strhodes 207135446Strhodes length = sizeof(dns_msgblock_t) + (sizeof_type * count); 208135446Strhodes 209135446Strhodes block = isc_mem_get(mctx, length); 210135446Strhodes if (block == NULL) 211135446Strhodes return (NULL); 212135446Strhodes 213135446Strhodes block->count = count; 214135446Strhodes block->remaining = count; 215135446Strhodes 216135446Strhodes ISC_LINK_INIT(block, link); 217135446Strhodes 218135446Strhodes return (block); 219135446Strhodes} 220135446Strhodes 221135446Strhodes/* 222135446Strhodes * Return an element from the msgblock. If no more are available, return 223135446Strhodes * NULL. 224135446Strhodes */ 225135446Strhodesstatic inline void * 226135446Strhodesmsgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) { 227135446Strhodes void *ptr; 228135446Strhodes 229135446Strhodes if (block == NULL || block->remaining == 0) 230135446Strhodes return (NULL); 231135446Strhodes 232135446Strhodes block->remaining--; 233135446Strhodes 234135446Strhodes ptr = (((unsigned char *)block) 235135446Strhodes + sizeof(dns_msgblock_t) 236135446Strhodes + (sizeof_type * block->remaining)); 237135446Strhodes 238135446Strhodes return (ptr); 239135446Strhodes} 240135446Strhodes 241135446Strhodesstatic inline void 242135446Strhodesmsgblock_reset(dns_msgblock_t *block) { 243135446Strhodes block->remaining = block->count; 244135446Strhodes} 245135446Strhodes 246135446Strhodes/* 247135446Strhodes * Release memory associated with a message block. 248135446Strhodes */ 249135446Strhodesstatic inline void 250135446Strhodesmsgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, unsigned int sizeof_type) 251135446Strhodes{ 252135446Strhodes unsigned int length; 253135446Strhodes 254135446Strhodes length = sizeof(dns_msgblock_t) + (sizeof_type * block->count); 255135446Strhodes 256135446Strhodes isc_mem_put(mctx, block, length); 257135446Strhodes} 258135446Strhodes 259135446Strhodes/* 260135446Strhodes * Allocate a new dynamic buffer, and attach it to this message as the 261135446Strhodes * "current" buffer. (which is always the last on the list, for our 262135446Strhodes * uses) 263135446Strhodes */ 264135446Strhodesstatic inline isc_result_t 265135446Strhodesnewbuffer(dns_message_t *msg, unsigned int size) { 266135446Strhodes isc_result_t result; 267135446Strhodes isc_buffer_t *dynbuf; 268135446Strhodes 269135446Strhodes dynbuf = NULL; 270135446Strhodes result = isc_buffer_allocate(msg->mctx, &dynbuf, size); 271135446Strhodes if (result != ISC_R_SUCCESS) 272135446Strhodes return (ISC_R_NOMEMORY); 273135446Strhodes 274135446Strhodes ISC_LIST_APPEND(msg->scratchpad, dynbuf, link); 275135446Strhodes return (ISC_R_SUCCESS); 276135446Strhodes} 277135446Strhodes 278135446Strhodesstatic inline isc_buffer_t * 279135446Strhodescurrentbuffer(dns_message_t *msg) { 280135446Strhodes isc_buffer_t *dynbuf; 281135446Strhodes 282135446Strhodes dynbuf = ISC_LIST_TAIL(msg->scratchpad); 283135446Strhodes INSIST(dynbuf != NULL); 284135446Strhodes 285135446Strhodes return (dynbuf); 286135446Strhodes} 287135446Strhodes 288135446Strhodesstatic inline void 289135446Strhodesreleaserdata(dns_message_t *msg, dns_rdata_t *rdata) { 290135446Strhodes ISC_LIST_PREPEND(msg->freerdata, rdata, link); 291135446Strhodes} 292135446Strhodes 293135446Strhodesstatic inline dns_rdata_t * 294135446Strhodesnewrdata(dns_message_t *msg) { 295135446Strhodes dns_msgblock_t *msgblock; 296135446Strhodes dns_rdata_t *rdata; 297135446Strhodes 298135446Strhodes rdata = ISC_LIST_HEAD(msg->freerdata); 299135446Strhodes if (rdata != NULL) { 300135446Strhodes ISC_LIST_UNLINK(msg->freerdata, rdata, link); 301135446Strhodes return (rdata); 302135446Strhodes } 303135446Strhodes 304135446Strhodes msgblock = ISC_LIST_TAIL(msg->rdatas); 305135446Strhodes rdata = msgblock_get(msgblock, dns_rdata_t); 306135446Strhodes if (rdata == NULL) { 307135446Strhodes msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t), 308135446Strhodes RDATA_COUNT); 309135446Strhodes if (msgblock == NULL) 310135446Strhodes return (NULL); 311135446Strhodes 312135446Strhodes ISC_LIST_APPEND(msg->rdatas, msgblock, link); 313135446Strhodes 314135446Strhodes rdata = msgblock_get(msgblock, dns_rdata_t); 315135446Strhodes } 316135446Strhodes 317135446Strhodes dns_rdata_init(rdata); 318135446Strhodes return (rdata); 319135446Strhodes} 320135446Strhodes 321135446Strhodesstatic inline void 322135446Strhodesreleaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) { 323135446Strhodes ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link); 324135446Strhodes} 325135446Strhodes 326135446Strhodesstatic inline dns_rdatalist_t * 327135446Strhodesnewrdatalist(dns_message_t *msg) { 328135446Strhodes dns_msgblock_t *msgblock; 329135446Strhodes dns_rdatalist_t *rdatalist; 330135446Strhodes 331135446Strhodes rdatalist = ISC_LIST_HEAD(msg->freerdatalist); 332135446Strhodes if (rdatalist != NULL) { 333135446Strhodes ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link); 334135446Strhodes return (rdatalist); 335135446Strhodes } 336135446Strhodes 337135446Strhodes msgblock = ISC_LIST_TAIL(msg->rdatalists); 338135446Strhodes rdatalist = msgblock_get(msgblock, dns_rdatalist_t); 339135446Strhodes if (rdatalist == NULL) { 340135446Strhodes msgblock = msgblock_allocate(msg->mctx, 341135446Strhodes sizeof(dns_rdatalist_t), 342135446Strhodes RDATALIST_COUNT); 343135446Strhodes if (msgblock == NULL) 344135446Strhodes return (NULL); 345135446Strhodes 346135446Strhodes ISC_LIST_APPEND(msg->rdatalists, msgblock, link); 347135446Strhodes 348135446Strhodes rdatalist = msgblock_get(msgblock, dns_rdatalist_t); 349135446Strhodes } 350135446Strhodes 351135446Strhodes return (rdatalist); 352135446Strhodes} 353135446Strhodes 354135446Strhodesstatic inline dns_offsets_t * 355135446Strhodesnewoffsets(dns_message_t *msg) { 356135446Strhodes dns_msgblock_t *msgblock; 357135446Strhodes dns_offsets_t *offsets; 358135446Strhodes 359135446Strhodes msgblock = ISC_LIST_TAIL(msg->offsets); 360135446Strhodes offsets = msgblock_get(msgblock, dns_offsets_t); 361135446Strhodes if (offsets == NULL) { 362135446Strhodes msgblock = msgblock_allocate(msg->mctx, 363135446Strhodes sizeof(dns_offsets_t), 364135446Strhodes OFFSET_COUNT); 365135446Strhodes if (msgblock == NULL) 366135446Strhodes return (NULL); 367135446Strhodes 368135446Strhodes ISC_LIST_APPEND(msg->offsets, msgblock, link); 369135446Strhodes 370135446Strhodes offsets = msgblock_get(msgblock, dns_offsets_t); 371135446Strhodes } 372135446Strhodes 373135446Strhodes return (offsets); 374135446Strhodes} 375135446Strhodes 376135446Strhodesstatic inline void 377135446Strhodesmsginitheader(dns_message_t *m) { 378135446Strhodes m->id = 0; 379135446Strhodes m->flags = 0; 380135446Strhodes m->rcode = 0; 381135446Strhodes m->opcode = 0; 382135446Strhodes m->rdclass = 0; 383135446Strhodes} 384135446Strhodes 385135446Strhodesstatic inline void 386135446Strhodesmsginitprivate(dns_message_t *m) { 387135446Strhodes unsigned int i; 388135446Strhodes 389135446Strhodes for (i = 0; i < DNS_SECTION_MAX; i++) { 390135446Strhodes m->cursors[i] = NULL; 391135446Strhodes m->counts[i] = 0; 392135446Strhodes } 393135446Strhodes m->opt = NULL; 394135446Strhodes m->sig0 = NULL; 395135446Strhodes m->sig0name = NULL; 396135446Strhodes m->tsig = NULL; 397135446Strhodes m->tsigname = NULL; 398135446Strhodes m->state = DNS_SECTION_ANY; /* indicate nothing parsed or rendered */ 399135446Strhodes m->opt_reserved = 0; 400135446Strhodes m->sig_reserved = 0; 401135446Strhodes m->reserved = 0; 402135446Strhodes m->buffer = NULL; 403135446Strhodes} 404135446Strhodes 405135446Strhodesstatic inline void 406135446Strhodesmsginittsig(dns_message_t *m) { 407135446Strhodes m->tsigstatus = dns_rcode_noerror; 408135446Strhodes m->querytsigstatus = dns_rcode_noerror; 409135446Strhodes m->tsigkey = NULL; 410135446Strhodes m->tsigctx = NULL; 411135446Strhodes m->sigstart = -1; 412135446Strhodes m->sig0key = NULL; 413135446Strhodes m->sig0status = dns_rcode_noerror; 414135446Strhodes m->timeadjust = 0; 415135446Strhodes} 416135446Strhodes 417135446Strhodes/* 418135446Strhodes * Init elements to default state. Used both when allocating a new element 419135446Strhodes * and when resetting one. 420135446Strhodes */ 421135446Strhodesstatic inline void 422135446Strhodesmsginit(dns_message_t *m) { 423135446Strhodes msginitheader(m); 424135446Strhodes msginitprivate(m); 425135446Strhodes msginittsig(m); 426135446Strhodes m->header_ok = 0; 427135446Strhodes m->question_ok = 0; 428135446Strhodes m->tcp_continuation = 0; 429135446Strhodes m->verified_sig = 0; 430135446Strhodes m->verify_attempted = 0; 431135446Strhodes m->order = NULL; 432135446Strhodes m->order_arg = NULL; 433135446Strhodes m->query.base = NULL; 434135446Strhodes m->query.length = 0; 435135446Strhodes m->free_query = 0; 436135446Strhodes m->saved.base = NULL; 437135446Strhodes m->saved.length = 0; 438135446Strhodes m->free_saved = 0; 439135446Strhodes m->querytsig = NULL; 440135446Strhodes} 441135446Strhodes 442135446Strhodesstatic inline void 443135446Strhodesmsgresetnames(dns_message_t *msg, unsigned int first_section) { 444135446Strhodes unsigned int i; 445135446Strhodes dns_name_t *name, *next_name; 446135446Strhodes dns_rdataset_t *rds, *next_rds; 447135446Strhodes 448135446Strhodes /* 449135446Strhodes * Clean up name lists by calling the rdataset disassociate function. 450135446Strhodes */ 451135446Strhodes for (i = first_section; i < DNS_SECTION_MAX; i++) { 452135446Strhodes name = ISC_LIST_HEAD(msg->sections[i]); 453135446Strhodes while (name != NULL) { 454135446Strhodes next_name = ISC_LIST_NEXT(name, link); 455135446Strhodes ISC_LIST_UNLINK(msg->sections[i], name, link); 456135446Strhodes 457135446Strhodes rds = ISC_LIST_HEAD(name->list); 458135446Strhodes while (rds != NULL) { 459135446Strhodes next_rds = ISC_LIST_NEXT(rds, link); 460135446Strhodes ISC_LIST_UNLINK(name->list, rds, link); 461135446Strhodes 462135446Strhodes INSIST(dns_rdataset_isassociated(rds)); 463135446Strhodes dns_rdataset_disassociate(rds); 464135446Strhodes isc_mempool_put(msg->rdspool, rds); 465135446Strhodes rds = next_rds; 466135446Strhodes } 467135446Strhodes if (dns_name_dynamic(name)) 468135446Strhodes dns_name_free(name, msg->mctx); 469135446Strhodes isc_mempool_put(msg->namepool, name); 470135446Strhodes name = next_name; 471135446Strhodes } 472135446Strhodes } 473135446Strhodes} 474135446Strhodes 475135446Strhodesstatic void 476135446Strhodesmsgresetopt(dns_message_t *msg) 477135446Strhodes{ 478135446Strhodes if (msg->opt != NULL) { 479135446Strhodes if (msg->opt_reserved > 0) { 480135446Strhodes dns_message_renderrelease(msg, msg->opt_reserved); 481135446Strhodes msg->opt_reserved = 0; 482135446Strhodes } 483135446Strhodes INSIST(dns_rdataset_isassociated(msg->opt)); 484135446Strhodes dns_rdataset_disassociate(msg->opt); 485135446Strhodes isc_mempool_put(msg->rdspool, msg->opt); 486135446Strhodes msg->opt = NULL; 487135446Strhodes } 488135446Strhodes} 489135446Strhodes 490135446Strhodesstatic void 491135446Strhodesmsgresetsigs(dns_message_t *msg, isc_boolean_t replying) { 492135446Strhodes if (msg->sig_reserved > 0) { 493135446Strhodes dns_message_renderrelease(msg, msg->sig_reserved); 494135446Strhodes msg->sig_reserved = 0; 495135446Strhodes } 496135446Strhodes if (msg->tsig != NULL) { 497135446Strhodes INSIST(dns_rdataset_isassociated(msg->tsig)); 498135446Strhodes INSIST(msg->namepool != NULL); 499135446Strhodes if (replying) { 500135446Strhodes INSIST(msg->querytsig == NULL); 501135446Strhodes msg->querytsig = msg->tsig; 502135446Strhodes } else { 503135446Strhodes dns_rdataset_disassociate(msg->tsig); 504135446Strhodes isc_mempool_put(msg->rdspool, msg->tsig); 505135446Strhodes if (msg->querytsig != NULL) { 506135446Strhodes dns_rdataset_disassociate(msg->querytsig); 507135446Strhodes isc_mempool_put(msg->rdspool, msg->querytsig); 508135446Strhodes } 509135446Strhodes } 510135446Strhodes if (dns_name_dynamic(msg->tsigname)) 511135446Strhodes dns_name_free(msg->tsigname, msg->mctx); 512135446Strhodes isc_mempool_put(msg->namepool, msg->tsigname); 513135446Strhodes msg->tsig = NULL; 514135446Strhodes msg->tsigname = NULL; 515135446Strhodes } else if (msg->querytsig != NULL && !replying) { 516135446Strhodes dns_rdataset_disassociate(msg->querytsig); 517135446Strhodes isc_mempool_put(msg->rdspool, msg->querytsig); 518135446Strhodes msg->querytsig = NULL; 519135446Strhodes } 520135446Strhodes if (msg->sig0 != NULL) { 521135446Strhodes INSIST(dns_rdataset_isassociated(msg->sig0)); 522135446Strhodes dns_rdataset_disassociate(msg->sig0); 523135446Strhodes isc_mempool_put(msg->rdspool, msg->sig0); 524135446Strhodes if (msg->sig0name != NULL) { 525135446Strhodes if (dns_name_dynamic(msg->sig0name)) 526135446Strhodes dns_name_free(msg->sig0name, msg->mctx); 527135446Strhodes isc_mempool_put(msg->namepool, msg->sig0name); 528135446Strhodes } 529135446Strhodes msg->sig0 = NULL; 530135446Strhodes msg->sig0name = NULL; 531135446Strhodes } 532135446Strhodes} 533135446Strhodes 534135446Strhodes/* 535135446Strhodes * Free all but one (or everything) for this message. This is used by 536135446Strhodes * both dns_message_reset() and dns_message_destroy(). 537135446Strhodes */ 538135446Strhodesstatic void 539135446Strhodesmsgreset(dns_message_t *msg, isc_boolean_t everything) { 540135446Strhodes dns_msgblock_t *msgblock, *next_msgblock; 541135446Strhodes isc_buffer_t *dynbuf, *next_dynbuf; 542135446Strhodes dns_rdata_t *rdata; 543135446Strhodes dns_rdatalist_t *rdatalist; 544135446Strhodes 545135446Strhodes msgresetnames(msg, 0); 546135446Strhodes msgresetopt(msg); 547135446Strhodes msgresetsigs(msg, ISC_FALSE); 548135446Strhodes 549135446Strhodes /* 550135446Strhodes * Clean up linked lists. 551135446Strhodes */ 552135446Strhodes 553135446Strhodes /* 554135446Strhodes * Run through the free lists, and just unlink anything found there. 555135446Strhodes * The memory isn't lost since these are part of message blocks we 556135446Strhodes * have allocated. 557135446Strhodes */ 558135446Strhodes rdata = ISC_LIST_HEAD(msg->freerdata); 559135446Strhodes while (rdata != NULL) { 560135446Strhodes ISC_LIST_UNLINK(msg->freerdata, rdata, link); 561135446Strhodes rdata = ISC_LIST_HEAD(msg->freerdata); 562135446Strhodes } 563135446Strhodes rdatalist = ISC_LIST_HEAD(msg->freerdatalist); 564135446Strhodes while (rdatalist != NULL) { 565135446Strhodes ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link); 566135446Strhodes rdatalist = ISC_LIST_HEAD(msg->freerdatalist); 567135446Strhodes } 568135446Strhodes 569135446Strhodes dynbuf = ISC_LIST_HEAD(msg->scratchpad); 570135446Strhodes INSIST(dynbuf != NULL); 571135446Strhodes if (!everything) { 572135446Strhodes isc_buffer_clear(dynbuf); 573135446Strhodes dynbuf = ISC_LIST_NEXT(dynbuf, link); 574135446Strhodes } 575135446Strhodes while (dynbuf != NULL) { 576135446Strhodes next_dynbuf = ISC_LIST_NEXT(dynbuf, link); 577135446Strhodes ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link); 578135446Strhodes isc_buffer_free(&dynbuf); 579135446Strhodes dynbuf = next_dynbuf; 580135446Strhodes } 581135446Strhodes 582135446Strhodes msgblock = ISC_LIST_HEAD(msg->rdatas); 583135446Strhodes if (!everything && msgblock != NULL) { 584135446Strhodes msgblock_reset(msgblock); 585135446Strhodes msgblock = ISC_LIST_NEXT(msgblock, link); 586135446Strhodes } 587135446Strhodes while (msgblock != NULL) { 588135446Strhodes next_msgblock = ISC_LIST_NEXT(msgblock, link); 589135446Strhodes ISC_LIST_UNLINK(msg->rdatas, msgblock, link); 590135446Strhodes msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t)); 591135446Strhodes msgblock = next_msgblock; 592135446Strhodes } 593135446Strhodes 594135446Strhodes /* 595135446Strhodes * rdatalists could be empty. 596135446Strhodes */ 597135446Strhodes 598135446Strhodes msgblock = ISC_LIST_HEAD(msg->rdatalists); 599135446Strhodes if (!everything && msgblock != NULL) { 600135446Strhodes msgblock_reset(msgblock); 601135446Strhodes msgblock = ISC_LIST_NEXT(msgblock, link); 602135446Strhodes } 603135446Strhodes while (msgblock != NULL) { 604135446Strhodes next_msgblock = ISC_LIST_NEXT(msgblock, link); 605135446Strhodes ISC_LIST_UNLINK(msg->rdatalists, msgblock, link); 606135446Strhodes msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t)); 607135446Strhodes msgblock = next_msgblock; 608135446Strhodes } 609135446Strhodes 610135446Strhodes msgblock = ISC_LIST_HEAD(msg->offsets); 611135446Strhodes if (!everything && msgblock != NULL) { 612135446Strhodes msgblock_reset(msgblock); 613135446Strhodes msgblock = ISC_LIST_NEXT(msgblock, link); 614135446Strhodes } 615135446Strhodes while (msgblock != NULL) { 616135446Strhodes next_msgblock = ISC_LIST_NEXT(msgblock, link); 617135446Strhodes ISC_LIST_UNLINK(msg->offsets, msgblock, link); 618135446Strhodes msgblock_free(msg->mctx, msgblock, sizeof(dns_offsets_t)); 619135446Strhodes msgblock = next_msgblock; 620135446Strhodes } 621135446Strhodes 622135446Strhodes if (msg->tsigkey != NULL) { 623135446Strhodes dns_tsigkey_detach(&msg->tsigkey); 624135446Strhodes msg->tsigkey = NULL; 625135446Strhodes } 626135446Strhodes 627186462Sdougb if (msg->tsigctx != NULL) 628186462Sdougb dst_context_destroy(&msg->tsigctx); 629186462Sdougb 630135446Strhodes if (msg->query.base != NULL) { 631135446Strhodes if (msg->free_query != 0) 632135446Strhodes isc_mem_put(msg->mctx, msg->query.base, 633135446Strhodes msg->query.length); 634135446Strhodes msg->query.base = NULL; 635135446Strhodes msg->query.length = 0; 636135446Strhodes } 637135446Strhodes 638135446Strhodes if (msg->saved.base != NULL) { 639135446Strhodes if (msg->free_saved != 0) 640135446Strhodes isc_mem_put(msg->mctx, msg->saved.base, 641135446Strhodes msg->saved.length); 642135446Strhodes msg->saved.base = NULL; 643135446Strhodes msg->saved.length = 0; 644135446Strhodes } 645135446Strhodes 646135446Strhodes /* 647135446Strhodes * cleanup the buffer cleanup list 648135446Strhodes */ 649135446Strhodes dynbuf = ISC_LIST_HEAD(msg->cleanup); 650135446Strhodes while (dynbuf != NULL) { 651135446Strhodes next_dynbuf = ISC_LIST_NEXT(dynbuf, link); 652135446Strhodes ISC_LIST_UNLINK(msg->cleanup, dynbuf, link); 653135446Strhodes isc_buffer_free(&dynbuf); 654135446Strhodes dynbuf = next_dynbuf; 655135446Strhodes } 656135446Strhodes 657135446Strhodes /* 658135446Strhodes * Set other bits to normal default values. 659135446Strhodes */ 660135446Strhodes if (!everything) 661135446Strhodes msginit(msg); 662135446Strhodes 663135446Strhodes ENSURE(isc_mempool_getallocated(msg->namepool) == 0); 664135446Strhodes ENSURE(isc_mempool_getallocated(msg->rdspool) == 0); 665135446Strhodes} 666135446Strhodes 667135446Strhodesstatic unsigned int 668135446Strhodesspacefortsig(dns_tsigkey_t *key, int otherlen) { 669135446Strhodes isc_region_t r1, r2; 670135446Strhodes unsigned int x; 671135446Strhodes isc_result_t result; 672135446Strhodes 673135446Strhodes /* 674135446Strhodes * The space required for an TSIG record is: 675135446Strhodes * 676135446Strhodes * n1 bytes for the name 677135446Strhodes * 2 bytes for the type 678135446Strhodes * 2 bytes for the class 679135446Strhodes * 4 bytes for the ttl 680135446Strhodes * 2 bytes for the rdlength 681135446Strhodes * n2 bytes for the algorithm name 682135446Strhodes * 6 bytes for the time signed 683135446Strhodes * 2 bytes for the fudge 684135446Strhodes * 2 bytes for the MAC size 685135446Strhodes * x bytes for the MAC 686135446Strhodes * 2 bytes for the original id 687135446Strhodes * 2 bytes for the error 688135446Strhodes * 2 bytes for the other data length 689135446Strhodes * y bytes for the other data (at most) 690135446Strhodes * --------------------------------- 691135446Strhodes * 26 + n1 + n2 + x + y bytes 692135446Strhodes */ 693135446Strhodes 694135446Strhodes dns_name_toregion(&key->name, &r1); 695135446Strhodes dns_name_toregion(key->algorithm, &r2); 696135446Strhodes if (key->key == NULL) 697135446Strhodes x = 0; 698135446Strhodes else { 699135446Strhodes result = dst_key_sigsize(key->key, &x); 700135446Strhodes if (result != ISC_R_SUCCESS) 701135446Strhodes x = 0; 702135446Strhodes } 703135446Strhodes return (26 + r1.length + r2.length + x + otherlen); 704135446Strhodes} 705135446Strhodes 706135446Strhodesisc_result_t 707135446Strhodesdns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp) 708135446Strhodes{ 709135446Strhodes dns_message_t *m; 710135446Strhodes isc_result_t result; 711135446Strhodes isc_buffer_t *dynbuf; 712135446Strhodes unsigned int i; 713135446Strhodes 714135446Strhodes REQUIRE(mctx != NULL); 715135446Strhodes REQUIRE(msgp != NULL); 716135446Strhodes REQUIRE(*msgp == NULL); 717135446Strhodes REQUIRE(intent == DNS_MESSAGE_INTENTPARSE 718135446Strhodes || intent == DNS_MESSAGE_INTENTRENDER); 719135446Strhodes 720135446Strhodes m = isc_mem_get(mctx, sizeof(dns_message_t)); 721135446Strhodes if (m == NULL) 722135446Strhodes return (ISC_R_NOMEMORY); 723135446Strhodes 724135446Strhodes /* 725135446Strhodes * No allocations until further notice. Just initialize all lists 726135446Strhodes * and other members that are freed in the cleanup phase here. 727135446Strhodes */ 728135446Strhodes 729135446Strhodes m->magic = DNS_MESSAGE_MAGIC; 730135446Strhodes m->from_to_wire = intent; 731135446Strhodes msginit(m); 732135446Strhodes 733135446Strhodes for (i = 0; i < DNS_SECTION_MAX; i++) 734135446Strhodes ISC_LIST_INIT(m->sections[i]); 735135446Strhodes m->mctx = mctx; 736135446Strhodes 737135446Strhodes ISC_LIST_INIT(m->scratchpad); 738135446Strhodes ISC_LIST_INIT(m->cleanup); 739135446Strhodes m->namepool = NULL; 740135446Strhodes m->rdspool = NULL; 741135446Strhodes ISC_LIST_INIT(m->rdatas); 742135446Strhodes ISC_LIST_INIT(m->rdatalists); 743135446Strhodes ISC_LIST_INIT(m->offsets); 744135446Strhodes ISC_LIST_INIT(m->freerdata); 745135446Strhodes ISC_LIST_INIT(m->freerdatalist); 746135446Strhodes 747135446Strhodes /* 748135446Strhodes * Ok, it is safe to allocate (and then "goto cleanup" if failure) 749135446Strhodes */ 750135446Strhodes 751135446Strhodes result = isc_mempool_create(m->mctx, sizeof(dns_name_t), &m->namepool); 752135446Strhodes if (result != ISC_R_SUCCESS) 753135446Strhodes goto cleanup; 754135446Strhodes isc_mempool_setfreemax(m->namepool, NAME_COUNT); 755135446Strhodes isc_mempool_setname(m->namepool, "msg:names"); 756135446Strhodes 757135446Strhodes result = isc_mempool_create(m->mctx, sizeof(dns_rdataset_t), 758135446Strhodes &m->rdspool); 759135446Strhodes if (result != ISC_R_SUCCESS) 760135446Strhodes goto cleanup; 761135446Strhodes isc_mempool_setfreemax(m->rdspool, NAME_COUNT); 762135446Strhodes isc_mempool_setname(m->rdspool, "msg:rdataset"); 763135446Strhodes 764135446Strhodes dynbuf = NULL; 765135446Strhodes result = isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE); 766135446Strhodes if (result != ISC_R_SUCCESS) 767135446Strhodes goto cleanup; 768135446Strhodes ISC_LIST_APPEND(m->scratchpad, dynbuf, link); 769135446Strhodes 770135446Strhodes m->cctx = NULL; 771135446Strhodes 772135446Strhodes *msgp = m; 773135446Strhodes return (ISC_R_SUCCESS); 774135446Strhodes 775135446Strhodes /* 776135446Strhodes * Cleanup for error returns. 777135446Strhodes */ 778135446Strhodes cleanup: 779135446Strhodes dynbuf = ISC_LIST_HEAD(m->scratchpad); 780135446Strhodes if (dynbuf != NULL) { 781135446Strhodes ISC_LIST_UNLINK(m->scratchpad, dynbuf, link); 782135446Strhodes isc_buffer_free(&dynbuf); 783135446Strhodes } 784135446Strhodes if (m->namepool != NULL) 785135446Strhodes isc_mempool_destroy(&m->namepool); 786135446Strhodes if (m->rdspool != NULL) 787135446Strhodes isc_mempool_destroy(&m->rdspool); 788135446Strhodes m->magic = 0; 789135446Strhodes isc_mem_put(mctx, m, sizeof(dns_message_t)); 790135446Strhodes 791135446Strhodes return (ISC_R_NOMEMORY); 792135446Strhodes} 793135446Strhodes 794135446Strhodesvoid 795135446Strhodesdns_message_reset(dns_message_t *msg, unsigned int intent) { 796135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 797135446Strhodes REQUIRE(intent == DNS_MESSAGE_INTENTPARSE 798135446Strhodes || intent == DNS_MESSAGE_INTENTRENDER); 799135446Strhodes 800135446Strhodes msgreset(msg, ISC_FALSE); 801135446Strhodes msg->from_to_wire = intent; 802135446Strhodes} 803135446Strhodes 804135446Strhodesvoid 805135446Strhodesdns_message_destroy(dns_message_t **msgp) { 806135446Strhodes dns_message_t *msg; 807135446Strhodes 808135446Strhodes REQUIRE(msgp != NULL); 809135446Strhodes REQUIRE(DNS_MESSAGE_VALID(*msgp)); 810135446Strhodes 811135446Strhodes msg = *msgp; 812135446Strhodes *msgp = NULL; 813135446Strhodes 814135446Strhodes msgreset(msg, ISC_TRUE); 815135446Strhodes isc_mempool_destroy(&msg->namepool); 816135446Strhodes isc_mempool_destroy(&msg->rdspool); 817135446Strhodes msg->magic = 0; 818135446Strhodes isc_mem_put(msg->mctx, msg, sizeof(dns_message_t)); 819135446Strhodes} 820135446Strhodes 821135446Strhodesstatic isc_result_t 822135446Strhodesfindname(dns_name_t **foundname, dns_name_t *target, 823135446Strhodes dns_namelist_t *section) 824135446Strhodes{ 825135446Strhodes dns_name_t *curr; 826135446Strhodes 827135446Strhodes for (curr = ISC_LIST_TAIL(*section); 828135446Strhodes curr != NULL; 829135446Strhodes curr = ISC_LIST_PREV(curr, link)) { 830135446Strhodes if (dns_name_equal(curr, target)) { 831135446Strhodes if (foundname != NULL) 832135446Strhodes *foundname = curr; 833135446Strhodes return (ISC_R_SUCCESS); 834135446Strhodes } 835135446Strhodes } 836135446Strhodes 837135446Strhodes return (ISC_R_NOTFOUND); 838135446Strhodes} 839135446Strhodes 840135446Strhodesisc_result_t 841165071Sdougbdns_message_find(dns_name_t *name, dns_rdataclass_t rdclass, 842165071Sdougb dns_rdatatype_t type, dns_rdatatype_t covers, 843165071Sdougb dns_rdataset_t **rdataset) 844165071Sdougb{ 845165071Sdougb dns_rdataset_t *curr; 846165071Sdougb 847165071Sdougb if (rdataset != NULL) { 848165071Sdougb REQUIRE(*rdataset == NULL); 849165071Sdougb } 850165071Sdougb 851165071Sdougb for (curr = ISC_LIST_TAIL(name->list); 852165071Sdougb curr != NULL; 853165071Sdougb curr = ISC_LIST_PREV(curr, link)) { 854165071Sdougb if (curr->rdclass == rdclass && 855165071Sdougb curr->type == type && curr->covers == covers) { 856165071Sdougb if (rdataset != NULL) 857165071Sdougb *rdataset = curr; 858165071Sdougb return (ISC_R_SUCCESS); 859165071Sdougb } 860165071Sdougb } 861165071Sdougb 862165071Sdougb return (ISC_R_NOTFOUND); 863165071Sdougb} 864165071Sdougb 865165071Sdougbisc_result_t 866135446Strhodesdns_message_findtype(dns_name_t *name, dns_rdatatype_t type, 867135446Strhodes dns_rdatatype_t covers, dns_rdataset_t **rdataset) 868135446Strhodes{ 869135446Strhodes dns_rdataset_t *curr; 870135446Strhodes 871165071Sdougb REQUIRE(name != NULL); 872135446Strhodes if (rdataset != NULL) { 873135446Strhodes REQUIRE(*rdataset == NULL); 874135446Strhodes } 875135446Strhodes 876135446Strhodes for (curr = ISC_LIST_TAIL(name->list); 877135446Strhodes curr != NULL; 878135446Strhodes curr = ISC_LIST_PREV(curr, link)) { 879135446Strhodes if (curr->type == type && curr->covers == covers) { 880135446Strhodes if (rdataset != NULL) 881135446Strhodes *rdataset = curr; 882135446Strhodes return (ISC_R_SUCCESS); 883135446Strhodes } 884135446Strhodes } 885135446Strhodes 886135446Strhodes return (ISC_R_NOTFOUND); 887135446Strhodes} 888135446Strhodes 889135446Strhodes/* 890135446Strhodes * Read a name from buffer "source". 891135446Strhodes */ 892135446Strhodesstatic isc_result_t 893135446Strhodesgetname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg, 894135446Strhodes dns_decompress_t *dctx) 895135446Strhodes{ 896135446Strhodes isc_buffer_t *scratch; 897135446Strhodes isc_result_t result; 898135446Strhodes unsigned int tries; 899135446Strhodes 900135446Strhodes scratch = currentbuffer(msg); 901135446Strhodes 902135446Strhodes /* 903135446Strhodes * First try: use current buffer. 904135446Strhodes * Second try: allocate a new buffer and use that. 905135446Strhodes */ 906135446Strhodes tries = 0; 907135446Strhodes while (tries < 2) { 908135446Strhodes result = dns_name_fromwire(name, source, dctx, ISC_FALSE, 909135446Strhodes scratch); 910135446Strhodes 911135446Strhodes if (result == ISC_R_NOSPACE) { 912135446Strhodes tries++; 913135446Strhodes 914135446Strhodes result = newbuffer(msg, SCRATCHPAD_SIZE); 915135446Strhodes if (result != ISC_R_SUCCESS) 916135446Strhodes return (result); 917135446Strhodes 918135446Strhodes scratch = currentbuffer(msg); 919135446Strhodes dns_name_reset(name); 920135446Strhodes } else { 921135446Strhodes return (result); 922135446Strhodes } 923135446Strhodes } 924135446Strhodes 925135446Strhodes INSIST(0); /* Cannot get here... */ 926135446Strhodes return (ISC_R_UNEXPECTED); 927135446Strhodes} 928135446Strhodes 929135446Strhodesstatic isc_result_t 930135446Strhodesgetrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, 931135446Strhodes dns_rdataclass_t rdclass, dns_rdatatype_t rdtype, 932135446Strhodes unsigned int rdatalen, dns_rdata_t *rdata) 933135446Strhodes{ 934135446Strhodes isc_buffer_t *scratch; 935135446Strhodes isc_result_t result; 936135446Strhodes unsigned int tries; 937135446Strhodes unsigned int trysize; 938135446Strhodes 939135446Strhodes scratch = currentbuffer(msg); 940135446Strhodes 941135446Strhodes isc_buffer_setactive(source, rdatalen); 942135446Strhodes 943135446Strhodes /* 944135446Strhodes * First try: use current buffer. 945135446Strhodes * Second try: allocate a new buffer of size 946135446Strhodes * max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen) 947135446Strhodes * (the data will fit if it was not more than 50% compressed) 948135446Strhodes * Subsequent tries: double buffer size on each try. 949135446Strhodes */ 950135446Strhodes tries = 0; 951135446Strhodes trysize = 0; 952135446Strhodes /* XXX possibly change this to a while (tries < 2) loop */ 953135446Strhodes for (;;) { 954135446Strhodes result = dns_rdata_fromwire(rdata, rdclass, rdtype, 955135446Strhodes source, dctx, 0, 956135446Strhodes scratch); 957135446Strhodes 958135446Strhodes if (result == ISC_R_NOSPACE) { 959135446Strhodes if (tries == 0) { 960135446Strhodes trysize = 2 * rdatalen; 961135446Strhodes if (trysize < SCRATCHPAD_SIZE) 962135446Strhodes trysize = SCRATCHPAD_SIZE; 963135446Strhodes } else { 964135446Strhodes INSIST(trysize != 0); 965135446Strhodes if (trysize >= 65535) 966135446Strhodes return (ISC_R_NOSPACE); 967135446Strhodes /* XXX DNS_R_RRTOOLONG? */ 968135446Strhodes trysize *= 2; 969135446Strhodes } 970135446Strhodes tries++; 971135446Strhodes result = newbuffer(msg, trysize); 972135446Strhodes if (result != ISC_R_SUCCESS) 973135446Strhodes return (result); 974135446Strhodes 975135446Strhodes scratch = currentbuffer(msg); 976135446Strhodes } else { 977135446Strhodes return (result); 978135446Strhodes } 979135446Strhodes } 980135446Strhodes} 981135446Strhodes 982135446Strhodes#define DO_FORMERR \ 983135446Strhodes do { \ 984135446Strhodes if (best_effort) \ 985135446Strhodes seen_problem = ISC_TRUE; \ 986135446Strhodes else { \ 987135446Strhodes result = DNS_R_FORMERR; \ 988135446Strhodes goto cleanup; \ 989135446Strhodes } \ 990135446Strhodes } while (0) 991135446Strhodes 992135446Strhodesstatic isc_result_t 993135446Strhodesgetquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, 994135446Strhodes unsigned int options) 995135446Strhodes{ 996135446Strhodes isc_region_t r; 997135446Strhodes unsigned int count; 998135446Strhodes dns_name_t *name; 999135446Strhodes dns_name_t *name2; 1000135446Strhodes dns_offsets_t *offsets; 1001135446Strhodes dns_rdataset_t *rdataset; 1002135446Strhodes dns_rdatalist_t *rdatalist; 1003135446Strhodes isc_result_t result; 1004135446Strhodes dns_rdatatype_t rdtype; 1005135446Strhodes dns_rdataclass_t rdclass; 1006135446Strhodes dns_namelist_t *section; 1007135446Strhodes isc_boolean_t free_name; 1008135446Strhodes isc_boolean_t best_effort; 1009135446Strhodes isc_boolean_t seen_problem; 1010135446Strhodes 1011135446Strhodes section = &msg->sections[DNS_SECTION_QUESTION]; 1012135446Strhodes 1013135446Strhodes best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT); 1014135446Strhodes seen_problem = ISC_FALSE; 1015135446Strhodes 1016135446Strhodes name = NULL; 1017135446Strhodes rdataset = NULL; 1018135446Strhodes rdatalist = NULL; 1019135446Strhodes 1020135446Strhodes for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) { 1021135446Strhodes name = isc_mempool_get(msg->namepool); 1022135446Strhodes if (name == NULL) 1023135446Strhodes return (ISC_R_NOMEMORY); 1024135446Strhodes free_name = ISC_TRUE; 1025186462Sdougb 1026135446Strhodes offsets = newoffsets(msg); 1027135446Strhodes if (offsets == NULL) { 1028135446Strhodes result = ISC_R_NOMEMORY; 1029135446Strhodes goto cleanup; 1030135446Strhodes } 1031135446Strhodes dns_name_init(name, *offsets); 1032135446Strhodes 1033135446Strhodes /* 1034135446Strhodes * Parse the name out of this packet. 1035135446Strhodes */ 1036135446Strhodes isc_buffer_remainingregion(source, &r); 1037135446Strhodes isc_buffer_setactive(source, r.length); 1038135446Strhodes result = getname(name, source, msg, dctx); 1039135446Strhodes if (result != ISC_R_SUCCESS) 1040135446Strhodes goto cleanup; 1041135446Strhodes 1042135446Strhodes /* 1043135446Strhodes * Run through the section, looking to see if this name 1044135446Strhodes * is already there. If it is found, put back the allocated 1045135446Strhodes * name since we no longer need it, and set our name pointer 1046135446Strhodes * to point to the name we found. 1047135446Strhodes */ 1048135446Strhodes result = findname(&name2, name, section); 1049135446Strhodes 1050135446Strhodes /* 1051135446Strhodes * If it is the first name in the section, accept it. 1052135446Strhodes * 1053135446Strhodes * If it is not, but is not the same as the name already 1054135446Strhodes * in the question section, append to the section. Note that 1055135446Strhodes * here in the question section this is illegal, so return 1056135446Strhodes * FORMERR. In the future, check the opcode to see if 1057135446Strhodes * this should be legal or not. In either case we no longer 1058135446Strhodes * need this name pointer. 1059135446Strhodes */ 1060135446Strhodes if (result != ISC_R_SUCCESS) { 1061135446Strhodes if (!ISC_LIST_EMPTY(*section)) 1062135446Strhodes DO_FORMERR; 1063135446Strhodes ISC_LIST_APPEND(*section, name, link); 1064135446Strhodes free_name = ISC_FALSE; 1065135446Strhodes } else { 1066135446Strhodes isc_mempool_put(msg->namepool, name); 1067135446Strhodes name = name2; 1068135446Strhodes name2 = NULL; 1069135446Strhodes free_name = ISC_FALSE; 1070135446Strhodes } 1071135446Strhodes 1072135446Strhodes /* 1073135446Strhodes * Get type and class. 1074135446Strhodes */ 1075135446Strhodes isc_buffer_remainingregion(source, &r); 1076135446Strhodes if (r.length < 4) { 1077135446Strhodes result = ISC_R_UNEXPECTEDEND; 1078135446Strhodes goto cleanup; 1079135446Strhodes } 1080135446Strhodes rdtype = isc_buffer_getuint16(source); 1081135446Strhodes rdclass = isc_buffer_getuint16(source); 1082135446Strhodes 1083135446Strhodes /* 1084135446Strhodes * If this class is different than the one we already read, 1085135446Strhodes * this is an error. 1086135446Strhodes */ 1087135446Strhodes if (msg->state == DNS_SECTION_ANY) { 1088135446Strhodes msg->state = DNS_SECTION_QUESTION; 1089135446Strhodes msg->rdclass = rdclass; 1090135446Strhodes } else if (msg->rdclass != rdclass) 1091135446Strhodes DO_FORMERR; 1092135446Strhodes 1093135446Strhodes /* 1094135446Strhodes * Can't ask the same question twice. 1095135446Strhodes */ 1096165071Sdougb result = dns_message_find(name, rdclass, rdtype, 0, NULL); 1097135446Strhodes if (result == ISC_R_SUCCESS) 1098135446Strhodes DO_FORMERR; 1099135446Strhodes 1100135446Strhodes /* 1101135446Strhodes * Allocate a new rdatalist. 1102135446Strhodes */ 1103135446Strhodes rdatalist = newrdatalist(msg); 1104135446Strhodes if (rdatalist == NULL) { 1105135446Strhodes result = ISC_R_NOMEMORY; 1106135446Strhodes goto cleanup; 1107135446Strhodes } 1108135446Strhodes rdataset = isc_mempool_get(msg->rdspool); 1109135446Strhodes if (rdataset == NULL) { 1110135446Strhodes result = ISC_R_NOMEMORY; 1111135446Strhodes goto cleanup; 1112135446Strhodes } 1113135446Strhodes 1114135446Strhodes /* 1115135446Strhodes * Convert rdatalist to rdataset, and attach the latter to 1116135446Strhodes * the name. 1117135446Strhodes */ 1118135446Strhodes rdatalist->type = rdtype; 1119135446Strhodes rdatalist->covers = 0; 1120135446Strhodes rdatalist->rdclass = rdclass; 1121135446Strhodes rdatalist->ttl = 0; 1122135446Strhodes ISC_LIST_INIT(rdatalist->rdata); 1123135446Strhodes 1124135446Strhodes dns_rdataset_init(rdataset); 1125135446Strhodes result = dns_rdatalist_tordataset(rdatalist, rdataset); 1126135446Strhodes if (result != ISC_R_SUCCESS) 1127135446Strhodes goto cleanup; 1128135446Strhodes 1129135446Strhodes rdataset->attributes |= DNS_RDATASETATTR_QUESTION; 1130135446Strhodes 1131135446Strhodes ISC_LIST_APPEND(name->list, rdataset, link); 1132135446Strhodes rdataset = NULL; 1133135446Strhodes } 1134135446Strhodes 1135135446Strhodes if (seen_problem) 1136135446Strhodes return (DNS_R_RECOVERABLE); 1137135446Strhodes return (ISC_R_SUCCESS); 1138135446Strhodes 1139135446Strhodes cleanup: 1140135446Strhodes if (rdataset != NULL) { 1141135446Strhodes INSIST(!dns_rdataset_isassociated(rdataset)); 1142135446Strhodes isc_mempool_put(msg->rdspool, rdataset); 1143135446Strhodes } 1144135446Strhodes#if 0 1145135446Strhodes if (rdatalist != NULL) 1146135446Strhodes isc_mempool_put(msg->rdlpool, rdatalist); 1147135446Strhodes#endif 1148135446Strhodes if (free_name) 1149135446Strhodes isc_mempool_put(msg->namepool, name); 1150135446Strhodes 1151135446Strhodes return (result); 1152135446Strhodes} 1153135446Strhodes 1154135446Strhodesstatic isc_boolean_t 1155135446Strhodesupdate(dns_section_t section, dns_rdataclass_t rdclass) { 1156135446Strhodes if (section == DNS_SECTION_PREREQUISITE) 1157135446Strhodes return (ISC_TF(rdclass == dns_rdataclass_any || 1158135446Strhodes rdclass == dns_rdataclass_none)); 1159135446Strhodes if (section == DNS_SECTION_UPDATE) 1160135446Strhodes return (ISC_TF(rdclass == dns_rdataclass_any)); 1161135446Strhodes return (ISC_FALSE); 1162135446Strhodes} 1163135446Strhodes 1164135446Strhodesstatic isc_result_t 1165135446Strhodesgetsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, 1166135446Strhodes dns_section_t sectionid, unsigned int options) 1167135446Strhodes{ 1168135446Strhodes isc_region_t r; 1169135446Strhodes unsigned int count, rdatalen; 1170135446Strhodes dns_name_t *name; 1171135446Strhodes dns_name_t *name2; 1172135446Strhodes dns_offsets_t *offsets; 1173135446Strhodes dns_rdataset_t *rdataset; 1174135446Strhodes dns_rdatalist_t *rdatalist; 1175135446Strhodes isc_result_t result; 1176135446Strhodes dns_rdatatype_t rdtype, covers; 1177135446Strhodes dns_rdataclass_t rdclass; 1178135446Strhodes dns_rdata_t *rdata; 1179135446Strhodes dns_ttl_t ttl; 1180135446Strhodes dns_namelist_t *section; 1181135446Strhodes isc_boolean_t free_name, free_rdataset; 1182135446Strhodes isc_boolean_t preserve_order, best_effort, seen_problem; 1183135446Strhodes isc_boolean_t issigzero; 1184135446Strhodes 1185135446Strhodes preserve_order = ISC_TF(options & DNS_MESSAGEPARSE_PRESERVEORDER); 1186135446Strhodes best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT); 1187135446Strhodes seen_problem = ISC_FALSE; 1188135446Strhodes 1189135446Strhodes for (count = 0; count < msg->counts[sectionid]; count++) { 1190135446Strhodes int recstart = source->current; 1191135446Strhodes isc_boolean_t skip_name_search, skip_type_search; 1192135446Strhodes 1193135446Strhodes section = &msg->sections[sectionid]; 1194135446Strhodes 1195135446Strhodes skip_name_search = ISC_FALSE; 1196135446Strhodes skip_type_search = ISC_FALSE; 1197135446Strhodes free_name = ISC_FALSE; 1198135446Strhodes free_rdataset = ISC_FALSE; 1199135446Strhodes 1200135446Strhodes name = isc_mempool_get(msg->namepool); 1201135446Strhodes if (name == NULL) 1202135446Strhodes return (ISC_R_NOMEMORY); 1203135446Strhodes free_name = ISC_TRUE; 1204135446Strhodes 1205135446Strhodes offsets = newoffsets(msg); 1206135446Strhodes if (offsets == NULL) { 1207135446Strhodes result = ISC_R_NOMEMORY; 1208135446Strhodes goto cleanup; 1209135446Strhodes } 1210135446Strhodes dns_name_init(name, *offsets); 1211135446Strhodes 1212135446Strhodes /* 1213135446Strhodes * Parse the name out of this packet. 1214135446Strhodes */ 1215135446Strhodes isc_buffer_remainingregion(source, &r); 1216135446Strhodes isc_buffer_setactive(source, r.length); 1217135446Strhodes result = getname(name, source, msg, dctx); 1218135446Strhodes if (result != ISC_R_SUCCESS) 1219135446Strhodes goto cleanup; 1220135446Strhodes 1221135446Strhodes /* 1222135446Strhodes * Get type, class, ttl, and rdatalen. Verify that at least 1223135446Strhodes * rdatalen bytes remain. (Some of this is deferred to 1224135446Strhodes * later.) 1225135446Strhodes */ 1226135446Strhodes isc_buffer_remainingregion(source, &r); 1227135446Strhodes if (r.length < 2 + 2 + 4 + 2) { 1228135446Strhodes result = ISC_R_UNEXPECTEDEND; 1229135446Strhodes goto cleanup; 1230135446Strhodes } 1231135446Strhodes rdtype = isc_buffer_getuint16(source); 1232135446Strhodes rdclass = isc_buffer_getuint16(source); 1233135446Strhodes 1234135446Strhodes /* 1235135446Strhodes * If there was no question section, we may not yet have 1236135446Strhodes * established a class. Do so now. 1237135446Strhodes */ 1238135446Strhodes if (msg->state == DNS_SECTION_ANY && 1239135446Strhodes rdtype != dns_rdatatype_opt && /* class is UDP SIZE */ 1240135446Strhodes rdtype != dns_rdatatype_tsig && /* class is ANY */ 1241135446Strhodes rdtype != dns_rdatatype_tkey) { /* class is undefined */ 1242135446Strhodes msg->rdclass = rdclass; 1243135446Strhodes msg->state = DNS_SECTION_QUESTION; 1244135446Strhodes } 1245135446Strhodes 1246135446Strhodes /* 1247135446Strhodes * If this class is different than the one in the question 1248135446Strhodes * section, bail. 1249135446Strhodes */ 1250135446Strhodes if (msg->opcode != dns_opcode_update 1251135446Strhodes && rdtype != dns_rdatatype_tsig 1252135446Strhodes && rdtype != dns_rdatatype_opt 1253135446Strhodes && rdtype != dns_rdatatype_dnskey /* in a TKEY query */ 1254135446Strhodes && rdtype != dns_rdatatype_sig /* SIG(0) */ 1255135446Strhodes && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */ 1256165071Sdougb && msg->rdclass != dns_rdataclass_any 1257135446Strhodes && msg->rdclass != rdclass) 1258135446Strhodes DO_FORMERR; 1259135446Strhodes 1260135446Strhodes /* 1261135446Strhodes * Special type handling for TSIG, OPT, and TKEY. 1262135446Strhodes */ 1263135446Strhodes if (rdtype == dns_rdatatype_tsig) { 1264135446Strhodes /* 1265135446Strhodes * If it is a tsig, verify that it is in the 1266135446Strhodes * additional data section. 1267135446Strhodes */ 1268135446Strhodes if (sectionid != DNS_SECTION_ADDITIONAL || 1269135446Strhodes rdclass != dns_rdataclass_any || 1270135446Strhodes count != msg->counts[sectionid] - 1) 1271135446Strhodes DO_FORMERR; 1272135446Strhodes msg->sigstart = recstart; 1273135446Strhodes skip_name_search = ISC_TRUE; 1274135446Strhodes skip_type_search = ISC_TRUE; 1275135446Strhodes } else if (rdtype == dns_rdatatype_opt) { 1276135446Strhodes /* 1277135446Strhodes * The name of an OPT record must be ".", it 1278135446Strhodes * must be in the additional data section, and 1279135446Strhodes * it must be the first OPT we've seen. 1280135446Strhodes */ 1281135446Strhodes if (!dns_name_equal(dns_rootname, name) || 1282135446Strhodes msg->opt != NULL) 1283135446Strhodes DO_FORMERR; 1284135446Strhodes skip_name_search = ISC_TRUE; 1285135446Strhodes skip_type_search = ISC_TRUE; 1286135446Strhodes } else if (rdtype == dns_rdatatype_tkey) { 1287135446Strhodes /* 1288135446Strhodes * A TKEY must be in the additional section if this 1289135446Strhodes * is a query, and the answer section if this is a 1290135446Strhodes * response. Unless it's a Win2000 client. 1291135446Strhodes * 1292135446Strhodes * Its class is ignored. 1293135446Strhodes */ 1294135446Strhodes dns_section_t tkeysection; 1295135446Strhodes 1296135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0) 1297135446Strhodes tkeysection = DNS_SECTION_ADDITIONAL; 1298135446Strhodes else 1299135446Strhodes tkeysection = DNS_SECTION_ANSWER; 1300135446Strhodes if (sectionid != tkeysection && 1301135446Strhodes sectionid != DNS_SECTION_ANSWER) 1302135446Strhodes DO_FORMERR; 1303135446Strhodes } 1304135446Strhodes 1305135446Strhodes /* 1306135446Strhodes * ... now get ttl and rdatalen, and check buffer. 1307135446Strhodes */ 1308135446Strhodes ttl = isc_buffer_getuint32(source); 1309135446Strhodes rdatalen = isc_buffer_getuint16(source); 1310135446Strhodes r.length -= (2 + 2 + 4 + 2); 1311135446Strhodes if (r.length < rdatalen) { 1312135446Strhodes result = ISC_R_UNEXPECTEDEND; 1313135446Strhodes goto cleanup; 1314135446Strhodes } 1315135446Strhodes 1316135446Strhodes /* 1317135446Strhodes * Read the rdata from the wire format. Interpret the 1318135446Strhodes * rdata according to its actual class, even if it had a 1319135446Strhodes * DynDNS meta-class in the packet (unless this is a TSIG). 1320135446Strhodes * Then put the meta-class back into the finished rdata. 1321135446Strhodes */ 1322135446Strhodes rdata = newrdata(msg); 1323135446Strhodes if (rdata == NULL) { 1324135446Strhodes result = ISC_R_NOMEMORY; 1325135446Strhodes goto cleanup; 1326135446Strhodes } 1327135446Strhodes if (msg->opcode == dns_opcode_update && 1328135446Strhodes update(sectionid, rdclass)) { 1329135446Strhodes if (rdatalen != 0) { 1330135446Strhodes result = DNS_R_FORMERR; 1331135446Strhodes goto cleanup; 1332135446Strhodes } 1333135446Strhodes /* 1334135446Strhodes * When the rdata is empty, the data pointer is 1335186462Sdougb * never dereferenced, but it must still be non-NULL. 1336135446Strhodes * Casting 1 rather than "" avoids warnings about 1337135446Strhodes * discarding the const attribute of a string, 1338135446Strhodes * for compilers that would warn about such things. 1339135446Strhodes */ 1340135446Strhodes rdata->data = (unsigned char *)1; 1341135446Strhodes rdata->length = 0; 1342135446Strhodes rdata->rdclass = rdclass; 1343135446Strhodes rdata->type = rdtype; 1344135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1345135446Strhodes result = ISC_R_SUCCESS; 1346174187Sdougb } else if (rdclass == dns_rdataclass_none && 1347174187Sdougb msg->opcode == dns_opcode_update && 1348174187Sdougb sectionid == DNS_SECTION_UPDATE) { 1349174187Sdougb result = getrdata(source, msg, dctx, msg->rdclass, 1350174187Sdougb rdtype, rdatalen, rdata); 1351165071Sdougb } else 1352135446Strhodes result = getrdata(source, msg, dctx, rdclass, 1353135446Strhodes rdtype, rdatalen, rdata); 1354135446Strhodes if (result != ISC_R_SUCCESS) 1355135446Strhodes goto cleanup; 1356135446Strhodes rdata->rdclass = rdclass; 1357135446Strhodes issigzero = ISC_FALSE; 1358135446Strhodes if (rdtype == dns_rdatatype_rrsig && 1359135446Strhodes rdata->flags == 0) { 1360135446Strhodes covers = dns_rdata_covers(rdata); 1361135446Strhodes if (covers == 0) 1362135446Strhodes DO_FORMERR; 1363135446Strhodes } else if (rdtype == dns_rdatatype_sig /* SIG(0) */ && 1364135446Strhodes rdata->flags == 0) { 1365135446Strhodes covers = dns_rdata_covers(rdata); 1366135446Strhodes if (covers == 0) { 1367135446Strhodes if (sectionid != DNS_SECTION_ADDITIONAL || 1368135446Strhodes count != msg->counts[sectionid] - 1) 1369135446Strhodes DO_FORMERR; 1370135446Strhodes msg->sigstart = recstart; 1371135446Strhodes skip_name_search = ISC_TRUE; 1372135446Strhodes skip_type_search = ISC_TRUE; 1373135446Strhodes issigzero = ISC_TRUE; 1374135446Strhodes } 1375135446Strhodes } else 1376135446Strhodes covers = 0; 1377135446Strhodes 1378135446Strhodes /* 1379135446Strhodes * If we are doing a dynamic update or this is a meta-type, 1380135446Strhodes * don't bother searching for a name, just append this one 1381135446Strhodes * to the end of the message. 1382135446Strhodes */ 1383135446Strhodes if (preserve_order || msg->opcode == dns_opcode_update || 1384135446Strhodes skip_name_search) { 1385135446Strhodes if (rdtype != dns_rdatatype_opt && 1386135446Strhodes rdtype != dns_rdatatype_tsig && 1387135446Strhodes !issigzero) 1388135446Strhodes { 1389135446Strhodes ISC_LIST_APPEND(*section, name, link); 1390135446Strhodes free_name = ISC_FALSE; 1391135446Strhodes } 1392135446Strhodes } else { 1393135446Strhodes /* 1394135446Strhodes * Run through the section, looking to see if this name 1395135446Strhodes * is already there. If it is found, put back the 1396135446Strhodes * allocated name since we no longer need it, and set 1397135446Strhodes * our name pointer to point to the name we found. 1398135446Strhodes */ 1399135446Strhodes result = findname(&name2, name, section); 1400135446Strhodes 1401135446Strhodes /* 1402135446Strhodes * If it is a new name, append to the section. 1403135446Strhodes */ 1404135446Strhodes if (result == ISC_R_SUCCESS) { 1405135446Strhodes isc_mempool_put(msg->namepool, name); 1406135446Strhodes name = name2; 1407135446Strhodes } else { 1408135446Strhodes ISC_LIST_APPEND(*section, name, link); 1409135446Strhodes } 1410135446Strhodes free_name = ISC_FALSE; 1411135446Strhodes } 1412135446Strhodes 1413135446Strhodes /* 1414135446Strhodes * Search name for the particular type and class. 1415135446Strhodes * Skip this stage if in update mode or this is a meta-type. 1416135446Strhodes */ 1417135446Strhodes if (preserve_order || msg->opcode == dns_opcode_update || 1418135446Strhodes skip_type_search) 1419135446Strhodes result = ISC_R_NOTFOUND; 1420135446Strhodes else { 1421135446Strhodes /* 1422135446Strhodes * If this is a type that can only occur in 1423135446Strhodes * the question section, fail. 1424135446Strhodes */ 1425135446Strhodes if (dns_rdatatype_questiononly(rdtype)) 1426135446Strhodes DO_FORMERR; 1427135446Strhodes 1428135446Strhodes rdataset = NULL; 1429165071Sdougb result = dns_message_find(name, rdclass, rdtype, 1430165071Sdougb covers, &rdataset); 1431135446Strhodes } 1432135446Strhodes 1433135446Strhodes /* 1434135446Strhodes * If we found an rdataset that matches, we need to 1435135446Strhodes * append this rdata to that set. If we did not, we need 1436135446Strhodes * to create a new rdatalist, store the important bits there, 1437135446Strhodes * convert it to an rdataset, and link the latter to the name. 1438135446Strhodes * Yuck. When appending, make certain that the type isn't 1439135446Strhodes * a singleton type, such as SOA or CNAME. 1440135446Strhodes * 1441135446Strhodes * Note that this check will be bypassed when preserving order, 1442135446Strhodes * the opcode is an update, or the type search is skipped. 1443135446Strhodes */ 1444135446Strhodes if (result == ISC_R_SUCCESS) { 1445135446Strhodes if (dns_rdatatype_issingleton(rdtype)) 1446135446Strhodes DO_FORMERR; 1447135446Strhodes } 1448135446Strhodes 1449135446Strhodes if (result == ISC_R_NOTFOUND) { 1450135446Strhodes rdataset = isc_mempool_get(msg->rdspool); 1451135446Strhodes if (rdataset == NULL) { 1452135446Strhodes result = ISC_R_NOMEMORY; 1453135446Strhodes goto cleanup; 1454135446Strhodes } 1455135446Strhodes free_rdataset = ISC_TRUE; 1456135446Strhodes 1457135446Strhodes rdatalist = newrdatalist(msg); 1458135446Strhodes if (rdatalist == NULL) { 1459135446Strhodes result = ISC_R_NOMEMORY; 1460135446Strhodes goto cleanup; 1461135446Strhodes } 1462135446Strhodes 1463135446Strhodes rdatalist->type = rdtype; 1464135446Strhodes rdatalist->covers = covers; 1465135446Strhodes rdatalist->rdclass = rdclass; 1466135446Strhodes rdatalist->ttl = ttl; 1467135446Strhodes ISC_LIST_INIT(rdatalist->rdata); 1468135446Strhodes 1469135446Strhodes dns_rdataset_init(rdataset); 1470135446Strhodes RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, 1471135446Strhodes rdataset) 1472135446Strhodes == ISC_R_SUCCESS); 1473135446Strhodes 1474186462Sdougb if (rdtype != dns_rdatatype_opt && 1475135446Strhodes rdtype != dns_rdatatype_tsig && 1476135446Strhodes !issigzero) 1477135446Strhodes { 1478135446Strhodes ISC_LIST_APPEND(name->list, rdataset, link); 1479135446Strhodes free_rdataset = ISC_FALSE; 1480135446Strhodes } 1481135446Strhodes } 1482135446Strhodes 1483135446Strhodes /* 1484135446Strhodes * Minimize TTLs. 1485135446Strhodes * 1486170222Sdougb * Section 5.2 of RFC2181 says we should drop 1487135446Strhodes * nonauthoritative rrsets where the TTLs differ, but we 1488135446Strhodes * currently treat them the as if they were authoritative and 1489135446Strhodes * minimize them. 1490135446Strhodes */ 1491135446Strhodes if (ttl != rdataset->ttl) { 1492135446Strhodes rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED; 1493135446Strhodes if (ttl < rdataset->ttl) 1494135446Strhodes rdataset->ttl = ttl; 1495135446Strhodes } 1496135446Strhodes 1497193149Sdougb /* Append this rdata to the rdataset. */ 1498193149Sdougb dns_rdatalist_fromrdataset(rdataset, &rdatalist); 1499135446Strhodes ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 1500135446Strhodes 1501135446Strhodes /* 1502135446Strhodes * If this is an OPT record, remember it. Also, set 1503135446Strhodes * the extended rcode. Note that msg->opt will only be set 1504135446Strhodes * if best-effort parsing is enabled. 1505135446Strhodes */ 1506135446Strhodes if (rdtype == dns_rdatatype_opt && msg->opt == NULL) { 1507135446Strhodes dns_rcode_t ercode; 1508135446Strhodes 1509135446Strhodes msg->opt = rdataset; 1510135446Strhodes rdataset = NULL; 1511135446Strhodes free_rdataset = ISC_FALSE; 1512135446Strhodes ercode = (dns_rcode_t) 1513135446Strhodes ((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK) 1514135446Strhodes >> 20); 1515135446Strhodes msg->rcode |= ercode; 1516135446Strhodes isc_mempool_put(msg->namepool, name); 1517135446Strhodes free_name = ISC_FALSE; 1518135446Strhodes } 1519135446Strhodes 1520135446Strhodes /* 1521135446Strhodes * If this is an SIG(0) or TSIG record, remember it. Note 1522135446Strhodes * that msg->sig0 or msg->tsig will only be set if best-effort 1523135446Strhodes * parsing is enabled. 1524135446Strhodes */ 1525135446Strhodes if (issigzero && msg->sig0 == NULL) { 1526135446Strhodes msg->sig0 = rdataset; 1527135446Strhodes msg->sig0name = name; 1528135446Strhodes rdataset = NULL; 1529135446Strhodes free_rdataset = ISC_FALSE; 1530135446Strhodes free_name = ISC_FALSE; 1531135446Strhodes } else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) { 1532135446Strhodes msg->tsig = rdataset; 1533135446Strhodes msg->tsigname = name; 1534218384Sdougb /* Windows doesn't like TSIG names to be compressed. */ 1535218384Sdougb msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS; 1536135446Strhodes rdataset = NULL; 1537135446Strhodes free_rdataset = ISC_FALSE; 1538135446Strhodes free_name = ISC_FALSE; 1539135446Strhodes } 1540135446Strhodes 1541153816Sdougb if (seen_problem) { 1542153816Sdougb if (free_name) 1543153816Sdougb isc_mempool_put(msg->namepool, name); 1544153816Sdougb if (free_rdataset) 1545153816Sdougb isc_mempool_put(msg->rdspool, rdataset); 1546153816Sdougb free_name = free_rdataset = ISC_FALSE; 1547153816Sdougb } 1548135446Strhodes INSIST(free_name == ISC_FALSE); 1549135446Strhodes INSIST(free_rdataset == ISC_FALSE); 1550135446Strhodes } 1551135446Strhodes 1552135446Strhodes if (seen_problem) 1553135446Strhodes return (DNS_R_RECOVERABLE); 1554135446Strhodes return (ISC_R_SUCCESS); 1555135446Strhodes 1556135446Strhodes cleanup: 1557135446Strhodes if (free_name) 1558135446Strhodes isc_mempool_put(msg->namepool, name); 1559135446Strhodes if (free_rdataset) 1560135446Strhodes isc_mempool_put(msg->rdspool, rdataset); 1561135446Strhodes 1562135446Strhodes return (result); 1563135446Strhodes} 1564135446Strhodes 1565135446Strhodesisc_result_t 1566135446Strhodesdns_message_parse(dns_message_t *msg, isc_buffer_t *source, 1567135446Strhodes unsigned int options) 1568135446Strhodes{ 1569135446Strhodes isc_region_t r; 1570135446Strhodes dns_decompress_t dctx; 1571135446Strhodes isc_result_t ret; 1572135446Strhodes isc_uint16_t tmpflags; 1573135446Strhodes isc_buffer_t origsource; 1574135446Strhodes isc_boolean_t seen_problem; 1575135446Strhodes isc_boolean_t ignore_tc; 1576135446Strhodes 1577135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 1578135446Strhodes REQUIRE(source != NULL); 1579135446Strhodes REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE); 1580135446Strhodes 1581135446Strhodes seen_problem = ISC_FALSE; 1582135446Strhodes ignore_tc = ISC_TF(options & DNS_MESSAGEPARSE_IGNORETRUNCATION); 1583135446Strhodes 1584135446Strhodes origsource = *source; 1585135446Strhodes 1586135446Strhodes msg->header_ok = 0; 1587135446Strhodes msg->question_ok = 0; 1588135446Strhodes 1589135446Strhodes isc_buffer_remainingregion(source, &r); 1590135446Strhodes if (r.length < DNS_MESSAGE_HEADERLEN) 1591135446Strhodes return (ISC_R_UNEXPECTEDEND); 1592135446Strhodes 1593135446Strhodes msg->id = isc_buffer_getuint16(source); 1594135446Strhodes tmpflags = isc_buffer_getuint16(source); 1595135446Strhodes msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK) 1596135446Strhodes >> DNS_MESSAGE_OPCODE_SHIFT); 1597135446Strhodes msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK); 1598135446Strhodes msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK); 1599135446Strhodes msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source); 1600135446Strhodes msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source); 1601135446Strhodes msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source); 1602135446Strhodes msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source); 1603135446Strhodes 1604135446Strhodes msg->header_ok = 1; 1605135446Strhodes 1606135446Strhodes /* 1607135446Strhodes * -1 means no EDNS. 1608135446Strhodes */ 1609135446Strhodes dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY); 1610135446Strhodes 1611135446Strhodes dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14); 1612135446Strhodes 1613135446Strhodes ret = getquestions(source, msg, &dctx, options); 1614135446Strhodes if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) 1615135446Strhodes goto truncated; 1616135446Strhodes if (ret == DNS_R_RECOVERABLE) { 1617135446Strhodes seen_problem = ISC_TRUE; 1618135446Strhodes ret = ISC_R_SUCCESS; 1619135446Strhodes } 1620135446Strhodes if (ret != ISC_R_SUCCESS) 1621135446Strhodes return (ret); 1622135446Strhodes msg->question_ok = 1; 1623135446Strhodes 1624135446Strhodes ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options); 1625135446Strhodes if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) 1626135446Strhodes goto truncated; 1627135446Strhodes if (ret == DNS_R_RECOVERABLE) { 1628135446Strhodes seen_problem = ISC_TRUE; 1629135446Strhodes ret = ISC_R_SUCCESS; 1630135446Strhodes } 1631135446Strhodes if (ret != ISC_R_SUCCESS) 1632135446Strhodes return (ret); 1633135446Strhodes 1634135446Strhodes ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options); 1635135446Strhodes if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) 1636135446Strhodes goto truncated; 1637135446Strhodes if (ret == DNS_R_RECOVERABLE) { 1638135446Strhodes seen_problem = ISC_TRUE; 1639135446Strhodes ret = ISC_R_SUCCESS; 1640135446Strhodes } 1641135446Strhodes if (ret != ISC_R_SUCCESS) 1642135446Strhodes return (ret); 1643135446Strhodes 1644135446Strhodes ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options); 1645135446Strhodes if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) 1646135446Strhodes goto truncated; 1647135446Strhodes if (ret == DNS_R_RECOVERABLE) { 1648135446Strhodes seen_problem = ISC_TRUE; 1649135446Strhodes ret = ISC_R_SUCCESS; 1650135446Strhodes } 1651135446Strhodes if (ret != ISC_R_SUCCESS) 1652135446Strhodes return (ret); 1653135446Strhodes 1654135446Strhodes isc_buffer_remainingregion(source, &r); 1655135446Strhodes if (r.length != 0) { 1656135446Strhodes isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1657135446Strhodes DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3), 1658135446Strhodes "message has %u byte(s) of trailing garbage", 1659135446Strhodes r.length); 1660135446Strhodes } 1661135446Strhodes 1662135446Strhodes truncated: 1663135446Strhodes if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0) 1664135446Strhodes isc_buffer_usedregion(&origsource, &msg->saved); 1665135446Strhodes else { 1666135446Strhodes msg->saved.length = isc_buffer_usedlength(&origsource); 1667135446Strhodes msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length); 1668135446Strhodes if (msg->saved.base == NULL) 1669135446Strhodes return (ISC_R_NOMEMORY); 1670135446Strhodes memcpy(msg->saved.base, isc_buffer_base(&origsource), 1671135446Strhodes msg->saved.length); 1672135446Strhodes msg->free_saved = 1; 1673135446Strhodes } 1674135446Strhodes 1675135446Strhodes if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) 1676135446Strhodes return (DNS_R_RECOVERABLE); 1677135446Strhodes if (seen_problem == ISC_TRUE) 1678135446Strhodes return (DNS_R_RECOVERABLE); 1679135446Strhodes return (ISC_R_SUCCESS); 1680135446Strhodes} 1681135446Strhodes 1682135446Strhodesisc_result_t 1683135446Strhodesdns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx, 1684135446Strhodes isc_buffer_t *buffer) 1685135446Strhodes{ 1686135446Strhodes isc_region_t r; 1687135446Strhodes 1688135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 1689135446Strhodes REQUIRE(buffer != NULL); 1690135446Strhodes REQUIRE(msg->buffer == NULL); 1691135446Strhodes REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 1692135446Strhodes 1693135446Strhodes msg->cctx = cctx; 1694135446Strhodes 1695135446Strhodes /* 1696135446Strhodes * Erase the contents of this buffer. 1697135446Strhodes */ 1698135446Strhodes isc_buffer_clear(buffer); 1699135446Strhodes 1700135446Strhodes /* 1701135446Strhodes * Make certain there is enough for at least the header in this 1702135446Strhodes * buffer. 1703135446Strhodes */ 1704135446Strhodes isc_buffer_availableregion(buffer, &r); 1705135446Strhodes if (r.length < DNS_MESSAGE_HEADERLEN) 1706135446Strhodes return (ISC_R_NOSPACE); 1707135446Strhodes 1708135446Strhodes if (r.length < msg->reserved) 1709135446Strhodes return (ISC_R_NOSPACE); 1710135446Strhodes 1711135446Strhodes /* 1712135446Strhodes * Reserve enough space for the header in this buffer. 1713135446Strhodes */ 1714135446Strhodes isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN); 1715135446Strhodes 1716135446Strhodes msg->buffer = buffer; 1717135446Strhodes 1718135446Strhodes return (ISC_R_SUCCESS); 1719135446Strhodes} 1720135446Strhodes 1721135446Strhodesisc_result_t 1722135446Strhodesdns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) { 1723135446Strhodes isc_region_t r, rn; 1724135446Strhodes 1725135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 1726135446Strhodes REQUIRE(buffer != NULL); 1727135446Strhodes REQUIRE(msg->buffer != NULL); 1728135446Strhodes 1729135446Strhodes /* 1730135446Strhodes * Ensure that the new buffer is empty, and has enough space to 1731135446Strhodes * hold the current contents. 1732135446Strhodes */ 1733135446Strhodes isc_buffer_clear(buffer); 1734135446Strhodes 1735135446Strhodes isc_buffer_availableregion(buffer, &rn); 1736135446Strhodes isc_buffer_usedregion(msg->buffer, &r); 1737135446Strhodes REQUIRE(rn.length > r.length); 1738135446Strhodes 1739135446Strhodes /* 1740135446Strhodes * Copy the contents from the old to the new buffer. 1741135446Strhodes */ 1742135446Strhodes isc_buffer_add(buffer, r.length); 1743135446Strhodes memcpy(rn.base, r.base, r.length); 1744135446Strhodes 1745135446Strhodes msg->buffer = buffer; 1746135446Strhodes 1747135446Strhodes return (ISC_R_SUCCESS); 1748135446Strhodes} 1749135446Strhodes 1750135446Strhodesvoid 1751135446Strhodesdns_message_renderrelease(dns_message_t *msg, unsigned int space) { 1752135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 1753135446Strhodes REQUIRE(space <= msg->reserved); 1754135446Strhodes 1755135446Strhodes msg->reserved -= space; 1756135446Strhodes} 1757135446Strhodes 1758135446Strhodesisc_result_t 1759135446Strhodesdns_message_renderreserve(dns_message_t *msg, unsigned int space) { 1760135446Strhodes isc_region_t r; 1761135446Strhodes 1762135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 1763135446Strhodes 1764135446Strhodes if (msg->buffer != NULL) { 1765135446Strhodes isc_buffer_availableregion(msg->buffer, &r); 1766135446Strhodes if (r.length < (space + msg->reserved)) 1767135446Strhodes return (ISC_R_NOSPACE); 1768135446Strhodes } 1769135446Strhodes 1770135446Strhodes msg->reserved += space; 1771135446Strhodes 1772135446Strhodes return (ISC_R_SUCCESS); 1773135446Strhodes} 1774135446Strhodes 1775135446Strhodesstatic inline isc_boolean_t 1776135446Strhodeswrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) { 1777135446Strhodes int pass_needed; 1778135446Strhodes 1779135446Strhodes /* 1780135446Strhodes * If we are not rendering class IN, this ordering is bogus. 1781135446Strhodes */ 1782135446Strhodes if (rds->rdclass != dns_rdataclass_in) 1783135446Strhodes return (ISC_FALSE); 1784135446Strhodes 1785135446Strhodes switch (rds->type) { 1786135446Strhodes case dns_rdatatype_a: 1787135446Strhodes case dns_rdatatype_aaaa: 1788135446Strhodes if (preferred_glue == rds->type) 1789135446Strhodes pass_needed = 4; 1790135446Strhodes else 1791135446Strhodes pass_needed = 3; 1792135446Strhodes break; 1793135446Strhodes case dns_rdatatype_rrsig: 1794135446Strhodes case dns_rdatatype_dnskey: 1795135446Strhodes pass_needed = 2; 1796135446Strhodes break; 1797135446Strhodes default: 1798135446Strhodes pass_needed = 1; 1799135446Strhodes } 1800135446Strhodes 1801135446Strhodes if (pass_needed >= pass) 1802135446Strhodes return (ISC_FALSE); 1803135446Strhodes 1804135446Strhodes return (ISC_TRUE); 1805135446Strhodes} 1806135446Strhodes 1807135446Strhodesisc_result_t 1808135446Strhodesdns_message_rendersection(dns_message_t *msg, dns_section_t sectionid, 1809135446Strhodes unsigned int options) 1810135446Strhodes{ 1811135446Strhodes dns_namelist_t *section; 1812135446Strhodes dns_name_t *name, *next_name; 1813135446Strhodes dns_rdataset_t *rdataset, *next_rdataset; 1814135446Strhodes unsigned int count, total; 1815135446Strhodes isc_result_t result; 1816135446Strhodes isc_buffer_t st; /* for rollbacks */ 1817135446Strhodes int pass; 1818135446Strhodes isc_boolean_t partial = ISC_FALSE; 1819135446Strhodes unsigned int rd_options; 1820135446Strhodes dns_rdatatype_t preferred_glue = 0; 1821135446Strhodes 1822135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 1823135446Strhodes REQUIRE(msg->buffer != NULL); 1824135446Strhodes REQUIRE(VALID_NAMED_SECTION(sectionid)); 1825135446Strhodes 1826135446Strhodes section = &msg->sections[sectionid]; 1827135446Strhodes 1828135446Strhodes if ((sectionid == DNS_SECTION_ADDITIONAL) 1829135446Strhodes && (options & DNS_MESSAGERENDER_ORDERED) == 0) { 1830135446Strhodes if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) { 1831135446Strhodes preferred_glue = dns_rdatatype_a; 1832135446Strhodes pass = 4; 1833135446Strhodes } else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) { 1834135446Strhodes preferred_glue = dns_rdatatype_aaaa; 1835135446Strhodes pass = 4; 1836135446Strhodes } else 1837135446Strhodes pass = 3; 1838135446Strhodes } else 1839135446Strhodes pass = 1; 1840135446Strhodes 1841135446Strhodes if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0) 1842135446Strhodes rd_options = 0; 1843135446Strhodes else 1844135446Strhodes rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC; 1845135446Strhodes 1846135446Strhodes /* 1847135446Strhodes * Shrink the space in the buffer by the reserved amount. 1848135446Strhodes */ 1849135446Strhodes msg->buffer->length -= msg->reserved; 1850135446Strhodes 1851135446Strhodes total = 0; 1852135446Strhodes if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0) 1853135446Strhodes partial = ISC_TRUE; 1854135446Strhodes 1855153816Sdougb /* 1856153816Sdougb * Render required glue first. Set TC if it won't fit. 1857153816Sdougb */ 1858153816Sdougb name = ISC_LIST_HEAD(*section); 1859153816Sdougb if (name != NULL) { 1860153816Sdougb rdataset = ISC_LIST_HEAD(name->list); 1861153816Sdougb if (rdataset != NULL && 1862153816Sdougb (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 0 && 1863153816Sdougb (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) { 1864165071Sdougb const void *order_arg = msg->order_arg; 1865153816Sdougb st = *(msg->buffer); 1866153816Sdougb count = 0; 1867153816Sdougb if (partial) 1868153816Sdougb result = dns_rdataset_towirepartial(rdataset, 1869153816Sdougb name, 1870153816Sdougb msg->cctx, 1871153816Sdougb msg->buffer, 1872153816Sdougb msg->order, 1873153816Sdougb order_arg, 1874153816Sdougb rd_options, 1875153816Sdougb &count, 1876153816Sdougb NULL); 1877153816Sdougb else 1878153816Sdougb result = dns_rdataset_towiresorted(rdataset, 1879153816Sdougb name, 1880153816Sdougb msg->cctx, 1881153816Sdougb msg->buffer, 1882153816Sdougb msg->order, 1883153816Sdougb order_arg, 1884153816Sdougb rd_options, 1885153816Sdougb &count); 1886153816Sdougb total += count; 1887153816Sdougb if (partial && result == ISC_R_NOSPACE) { 1888153816Sdougb msg->flags |= DNS_MESSAGEFLAG_TC; 1889153816Sdougb msg->buffer->length += msg->reserved; 1890153816Sdougb msg->counts[sectionid] += total; 1891153816Sdougb return (result); 1892153816Sdougb } 1893204619Sdougb if (result == ISC_R_NOSPACE) 1894204619Sdougb msg->flags |= DNS_MESSAGEFLAG_TC; 1895153816Sdougb if (result != ISC_R_SUCCESS) { 1896153816Sdougb INSIST(st.used < 65536); 1897153816Sdougb dns_compress_rollback(msg->cctx, 1898153816Sdougb (isc_uint16_t)st.used); 1899153816Sdougb *(msg->buffer) = st; /* rollback */ 1900153816Sdougb msg->buffer->length += msg->reserved; 1901153816Sdougb msg->counts[sectionid] += total; 1902153816Sdougb return (result); 1903153816Sdougb } 1904153816Sdougb rdataset->attributes |= DNS_RDATASETATTR_RENDERED; 1905153816Sdougb } 1906153816Sdougb } 1907153816Sdougb 1908135446Strhodes do { 1909135446Strhodes name = ISC_LIST_HEAD(*section); 1910135446Strhodes if (name == NULL) { 1911135446Strhodes msg->buffer->length += msg->reserved; 1912135446Strhodes msg->counts[sectionid] += total; 1913135446Strhodes return (ISC_R_SUCCESS); 1914135446Strhodes } 1915135446Strhodes 1916135446Strhodes while (name != NULL) { 1917135446Strhodes next_name = ISC_LIST_NEXT(name, link); 1918135446Strhodes 1919135446Strhodes rdataset = ISC_LIST_HEAD(name->list); 1920135446Strhodes while (rdataset != NULL) { 1921135446Strhodes next_rdataset = ISC_LIST_NEXT(rdataset, link); 1922135446Strhodes 1923135446Strhodes if ((rdataset->attributes & 1924135446Strhodes DNS_RDATASETATTR_RENDERED) != 0) 1925135446Strhodes goto next; 1926135446Strhodes 1927135446Strhodes if (((options & DNS_MESSAGERENDER_ORDERED) 1928135446Strhodes == 0) 1929135446Strhodes && (sectionid == DNS_SECTION_ADDITIONAL) 1930135446Strhodes && wrong_priority(rdataset, pass, 1931135446Strhodes preferred_glue)) 1932135446Strhodes goto next; 1933135446Strhodes 1934135446Strhodes st = *(msg->buffer); 1935135446Strhodes 1936135446Strhodes count = 0; 1937135446Strhodes if (partial) 1938135446Strhodes result = dns_rdataset_towirepartial( 1939135446Strhodes rdataset, 1940135446Strhodes name, 1941135446Strhodes msg->cctx, 1942135446Strhodes msg->buffer, 1943135446Strhodes msg->order, 1944135446Strhodes msg->order_arg, 1945135446Strhodes rd_options, 1946135446Strhodes &count, 1947135446Strhodes NULL); 1948135446Strhodes else 1949135446Strhodes result = dns_rdataset_towiresorted( 1950135446Strhodes rdataset, 1951135446Strhodes name, 1952135446Strhodes msg->cctx, 1953135446Strhodes msg->buffer, 1954135446Strhodes msg->order, 1955135446Strhodes msg->order_arg, 1956135446Strhodes rd_options, 1957135446Strhodes &count); 1958135446Strhodes 1959135446Strhodes total += count; 1960135446Strhodes 1961135446Strhodes /* 1962135446Strhodes * If out of space, record stats on what we 1963135446Strhodes * rendered so far, and return that status. 1964135446Strhodes * 1965135446Strhodes * XXXMLG Need to change this when 1966135446Strhodes * dns_rdataset_towire() can render partial 1967193149Sdougb * sets starting at some arbitrary point in the 1968135446Strhodes * set. This will include setting a bit in the 1969135446Strhodes * rdataset to indicate that a partial 1970135446Strhodes * rendering was done, and some state saved 1971135446Strhodes * somewhere (probably in the message struct) 1972135446Strhodes * to indicate where to continue from. 1973135446Strhodes */ 1974135446Strhodes if (partial && result == ISC_R_NOSPACE) { 1975135446Strhodes msg->buffer->length += msg->reserved; 1976135446Strhodes msg->counts[sectionid] += total; 1977135446Strhodes return (result); 1978135446Strhodes } 1979135446Strhodes if (result != ISC_R_SUCCESS) { 1980135446Strhodes INSIST(st.used < 65536); 1981135446Strhodes dns_compress_rollback(msg->cctx, 1982135446Strhodes (isc_uint16_t)st.used); 1983135446Strhodes *(msg->buffer) = st; /* rollback */ 1984135446Strhodes msg->buffer->length += msg->reserved; 1985135446Strhodes msg->counts[sectionid] += total; 1986135446Strhodes return (result); 1987135446Strhodes } 1988135446Strhodes 1989135446Strhodes /* 1990135446Strhodes * If we have rendered non-validated data, 1991135446Strhodes * ensure that the AD bit is not set. 1992135446Strhodes */ 1993135446Strhodes if (rdataset->trust != dns_trust_secure && 1994135446Strhodes (sectionid == DNS_SECTION_ANSWER || 1995135446Strhodes sectionid == DNS_SECTION_AUTHORITY)) 1996135446Strhodes msg->flags &= ~DNS_MESSAGEFLAG_AD; 1997193149Sdougb if (OPTOUT(rdataset)) 1998193149Sdougb msg->flags &= ~DNS_MESSAGEFLAG_AD; 1999135446Strhodes 2000135446Strhodes rdataset->attributes |= 2001135446Strhodes DNS_RDATASETATTR_RENDERED; 2002135446Strhodes 2003135446Strhodes next: 2004135446Strhodes rdataset = next_rdataset; 2005135446Strhodes } 2006135446Strhodes 2007135446Strhodes name = next_name; 2008135446Strhodes } 2009135446Strhodes } while (--pass != 0); 2010135446Strhodes 2011135446Strhodes msg->buffer->length += msg->reserved; 2012135446Strhodes msg->counts[sectionid] += total; 2013135446Strhodes 2014135446Strhodes return (ISC_R_SUCCESS); 2015135446Strhodes} 2016135446Strhodes 2017135446Strhodesvoid 2018135446Strhodesdns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) { 2019135446Strhodes isc_uint16_t tmp; 2020135446Strhodes isc_region_t r; 2021135446Strhodes 2022135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2023135446Strhodes REQUIRE(target != NULL); 2024135446Strhodes 2025135446Strhodes isc_buffer_availableregion(target, &r); 2026135446Strhodes REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN); 2027135446Strhodes 2028135446Strhodes isc_buffer_putuint16(target, msg->id); 2029135446Strhodes 2030135446Strhodes tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT) 2031135446Strhodes & DNS_MESSAGE_OPCODE_MASK); 2032135446Strhodes tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK); 2033135446Strhodes tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK); 2034135446Strhodes 2035135446Strhodes INSIST(msg->counts[DNS_SECTION_QUESTION] < 65536 && 2036135446Strhodes msg->counts[DNS_SECTION_ANSWER] < 65536 && 2037135446Strhodes msg->counts[DNS_SECTION_AUTHORITY] < 65536 && 2038135446Strhodes msg->counts[DNS_SECTION_ADDITIONAL] < 65536); 2039135446Strhodes 2040135446Strhodes isc_buffer_putuint16(target, tmp); 2041135446Strhodes isc_buffer_putuint16(target, 2042135446Strhodes (isc_uint16_t)msg->counts[DNS_SECTION_QUESTION]); 2043135446Strhodes isc_buffer_putuint16(target, 2044135446Strhodes (isc_uint16_t)msg->counts[DNS_SECTION_ANSWER]); 2045135446Strhodes isc_buffer_putuint16(target, 2046135446Strhodes (isc_uint16_t)msg->counts[DNS_SECTION_AUTHORITY]); 2047135446Strhodes isc_buffer_putuint16(target, 2048135446Strhodes (isc_uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]); 2049135446Strhodes} 2050135446Strhodes 2051135446Strhodesisc_result_t 2052135446Strhodesdns_message_renderend(dns_message_t *msg) { 2053135446Strhodes isc_buffer_t tmpbuf; 2054135446Strhodes isc_region_t r; 2055135446Strhodes int result; 2056135446Strhodes unsigned int count; 2057135446Strhodes 2058135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2059135446Strhodes REQUIRE(msg->buffer != NULL); 2060135446Strhodes 2061135446Strhodes if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) { 2062135446Strhodes /* 2063135446Strhodes * We have an extended rcode but are not using EDNS. 2064135446Strhodes */ 2065135446Strhodes return (DNS_R_FORMERR); 2066135446Strhodes } 2067135446Strhodes 2068135446Strhodes /* 2069135446Strhodes * If we've got an OPT record, render it. 2070135446Strhodes */ 2071135446Strhodes if (msg->opt != NULL) { 2072135446Strhodes dns_message_renderrelease(msg, msg->opt_reserved); 2073135446Strhodes msg->opt_reserved = 0; 2074135446Strhodes /* 2075135446Strhodes * Set the extended rcode. 2076135446Strhodes */ 2077135446Strhodes msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK; 2078135446Strhodes msg->opt->ttl |= ((msg->rcode << 20) & 2079135446Strhodes DNS_MESSAGE_EDNSRCODE_MASK); 2080135446Strhodes /* 2081135446Strhodes * Render. 2082135446Strhodes */ 2083135446Strhodes count = 0; 2084135446Strhodes result = dns_rdataset_towire(msg->opt, dns_rootname, 2085135446Strhodes msg->cctx, msg->buffer, 0, 2086135446Strhodes &count); 2087135446Strhodes msg->counts[DNS_SECTION_ADDITIONAL] += count; 2088135446Strhodes if (result != ISC_R_SUCCESS) 2089135446Strhodes return (result); 2090135446Strhodes } 2091135446Strhodes 2092135446Strhodes /* 2093135446Strhodes * If we're adding a TSIG or SIG(0) to a truncated message, 2094135446Strhodes * clear all rdatasets from the message except for the question 2095135446Strhodes * before adding the TSIG or SIG(0). If the question doesn't fit, 2096135446Strhodes * don't include it. 2097135446Strhodes */ 2098135446Strhodes if ((msg->tsigkey != NULL || msg->sig0key != NULL) && 2099135446Strhodes (msg->flags & DNS_MESSAGEFLAG_TC) != 0) 2100135446Strhodes { 2101135446Strhodes isc_buffer_t *buf; 2102135446Strhodes 2103135446Strhodes msgresetnames(msg, DNS_SECTION_ANSWER); 2104135446Strhodes buf = msg->buffer; 2105135446Strhodes dns_message_renderreset(msg); 2106135446Strhodes msg->buffer = buf; 2107135446Strhodes isc_buffer_clear(msg->buffer); 2108135446Strhodes isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN); 2109135446Strhodes dns_compress_rollback(msg->cctx, 0); 2110135446Strhodes result = dns_message_rendersection(msg, DNS_SECTION_QUESTION, 2111135446Strhodes 0); 2112135446Strhodes if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE) 2113135446Strhodes return (result); 2114135446Strhodes } 2115135446Strhodes 2116135446Strhodes /* 2117135446Strhodes * If we're adding a TSIG record, generate and render it. 2118135446Strhodes */ 2119135446Strhodes if (msg->tsigkey != NULL) { 2120135446Strhodes dns_message_renderrelease(msg, msg->sig_reserved); 2121135446Strhodes msg->sig_reserved = 0; 2122135446Strhodes result = dns_tsig_sign(msg); 2123135446Strhodes if (result != ISC_R_SUCCESS) 2124135446Strhodes return (result); 2125135446Strhodes count = 0; 2126135446Strhodes result = dns_rdataset_towire(msg->tsig, msg->tsigname, 2127135446Strhodes msg->cctx, msg->buffer, 0, 2128135446Strhodes &count); 2129135446Strhodes msg->counts[DNS_SECTION_ADDITIONAL] += count; 2130135446Strhodes if (result != ISC_R_SUCCESS) 2131135446Strhodes return (result); 2132135446Strhodes } 2133135446Strhodes 2134135446Strhodes /* 2135135446Strhodes * If we're adding a SIG(0) record, generate and render it. 2136135446Strhodes */ 2137135446Strhodes if (msg->sig0key != NULL) { 2138135446Strhodes dns_message_renderrelease(msg, msg->sig_reserved); 2139135446Strhodes msg->sig_reserved = 0; 2140135446Strhodes result = dns_dnssec_signmessage(msg, msg->sig0key); 2141135446Strhodes if (result != ISC_R_SUCCESS) 2142135446Strhodes return (result); 2143135446Strhodes count = 0; 2144135446Strhodes /* 2145135446Strhodes * Note: dns_rootname is used here, not msg->sig0name, since 2146135446Strhodes * the owner name of a SIG(0) is irrelevant, and will not 2147135446Strhodes * be set in a message being rendered. 2148135446Strhodes */ 2149135446Strhodes result = dns_rdataset_towire(msg->sig0, dns_rootname, 2150135446Strhodes msg->cctx, msg->buffer, 0, 2151135446Strhodes &count); 2152135446Strhodes msg->counts[DNS_SECTION_ADDITIONAL] += count; 2153135446Strhodes if (result != ISC_R_SUCCESS) 2154135446Strhodes return (result); 2155135446Strhodes } 2156135446Strhodes 2157135446Strhodes isc_buffer_usedregion(msg->buffer, &r); 2158135446Strhodes isc_buffer_init(&tmpbuf, r.base, r.length); 2159135446Strhodes 2160135446Strhodes dns_message_renderheader(msg, &tmpbuf); 2161135446Strhodes 2162135446Strhodes msg->buffer = NULL; /* forget about this buffer only on success XXX */ 2163135446Strhodes 2164135446Strhodes return (ISC_R_SUCCESS); 2165135446Strhodes} 2166135446Strhodes 2167135446Strhodesvoid 2168135446Strhodesdns_message_renderreset(dns_message_t *msg) { 2169135446Strhodes unsigned int i; 2170135446Strhodes dns_name_t *name; 2171135446Strhodes dns_rdataset_t *rds; 2172135446Strhodes 2173135446Strhodes /* 2174135446Strhodes * Reset the message so that it may be rendered again. 2175135446Strhodes */ 2176135446Strhodes 2177135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2178135446Strhodes REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 2179135446Strhodes 2180135446Strhodes msg->buffer = NULL; 2181135446Strhodes 2182135446Strhodes for (i = 0; i < DNS_SECTION_MAX; i++) { 2183135446Strhodes msg->cursors[i] = NULL; 2184135446Strhodes msg->counts[i] = 0; 2185135446Strhodes for (name = ISC_LIST_HEAD(msg->sections[i]); 2186135446Strhodes name != NULL; 2187135446Strhodes name = ISC_LIST_NEXT(name, link)) { 2188135446Strhodes for (rds = ISC_LIST_HEAD(name->list); 2189135446Strhodes rds != NULL; 2190135446Strhodes rds = ISC_LIST_NEXT(rds, link)) { 2191135446Strhodes rds->attributes &= ~DNS_RDATASETATTR_RENDERED; 2192135446Strhodes } 2193135446Strhodes } 2194135446Strhodes } 2195135446Strhodes if (msg->tsigname != NULL) 2196135446Strhodes dns_message_puttempname(msg, &msg->tsigname); 2197135446Strhodes if (msg->tsig != NULL) { 2198135446Strhodes dns_rdataset_disassociate(msg->tsig); 2199135446Strhodes dns_message_puttemprdataset(msg, &msg->tsig); 2200135446Strhodes } 2201135446Strhodes if (msg->sig0 != NULL) { 2202135446Strhodes dns_rdataset_disassociate(msg->sig0); 2203135446Strhodes dns_message_puttemprdataset(msg, &msg->sig0); 2204135446Strhodes } 2205135446Strhodes} 2206135446Strhodes 2207135446Strhodesisc_result_t 2208135446Strhodesdns_message_firstname(dns_message_t *msg, dns_section_t section) { 2209135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2210135446Strhodes REQUIRE(VALID_NAMED_SECTION(section)); 2211135446Strhodes 2212135446Strhodes msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]); 2213135446Strhodes 2214135446Strhodes if (msg->cursors[section] == NULL) 2215135446Strhodes return (ISC_R_NOMORE); 2216135446Strhodes 2217135446Strhodes return (ISC_R_SUCCESS); 2218135446Strhodes} 2219135446Strhodes 2220135446Strhodesisc_result_t 2221135446Strhodesdns_message_nextname(dns_message_t *msg, dns_section_t section) { 2222135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2223135446Strhodes REQUIRE(VALID_NAMED_SECTION(section)); 2224135446Strhodes REQUIRE(msg->cursors[section] != NULL); 2225135446Strhodes 2226135446Strhodes msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link); 2227135446Strhodes 2228135446Strhodes if (msg->cursors[section] == NULL) 2229135446Strhodes return (ISC_R_NOMORE); 2230135446Strhodes 2231135446Strhodes return (ISC_R_SUCCESS); 2232135446Strhodes} 2233135446Strhodes 2234135446Strhodesvoid 2235135446Strhodesdns_message_currentname(dns_message_t *msg, dns_section_t section, 2236135446Strhodes dns_name_t **name) 2237135446Strhodes{ 2238135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2239135446Strhodes REQUIRE(VALID_NAMED_SECTION(section)); 2240135446Strhodes REQUIRE(name != NULL && *name == NULL); 2241135446Strhodes REQUIRE(msg->cursors[section] != NULL); 2242135446Strhodes 2243135446Strhodes *name = msg->cursors[section]; 2244135446Strhodes} 2245135446Strhodes 2246135446Strhodesisc_result_t 2247135446Strhodesdns_message_findname(dns_message_t *msg, dns_section_t section, 2248135446Strhodes dns_name_t *target, dns_rdatatype_t type, 2249135446Strhodes dns_rdatatype_t covers, dns_name_t **name, 2250135446Strhodes dns_rdataset_t **rdataset) 2251135446Strhodes{ 2252135446Strhodes dns_name_t *foundname; 2253135446Strhodes isc_result_t result; 2254135446Strhodes 2255135446Strhodes /* 2256135446Strhodes * XXX These requirements are probably too intensive, especially 2257135446Strhodes * where things can be NULL, but as they are they ensure that if 2258135446Strhodes * something is NON-NULL, indicating that the caller expects it 2259135446Strhodes * to be filled in, that we can in fact fill it in. 2260135446Strhodes */ 2261135446Strhodes REQUIRE(msg != NULL); 2262135446Strhodes REQUIRE(VALID_SECTION(section)); 2263135446Strhodes REQUIRE(target != NULL); 2264135446Strhodes if (name != NULL) 2265135446Strhodes REQUIRE(*name == NULL); 2266135446Strhodes if (type == dns_rdatatype_any) { 2267135446Strhodes REQUIRE(rdataset == NULL); 2268135446Strhodes } else { 2269135446Strhodes if (rdataset != NULL) 2270135446Strhodes REQUIRE(*rdataset == NULL); 2271135446Strhodes } 2272135446Strhodes 2273135446Strhodes result = findname(&foundname, target, 2274135446Strhodes &msg->sections[section]); 2275135446Strhodes 2276135446Strhodes if (result == ISC_R_NOTFOUND) 2277135446Strhodes return (DNS_R_NXDOMAIN); 2278135446Strhodes else if (result != ISC_R_SUCCESS) 2279135446Strhodes return (result); 2280135446Strhodes 2281135446Strhodes if (name != NULL) 2282135446Strhodes *name = foundname; 2283135446Strhodes 2284135446Strhodes /* 2285135446Strhodes * And now look for the type. 2286135446Strhodes */ 2287135446Strhodes if (type == dns_rdatatype_any) 2288135446Strhodes return (ISC_R_SUCCESS); 2289135446Strhodes 2290135446Strhodes result = dns_message_findtype(foundname, type, covers, rdataset); 2291135446Strhodes if (result == ISC_R_NOTFOUND) 2292135446Strhodes return (DNS_R_NXRRSET); 2293135446Strhodes 2294135446Strhodes return (result); 2295135446Strhodes} 2296135446Strhodes 2297135446Strhodesvoid 2298135446Strhodesdns_message_movename(dns_message_t *msg, dns_name_t *name, 2299135446Strhodes dns_section_t fromsection, 2300135446Strhodes dns_section_t tosection) 2301135446Strhodes{ 2302135446Strhodes REQUIRE(msg != NULL); 2303135446Strhodes REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 2304135446Strhodes REQUIRE(name != NULL); 2305135446Strhodes REQUIRE(VALID_NAMED_SECTION(fromsection)); 2306135446Strhodes REQUIRE(VALID_NAMED_SECTION(tosection)); 2307135446Strhodes 2308135446Strhodes /* 2309135446Strhodes * Unlink the name from the old section 2310135446Strhodes */ 2311135446Strhodes ISC_LIST_UNLINK(msg->sections[fromsection], name, link); 2312135446Strhodes ISC_LIST_APPEND(msg->sections[tosection], name, link); 2313135446Strhodes} 2314135446Strhodes 2315135446Strhodesvoid 2316135446Strhodesdns_message_addname(dns_message_t *msg, dns_name_t *name, 2317135446Strhodes dns_section_t section) 2318135446Strhodes{ 2319135446Strhodes REQUIRE(msg != NULL); 2320135446Strhodes REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 2321135446Strhodes REQUIRE(name != NULL); 2322135446Strhodes REQUIRE(VALID_NAMED_SECTION(section)); 2323135446Strhodes 2324135446Strhodes ISC_LIST_APPEND(msg->sections[section], name, link); 2325135446Strhodes} 2326135446Strhodes 2327170222Sdougbvoid 2328170222Sdougbdns_message_removename(dns_message_t *msg, dns_name_t *name, 2329170222Sdougb dns_section_t section) 2330170222Sdougb{ 2331170222Sdougb REQUIRE(msg != NULL); 2332170222Sdougb REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 2333170222Sdougb REQUIRE(name != NULL); 2334170222Sdougb REQUIRE(VALID_NAMED_SECTION(section)); 2335170222Sdougb 2336170222Sdougb ISC_LIST_UNLINK(msg->sections[section], name, link); 2337170222Sdougb} 2338170222Sdougb 2339135446Strhodesisc_result_t 2340135446Strhodesdns_message_gettempname(dns_message_t *msg, dns_name_t **item) { 2341135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2342135446Strhodes REQUIRE(item != NULL && *item == NULL); 2343135446Strhodes 2344135446Strhodes *item = isc_mempool_get(msg->namepool); 2345135446Strhodes if (*item == NULL) 2346135446Strhodes return (ISC_R_NOMEMORY); 2347135446Strhodes dns_name_init(*item, NULL); 2348135446Strhodes 2349135446Strhodes return (ISC_R_SUCCESS); 2350135446Strhodes} 2351135446Strhodes 2352135446Strhodesisc_result_t 2353135446Strhodesdns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) { 2354135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2355135446Strhodes REQUIRE(item != NULL && *item == NULL); 2356135446Strhodes 2357135446Strhodes *item = newoffsets(msg); 2358135446Strhodes if (*item == NULL) 2359135446Strhodes return (ISC_R_NOMEMORY); 2360135446Strhodes 2361135446Strhodes return (ISC_R_SUCCESS); 2362135446Strhodes} 2363135446Strhodes 2364135446Strhodesisc_result_t 2365135446Strhodesdns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) { 2366135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2367135446Strhodes REQUIRE(item != NULL && *item == NULL); 2368135446Strhodes 2369135446Strhodes *item = newrdata(msg); 2370135446Strhodes if (*item == NULL) 2371135446Strhodes return (ISC_R_NOMEMORY); 2372135446Strhodes 2373135446Strhodes return (ISC_R_SUCCESS); 2374135446Strhodes} 2375135446Strhodes 2376135446Strhodesisc_result_t 2377135446Strhodesdns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) { 2378135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2379135446Strhodes REQUIRE(item != NULL && *item == NULL); 2380135446Strhodes 2381135446Strhodes *item = isc_mempool_get(msg->rdspool); 2382135446Strhodes if (*item == NULL) 2383135446Strhodes return (ISC_R_NOMEMORY); 2384135446Strhodes 2385135446Strhodes dns_rdataset_init(*item); 2386135446Strhodes 2387135446Strhodes return (ISC_R_SUCCESS); 2388135446Strhodes} 2389135446Strhodes 2390135446Strhodesisc_result_t 2391135446Strhodesdns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) { 2392135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2393135446Strhodes REQUIRE(item != NULL && *item == NULL); 2394135446Strhodes 2395135446Strhodes *item = newrdatalist(msg); 2396135446Strhodes if (*item == NULL) 2397135446Strhodes return (ISC_R_NOMEMORY); 2398135446Strhodes 2399135446Strhodes return (ISC_R_SUCCESS); 2400135446Strhodes} 2401135446Strhodes 2402135446Strhodesvoid 2403135446Strhodesdns_message_puttempname(dns_message_t *msg, dns_name_t **item) { 2404135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2405135446Strhodes REQUIRE(item != NULL && *item != NULL); 2406135446Strhodes 2407135446Strhodes if (dns_name_dynamic(*item)) 2408135446Strhodes dns_name_free(*item, msg->mctx); 2409135446Strhodes isc_mempool_put(msg->namepool, *item); 2410135446Strhodes *item = NULL; 2411135446Strhodes} 2412135446Strhodes 2413135446Strhodesvoid 2414135446Strhodesdns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) { 2415135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2416135446Strhodes REQUIRE(item != NULL && *item != NULL); 2417135446Strhodes 2418135446Strhodes releaserdata(msg, *item); 2419135446Strhodes *item = NULL; 2420135446Strhodes} 2421135446Strhodes 2422135446Strhodesvoid 2423135446Strhodesdns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) { 2424135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2425135446Strhodes REQUIRE(item != NULL && *item != NULL); 2426135446Strhodes 2427135446Strhodes REQUIRE(!dns_rdataset_isassociated(*item)); 2428135446Strhodes isc_mempool_put(msg->rdspool, *item); 2429135446Strhodes *item = NULL; 2430135446Strhodes} 2431135446Strhodes 2432135446Strhodesvoid 2433135446Strhodesdns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) { 2434135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2435135446Strhodes REQUIRE(item != NULL && *item != NULL); 2436135446Strhodes 2437135446Strhodes releaserdatalist(msg, *item); 2438135446Strhodes *item = NULL; 2439135446Strhodes} 2440135446Strhodes 2441135446Strhodesisc_result_t 2442135446Strhodesdns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp, 2443135446Strhodes unsigned int *flagsp) 2444135446Strhodes{ 2445135446Strhodes isc_region_t r; 2446135446Strhodes isc_buffer_t buffer; 2447135446Strhodes dns_messageid_t id; 2448135446Strhodes unsigned int flags; 2449135446Strhodes 2450135446Strhodes REQUIRE(source != NULL); 2451135446Strhodes 2452135446Strhodes buffer = *source; 2453135446Strhodes 2454135446Strhodes isc_buffer_remainingregion(&buffer, &r); 2455135446Strhodes if (r.length < DNS_MESSAGE_HEADERLEN) 2456135446Strhodes return (ISC_R_UNEXPECTEDEND); 2457135446Strhodes 2458135446Strhodes id = isc_buffer_getuint16(&buffer); 2459135446Strhodes flags = isc_buffer_getuint16(&buffer); 2460135446Strhodes flags &= DNS_MESSAGE_FLAG_MASK; 2461135446Strhodes 2462135446Strhodes if (flagsp != NULL) 2463135446Strhodes *flagsp = flags; 2464135446Strhodes if (idp != NULL) 2465135446Strhodes *idp = id; 2466135446Strhodes 2467135446Strhodes return (ISC_R_SUCCESS); 2468135446Strhodes} 2469135446Strhodes 2470135446Strhodesisc_result_t 2471135446Strhodesdns_message_reply(dns_message_t *msg, isc_boolean_t want_question_section) { 2472135446Strhodes unsigned int first_section; 2473135446Strhodes isc_result_t result; 2474135446Strhodes 2475135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2476135446Strhodes REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0); 2477135446Strhodes 2478135446Strhodes if (!msg->header_ok) 2479135446Strhodes return (DNS_R_FORMERR); 2480135446Strhodes if (msg->opcode != dns_opcode_query && 2481135446Strhodes msg->opcode != dns_opcode_notify) 2482135446Strhodes want_question_section = ISC_FALSE; 2483218384Sdougb if (msg->opcode == dns_opcode_update) 2484218384Sdougb first_section = DNS_SECTION_ADDITIONAL; 2485218384Sdougb else if (want_question_section) { 2486135446Strhodes if (!msg->question_ok) 2487135446Strhodes return (DNS_R_FORMERR); 2488135446Strhodes first_section = DNS_SECTION_ANSWER; 2489135446Strhodes } else 2490135446Strhodes first_section = DNS_SECTION_QUESTION; 2491135446Strhodes msg->from_to_wire = DNS_MESSAGE_INTENTRENDER; 2492135446Strhodes msgresetnames(msg, first_section); 2493135446Strhodes msgresetopt(msg); 2494135446Strhodes msgresetsigs(msg, ISC_TRUE); 2495135446Strhodes msginitprivate(msg); 2496135446Strhodes /* 2497135446Strhodes * We now clear most flags and then set QR, ensuring that the 2498135446Strhodes * reply's flags will be in a reasonable state. 2499135446Strhodes */ 2500135446Strhodes msg->flags &= DNS_MESSAGE_REPLYPRESERVE; 2501135446Strhodes msg->flags |= DNS_MESSAGEFLAG_QR; 2502135446Strhodes 2503135446Strhodes /* 2504135446Strhodes * This saves the query TSIG status, if the query was signed, and 2505135446Strhodes * reserves space in the reply for the TSIG. 2506135446Strhodes */ 2507135446Strhodes if (msg->tsigkey != NULL) { 2508135446Strhodes unsigned int otherlen = 0; 2509135446Strhodes msg->querytsigstatus = msg->tsigstatus; 2510135446Strhodes msg->tsigstatus = dns_rcode_noerror; 2511135446Strhodes if (msg->querytsigstatus == dns_tsigerror_badtime) 2512135446Strhodes otherlen = 6; 2513135446Strhodes msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen); 2514135446Strhodes result = dns_message_renderreserve(msg, msg->sig_reserved); 2515135446Strhodes if (result != ISC_R_SUCCESS) { 2516135446Strhodes msg->sig_reserved = 0; 2517135446Strhodes return (result); 2518135446Strhodes } 2519135446Strhodes } 2520135446Strhodes if (msg->saved.base != NULL) { 2521135446Strhodes msg->query.base = msg->saved.base; 2522135446Strhodes msg->query.length = msg->saved.length; 2523135446Strhodes msg->free_query = msg->free_saved; 2524135446Strhodes msg->saved.base = NULL; 2525135446Strhodes msg->saved.length = 0; 2526135446Strhodes msg->free_saved = 0; 2527135446Strhodes } 2528135446Strhodes 2529135446Strhodes return (ISC_R_SUCCESS); 2530135446Strhodes} 2531135446Strhodes 2532135446Strhodesdns_rdataset_t * 2533135446Strhodesdns_message_getopt(dns_message_t *msg) { 2534135446Strhodes 2535135446Strhodes /* 2536135446Strhodes * Get the OPT record for 'msg'. 2537135446Strhodes */ 2538135446Strhodes 2539135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2540135446Strhodes 2541135446Strhodes return (msg->opt); 2542135446Strhodes} 2543135446Strhodes 2544135446Strhodesisc_result_t 2545135446Strhodesdns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) { 2546135446Strhodes isc_result_t result; 2547135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 2548135446Strhodes 2549135446Strhodes /* 2550135446Strhodes * Set the OPT record for 'msg'. 2551135446Strhodes */ 2552135446Strhodes 2553135446Strhodes /* 2554135446Strhodes * The space required for an OPT record is: 2555135446Strhodes * 2556135446Strhodes * 1 byte for the name 2557135446Strhodes * 2 bytes for the type 2558135446Strhodes * 2 bytes for the class 2559135446Strhodes * 4 bytes for the ttl 2560135446Strhodes * 2 bytes for the rdata length 2561135446Strhodes * --------------------------------- 2562135446Strhodes * 11 bytes 2563135446Strhodes * 2564135446Strhodes * plus the length of the rdata. 2565135446Strhodes */ 2566135446Strhodes 2567135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2568135446Strhodes REQUIRE(opt->type == dns_rdatatype_opt); 2569135446Strhodes REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 2570135446Strhodes REQUIRE(msg->state == DNS_SECTION_ANY); 2571135446Strhodes 2572135446Strhodes msgresetopt(msg); 2573135446Strhodes 2574135446Strhodes result = dns_rdataset_first(opt); 2575135446Strhodes if (result != ISC_R_SUCCESS) 2576135446Strhodes goto cleanup; 2577135446Strhodes dns_rdataset_current(opt, &rdata); 2578135446Strhodes msg->opt_reserved = 11 + rdata.length; 2579135446Strhodes result = dns_message_renderreserve(msg, msg->opt_reserved); 2580135446Strhodes if (result != ISC_R_SUCCESS) { 2581135446Strhodes msg->opt_reserved = 0; 2582135446Strhodes goto cleanup; 2583135446Strhodes } 2584135446Strhodes 2585135446Strhodes msg->opt = opt; 2586135446Strhodes 2587135446Strhodes return (ISC_R_SUCCESS); 2588135446Strhodes 2589135446Strhodes cleanup: 2590135446Strhodes dns_message_puttemprdataset(msg, &opt); 2591135446Strhodes return (result); 2592135446Strhodes 2593135446Strhodes} 2594135446Strhodes 2595135446Strhodesdns_rdataset_t * 2596135446Strhodesdns_message_gettsig(dns_message_t *msg, dns_name_t **owner) { 2597135446Strhodes 2598135446Strhodes /* 2599135446Strhodes * Get the TSIG record and owner for 'msg'. 2600135446Strhodes */ 2601135446Strhodes 2602135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2603135446Strhodes REQUIRE(owner == NULL || *owner == NULL); 2604135446Strhodes 2605135446Strhodes if (owner != NULL) 2606135446Strhodes *owner = msg->tsigname; 2607135446Strhodes return (msg->tsig); 2608135446Strhodes} 2609135446Strhodes 2610135446Strhodesisc_result_t 2611135446Strhodesdns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) { 2612135446Strhodes isc_result_t result; 2613135446Strhodes 2614135446Strhodes /* 2615135446Strhodes * Set the TSIG key for 'msg' 2616135446Strhodes */ 2617135446Strhodes 2618135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2619135446Strhodes REQUIRE(msg->state == DNS_SECTION_ANY); 2620135446Strhodes 2621135446Strhodes if (key == NULL && msg->tsigkey != NULL) { 2622135446Strhodes if (msg->sig_reserved != 0) { 2623135446Strhodes dns_message_renderrelease(msg, msg->sig_reserved); 2624135446Strhodes msg->sig_reserved = 0; 2625135446Strhodes } 2626135446Strhodes dns_tsigkey_detach(&msg->tsigkey); 2627135446Strhodes } 2628135446Strhodes if (key != NULL) { 2629135446Strhodes REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL); 2630135446Strhodes dns_tsigkey_attach(key, &msg->tsigkey); 2631135446Strhodes if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) { 2632135446Strhodes msg->sig_reserved = spacefortsig(msg->tsigkey, 0); 2633135446Strhodes result = dns_message_renderreserve(msg, 2634135446Strhodes msg->sig_reserved); 2635135446Strhodes if (result != ISC_R_SUCCESS) { 2636135446Strhodes dns_tsigkey_detach(&msg->tsigkey); 2637135446Strhodes msg->sig_reserved = 0; 2638135446Strhodes return (result); 2639135446Strhodes } 2640135446Strhodes } 2641135446Strhodes } 2642135446Strhodes return (ISC_R_SUCCESS); 2643135446Strhodes} 2644135446Strhodes 2645135446Strhodesdns_tsigkey_t * 2646135446Strhodesdns_message_gettsigkey(dns_message_t *msg) { 2647135446Strhodes 2648135446Strhodes /* 2649135446Strhodes * Get the TSIG key for 'msg' 2650135446Strhodes */ 2651135446Strhodes 2652135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2653135446Strhodes 2654135446Strhodes return (msg->tsigkey); 2655135446Strhodes} 2656135446Strhodes 2657135446Strhodesisc_result_t 2658135446Strhodesdns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) { 2659135446Strhodes dns_rdata_t *rdata = NULL; 2660135446Strhodes dns_rdatalist_t *list = NULL; 2661135446Strhodes dns_rdataset_t *set = NULL; 2662135446Strhodes isc_buffer_t *buf = NULL; 2663135446Strhodes isc_region_t r; 2664135446Strhodes isc_result_t result; 2665135446Strhodes 2666135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2667135446Strhodes REQUIRE(msg->querytsig == NULL); 2668135446Strhodes 2669135446Strhodes if (querytsig == NULL) 2670135446Strhodes return (ISC_R_SUCCESS); 2671135446Strhodes 2672135446Strhodes result = dns_message_gettemprdata(msg, &rdata); 2673135446Strhodes if (result != ISC_R_SUCCESS) 2674135446Strhodes goto cleanup; 2675135446Strhodes 2676135446Strhodes result = dns_message_gettemprdatalist(msg, &list); 2677135446Strhodes if (result != ISC_R_SUCCESS) 2678135446Strhodes goto cleanup; 2679135446Strhodes result = dns_message_gettemprdataset(msg, &set); 2680135446Strhodes if (result != ISC_R_SUCCESS) 2681135446Strhodes goto cleanup; 2682135446Strhodes 2683135446Strhodes isc_buffer_usedregion(querytsig, &r); 2684135446Strhodes result = isc_buffer_allocate(msg->mctx, &buf, r.length); 2685135446Strhodes if (result != ISC_R_SUCCESS) 2686135446Strhodes goto cleanup; 2687135446Strhodes isc_buffer_putmem(buf, r.base, r.length); 2688135446Strhodes isc_buffer_usedregion(buf, &r); 2689135446Strhodes dns_rdata_init(rdata); 2690135446Strhodes dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r); 2691135446Strhodes dns_message_takebuffer(msg, &buf); 2692135446Strhodes ISC_LIST_INIT(list->rdata); 2693135446Strhodes ISC_LIST_APPEND(list->rdata, rdata, link); 2694135446Strhodes result = dns_rdatalist_tordataset(list, set); 2695135446Strhodes if (result != ISC_R_SUCCESS) 2696135446Strhodes goto cleanup; 2697135446Strhodes 2698135446Strhodes msg->querytsig = set; 2699135446Strhodes 2700135446Strhodes return (result); 2701135446Strhodes 2702135446Strhodes cleanup: 2703135446Strhodes if (rdata != NULL) 2704135446Strhodes dns_message_puttemprdata(msg, &rdata); 2705135446Strhodes if (list != NULL) 2706135446Strhodes dns_message_puttemprdatalist(msg, &list); 2707135446Strhodes if (set != NULL) 2708135446Strhodes dns_message_puttemprdataset(msg, &set); 2709135446Strhodes return (ISC_R_NOMEMORY); 2710135446Strhodes} 2711135446Strhodes 2712135446Strhodesisc_result_t 2713135446Strhodesdns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx, 2714135446Strhodes isc_buffer_t **querytsig) { 2715135446Strhodes isc_result_t result; 2716135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 2717135446Strhodes isc_region_t r; 2718135446Strhodes 2719135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2720135446Strhodes REQUIRE(mctx != NULL); 2721135446Strhodes REQUIRE(querytsig != NULL && *querytsig == NULL); 2722135446Strhodes 2723135446Strhodes if (msg->tsig == NULL) 2724135446Strhodes return (ISC_R_SUCCESS); 2725135446Strhodes 2726135446Strhodes result = dns_rdataset_first(msg->tsig); 2727135446Strhodes if (result != ISC_R_SUCCESS) 2728135446Strhodes return (result); 2729135446Strhodes dns_rdataset_current(msg->tsig, &rdata); 2730135446Strhodes dns_rdata_toregion(&rdata, &r); 2731135446Strhodes 2732135446Strhodes result = isc_buffer_allocate(mctx, querytsig, r.length); 2733135446Strhodes if (result != ISC_R_SUCCESS) 2734135446Strhodes return (result); 2735135446Strhodes isc_buffer_putmem(*querytsig, r.base, r.length); 2736135446Strhodes return (ISC_R_SUCCESS); 2737135446Strhodes} 2738135446Strhodes 2739135446Strhodesdns_rdataset_t * 2740135446Strhodesdns_message_getsig0(dns_message_t *msg, dns_name_t **owner) { 2741135446Strhodes 2742135446Strhodes /* 2743135446Strhodes * Get the SIG(0) record for 'msg'. 2744135446Strhodes */ 2745135446Strhodes 2746135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2747135446Strhodes REQUIRE(owner == NULL || *owner == NULL); 2748135446Strhodes 2749135446Strhodes if (msg->sig0 != NULL && owner != NULL) { 2750135446Strhodes /* If dns_message_getsig0 is called on a rendered message 2751135446Strhodes * after the SIG(0) has been applied, we need to return the 2752135446Strhodes * root name, not NULL. 2753135446Strhodes */ 2754135446Strhodes if (msg->sig0name == NULL) 2755135446Strhodes *owner = dns_rootname; 2756135446Strhodes else 2757135446Strhodes *owner = msg->sig0name; 2758135446Strhodes } 2759135446Strhodes return (msg->sig0); 2760135446Strhodes} 2761135446Strhodes 2762135446Strhodesisc_result_t 2763135446Strhodesdns_message_setsig0key(dns_message_t *msg, dst_key_t *key) { 2764135446Strhodes isc_region_t r; 2765135446Strhodes unsigned int x; 2766135446Strhodes isc_result_t result; 2767135446Strhodes 2768135446Strhodes /* 2769135446Strhodes * Set the SIG(0) key for 'msg' 2770135446Strhodes */ 2771135446Strhodes 2772135446Strhodes /* 2773135446Strhodes * The space required for an SIG(0) record is: 2774135446Strhodes * 2775135446Strhodes * 1 byte for the name 2776135446Strhodes * 2 bytes for the type 2777135446Strhodes * 2 bytes for the class 2778135446Strhodes * 4 bytes for the ttl 2779135446Strhodes * 2 bytes for the type covered 2780135446Strhodes * 1 byte for the algorithm 2781135446Strhodes * 1 bytes for the labels 2782135446Strhodes * 4 bytes for the original ttl 2783135446Strhodes * 4 bytes for the signature expiration 2784135446Strhodes * 4 bytes for the signature inception 2785135446Strhodes * 2 bytes for the key tag 2786135446Strhodes * n bytes for the signer's name 2787135446Strhodes * x bytes for the signature 2788135446Strhodes * --------------------------------- 2789135446Strhodes * 27 + n + x bytes 2790135446Strhodes */ 2791135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2792135446Strhodes REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 2793135446Strhodes REQUIRE(msg->state == DNS_SECTION_ANY); 2794135446Strhodes 2795135446Strhodes if (key != NULL) { 2796135446Strhodes REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL); 2797135446Strhodes dns_name_toregion(dst_key_name(key), &r); 2798135446Strhodes result = dst_key_sigsize(key, &x); 2799135446Strhodes if (result != ISC_R_SUCCESS) { 2800135446Strhodes msg->sig_reserved = 0; 2801135446Strhodes return (result); 2802135446Strhodes } 2803135446Strhodes msg->sig_reserved = 27 + r.length + x; 2804135446Strhodes result = dns_message_renderreserve(msg, msg->sig_reserved); 2805135446Strhodes if (result != ISC_R_SUCCESS) { 2806135446Strhodes msg->sig_reserved = 0; 2807135446Strhodes return (result); 2808135446Strhodes } 2809135446Strhodes msg->sig0key = key; 2810135446Strhodes } 2811135446Strhodes return (ISC_R_SUCCESS); 2812135446Strhodes} 2813135446Strhodes 2814135446Strhodesdst_key_t * 2815135446Strhodesdns_message_getsig0key(dns_message_t *msg) { 2816135446Strhodes 2817135446Strhodes /* 2818135446Strhodes * Get the SIG(0) key for 'msg' 2819135446Strhodes */ 2820135446Strhodes 2821135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2822135446Strhodes 2823135446Strhodes return (msg->sig0key); 2824135446Strhodes} 2825135446Strhodes 2826135446Strhodesvoid 2827135446Strhodesdns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) { 2828135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2829135446Strhodes REQUIRE(buffer != NULL); 2830135446Strhodes REQUIRE(ISC_BUFFER_VALID(*buffer)); 2831135446Strhodes 2832135446Strhodes ISC_LIST_APPEND(msg->cleanup, *buffer, link); 2833135446Strhodes *buffer = NULL; 2834135446Strhodes} 2835135446Strhodes 2836135446Strhodesisc_result_t 2837135446Strhodesdns_message_signer(dns_message_t *msg, dns_name_t *signer) { 2838135446Strhodes isc_result_t result = ISC_R_SUCCESS; 2839135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 2840135446Strhodes 2841135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2842135446Strhodes REQUIRE(signer != NULL); 2843135446Strhodes REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE); 2844135446Strhodes 2845135446Strhodes if (msg->tsig == NULL && msg->sig0 == NULL) 2846135446Strhodes return (ISC_R_NOTFOUND); 2847135446Strhodes 2848135446Strhodes if (msg->verify_attempted == 0) 2849135446Strhodes return (DNS_R_NOTVERIFIEDYET); 2850135446Strhodes 2851135446Strhodes if (!dns_name_hasbuffer(signer)) { 2852135446Strhodes isc_buffer_t *dynbuf = NULL; 2853135446Strhodes result = isc_buffer_allocate(msg->mctx, &dynbuf, 512); 2854135446Strhodes if (result != ISC_R_SUCCESS) 2855135446Strhodes return (result); 2856135446Strhodes dns_name_setbuffer(signer, dynbuf); 2857135446Strhodes dns_message_takebuffer(msg, &dynbuf); 2858135446Strhodes } 2859135446Strhodes 2860135446Strhodes if (msg->sig0 != NULL) { 2861135446Strhodes dns_rdata_sig_t sig; 2862135446Strhodes 2863135446Strhodes result = dns_rdataset_first(msg->sig0); 2864135446Strhodes INSIST(result == ISC_R_SUCCESS); 2865135446Strhodes dns_rdataset_current(msg->sig0, &rdata); 2866135446Strhodes 2867135446Strhodes result = dns_rdata_tostruct(&rdata, &sig, NULL); 2868135446Strhodes if (result != ISC_R_SUCCESS) 2869135446Strhodes return (result); 2870135446Strhodes 2871135446Strhodes if (msg->verified_sig && msg->sig0status == dns_rcode_noerror) 2872135446Strhodes result = ISC_R_SUCCESS; 2873135446Strhodes else 2874135446Strhodes result = DNS_R_SIGINVALID; 2875135446Strhodes dns_name_clone(&sig.signer, signer); 2876135446Strhodes dns_rdata_freestruct(&sig); 2877135446Strhodes } else { 2878135446Strhodes dns_name_t *identity; 2879135446Strhodes dns_rdata_any_tsig_t tsig; 2880135446Strhodes 2881135446Strhodes result = dns_rdataset_first(msg->tsig); 2882135446Strhodes INSIST(result == ISC_R_SUCCESS); 2883135446Strhodes dns_rdataset_current(msg->tsig, &rdata); 2884135446Strhodes 2885135446Strhodes result = dns_rdata_tostruct(&rdata, &tsig, NULL); 2886135446Strhodes if (msg->tsigstatus != dns_rcode_noerror) 2887135446Strhodes result = DNS_R_TSIGVERIFYFAILURE; 2888135446Strhodes else if (tsig.error != dns_rcode_noerror) 2889135446Strhodes result = DNS_R_TSIGERRORSET; 2890135446Strhodes else 2891135446Strhodes result = ISC_R_SUCCESS; 2892135446Strhodes dns_rdata_freestruct(&tsig); 2893135446Strhodes 2894135446Strhodes if (msg->tsigkey == NULL) { 2895135446Strhodes /* 2896135446Strhodes * If msg->tsigstatus & tsig.error are both 2897135446Strhodes * dns_rcode_noerror, the message must have been 2898135446Strhodes * verified, which means msg->tsigkey will be 2899135446Strhodes * non-NULL. 2900135446Strhodes */ 2901135446Strhodes INSIST(result != ISC_R_SUCCESS); 2902135446Strhodes } else { 2903135446Strhodes identity = dns_tsigkey_identity(msg->tsigkey); 2904135446Strhodes if (identity == NULL) { 2905135446Strhodes if (result == ISC_R_SUCCESS) 2906135446Strhodes result = DNS_R_NOIDENTITY; 2907135446Strhodes identity = &msg->tsigkey->name; 2908135446Strhodes } 2909135446Strhodes dns_name_clone(identity, signer); 2910135446Strhodes } 2911135446Strhodes } 2912135446Strhodes 2913135446Strhodes return (result); 2914135446Strhodes} 2915135446Strhodes 2916135446Strhodesvoid 2917135446Strhodesdns_message_resetsig(dns_message_t *msg) { 2918135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2919135446Strhodes msg->verified_sig = 0; 2920135446Strhodes msg->verify_attempted = 0; 2921135446Strhodes msg->tsigstatus = dns_rcode_noerror; 2922135446Strhodes msg->sig0status = dns_rcode_noerror; 2923135446Strhodes msg->timeadjust = 0; 2924135446Strhodes if (msg->tsigkey != NULL) { 2925135446Strhodes dns_tsigkey_detach(&msg->tsigkey); 2926135446Strhodes msg->tsigkey = NULL; 2927135446Strhodes } 2928135446Strhodes} 2929135446Strhodes 2930135446Strhodesisc_result_t 2931135446Strhodesdns_message_rechecksig(dns_message_t *msg, dns_view_t *view) { 2932135446Strhodes dns_message_resetsig(msg); 2933135446Strhodes return (dns_message_checksig(msg, view)); 2934135446Strhodes} 2935135446Strhodes 2936193149Sdougb#ifdef SKAN_MSG_DEBUG 2937193149Sdougbvoid 2938193149Sdougbdns_message_dumpsig(dns_message_t *msg, char *txt1) { 2939193149Sdougb dns_rdata_t querytsigrdata = DNS_RDATA_INIT; 2940193149Sdougb dns_rdata_any_tsig_t querytsig; 2941193149Sdougb isc_result_t result; 2942193149Sdougb 2943193149Sdougb if (msg->tsig != NULL) { 2944193149Sdougb result = dns_rdataset_first(msg->tsig); 2945193149Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 2946193149Sdougb dns_rdataset_current(msg->tsig, &querytsigrdata); 2947193149Sdougb result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL); 2948193149Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 2949193149Sdougb hexdump(txt1, "TSIG", querytsig.signature, 2950193149Sdougb querytsig.siglen); 2951193149Sdougb } 2952193149Sdougb 2953193149Sdougb if (msg->querytsig != NULL) { 2954193149Sdougb result = dns_rdataset_first(msg->querytsig); 2955193149Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 2956193149Sdougb dns_rdataset_current(msg->querytsig, &querytsigrdata); 2957193149Sdougb result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL); 2958193149Sdougb RUNTIME_CHECK(result == ISC_R_SUCCESS); 2959193149Sdougb hexdump(txt1, "QUERYTSIG", querytsig.signature, 2960193149Sdougb querytsig.siglen); 2961193149Sdougb } 2962193149Sdougb} 2963193149Sdougb#endif 2964193149Sdougb 2965135446Strhodesisc_result_t 2966135446Strhodesdns_message_checksig(dns_message_t *msg, dns_view_t *view) { 2967135446Strhodes isc_buffer_t b, msgb; 2968135446Strhodes 2969135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 2970135446Strhodes 2971135446Strhodes if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL) 2972135446Strhodes return (ISC_R_SUCCESS); 2973193149Sdougb 2974135446Strhodes INSIST(msg->saved.base != NULL); 2975135446Strhodes isc_buffer_init(&msgb, msg->saved.base, msg->saved.length); 2976135446Strhodes isc_buffer_add(&msgb, msg->saved.length); 2977135446Strhodes if (msg->tsigkey != NULL || msg->tsig != NULL) { 2978193149Sdougb#ifdef SKAN_MSG_DEBUG 2979193149Sdougb dns_message_dumpsig(msg, "dns_message_checksig#1"); 2980193149Sdougb#endif 2981135446Strhodes if (view != NULL) 2982135446Strhodes return (dns_view_checksig(view, &msgb, msg)); 2983135446Strhodes else 2984135446Strhodes return (dns_tsig_verify(&msgb, msg, NULL, NULL)); 2985135446Strhodes } else { 2986135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 2987135446Strhodes dns_rdata_sig_t sig; 2988135446Strhodes dns_rdataset_t keyset; 2989135446Strhodes isc_result_t result; 2990135446Strhodes 2991135446Strhodes result = dns_rdataset_first(msg->sig0); 2992135446Strhodes INSIST(result == ISC_R_SUCCESS); 2993135446Strhodes dns_rdataset_current(msg->sig0, &rdata); 2994135446Strhodes 2995135446Strhodes /* 2996135446Strhodes * This can occur when the message is a dynamic update, since 2997135446Strhodes * the rdata length checking is relaxed. This should not 2998135446Strhodes * happen in a well-formed message, since the SIG(0) is only 2999135446Strhodes * looked for in the additional section, and the dynamic update 3000135446Strhodes * meta-records are in the prerequisite and update sections. 3001135446Strhodes */ 3002135446Strhodes if (rdata.length == 0) 3003135446Strhodes return (ISC_R_UNEXPECTEDEND); 3004135446Strhodes 3005135446Strhodes result = dns_rdata_tostruct(&rdata, &sig, msg->mctx); 3006135446Strhodes if (result != ISC_R_SUCCESS) 3007135446Strhodes return (result); 3008135446Strhodes 3009135446Strhodes dns_rdataset_init(&keyset); 3010135446Strhodes if (view == NULL) 3011135446Strhodes return (DNS_R_KEYUNAUTHORIZED); 3012135446Strhodes result = dns_view_simplefind(view, &sig.signer, 3013135446Strhodes dns_rdatatype_key /* SIG(0) */, 3014135446Strhodes 0, 0, ISC_FALSE, &keyset, NULL); 3015135446Strhodes 3016135446Strhodes if (result != ISC_R_SUCCESS) { 3017135446Strhodes /* XXXBEW Should possibly create a fetch here */ 3018135446Strhodes result = DNS_R_KEYUNAUTHORIZED; 3019135446Strhodes goto freesig; 3020135446Strhodes } else if (keyset.trust < dns_trust_secure) { 3021135446Strhodes /* XXXBEW Should call a validator here */ 3022135446Strhodes result = DNS_R_KEYUNAUTHORIZED; 3023135446Strhodes goto freesig; 3024135446Strhodes } 3025135446Strhodes result = dns_rdataset_first(&keyset); 3026135446Strhodes INSIST(result == ISC_R_SUCCESS); 3027135446Strhodes for (; 3028135446Strhodes result == ISC_R_SUCCESS; 3029135446Strhodes result = dns_rdataset_next(&keyset)) 3030135446Strhodes { 3031135446Strhodes dst_key_t *key = NULL; 3032135446Strhodes 3033193149Sdougb dns_rdata_reset(&rdata); 3034135446Strhodes dns_rdataset_current(&keyset, &rdata); 3035135446Strhodes isc_buffer_init(&b, rdata.data, rdata.length); 3036135446Strhodes isc_buffer_add(&b, rdata.length); 3037135446Strhodes 3038135446Strhodes result = dst_key_fromdns(&sig.signer, rdata.rdclass, 3039135446Strhodes &b, view->mctx, &key); 3040135446Strhodes if (result != ISC_R_SUCCESS) 3041135446Strhodes continue; 3042135446Strhodes if (dst_key_alg(key) != sig.algorithm || 3043135446Strhodes dst_key_id(key) != sig.keyid || 3044135446Strhodes !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC || 3045135446Strhodes dst_key_proto(key) == DNS_KEYPROTO_ANY)) 3046135446Strhodes { 3047135446Strhodes dst_key_free(&key); 3048135446Strhodes continue; 3049135446Strhodes } 3050135446Strhodes result = dns_dnssec_verifymessage(&msgb, msg, key); 3051135446Strhodes dst_key_free(&key); 3052135446Strhodes if (result == ISC_R_SUCCESS) 3053135446Strhodes break; 3054135446Strhodes } 3055135446Strhodes if (result == ISC_R_NOMORE) 3056135446Strhodes result = DNS_R_KEYUNAUTHORIZED; 3057135446Strhodes 3058135446Strhodes freesig: 3059135446Strhodes if (dns_rdataset_isassociated(&keyset)) 3060135446Strhodes dns_rdataset_disassociate(&keyset); 3061135446Strhodes dns_rdata_freestruct(&sig); 3062135446Strhodes return (result); 3063135446Strhodes } 3064135446Strhodes} 3065135446Strhodes 3066135446Strhodesisc_result_t 3067135446Strhodesdns_message_sectiontotext(dns_message_t *msg, dns_section_t section, 3068135446Strhodes const dns_master_style_t *style, 3069135446Strhodes dns_messagetextflag_t flags, 3070135446Strhodes isc_buffer_t *target) { 3071135446Strhodes dns_name_t *name, empty_name; 3072135446Strhodes dns_rdataset_t *rdataset; 3073135446Strhodes isc_result_t result; 3074135446Strhodes 3075135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 3076135446Strhodes REQUIRE(target != NULL); 3077135446Strhodes REQUIRE(VALID_SECTION(section)); 3078135446Strhodes 3079135446Strhodes if (ISC_LIST_EMPTY(msg->sections[section])) 3080135446Strhodes return (ISC_R_SUCCESS); 3081135446Strhodes 3082135446Strhodes if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) { 3083135446Strhodes ADD_STRING(target, ";; "); 3084135446Strhodes if (msg->opcode != dns_opcode_update) { 3085135446Strhodes ADD_STRING(target, sectiontext[section]); 3086174187Sdougb } else { 3087135446Strhodes ADD_STRING(target, updsectiontext[section]); 3088135446Strhodes } 3089135446Strhodes ADD_STRING(target, " SECTION:\n"); 3090135446Strhodes } 3091135446Strhodes 3092135446Strhodes dns_name_init(&empty_name, NULL); 3093135446Strhodes result = dns_message_firstname(msg, section); 3094135446Strhodes if (result != ISC_R_SUCCESS) { 3095135446Strhodes return (result); 3096135446Strhodes } 3097135446Strhodes do { 3098135446Strhodes name = NULL; 3099135446Strhodes dns_message_currentname(msg, section, &name); 3100135446Strhodes for (rdataset = ISC_LIST_HEAD(name->list); 3101135446Strhodes rdataset != NULL; 3102135446Strhodes rdataset = ISC_LIST_NEXT(rdataset, link)) { 3103135446Strhodes if (section == DNS_SECTION_QUESTION) { 3104135446Strhodes ADD_STRING(target, ";"); 3105135446Strhodes result = dns_master_questiontotext(name, 3106135446Strhodes rdataset, 3107135446Strhodes style, 3108135446Strhodes target); 3109135446Strhodes } else { 3110135446Strhodes result = dns_master_rdatasettotext(name, 3111135446Strhodes rdataset, 3112135446Strhodes style, 3113135446Strhodes target); 3114135446Strhodes } 3115135446Strhodes if (result != ISC_R_SUCCESS) 3116135446Strhodes return (result); 3117135446Strhodes } 3118135446Strhodes result = dns_message_nextname(msg, section); 3119135446Strhodes } while (result == ISC_R_SUCCESS); 3120135446Strhodes if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 && 3121135446Strhodes (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 3122135446Strhodes ADD_STRING(target, "\n"); 3123135446Strhodes if (result == ISC_R_NOMORE) 3124135446Strhodes result = ISC_R_SUCCESS; 3125135446Strhodes return (result); 3126135446Strhodes} 3127135446Strhodes 3128135446Strhodesisc_result_t 3129135446Strhodesdns_message_pseudosectiontotext(dns_message_t *msg, 3130135446Strhodes dns_pseudosection_t section, 3131135446Strhodes const dns_master_style_t *style, 3132135446Strhodes dns_messagetextflag_t flags, 3133135446Strhodes isc_buffer_t *target) { 3134135446Strhodes dns_rdataset_t *ps = NULL; 3135135446Strhodes dns_name_t *name = NULL; 3136135446Strhodes isc_result_t result; 3137135446Strhodes char buf[sizeof("1234567890")]; 3138135446Strhodes isc_uint32_t mbz; 3139193149Sdougb dns_rdata_t rdata; 3140193149Sdougb isc_buffer_t optbuf; 3141193149Sdougb isc_uint16_t optcode, optlen; 3142193149Sdougb unsigned char *optdata; 3143135446Strhodes 3144135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 3145135446Strhodes REQUIRE(target != NULL); 3146135446Strhodes REQUIRE(VALID_PSEUDOSECTION(section)); 3147135446Strhodes 3148135446Strhodes switch (section) { 3149135446Strhodes case DNS_PSEUDOSECTION_OPT: 3150135446Strhodes ps = dns_message_getopt(msg); 3151135446Strhodes if (ps == NULL) 3152135446Strhodes return (ISC_R_SUCCESS); 3153135446Strhodes if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 3154135446Strhodes ADD_STRING(target, ";; OPT PSEUDOSECTION:\n"); 3155135446Strhodes ADD_STRING(target, "; EDNS: version: "); 3156135446Strhodes snprintf(buf, sizeof(buf), "%u", 3157135446Strhodes (unsigned int)((ps->ttl & 0x00ff0000) >> 16)); 3158135446Strhodes ADD_STRING(target, buf); 3159135446Strhodes ADD_STRING(target, ", flags:"); 3160135446Strhodes if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0) 3161135446Strhodes ADD_STRING(target, " do"); 3162218384Sdougb mbz = ps->ttl & 0xffff; 3163218384Sdougb mbz &= ~DNS_MESSAGEEXTFLAG_DO; /* Known Flags. */ 3164135446Strhodes if (mbz != 0) { 3165135446Strhodes ADD_STRING(target, "; MBZ: "); 3166135446Strhodes snprintf(buf, sizeof(buf), "%.4x ", mbz); 3167135446Strhodes ADD_STRING(target, buf); 3168135446Strhodes ADD_STRING(target, ", udp: "); 3169135446Strhodes } else 3170135446Strhodes ADD_STRING(target, "; udp: "); 3171135446Strhodes snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass); 3172135446Strhodes ADD_STRING(target, buf); 3173193149Sdougb 3174193149Sdougb result = dns_rdataset_first(ps); 3175193149Sdougb if (result != ISC_R_SUCCESS) 3176193149Sdougb return (ISC_R_SUCCESS); 3177193149Sdougb 3178193149Sdougb /* Print EDNS info, if any */ 3179193149Sdougb dns_rdata_init(&rdata); 3180193149Sdougb dns_rdataset_current(ps, &rdata); 3181193149Sdougb 3182193149Sdougb isc_buffer_init(&optbuf, rdata.data, rdata.length); 3183193149Sdougb isc_buffer_add(&optbuf, rdata.length); 3184218384Sdougb while (isc_buffer_remaininglength(&optbuf) != 0) { 3185218384Sdougb INSIST(isc_buffer_remaininglength(&optbuf) >= 4U); 3186218384Sdougb optcode = isc_buffer_getuint16(&optbuf); 3187218384Sdougb optlen = isc_buffer_getuint16(&optbuf); 3188218384Sdougb INSIST(isc_buffer_remaininglength(&optbuf) >= optlen); 3189193149Sdougb 3190218384Sdougb if (optcode == DNS_OPT_NSID) { 3191218384Sdougb ADD_STRING(target, "; NSID"); 3192218384Sdougb } else { 3193218384Sdougb ADD_STRING(target, "; OPT="); 3194218384Sdougb sprintf(buf, "%u", optcode); 3195218384Sdougb ADD_STRING(target, buf); 3196218384Sdougb } 3197193149Sdougb 3198218384Sdougb if (optlen != 0) { 3199218384Sdougb int i; 3200218384Sdougb ADD_STRING(target, ": "); 3201193149Sdougb 3202218384Sdougb optdata = isc_buffer_current(&optbuf); 3203218384Sdougb for (i = 0; i < optlen; i++) { 3204218384Sdougb sprintf(buf, "%02x ", optdata[i]); 3205218384Sdougb ADD_STRING(target, buf); 3206218384Sdougb } 3207218384Sdougb for (i = 0; i < optlen; i++) { 3208218384Sdougb ADD_STRING(target, " ("); 3209218384Sdougb if (isprint(optdata[i])) 3210218384Sdougb isc_buffer_putmem(target, 3211218384Sdougb &optdata[i], 3212218384Sdougb 1); 3213218384Sdougb else 3214218384Sdougb isc_buffer_putstr(target, "."); 3215218384Sdougb ADD_STRING(target, ")"); 3216218384Sdougb } 3217218384Sdougb isc_buffer_forward(&optbuf, optlen); 3218193149Sdougb } 3219218384Sdougb ADD_STRING(target, "\n"); 3220193149Sdougb } 3221135446Strhodes return (ISC_R_SUCCESS); 3222135446Strhodes case DNS_PSEUDOSECTION_TSIG: 3223135446Strhodes ps = dns_message_gettsig(msg, &name); 3224135446Strhodes if (ps == NULL) 3225135446Strhodes return (ISC_R_SUCCESS); 3226135446Strhodes if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 3227135446Strhodes ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n"); 3228135446Strhodes result = dns_master_rdatasettotext(name, ps, style, target); 3229135446Strhodes if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 && 3230135446Strhodes (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 3231135446Strhodes ADD_STRING(target, "\n"); 3232135446Strhodes return (result); 3233135446Strhodes case DNS_PSEUDOSECTION_SIG0: 3234135446Strhodes ps = dns_message_getsig0(msg, &name); 3235135446Strhodes if (ps == NULL) 3236135446Strhodes return (ISC_R_SUCCESS); 3237135446Strhodes if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 3238135446Strhodes ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n"); 3239135446Strhodes result = dns_master_rdatasettotext(name, ps, style, target); 3240135446Strhodes if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 && 3241135446Strhodes (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 3242135446Strhodes ADD_STRING(target, "\n"); 3243135446Strhodes return (result); 3244135446Strhodes } 3245135446Strhodes return (ISC_R_UNEXPECTED); 3246135446Strhodes} 3247135446Strhodes 3248135446Strhodesisc_result_t 3249135446Strhodesdns_message_totext(dns_message_t *msg, const dns_master_style_t *style, 3250135446Strhodes dns_messagetextflag_t flags, isc_buffer_t *target) { 3251135446Strhodes char buf[sizeof("1234567890")]; 3252135446Strhodes isc_result_t result; 3253135446Strhodes 3254135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 3255135446Strhodes REQUIRE(target != NULL); 3256135446Strhodes 3257135446Strhodes if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) { 3258135446Strhodes ADD_STRING(target, ";; ->>HEADER<<- opcode: "); 3259135446Strhodes ADD_STRING(target, opcodetext[msg->opcode]); 3260135446Strhodes ADD_STRING(target, ", status: "); 3261174187Sdougb if (msg->rcode < (sizeof(rcodetext)/sizeof(rcodetext[0]))) { 3262174187Sdougb ADD_STRING(target, rcodetext[msg->rcode]); 3263174187Sdougb } else { 3264174187Sdougb snprintf(buf, sizeof(buf), "%4u", msg->rcode); 3265174187Sdougb ADD_STRING(target, buf); 3266174187Sdougb } 3267135446Strhodes ADD_STRING(target, ", id: "); 3268135446Strhodes snprintf(buf, sizeof(buf), "%6u", msg->id); 3269135446Strhodes ADD_STRING(target, buf); 3270218384Sdougb ADD_STRING(target, "\n;; flags:"); 3271135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) 3272218384Sdougb ADD_STRING(target, " qr"); 3273135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) 3274218384Sdougb ADD_STRING(target, " aa"); 3275135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) 3276218384Sdougb ADD_STRING(target, " tc"); 3277135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) 3278218384Sdougb ADD_STRING(target, " rd"); 3279135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) 3280218384Sdougb ADD_STRING(target, " ra"); 3281135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) 3282218384Sdougb ADD_STRING(target, " ad"); 3283135446Strhodes if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) 3284218384Sdougb ADD_STRING(target, " cd"); 3285218384Sdougb /* 3286218384Sdougb * The final unnamed flag must be zero. 3287218384Sdougb */ 3288218384Sdougb if ((msg->flags & 0x0040U) != 0) 3289218384Sdougb ADD_STRING(target, "; MBZ: 0x4"); 3290135446Strhodes if (msg->opcode != dns_opcode_update) { 3291135446Strhodes ADD_STRING(target, "; QUESTION: "); 3292135446Strhodes } else { 3293135446Strhodes ADD_STRING(target, "; ZONE: "); 3294135446Strhodes } 3295135446Strhodes snprintf(buf, sizeof(buf), "%1u", 3296135446Strhodes msg->counts[DNS_SECTION_QUESTION]); 3297135446Strhodes ADD_STRING(target, buf); 3298135446Strhodes if (msg->opcode != dns_opcode_update) { 3299135446Strhodes ADD_STRING(target, ", ANSWER: "); 3300135446Strhodes } else { 3301135446Strhodes ADD_STRING(target, ", PREREQ: "); 3302135446Strhodes } 3303135446Strhodes snprintf(buf, sizeof(buf), "%1u", 3304135446Strhodes msg->counts[DNS_SECTION_ANSWER]); 3305135446Strhodes ADD_STRING(target, buf); 3306135446Strhodes if (msg->opcode != dns_opcode_update) { 3307135446Strhodes ADD_STRING(target, ", AUTHORITY: "); 3308135446Strhodes } else { 3309135446Strhodes ADD_STRING(target, ", UPDATE: "); 3310135446Strhodes } 3311135446Strhodes snprintf(buf, sizeof(buf), "%1u", 3312135446Strhodes msg->counts[DNS_SECTION_AUTHORITY]); 3313135446Strhodes ADD_STRING(target, buf); 3314135446Strhodes ADD_STRING(target, ", ADDITIONAL: "); 3315135446Strhodes snprintf(buf, sizeof(buf), "%1u", 3316135446Strhodes msg->counts[DNS_SECTION_ADDITIONAL]); 3317135446Strhodes ADD_STRING(target, buf); 3318135446Strhodes ADD_STRING(target, "\n"); 3319135446Strhodes } 3320135446Strhodes result = dns_message_pseudosectiontotext(msg, 3321135446Strhodes DNS_PSEUDOSECTION_OPT, 3322135446Strhodes style, flags, target); 3323135446Strhodes if (result != ISC_R_SUCCESS) 3324135446Strhodes return (result); 3325135446Strhodes 3326135446Strhodes result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION, 3327135446Strhodes style, flags, target); 3328135446Strhodes if (result != ISC_R_SUCCESS) 3329135446Strhodes return (result); 3330135446Strhodes result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER, 3331135446Strhodes style, flags, target); 3332135446Strhodes if (result != ISC_R_SUCCESS) 3333135446Strhodes return (result); 3334135446Strhodes result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY, 3335135446Strhodes style, flags, target); 3336135446Strhodes if (result != ISC_R_SUCCESS) 3337135446Strhodes return (result); 3338135446Strhodes result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL, 3339135446Strhodes style, flags, target); 3340135446Strhodes if (result != ISC_R_SUCCESS) 3341135446Strhodes return (result); 3342135446Strhodes 3343135446Strhodes result = dns_message_pseudosectiontotext(msg, 3344135446Strhodes DNS_PSEUDOSECTION_TSIG, 3345135446Strhodes style, flags, target); 3346135446Strhodes if (result != ISC_R_SUCCESS) 3347135446Strhodes return (result); 3348135446Strhodes 3349135446Strhodes result = dns_message_pseudosectiontotext(msg, 3350135446Strhodes DNS_PSEUDOSECTION_SIG0, 3351135446Strhodes style, flags, target); 3352135446Strhodes if (result != ISC_R_SUCCESS) 3353135446Strhodes return (result); 3354135446Strhodes 3355135446Strhodes return (ISC_R_SUCCESS); 3356135446Strhodes} 3357135446Strhodes 3358135446Strhodesisc_region_t * 3359135446Strhodesdns_message_getrawmessage(dns_message_t *msg) { 3360135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 3361135446Strhodes return (&msg->saved); 3362135446Strhodes} 3363135446Strhodes 3364135446Strhodesvoid 3365135446Strhodesdns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order, 3366165071Sdougb const void *order_arg) 3367135446Strhodes{ 3368135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 3369135446Strhodes msg->order = order; 3370135446Strhodes msg->order_arg = order_arg; 3371135446Strhodes} 3372135446Strhodes 3373135446Strhodesvoid 3374135446Strhodesdns_message_settimeadjust(dns_message_t *msg, int timeadjust) { 3375135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 3376135446Strhodes msg->timeadjust = timeadjust; 3377135446Strhodes} 3378135446Strhodes 3379135446Strhodesint 3380135446Strhodesdns_message_gettimeadjust(dns_message_t *msg) { 3381135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 3382135446Strhodes return (msg->timeadjust); 3383135446Strhodes} 3384135446Strhodes 3385135446Strhodesisc_result_t 3386135446Strhodesdns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) { 3387135446Strhodes 3388135446Strhodes REQUIRE(opcode < 16); 3389135446Strhodes 3390135446Strhodes if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode])) 3391135446Strhodes return (ISC_R_NOSPACE); 3392135446Strhodes isc_buffer_putstr(target, opcodetext[opcode]); 3393135446Strhodes return (ISC_R_SUCCESS); 3394135446Strhodes} 3395