message.c revision 153816
1135446Strhodes/* 2245163Serwin * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1999-2003 Internet Software Consortium. 4135446Strhodes * 5174187Sdougb * Permission to use, copy, modify, and 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 18234010Sdougb/* $Id: message.c,v 1.194.2.10.2.20 2005/06/07 01:42:23 marka Exp $ */ 19135446Strhodes 20135446Strhodes/*** 21135446Strhodes *** Imports 22135446Strhodes ***/ 23135446Strhodes 24135446Strhodes#include <config.h> 25135446Strhodes 26135446Strhodes#include <isc/buffer.h> 27135446Strhodes#include <isc/mem.h> 28135446Strhodes#include <isc/print.h> 29193149Sdougb#include <isc/string.h> /* Required for HP/UX (and others?) */ 30135446Strhodes#include <isc/util.h> 31135446Strhodes 32135446Strhodes#include <dns/dnssec.h> 33135446Strhodes#include <dns/keyvalues.h> 34135446Strhodes#include <dns/log.h> 35135446Strhodes#include <dns/masterdump.h> 36135446Strhodes#include <dns/message.h> 37135446Strhodes#include <dns/opcode.h> 38135446Strhodes#include <dns/rdata.h> 39135446Strhodes#include <dns/rdatalist.h> 40135446Strhodes#include <dns/rdataset.h> 41135446Strhodes#include <dns/rdatastruct.h> 42135446Strhodes#include <dns/result.h> 43135446Strhodes#include <dns/tsig.h> 44135446Strhodes#include <dns/view.h> 45135446Strhodes 46135446Strhodes#define DNS_MESSAGE_OPCODE_MASK 0x7800U 47135446Strhodes#define DNS_MESSAGE_OPCODE_SHIFT 11 48135446Strhodes#define DNS_MESSAGE_RCODE_MASK 0x000fU 49135446Strhodes#define DNS_MESSAGE_FLAG_MASK 0x8ff0U 50135446Strhodes#define DNS_MESSAGE_EDNSRCODE_MASK 0xff000000U 51135446Strhodes#define DNS_MESSAGE_EDNSRCODE_SHIFT 24 52135446Strhodes#define DNS_MESSAGE_EDNSVERSION_MASK 0x00ff0000U 53135446Strhodes#define DNS_MESSAGE_EDNSVERSION_SHIFT 16 54170222Sdougb 55170222Sdougb#define VALID_NAMED_SECTION(s) (((s) > DNS_SECTION_ANY) \ 56135446Strhodes && ((s) < DNS_SECTION_MAX)) 57135446Strhodes#define VALID_SECTION(s) (((s) >= DNS_SECTION_ANY) \ 58135446Strhodes && ((s) < DNS_SECTION_MAX)) 59135446Strhodes#define ADD_STRING(b, s) {if (strlen(s) >= \ 60245163Serwin isc_buffer_availablelength(b)) \ 61135446Strhodes return(ISC_R_NOSPACE); else \ 62135446Strhodes isc_buffer_putstr(b, s);} 63135446Strhodes#define VALID_PSEUDOSECTION(s) (((s) >= DNS_PSEUDOSECTION_ANY) \ 64135446Strhodes && ((s) < DNS_PSEUDOSECTION_MAX)) 65135446Strhodes 66135446Strhodes/* 67135446Strhodes * This is the size of each individual scratchpad buffer, and the numbers 68135446Strhodes * of various block allocations used within the server. 69135446Strhodes * XXXMLG These should come from a config setting. 70135446Strhodes */ 71135446Strhodes#define SCRATCHPAD_SIZE 512 72135446Strhodes#define NAME_COUNT 8 73135446Strhodes#define OFFSET_COUNT 4 74135446Strhodes#define RDATA_COUNT 8 75135446Strhodes#define RDATALIST_COUNT 8 76135446Strhodes#define RDATASET_COUNT RDATALIST_COUNT 77135446Strhodes 78135446Strhodes/* 79135446Strhodes * Text representation of the different items, for message_totext 80135446Strhodes * functions. 81135446Strhodes */ 82135446Strhodesstatic const char *sectiontext[] = { 83135446Strhodes "QUESTION", 84135446Strhodes "ANSWER", 85135446Strhodes "AUTHORITY", 86135446Strhodes "ADDITIONAL" 87135446Strhodes}; 88135446Strhodes 89135446Strhodesstatic const char *updsectiontext[] = { 90135446Strhodes "ZONE", 91135446Strhodes "PREREQUISITE", 92135446Strhodes "UPDATE", 93135446Strhodes "ADDITIONAL" 94135446Strhodes}; 95135446Strhodes 96135446Strhodesstatic const char *opcodetext[] = { 97135446Strhodes "QUERY", 98135446Strhodes "IQUERY", 99135446Strhodes "STATUS", 100135446Strhodes "RESERVED3", 101135446Strhodes "NOTIFY", 102135446Strhodes "UPDATE", 103135446Strhodes "RESERVED6", 104135446Strhodes "RESERVED7", 105135446Strhodes "RESERVED8", 106135446Strhodes "RESERVED9", 107135446Strhodes "RESERVED10", 108135446Strhodes "RESERVED11", 109135446Strhodes "RESERVED12", 110135446Strhodes "RESERVED13", 111135446Strhodes "RESERVED14", 112135446Strhodes "RESERVED15" 113135446Strhodes}; 114135446Strhodes 115135446Strhodesstatic const char *rcodetext[] = { 116135446Strhodes "NOERROR", 117135446Strhodes "FORMERR", 118135446Strhodes "SERVFAIL", 119135446Strhodes "NXDOMAIN", 120135446Strhodes "NOTIMP", 121135446Strhodes "REFUSED", 122135446Strhodes "YXDOMAIN", 123135446Strhodes "YXRRSET", 124135446Strhodes "NXRRSET", 125135446Strhodes "NOTAUTH", 126135446Strhodes "NOTZONE", 127135446Strhodes "RESERVED11", 128135446Strhodes "RESERVED12", 129135446Strhodes "RESERVED13", 130135446Strhodes "RESERVED14", 131135446Strhodes "RESERVED15", 132135446Strhodes "BADVERS" 133135446Strhodes}; 134193149Sdougb 135193149Sdougb 136193149Sdougb/* 137193149Sdougb * "helper" type, which consists of a block of some type, and is linkable. 138193149Sdougb * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer 139193149Sdougb * size, or the allocated elements will not be alligned correctly. 140193149Sdougb */ 141193149Sdougbstruct dns_msgblock { 142193149Sdougb unsigned int count; 143193149Sdougb unsigned int remaining; 144193149Sdougb ISC_LINK(dns_msgblock_t) link; 145193149Sdougb}; /* dynamically sized */ 146193149Sdougb 147193149Sdougbstatic inline dns_msgblock_t * 148193149Sdougbmsgblock_allocate(isc_mem_t *, unsigned int, unsigned int); 149193149Sdougb 150193149Sdougb#define msgblock_get(block, type) \ 151135446Strhodes ((type *)msgblock_internalget(block, sizeof(type))) 152135446Strhodes 153135446Strhodesstatic inline void * 154135446Strhodesmsgblock_internalget(dns_msgblock_t *, unsigned int); 155135446Strhodes 156135446Strhodesstatic inline void 157135446Strhodesmsgblock_reset(dns_msgblock_t *); 158135446Strhodes 159135446Strhodesstatic inline void 160135446Strhodesmsgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int); 161135446Strhodes 162135446Strhodes/* 163135446Strhodes * Allocate a new dns_msgblock_t, and return a pointer to it. If no memory 164135446Strhodes * is free, return NULL. 165135446Strhodes */ 166135446Strhodesstatic inline dns_msgblock_t * 167135446Strhodesmsgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type, 168135446Strhodes unsigned int count) 169135446Strhodes{ 170135446Strhodes dns_msgblock_t *block; 171135446Strhodes unsigned int length; 172135446Strhodes 173135446Strhodes length = sizeof(dns_msgblock_t) + (sizeof_type * count); 174135446Strhodes 175135446Strhodes block = isc_mem_get(mctx, length); 176135446Strhodes if (block == NULL) 177135446Strhodes return (NULL); 178135446Strhodes 179135446Strhodes block->count = count; 180135446Strhodes block->remaining = count; 181135446Strhodes 182135446Strhodes ISC_LINK_INIT(block, link); 183135446Strhodes 184135446Strhodes return (block); 185135446Strhodes} 186135446Strhodes 187135446Strhodes/* 188135446Strhodes * Return an element from the msgblock. If no more are available, return 189135446Strhodes * NULL. 190135446Strhodes */ 191135446Strhodesstatic inline void * 192135446Strhodesmsgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) { 193135446Strhodes void *ptr; 194135446Strhodes 195135446Strhodes if (block == NULL || block->remaining == 0) 196135446Strhodes return (NULL); 197135446Strhodes 198135446Strhodes block->remaining--; 199135446Strhodes 200135446Strhodes ptr = (((unsigned char *)block) 201135446Strhodes + sizeof(dns_msgblock_t) 202135446Strhodes + (sizeof_type * block->remaining)); 203135446Strhodes 204135446Strhodes return (ptr); 205135446Strhodes} 206135446Strhodes 207135446Strhodesstatic inline void 208135446Strhodesmsgblock_reset(dns_msgblock_t *block) { 209135446Strhodes block->remaining = block->count; 210135446Strhodes} 211135446Strhodes 212135446Strhodes/* 213135446Strhodes * Release memory associated with a message block. 214135446Strhodes */ 215135446Strhodesstatic inline void 216135446Strhodesmsgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, unsigned int sizeof_type) 217135446Strhodes{ 218135446Strhodes unsigned int length; 219135446Strhodes 220135446Strhodes length = sizeof(dns_msgblock_t) + (sizeof_type * block->count); 221135446Strhodes 222135446Strhodes isc_mem_put(mctx, block, length); 223135446Strhodes} 224135446Strhodes 225135446Strhodes/* 226135446Strhodes * Allocate a new dynamic buffer, and attach it to this message as the 227135446Strhodes * "current" buffer. (which is always the last on the list, for our 228135446Strhodes * uses) 229135446Strhodes */ 230135446Strhodesstatic inline isc_result_t 231135446Strhodesnewbuffer(dns_message_t *msg, unsigned int size) { 232135446Strhodes isc_result_t result; 233135446Strhodes isc_buffer_t *dynbuf; 234135446Strhodes 235135446Strhodes dynbuf = NULL; 236135446Strhodes result = isc_buffer_allocate(msg->mctx, &dynbuf, size); 237135446Strhodes if (result != ISC_R_SUCCESS) 238135446Strhodes return (ISC_R_NOMEMORY); 239135446Strhodes 240135446Strhodes ISC_LIST_APPEND(msg->scratchpad, dynbuf, link); 241135446Strhodes return (ISC_R_SUCCESS); 242135446Strhodes} 243135446Strhodes 244135446Strhodesstatic inline isc_buffer_t * 245135446Strhodescurrentbuffer(dns_message_t *msg) { 246135446Strhodes isc_buffer_t *dynbuf; 247135446Strhodes 248135446Strhodes dynbuf = ISC_LIST_TAIL(msg->scratchpad); 249135446Strhodes INSIST(dynbuf != NULL); 250135446Strhodes 251135446Strhodes return (dynbuf); 252135446Strhodes} 253135446Strhodes 254135446Strhodesstatic inline void 255135446Strhodesreleaserdata(dns_message_t *msg, dns_rdata_t *rdata) { 256135446Strhodes ISC_LIST_PREPEND(msg->freerdata, rdata, link); 257135446Strhodes} 258135446Strhodes 259135446Strhodesstatic inline dns_rdata_t * 260135446Strhodesnewrdata(dns_message_t *msg) { 261135446Strhodes dns_msgblock_t *msgblock; 262135446Strhodes dns_rdata_t *rdata; 263135446Strhodes 264135446Strhodes rdata = ISC_LIST_HEAD(msg->freerdata); 265135446Strhodes if (rdata != NULL) { 266135446Strhodes ISC_LIST_UNLINK(msg->freerdata, rdata, link); 267135446Strhodes return (rdata); 268135446Strhodes } 269135446Strhodes 270135446Strhodes msgblock = ISC_LIST_TAIL(msg->rdatas); 271135446Strhodes rdata = msgblock_get(msgblock, dns_rdata_t); 272135446Strhodes if (rdata == NULL) { 273135446Strhodes msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t), 274135446Strhodes RDATA_COUNT); 275135446Strhodes if (msgblock == NULL) 276135446Strhodes return (NULL); 277135446Strhodes 278135446Strhodes ISC_LIST_APPEND(msg->rdatas, msgblock, link); 279135446Strhodes 280135446Strhodes rdata = msgblock_get(msgblock, dns_rdata_t); 281135446Strhodes } 282135446Strhodes 283135446Strhodes dns_rdata_init(rdata); 284135446Strhodes return (rdata); 285135446Strhodes} 286135446Strhodes 287135446Strhodesstatic inline void 288135446Strhodesreleaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) { 289135446Strhodes ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link); 290135446Strhodes} 291135446Strhodes 292135446Strhodesstatic inline dns_rdatalist_t * 293135446Strhodesnewrdatalist(dns_message_t *msg) { 294135446Strhodes dns_msgblock_t *msgblock; 295135446Strhodes dns_rdatalist_t *rdatalist; 296135446Strhodes 297135446Strhodes rdatalist = ISC_LIST_HEAD(msg->freerdatalist); 298135446Strhodes if (rdatalist != NULL) { 299135446Strhodes ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link); 300135446Strhodes return (rdatalist); 301135446Strhodes } 302135446Strhodes 303135446Strhodes msgblock = ISC_LIST_TAIL(msg->rdatalists); 304135446Strhodes rdatalist = msgblock_get(msgblock, dns_rdatalist_t); 305135446Strhodes if (rdatalist == NULL) { 306135446Strhodes msgblock = msgblock_allocate(msg->mctx, 307135446Strhodes sizeof(dns_rdatalist_t), 308135446Strhodes RDATALIST_COUNT); 309135446Strhodes if (msgblock == NULL) 310135446Strhodes return (NULL); 311135446Strhodes 312135446Strhodes ISC_LIST_APPEND(msg->rdatalists, msgblock, link); 313135446Strhodes 314135446Strhodes rdatalist = msgblock_get(msgblock, dns_rdatalist_t); 315135446Strhodes } 316135446Strhodes 317135446Strhodes return (rdatalist); 318135446Strhodes} 319135446Strhodes 320135446Strhodesstatic inline dns_offsets_t * 321135446Strhodesnewoffsets(dns_message_t *msg) { 322135446Strhodes dns_msgblock_t *msgblock; 323135446Strhodes dns_offsets_t *offsets; 324135446Strhodes 325135446Strhodes msgblock = ISC_LIST_TAIL(msg->offsets); 326135446Strhodes offsets = msgblock_get(msgblock, dns_offsets_t); 327135446Strhodes if (offsets == NULL) { 328135446Strhodes msgblock = msgblock_allocate(msg->mctx, 329135446Strhodes sizeof(dns_offsets_t), 330135446Strhodes OFFSET_COUNT); 331135446Strhodes if (msgblock == NULL) 332135446Strhodes return (NULL); 333135446Strhodes 334135446Strhodes ISC_LIST_APPEND(msg->offsets, msgblock, link); 335135446Strhodes 336135446Strhodes offsets = msgblock_get(msgblock, dns_offsets_t); 337135446Strhodes } 338135446Strhodes 339135446Strhodes return (offsets); 340135446Strhodes} 341135446Strhodes 342135446Strhodesstatic inline void 343135446Strhodesmsginitheader(dns_message_t *m) { 344135446Strhodes m->id = 0; 345135446Strhodes m->flags = 0; 346135446Strhodes m->rcode = 0; 347135446Strhodes m->opcode = 0; 348135446Strhodes m->rdclass = 0; 349135446Strhodes} 350135446Strhodes 351135446Strhodesstatic inline void 352135446Strhodesmsginitprivate(dns_message_t *m) { 353135446Strhodes unsigned int i; 354135446Strhodes 355135446Strhodes for (i = 0; i < DNS_SECTION_MAX; i++) { 356135446Strhodes m->cursors[i] = NULL; 357135446Strhodes m->counts[i] = 0; 358135446Strhodes } 359135446Strhodes m->opt = NULL; 360135446Strhodes m->sig0 = NULL; 361135446Strhodes m->sig0name = NULL; 362135446Strhodes m->tsig = NULL; 363135446Strhodes m->tsigname = NULL; 364135446Strhodes m->state = DNS_SECTION_ANY; /* indicate nothing parsed or rendered */ 365135446Strhodes m->opt_reserved = 0; 366135446Strhodes m->sig_reserved = 0; 367135446Strhodes m->reserved = 0; 368135446Strhodes m->buffer = NULL; 369135446Strhodes} 370135446Strhodes 371135446Strhodesstatic inline void 372135446Strhodesmsginittsig(dns_message_t *m) { 373135446Strhodes m->tsigstatus = dns_rcode_noerror; 374135446Strhodes m->querytsigstatus = dns_rcode_noerror; 375135446Strhodes m->tsigkey = NULL; 376135446Strhodes m->tsigctx = NULL; 377204619Sdougb m->sigstart = -1; 378135446Strhodes m->sig0key = NULL; 379135446Strhodes m->sig0status = dns_rcode_noerror; 380135446Strhodes m->timeadjust = 0; 381135446Strhodes} 382135446Strhodes 383135446Strhodes/* 384135446Strhodes * Init elements to default state. Used both when allocating a new element 385135446Strhodes * and when resetting one. 386135446Strhodes */ 387135446Strhodesstatic inline void 388135446Strhodesmsginit(dns_message_t *m) { 389135446Strhodes msginitheader(m); 390135446Strhodes msginitprivate(m); 391135446Strhodes msginittsig(m); 392135446Strhodes m->header_ok = 0; 393135446Strhodes m->question_ok = 0; 394135446Strhodes m->tcp_continuation = 0; 395135446Strhodes m->verified_sig = 0; 396135446Strhodes m->verify_attempted = 0; 397135446Strhodes m->order = NULL; 398135446Strhodes m->order_arg = NULL; 399135446Strhodes m->query.base = NULL; 400135446Strhodes m->query.length = 0; 401135446Strhodes m->free_query = 0; 402135446Strhodes m->saved.base = NULL; 403135446Strhodes m->saved.length = 0; 404135446Strhodes m->free_saved = 0; 405135446Strhodes m->querytsig = NULL; 406135446Strhodes} 407135446Strhodes 408193149Sdougbstatic inline void 409135446Strhodesmsgresetnames(dns_message_t *msg, unsigned int first_section) { 410245163Serwin unsigned int i; 411245163Serwin dns_name_t *name, *next_name; 412245163Serwin dns_rdataset_t *rds, *next_rds; 413135446Strhodes 414135446Strhodes /* 415135446Strhodes * Clean up name lists by calling the rdataset disassociate function. 416143731Sdougb */ 417135446Strhodes for (i = first_section; i < DNS_SECTION_MAX; i++) { 418193149Sdougb name = ISC_LIST_HEAD(msg->sections[i]); 419135446Strhodes while (name != NULL) { 420135446Strhodes next_name = ISC_LIST_NEXT(name, link); 421135446Strhodes ISC_LIST_UNLINK(msg->sections[i], name, link); 422135446Strhodes 423135446Strhodes rds = ISC_LIST_HEAD(name->list); 424135446Strhodes while (rds != NULL) { 425135446Strhodes next_rds = ISC_LIST_NEXT(rds, link); 426135446Strhodes ISC_LIST_UNLINK(name->list, rds, link); 427135446Strhodes 428135446Strhodes INSIST(dns_rdataset_isassociated(rds)); 429135446Strhodes dns_rdataset_disassociate(rds); 430135446Strhodes isc_mempool_put(msg->rdspool, rds); 431135446Strhodes rds = next_rds; 432135446Strhodes } 433135446Strhodes if (dns_name_dynamic(name)) 434135446Strhodes dns_name_free(name, msg->mctx); 435135446Strhodes isc_mempool_put(msg->namepool, name); 436174187Sdougb name = next_name; 437174187Sdougb } 438193149Sdougb } 439135446Strhodes} 440245163Serwin 441245163Serwinstatic void 442245163Serwinmsgresetopt(dns_message_t *msg) 443135446Strhodes{ 444135446Strhodes if (msg->opt != NULL) { 445135446Strhodes if (msg->opt_reserved > 0) { 446135446Strhodes dns_message_renderrelease(msg, msg->opt_reserved); 447135446Strhodes msg->opt_reserved = 0; 448135446Strhodes } 449135446Strhodes INSIST(dns_rdataset_isassociated(msg->opt)); 450135446Strhodes dns_rdataset_disassociate(msg->opt); 451135446Strhodes isc_mempool_put(msg->rdspool, msg->opt); 452135446Strhodes msg->opt = NULL; 453135446Strhodes } 454135446Strhodes} 455135446Strhodes 456135446Strhodesstatic void 457135446Strhodesmsgresetsigs(dns_message_t *msg, isc_boolean_t replying) { 458135446Strhodes if (msg->sig_reserved > 0) { 459135446Strhodes dns_message_renderrelease(msg, msg->sig_reserved); 460135446Strhodes msg->sig_reserved = 0; 461135446Strhodes } 462135446Strhodes if (msg->tsig != NULL) { 463135446Strhodes INSIST(dns_rdataset_isassociated(msg->tsig)); 464135446Strhodes INSIST(msg->namepool != NULL); 465135446Strhodes if (replying) { 466135446Strhodes INSIST(msg->querytsig == NULL); 467135446Strhodes msg->querytsig = msg->tsig; 468135446Strhodes } else { 469135446Strhodes dns_rdataset_disassociate(msg->tsig); 470193149Sdougb isc_mempool_put(msg->rdspool, msg->tsig); 471135446Strhodes if (msg->querytsig != NULL) { 472135446Strhodes dns_rdataset_disassociate(msg->querytsig); 473135446Strhodes isc_mempool_put(msg->rdspool, msg->querytsig); 474135446Strhodes } 475135446Strhodes } 476135446Strhodes if (dns_name_dynamic(msg->tsigname)) 477193149Sdougb dns_name_free(msg->tsigname, msg->mctx); 478193149Sdougb isc_mempool_put(msg->namepool, msg->tsigname); 479193149Sdougb msg->tsig = NULL; 480135446Strhodes msg->tsigname = NULL; 481135446Strhodes } else if (msg->querytsig != NULL && !replying) { 482143731Sdougb dns_rdataset_disassociate(msg->querytsig); 483135446Strhodes isc_mempool_put(msg->rdspool, msg->querytsig); 484135446Strhodes msg->querytsig = NULL; 485135446Strhodes } 486135446Strhodes if (msg->sig0 != NULL) { 487135446Strhodes INSIST(dns_rdataset_isassociated(msg->sig0)); 488135446Strhodes dns_rdataset_disassociate(msg->sig0); 489135446Strhodes isc_mempool_put(msg->rdspool, msg->sig0); 490135446Strhodes if (msg->sig0name != NULL) { 491135446Strhodes if (dns_name_dynamic(msg->sig0name)) 492135446Strhodes dns_name_free(msg->sig0name, msg->mctx); 493135446Strhodes isc_mempool_put(msg->namepool, msg->sig0name); 494135446Strhodes } 495135446Strhodes msg->sig0 = NULL; 496135446Strhodes msg->sig0name = NULL; 497135446Strhodes } 498135446Strhodes} 499135446Strhodes 500135446Strhodes/* 501135446Strhodes * Free all but one (or everything) for this message. This is used by 502135446Strhodes * both dns_message_reset() and dns_message_destroy(). 503135446Strhodes */ 504135446Strhodesstatic void 505135446Strhodesmsgreset(dns_message_t *msg, isc_boolean_t everything) { 506135446Strhodes dns_msgblock_t *msgblock, *next_msgblock; 507135446Strhodes isc_buffer_t *dynbuf, *next_dynbuf; 508135446Strhodes dns_rdata_t *rdata; 509135446Strhodes dns_rdatalist_t *rdatalist; 510135446Strhodes 511135446Strhodes msgresetnames(msg, 0); 512135446Strhodes msgresetopt(msg); 513135446Strhodes msgresetsigs(msg, ISC_FALSE); 514135446Strhodes 515135446Strhodes /* 516135446Strhodes * Clean up linked lists. 517135446Strhodes */ 518135446Strhodes 519135446Strhodes /* 520135446Strhodes * Run through the free lists, and just unlink anything found there. 521135446Strhodes * The memory isn't lost since these are part of message blocks we 522135446Strhodes * have allocated. 523135446Strhodes */ 524135446Strhodes rdata = ISC_LIST_HEAD(msg->freerdata); 525135446Strhodes while (rdata != NULL) { 526135446Strhodes ISC_LIST_UNLINK(msg->freerdata, rdata, link); 527135446Strhodes rdata = ISC_LIST_HEAD(msg->freerdata); 528135446Strhodes } 529135446Strhodes rdatalist = ISC_LIST_HEAD(msg->freerdatalist); 530135446Strhodes while (rdatalist != NULL) { 531135446Strhodes ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link); 532135446Strhodes rdatalist = ISC_LIST_HEAD(msg->freerdatalist); 533135446Strhodes } 534135446Strhodes 535135446Strhodes dynbuf = ISC_LIST_HEAD(msg->scratchpad); 536135446Strhodes INSIST(dynbuf != NULL); 537193149Sdougb if (!everything) { 538135446Strhodes isc_buffer_clear(dynbuf); 539135446Strhodes dynbuf = ISC_LIST_NEXT(dynbuf, link); 540135446Strhodes } 541135446Strhodes while (dynbuf != NULL) { 542135446Strhodes next_dynbuf = ISC_LIST_NEXT(dynbuf, link); 543135446Strhodes ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link); 544135446Strhodes isc_buffer_free(&dynbuf); 545135446Strhodes dynbuf = next_dynbuf; 546135446Strhodes } 547135446Strhodes 548135446Strhodes msgblock = ISC_LIST_HEAD(msg->rdatas); 549135446Strhodes if (!everything && msgblock != NULL) { 550135446Strhodes msgblock_reset(msgblock); 551135446Strhodes msgblock = ISC_LIST_NEXT(msgblock, link); 552135446Strhodes } 553135446Strhodes while (msgblock != NULL) { 554135446Strhodes next_msgblock = ISC_LIST_NEXT(msgblock, link); 555135446Strhodes ISC_LIST_UNLINK(msg->rdatas, msgblock, link); 556135446Strhodes msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t)); 557135446Strhodes msgblock = next_msgblock; 558135446Strhodes } 559135446Strhodes 560135446Strhodes /* 561135446Strhodes * rdatalists could be empty. 562135446Strhodes */ 563135446Strhodes 564135446Strhodes msgblock = ISC_LIST_HEAD(msg->rdatalists); 565135446Strhodes if (!everything && msgblock != NULL) { 566135446Strhodes msgblock_reset(msgblock); 567135446Strhodes msgblock = ISC_LIST_NEXT(msgblock, link); 568135446Strhodes } 569135446Strhodes while (msgblock != NULL) { 570135446Strhodes next_msgblock = ISC_LIST_NEXT(msgblock, link); 571135446Strhodes ISC_LIST_UNLINK(msg->rdatalists, msgblock, link); 572135446Strhodes msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t)); 573135446Strhodes msgblock = next_msgblock; 574135446Strhodes } 575225361Sdougb 576135446Strhodes msgblock = ISC_LIST_HEAD(msg->offsets); 577135446Strhodes if (!everything && msgblock != NULL) { 578225361Sdougb msgblock_reset(msgblock); 579135446Strhodes msgblock = ISC_LIST_NEXT(msgblock, link); 580135446Strhodes } 581225361Sdougb while (msgblock != NULL) { 582135446Strhodes next_msgblock = ISC_LIST_NEXT(msgblock, link); 583135446Strhodes ISC_LIST_UNLINK(msg->offsets, msgblock, link); 584225361Sdougb msgblock_free(msg->mctx, msgblock, sizeof(dns_offsets_t)); 585135446Strhodes msgblock = next_msgblock; 586135446Strhodes } 587225361Sdougb 588135446Strhodes if (msg->tsigkey != NULL) { 589135446Strhodes dns_tsigkey_detach(&msg->tsigkey); 590225361Sdougb msg->tsigkey = NULL; 591135446Strhodes } 592135446Strhodes 593225361Sdougb if (msg->query.base != NULL) { 594135446Strhodes if (msg->free_query != 0) 595135446Strhodes isc_mem_put(msg->mctx, msg->query.base, 596225361Sdougb msg->query.length); 597135446Strhodes msg->query.base = NULL; 598225361Sdougb msg->query.length = 0; 599135446Strhodes } 600135446Strhodes 601135446Strhodes if (msg->saved.base != NULL) { 602225361Sdougb if (msg->free_saved != 0) 603135446Strhodes isc_mem_put(msg->mctx, msg->saved.base, 604135446Strhodes msg->saved.length); 605135446Strhodes msg->saved.base = NULL; 606135446Strhodes msg->saved.length = 0; 607135446Strhodes } 608135446Strhodes 609135446Strhodes /* 610135446Strhodes * cleanup the buffer cleanup list 611135446Strhodes */ 612135446Strhodes dynbuf = ISC_LIST_HEAD(msg->cleanup); 613193149Sdougb while (dynbuf != NULL) { 614135446Strhodes next_dynbuf = ISC_LIST_NEXT(dynbuf, link); 615135446Strhodes ISC_LIST_UNLINK(msg->cleanup, dynbuf, link); 616135446Strhodes isc_buffer_free(&dynbuf); 617135446Strhodes dynbuf = next_dynbuf; 618135446Strhodes } 619135446Strhodes 620135446Strhodes /* 621193149Sdougb * Set other bits to normal default values. 622135446Strhodes */ 623135446Strhodes if (!everything) 624135446Strhodes msginit(msg); 625193149Sdougb 626135446Strhodes ENSURE(isc_mempool_getallocated(msg->namepool) == 0); 627135446Strhodes ENSURE(isc_mempool_getallocated(msg->rdspool) == 0); 628135446Strhodes} 629193149Sdougb 630135446Strhodesstatic unsigned int 631170222Sdougbspacefortsig(dns_tsigkey_t *key, int otherlen) { 632135446Strhodes isc_region_t r1, r2; 633135446Strhodes unsigned int x; 634170222Sdougb isc_result_t result; 635193149Sdougb 636135446Strhodes /* 637135446Strhodes * The space required for an TSIG record is: 638135446Strhodes * 639135446Strhodes * n1 bytes for the name 640135446Strhodes * 2 bytes for the type 641135446Strhodes * 2 bytes for the class 642135446Strhodes * 4 bytes for the ttl 643135446Strhodes * 2 bytes for the rdlength 644135446Strhodes * n2 bytes for the algorithm name 645170222Sdougb * 6 bytes for the time signed 646170222Sdougb * 2 bytes for the fudge 647170222Sdougb * 2 bytes for the MAC size 648170222Sdougb * x bytes for the MAC 649135446Strhodes * 2 bytes for the original id 650193149Sdougb * 2 bytes for the error 651135446Strhodes * 2 bytes for the other data length 652135446Strhodes * y bytes for the other data (at most) 653135446Strhodes * --------------------------------- 654135446Strhodes * 26 + n1 + n2 + x + y bytes 655135446Strhodes */ 656135446Strhodes 657135446Strhodes dns_name_toregion(&key->name, &r1); 658135446Strhodes dns_name_toregion(key->algorithm, &r2); 659135446Strhodes if (key->key == NULL) 660135446Strhodes x = 0; 661135446Strhodes else { 662135446Strhodes result = dst_key_sigsize(key->key, &x); 663135446Strhodes if (result != ISC_R_SUCCESS) 664135446Strhodes x = 0; 665135446Strhodes } 666135446Strhodes return (26 + r1.length + r2.length + x + otherlen); 667135446Strhodes} 668135446Strhodes 669135446Strhodesisc_result_t 670135446Strhodesdns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp) 671135446Strhodes{ 672135446Strhodes dns_message_t *m; 673135446Strhodes isc_result_t result; 674135446Strhodes isc_buffer_t *dynbuf; 675135446Strhodes unsigned int i; 676135446Strhodes 677135446Strhodes REQUIRE(mctx != NULL); 678135446Strhodes REQUIRE(msgp != NULL); 679135446Strhodes REQUIRE(*msgp == NULL); 680135446Strhodes REQUIRE(intent == DNS_MESSAGE_INTENTPARSE 681225361Sdougb || intent == DNS_MESSAGE_INTENTRENDER); 682135446Strhodes 683135446Strhodes m = isc_mem_get(mctx, sizeof(dns_message_t)); 684135446Strhodes if (m == NULL) 685225361Sdougb return (ISC_R_NOMEMORY); 686135446Strhodes 687135446Strhodes /* 688135446Strhodes * No allocations until further notice. Just initialize all lists 689135446Strhodes * and other members that are freed in the cleanup phase here. 690135446Strhodes */ 691135446Strhodes 692135446Strhodes m->magic = DNS_MESSAGE_MAGIC; 693135446Strhodes m->from_to_wire = intent; 694135446Strhodes msginit(m); 695135446Strhodes 696135446Strhodes for (i = 0; i < DNS_SECTION_MAX; i++) 697135446Strhodes ISC_LIST_INIT(m->sections[i]); 698135446Strhodes m->mctx = mctx; 699135446Strhodes 700135446Strhodes ISC_LIST_INIT(m->scratchpad); 701135446Strhodes ISC_LIST_INIT(m->cleanup); 702135446Strhodes m->namepool = NULL; 703135446Strhodes m->rdspool = NULL; 704135446Strhodes ISC_LIST_INIT(m->rdatas); 705135446Strhodes ISC_LIST_INIT(m->rdatalists); 706135446Strhodes ISC_LIST_INIT(m->offsets); 707170222Sdougb ISC_LIST_INIT(m->freerdata); 708170222Sdougb ISC_LIST_INIT(m->freerdatalist); 709135446Strhodes 710135446Strhodes /* 711135446Strhodes * Ok, it is safe to allocate (and then "goto cleanup" if failure) 712135446Strhodes */ 713135446Strhodes 714135446Strhodes result = isc_mempool_create(m->mctx, sizeof(dns_name_t), &m->namepool); 715135446Strhodes if (result != ISC_R_SUCCESS) 716135446Strhodes goto cleanup; 717135446Strhodes isc_mempool_setfreemax(m->namepool, NAME_COUNT); 718135446Strhodes isc_mempool_setname(m->namepool, "msg:names"); 719135446Strhodes 720135446Strhodes result = isc_mempool_create(m->mctx, sizeof(dns_rdataset_t), 721135446Strhodes &m->rdspool); 722135446Strhodes if (result != ISC_R_SUCCESS) 723135446Strhodes goto cleanup; 724135446Strhodes isc_mempool_setfreemax(m->rdspool, NAME_COUNT); 725135446Strhodes isc_mempool_setname(m->rdspool, "msg:rdataset"); 726135446Strhodes 727135446Strhodes dynbuf = NULL; 728165071Sdougb result = isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE); 729135446Strhodes if (result != ISC_R_SUCCESS) 730135446Strhodes goto cleanup; 731135446Strhodes ISC_LIST_APPEND(m->scratchpad, dynbuf, link); 732135446Strhodes 733135446Strhodes m->cctx = NULL; 734135446Strhodes 735135446Strhodes *msgp = m; 736135446Strhodes return (ISC_R_SUCCESS); 737135446Strhodes 738135446Strhodes /* 739135446Strhodes * Cleanup for error returns. 740135446Strhodes */ 741135446Strhodes cleanup: 742135446Strhodes dynbuf = ISC_LIST_HEAD(m->scratchpad); 743135446Strhodes if (dynbuf != NULL) { 744135446Strhodes ISC_LIST_UNLINK(m->scratchpad, dynbuf, link); 745135446Strhodes isc_buffer_free(&dynbuf); 746143731Sdougb } 747135446Strhodes if (m->namepool != NULL) 748170222Sdougb isc_mempool_destroy(&m->namepool); 749143731Sdougb if (m->rdspool != NULL) 750135446Strhodes isc_mempool_destroy(&m->rdspool); 751135446Strhodes m->magic = 0; 752135446Strhodes isc_mem_put(mctx, m, sizeof(dns_message_t)); 753135446Strhodes 754135446Strhodes return (ISC_R_NOMEMORY); 755135446Strhodes} 756135446Strhodes 757135446Strhodesvoid 758135446Strhodesdns_message_reset(dns_message_t *msg, unsigned int intent) { 759135446Strhodes REQUIRE(DNS_MESSAGE_VALID(msg)); 760135446Strhodes REQUIRE(intent == DNS_MESSAGE_INTENTPARSE 761135446Strhodes || intent == DNS_MESSAGE_INTENTRENDER); 762135446Strhodes 763135446Strhodes msgreset(msg, ISC_FALSE); 764135446Strhodes msg->from_to_wire = intent; 765135446Strhodes} 766135446Strhodes 767135446Strhodesvoid 768135446Strhodesdns_message_destroy(dns_message_t **msgp) { 769135446Strhodes dns_message_t *msg; 770135446Strhodes 771135446Strhodes REQUIRE(msgp != NULL); 772135446Strhodes REQUIRE(DNS_MESSAGE_VALID(*msgp)); 773135446Strhodes 774135446Strhodes msg = *msgp; 775135446Strhodes *msgp = NULL; 776135446Strhodes 777135446Strhodes msgreset(msg, ISC_TRUE); 778135446Strhodes isc_mempool_destroy(&msg->namepool); 779135446Strhodes isc_mempool_destroy(&msg->rdspool); 780135446Strhodes msg->magic = 0; 781135446Strhodes isc_mem_put(msg->mctx, msg, sizeof(dns_message_t)); 782135446Strhodes} 783135446Strhodes 784135446Strhodesstatic isc_result_t 785135446Strhodesfindname(dns_name_t **foundname, dns_name_t *target, 786135446Strhodes dns_namelist_t *section) 787170222Sdougb{ 788170222Sdougb dns_name_t *curr; 789170222Sdougb 790135446Strhodes for (curr = ISC_LIST_TAIL(*section); 791135446Strhodes curr != NULL; 792135446Strhodes curr = ISC_LIST_PREV(curr, link)) { 793135446Strhodes if (dns_name_equal(curr, target)) { 794135446Strhodes if (foundname != NULL) 795135446Strhodes *foundname = curr; 796135446Strhodes return (ISC_R_SUCCESS); 797135446Strhodes } 798135446Strhodes } 799135446Strhodes 800135446Strhodes return (ISC_R_NOTFOUND); 801135446Strhodes} 802135446Strhodes 803135446Strhodesisc_result_t 804135446Strhodesdns_message_findtype(dns_name_t *name, dns_rdatatype_t type, 805135446Strhodes dns_rdatatype_t covers, dns_rdataset_t **rdataset) 806135446Strhodes{ 807135446Strhodes dns_rdataset_t *curr; 808135446Strhodes 809135446Strhodes if (rdataset != NULL) { 810135446Strhodes REQUIRE(*rdataset == NULL); 811135446Strhodes } 812135446Strhodes 813135446Strhodes for (curr = ISC_LIST_TAIL(name->list); 814135446Strhodes curr != NULL; 815135446Strhodes curr = ISC_LIST_PREV(curr, link)) { 816135446Strhodes if (curr->type == type && curr->covers == covers) { 817135446Strhodes if (rdataset != NULL) 818135446Strhodes *rdataset = curr; 819135446Strhodes return (ISC_R_SUCCESS); 820135446Strhodes } 821135446Strhodes } 822135446Strhodes 823135446Strhodes return (ISC_R_NOTFOUND); 824135446Strhodes} 825135446Strhodes 826135446Strhodes/* 827135446Strhodes * Read a name from buffer "source". 828135446Strhodes */ 829135446Strhodesstatic isc_result_t 830135446Strhodesgetname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg, 831135446Strhodes dns_decompress_t *dctx) 832135446Strhodes{ 833135446Strhodes isc_buffer_t *scratch; 834135446Strhodes isc_result_t result; 835135446Strhodes unsigned int tries; 836135446Strhodes 837135446Strhodes scratch = currentbuffer(msg); 838135446Strhodes 839135446Strhodes /* 840135446Strhodes * First try: use current buffer. 841135446Strhodes * Second try: allocate a new buffer and use that. 842135446Strhodes */ 843135446Strhodes tries = 0; 844135446Strhodes while (tries < 2) { 845135446Strhodes result = dns_name_fromwire(name, source, dctx, ISC_FALSE, 846135446Strhodes scratch); 847135446Strhodes 848135446Strhodes if (result == ISC_R_NOSPACE) { 849135446Strhodes tries++; 850135446Strhodes 851135446Strhodes result = newbuffer(msg, SCRATCHPAD_SIZE); 852135446Strhodes if (result != ISC_R_SUCCESS) 853135446Strhodes return (result); 854135446Strhodes 855135446Strhodes scratch = currentbuffer(msg); 856135446Strhodes dns_name_reset(name); 857135446Strhodes } else { 858135446Strhodes return (result); 859135446Strhodes } 860135446Strhodes } 861135446Strhodes 862135446Strhodes INSIST(0); /* Cannot get here... */ 863135446Strhodes return (ISC_R_UNEXPECTED); 864135446Strhodes} 865135446Strhodes 866170222Sdougbstatic isc_result_t 867170222Sdougbgetrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, 868135446Strhodes dns_rdataclass_t rdclass, dns_rdatatype_t rdtype, 869135446Strhodes unsigned int rdatalen, dns_rdata_t *rdata) 870135446Strhodes{ 871135446Strhodes isc_buffer_t *scratch; 872135446Strhodes isc_result_t result; 873135446Strhodes unsigned int tries; 874135446Strhodes unsigned int trysize; 875135446Strhodes 876135446Strhodes scratch = currentbuffer(msg); 877135446Strhodes 878135446Strhodes isc_buffer_setactive(source, rdatalen); 879135446Strhodes 880135446Strhodes /* 881135446Strhodes * First try: use current buffer. 882135446Strhodes * Second try: allocate a new buffer of size 883135446Strhodes * max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen) 884135446Strhodes * (the data will fit if it was not more than 50% compressed) 885135446Strhodes * Subsequent tries: double buffer size on each try. 886135446Strhodes */ 887135446Strhodes tries = 0; 888135446Strhodes trysize = 0; 889135446Strhodes /* XXX possibly change this to a while (tries < 2) loop */ 890135446Strhodes for (;;) { 891135446Strhodes result = dns_rdata_fromwire(rdata, rdclass, rdtype, 892135446Strhodes source, dctx, 0, 893135446Strhodes scratch); 894135446Strhodes 895135446Strhodes if (result == ISC_R_NOSPACE) { 896135446Strhodes if (tries == 0) { 897245163Serwin trysize = 2 * rdatalen; 898135446Strhodes if (trysize < SCRATCHPAD_SIZE) 899 trysize = SCRATCHPAD_SIZE; 900 } else { 901 INSIST(trysize != 0); 902 if (trysize >= 65535) 903 return (ISC_R_NOSPACE); 904 /* XXX DNS_R_RRTOOLONG? */ 905 trysize *= 2; 906 } 907 tries++; 908 result = newbuffer(msg, trysize); 909 if (result != ISC_R_SUCCESS) 910 return (result); 911 912 scratch = currentbuffer(msg); 913 } else { 914 return (result); 915 } 916 } 917} 918 919#define DO_FORMERR \ 920 do { \ 921 if (best_effort) \ 922 seen_problem = ISC_TRUE; \ 923 else { \ 924 result = DNS_R_FORMERR; \ 925 goto cleanup; \ 926 } \ 927 } while (0) 928 929static isc_result_t 930getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, 931 unsigned int options) 932{ 933 isc_region_t r; 934 unsigned int count; 935 dns_name_t *name; 936 dns_name_t *name2; 937 dns_offsets_t *offsets; 938 dns_rdataset_t *rdataset; 939 dns_rdatalist_t *rdatalist; 940 isc_result_t result; 941 dns_rdatatype_t rdtype; 942 dns_rdataclass_t rdclass; 943 dns_namelist_t *section; 944 isc_boolean_t free_name; 945 isc_boolean_t best_effort; 946 isc_boolean_t seen_problem; 947 948 section = &msg->sections[DNS_SECTION_QUESTION]; 949 950 best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT); 951 seen_problem = ISC_FALSE; 952 953 name = NULL; 954 rdataset = NULL; 955 rdatalist = NULL; 956 957 for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) { 958 name = isc_mempool_get(msg->namepool); 959 if (name == NULL) 960 return (ISC_R_NOMEMORY); 961 free_name = ISC_TRUE; 962 963 offsets = newoffsets(msg); 964 if (offsets == NULL) { 965 result = ISC_R_NOMEMORY; 966 goto cleanup; 967 } 968 dns_name_init(name, *offsets); 969 970 /* 971 * Parse the name out of this packet. 972 */ 973 isc_buffer_remainingregion(source, &r); 974 isc_buffer_setactive(source, r.length); 975 result = getname(name, source, msg, dctx); 976 if (result != ISC_R_SUCCESS) 977 goto cleanup; 978 979 /* 980 * Run through the section, looking to see if this name 981 * is already there. If it is found, put back the allocated 982 * name since we no longer need it, and set our name pointer 983 * to point to the name we found. 984 */ 985 result = findname(&name2, name, section); 986 987 /* 988 * If it is the first name in the section, accept it. 989 * 990 * If it is not, but is not the same as the name already 991 * in the question section, append to the section. Note that 992 * here in the question section this is illegal, so return 993 * FORMERR. In the future, check the opcode to see if 994 * this should be legal or not. In either case we no longer 995 * need this name pointer. 996 */ 997 if (result != ISC_R_SUCCESS) { 998 if (!ISC_LIST_EMPTY(*section)) 999 DO_FORMERR; 1000 ISC_LIST_APPEND(*section, name, link); 1001 free_name = ISC_FALSE; 1002 } else { 1003 isc_mempool_put(msg->namepool, name); 1004 name = name2; 1005 name2 = NULL; 1006 free_name = ISC_FALSE; 1007 } 1008 1009 /* 1010 * Get type and class. 1011 */ 1012 isc_buffer_remainingregion(source, &r); 1013 if (r.length < 4) { 1014 result = ISC_R_UNEXPECTEDEND; 1015 goto cleanup; 1016 } 1017 rdtype = isc_buffer_getuint16(source); 1018 rdclass = isc_buffer_getuint16(source); 1019 1020 /* 1021 * If this class is different than the one we already read, 1022 * this is an error. 1023 */ 1024 if (msg->state == DNS_SECTION_ANY) { 1025 msg->state = DNS_SECTION_QUESTION; 1026 msg->rdclass = rdclass; 1027 } else if (msg->rdclass != rdclass) 1028 DO_FORMERR; 1029 1030 /* 1031 * Can't ask the same question twice. 1032 */ 1033 result = dns_message_findtype(name, rdtype, 0, NULL); 1034 if (result == ISC_R_SUCCESS) 1035 DO_FORMERR; 1036 1037 /* 1038 * Allocate a new rdatalist. 1039 */ 1040 rdatalist = newrdatalist(msg); 1041 if (rdatalist == NULL) { 1042 result = ISC_R_NOMEMORY; 1043 goto cleanup; 1044 } 1045 rdataset = isc_mempool_get(msg->rdspool); 1046 if (rdataset == NULL) { 1047 result = ISC_R_NOMEMORY; 1048 goto cleanup; 1049 } 1050 1051 /* 1052 * Convert rdatalist to rdataset, and attach the latter to 1053 * the name. 1054 */ 1055 rdatalist->type = rdtype; 1056 rdatalist->covers = 0; 1057 rdatalist->rdclass = rdclass; 1058 rdatalist->ttl = 0; 1059 ISC_LIST_INIT(rdatalist->rdata); 1060 1061 dns_rdataset_init(rdataset); 1062 result = dns_rdatalist_tordataset(rdatalist, rdataset); 1063 if (result != ISC_R_SUCCESS) 1064 goto cleanup; 1065 1066 rdataset->attributes |= DNS_RDATASETATTR_QUESTION; 1067 1068 ISC_LIST_APPEND(name->list, rdataset, link); 1069 rdataset = NULL; 1070 } 1071 1072 if (seen_problem) 1073 return (DNS_R_RECOVERABLE); 1074 return (ISC_R_SUCCESS); 1075 1076 cleanup: 1077 if (rdataset != NULL) { 1078 INSIST(!dns_rdataset_isassociated(rdataset)); 1079 isc_mempool_put(msg->rdspool, rdataset); 1080 } 1081#if 0 1082 if (rdatalist != NULL) 1083 isc_mempool_put(msg->rdlpool, rdatalist); 1084#endif 1085 if (free_name) 1086 isc_mempool_put(msg->namepool, name); 1087 1088 return (result); 1089} 1090 1091static isc_boolean_t 1092update(dns_section_t section, dns_rdataclass_t rdclass) { 1093 if (section == DNS_SECTION_PREREQUISITE) 1094 return (ISC_TF(rdclass == dns_rdataclass_any || 1095 rdclass == dns_rdataclass_none)); 1096 if (section == DNS_SECTION_UPDATE) 1097 return (ISC_TF(rdclass == dns_rdataclass_any)); 1098 return (ISC_FALSE); 1099} 1100 1101static isc_result_t 1102getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, 1103 dns_section_t sectionid, unsigned int options) 1104{ 1105 isc_region_t r; 1106 unsigned int count, rdatalen; 1107 dns_name_t *name; 1108 dns_name_t *name2; 1109 dns_offsets_t *offsets; 1110 dns_rdataset_t *rdataset; 1111 dns_rdatalist_t *rdatalist; 1112 isc_result_t result; 1113 dns_rdatatype_t rdtype, covers; 1114 dns_rdataclass_t rdclass; 1115 dns_rdata_t *rdata; 1116 dns_ttl_t ttl; 1117 dns_namelist_t *section; 1118 isc_boolean_t free_name, free_rdataset; 1119 isc_boolean_t preserve_order, best_effort, seen_problem; 1120 isc_boolean_t issigzero; 1121 1122 preserve_order = ISC_TF(options & DNS_MESSAGEPARSE_PRESERVEORDER); 1123 best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT); 1124 seen_problem = ISC_FALSE; 1125 1126 for (count = 0; count < msg->counts[sectionid]; count++) { 1127 int recstart = source->current; 1128 isc_boolean_t skip_name_search, skip_type_search; 1129 1130 section = &msg->sections[sectionid]; 1131 1132 skip_name_search = ISC_FALSE; 1133 skip_type_search = ISC_FALSE; 1134 free_name = ISC_FALSE; 1135 free_rdataset = ISC_FALSE; 1136 1137 name = isc_mempool_get(msg->namepool); 1138 if (name == NULL) 1139 return (ISC_R_NOMEMORY); 1140 free_name = ISC_TRUE; 1141 1142 offsets = newoffsets(msg); 1143 if (offsets == NULL) { 1144 result = ISC_R_NOMEMORY; 1145 goto cleanup; 1146 } 1147 dns_name_init(name, *offsets); 1148 1149 /* 1150 * Parse the name out of this packet. 1151 */ 1152 isc_buffer_remainingregion(source, &r); 1153 isc_buffer_setactive(source, r.length); 1154 result = getname(name, source, msg, dctx); 1155 if (result != ISC_R_SUCCESS) 1156 goto cleanup; 1157 1158 /* 1159 * Get type, class, ttl, and rdatalen. Verify that at least 1160 * rdatalen bytes remain. (Some of this is deferred to 1161 * later.) 1162 */ 1163 isc_buffer_remainingregion(source, &r); 1164 if (r.length < 2 + 2 + 4 + 2) { 1165 result = ISC_R_UNEXPECTEDEND; 1166 goto cleanup; 1167 } 1168 rdtype = isc_buffer_getuint16(source); 1169 rdclass = isc_buffer_getuint16(source); 1170 1171 /* 1172 * If there was no question section, we may not yet have 1173 * established a class. Do so now. 1174 */ 1175 if (msg->state == DNS_SECTION_ANY && 1176 rdtype != dns_rdatatype_opt && /* class is UDP SIZE */ 1177 rdtype != dns_rdatatype_tsig && /* class is ANY */ 1178 rdtype != dns_rdatatype_tkey) { /* class is undefined */ 1179 msg->rdclass = rdclass; 1180 msg->state = DNS_SECTION_QUESTION; 1181 } 1182 1183 /* 1184 * If this class is different than the one in the question 1185 * section, bail. 1186 */ 1187 if (msg->opcode != dns_opcode_update 1188 && rdtype != dns_rdatatype_tsig 1189 && rdtype != dns_rdatatype_opt 1190 && rdtype != dns_rdatatype_dnskey /* in a TKEY query */ 1191 && rdtype != dns_rdatatype_sig /* SIG(0) */ 1192 && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */ 1193 && msg->rdclass != rdclass) 1194 DO_FORMERR; 1195 1196 /* 1197 * Special type handling for TSIG, OPT, and TKEY. 1198 */ 1199 if (rdtype == dns_rdatatype_tsig) { 1200 /* 1201 * If it is a tsig, verify that it is in the 1202 * additional data section. 1203 */ 1204 if (sectionid != DNS_SECTION_ADDITIONAL || 1205 rdclass != dns_rdataclass_any || 1206 count != msg->counts[sectionid] - 1) 1207 DO_FORMERR; 1208 msg->sigstart = recstart; 1209 skip_name_search = ISC_TRUE; 1210 skip_type_search = ISC_TRUE; 1211 } else if (rdtype == dns_rdatatype_opt) { 1212 /* 1213 * The name of an OPT record must be ".", it 1214 * must be in the additional data section, and 1215 * it must be the first OPT we've seen. 1216 */ 1217 if (!dns_name_equal(dns_rootname, name) || 1218 msg->opt != NULL) 1219 DO_FORMERR; 1220 skip_name_search = ISC_TRUE; 1221 skip_type_search = ISC_TRUE; 1222 } else if (rdtype == dns_rdatatype_tkey) { 1223 /* 1224 * A TKEY must be in the additional section if this 1225 * is a query, and the answer section if this is a 1226 * response. Unless it's a Win2000 client. 1227 * 1228 * Its class is ignored. 1229 */ 1230 dns_section_t tkeysection; 1231 1232 if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0) 1233 tkeysection = DNS_SECTION_ADDITIONAL; 1234 else 1235 tkeysection = DNS_SECTION_ANSWER; 1236 if (sectionid != tkeysection && 1237 sectionid != DNS_SECTION_ANSWER) 1238 DO_FORMERR; 1239 } 1240 1241 /* 1242 * ... now get ttl and rdatalen, and check buffer. 1243 */ 1244 ttl = isc_buffer_getuint32(source); 1245 rdatalen = isc_buffer_getuint16(source); 1246 r.length -= (2 + 2 + 4 + 2); 1247 if (r.length < rdatalen) { 1248 result = ISC_R_UNEXPECTEDEND; 1249 goto cleanup; 1250 } 1251 1252 /* 1253 * Read the rdata from the wire format. Interpret the 1254 * rdata according to its actual class, even if it had a 1255 * DynDNS meta-class in the packet (unless this is a TSIG). 1256 * Then put the meta-class back into the finished rdata. 1257 */ 1258 rdata = newrdata(msg); 1259 if (rdata == NULL) { 1260 result = ISC_R_NOMEMORY; 1261 goto cleanup; 1262 } 1263 if (msg->opcode == dns_opcode_update && 1264 update(sectionid, rdclass)) { 1265 if (rdatalen != 0) { 1266 result = DNS_R_FORMERR; 1267 goto cleanup; 1268 } 1269 /* 1270 * When the rdata is empty, the data pointer is 1271 * never dereferenced, but it must still be non-NULL. 1272 * Casting 1 rather than "" avoids warnings about 1273 * discarding the const attribute of a string, 1274 * for compilers that would warn about such things. 1275 */ 1276 rdata->data = (unsigned char *)1; 1277 rdata->length = 0; 1278 rdata->rdclass = rdclass; 1279 rdata->type = rdtype; 1280 rdata->flags = DNS_RDATA_UPDATE; 1281 result = ISC_R_SUCCESS; 1282 } else if (rdtype == dns_rdatatype_tsig) 1283 result = getrdata(source, msg, dctx, rdclass, 1284 rdtype, rdatalen, rdata); 1285 else 1286 result = getrdata(source, msg, dctx, msg->rdclass, 1287 rdtype, rdatalen, rdata); 1288 if (result != ISC_R_SUCCESS) 1289 goto cleanup; 1290 rdata->rdclass = rdclass; 1291 issigzero = ISC_FALSE; 1292 if (rdtype == dns_rdatatype_rrsig && 1293 rdata->flags == 0) { 1294 covers = dns_rdata_covers(rdata); 1295 if (covers == 0) 1296 DO_FORMERR; 1297 } else if (rdtype == dns_rdatatype_sig /* SIG(0) */ && 1298 rdata->flags == 0) { 1299 covers = dns_rdata_covers(rdata); 1300 if (covers == 0) { 1301 if (sectionid != DNS_SECTION_ADDITIONAL || 1302 count != msg->counts[sectionid] - 1) 1303 DO_FORMERR; 1304 msg->sigstart = recstart; 1305 skip_name_search = ISC_TRUE; 1306 skip_type_search = ISC_TRUE; 1307 issigzero = ISC_TRUE; 1308 } 1309 } else 1310 covers = 0; 1311 1312 /* 1313 * If we are doing a dynamic update or this is a meta-type, 1314 * don't bother searching for a name, just append this one 1315 * to the end of the message. 1316 */ 1317 if (preserve_order || msg->opcode == dns_opcode_update || 1318 skip_name_search) { 1319 if (rdtype != dns_rdatatype_opt && 1320 rdtype != dns_rdatatype_tsig && 1321 !issigzero) 1322 { 1323 ISC_LIST_APPEND(*section, name, link); 1324 free_name = ISC_FALSE; 1325 } 1326 } else { 1327 /* 1328 * Run through the section, looking to see if this name 1329 * is already there. If it is found, put back the 1330 * allocated name since we no longer need it, and set 1331 * our name pointer to point to the name we found. 1332 */ 1333 result = findname(&name2, name, section); 1334 1335 /* 1336 * If it is a new name, append to the section. 1337 */ 1338 if (result == ISC_R_SUCCESS) { 1339 isc_mempool_put(msg->namepool, name); 1340 name = name2; 1341 } else { 1342 ISC_LIST_APPEND(*section, name, link); 1343 } 1344 free_name = ISC_FALSE; 1345 } 1346 1347 /* 1348 * Search name for the particular type and class. 1349 * Skip this stage if in update mode or this is a meta-type. 1350 */ 1351 if (preserve_order || msg->opcode == dns_opcode_update || 1352 skip_type_search) 1353 result = ISC_R_NOTFOUND; 1354 else { 1355 /* 1356 * If this is a type that can only occur in 1357 * the question section, fail. 1358 */ 1359 if (dns_rdatatype_questiononly(rdtype)) 1360 DO_FORMERR; 1361 1362 rdataset = NULL; 1363 result = dns_message_findtype(name, rdtype, covers, 1364 &rdataset); 1365 } 1366 1367 /* 1368 * If we found an rdataset that matches, we need to 1369 * append this rdata to that set. If we did not, we need 1370 * to create a new rdatalist, store the important bits there, 1371 * convert it to an rdataset, and link the latter to the name. 1372 * Yuck. When appending, make certain that the type isn't 1373 * a singleton type, such as SOA or CNAME. 1374 * 1375 * Note that this check will be bypassed when preserving order, 1376 * the opcode is an update, or the type search is skipped. 1377 */ 1378 if (result == ISC_R_SUCCESS) { 1379 if (dns_rdatatype_issingleton(rdtype)) 1380 DO_FORMERR; 1381 } 1382 1383 if (result == ISC_R_NOTFOUND) { 1384 rdataset = isc_mempool_get(msg->rdspool); 1385 if (rdataset == NULL) { 1386 result = ISC_R_NOMEMORY; 1387 goto cleanup; 1388 } 1389 free_rdataset = ISC_TRUE; 1390 1391 rdatalist = newrdatalist(msg); 1392 if (rdatalist == NULL) { 1393 result = ISC_R_NOMEMORY; 1394 goto cleanup; 1395 } 1396 1397 rdatalist->type = rdtype; 1398 rdatalist->covers = covers; 1399 rdatalist->rdclass = rdclass; 1400 rdatalist->ttl = ttl; 1401 ISC_LIST_INIT(rdatalist->rdata); 1402 1403 dns_rdataset_init(rdataset); 1404 RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, 1405 rdataset) 1406 == ISC_R_SUCCESS); 1407 1408 if (rdtype != dns_rdatatype_opt && 1409 rdtype != dns_rdatatype_tsig && 1410 !issigzero) 1411 { 1412 ISC_LIST_APPEND(name->list, rdataset, link); 1413 free_rdataset = ISC_FALSE; 1414 } 1415 } 1416 1417 /* 1418 * Minimize TTLs. 1419 * 1420 * Section 5.2 of RFC 2181 says we should drop 1421 * nonauthoritative rrsets where the TTLs differ, but we 1422 * currently treat them the as if they were authoritative and 1423 * minimize them. 1424 */ 1425 if (ttl != rdataset->ttl) { 1426 rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED; 1427 if (ttl < rdataset->ttl) 1428 rdataset->ttl = ttl; 1429 } 1430 1431 /* 1432 * XXXMLG Perform a totally ugly hack here to pull 1433 * the rdatalist out of the private field in the rdataset, 1434 * and append this rdata to the rdatalist's linked list 1435 * of rdata. 1436 */ 1437 rdatalist = (dns_rdatalist_t *)(rdataset->private1); 1438 1439 ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 1440 1441 /* 1442 * If this is an OPT record, remember it. Also, set 1443 * the extended rcode. Note that msg->opt will only be set 1444 * if best-effort parsing is enabled. 1445 */ 1446 if (rdtype == dns_rdatatype_opt && msg->opt == NULL) { 1447 dns_rcode_t ercode; 1448 1449 msg->opt = rdataset; 1450 rdataset = NULL; 1451 free_rdataset = ISC_FALSE; 1452 ercode = (dns_rcode_t) 1453 ((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK) 1454 >> 20); 1455 msg->rcode |= ercode; 1456 isc_mempool_put(msg->namepool, name); 1457 free_name = ISC_FALSE; 1458 } 1459 1460 /* 1461 * If this is an SIG(0) or TSIG record, remember it. Note 1462 * that msg->sig0 or msg->tsig will only be set if best-effort 1463 * parsing is enabled. 1464 */ 1465 if (issigzero && msg->sig0 == NULL) { 1466 msg->sig0 = rdataset; 1467 msg->sig0name = name; 1468 rdataset = NULL; 1469 free_rdataset = ISC_FALSE; 1470 free_name = ISC_FALSE; 1471 } else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) { 1472 msg->tsig = rdataset; 1473 msg->tsigname = name; 1474 rdataset = NULL; 1475 free_rdataset = ISC_FALSE; 1476 free_name = ISC_FALSE; 1477 } 1478 1479 if (seen_problem) { 1480 if (free_name) 1481 isc_mempool_put(msg->namepool, name); 1482 if (free_rdataset) 1483 isc_mempool_put(msg->rdspool, rdataset); 1484 free_name = free_rdataset = ISC_FALSE; 1485 } 1486 INSIST(free_name == ISC_FALSE); 1487 INSIST(free_rdataset == ISC_FALSE); 1488 } 1489 1490 if (seen_problem) 1491 return (DNS_R_RECOVERABLE); 1492 return (ISC_R_SUCCESS); 1493 1494 cleanup: 1495 if (free_name) 1496 isc_mempool_put(msg->namepool, name); 1497 if (free_rdataset) 1498 isc_mempool_put(msg->rdspool, rdataset); 1499 1500 return (result); 1501} 1502 1503isc_result_t 1504dns_message_parse(dns_message_t *msg, isc_buffer_t *source, 1505 unsigned int options) 1506{ 1507 isc_region_t r; 1508 dns_decompress_t dctx; 1509 isc_result_t ret; 1510 isc_uint16_t tmpflags; 1511 isc_buffer_t origsource; 1512 isc_boolean_t seen_problem; 1513 isc_boolean_t ignore_tc; 1514 1515 REQUIRE(DNS_MESSAGE_VALID(msg)); 1516 REQUIRE(source != NULL); 1517 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE); 1518 1519 seen_problem = ISC_FALSE; 1520 ignore_tc = ISC_TF(options & DNS_MESSAGEPARSE_IGNORETRUNCATION); 1521 1522 origsource = *source; 1523 1524 msg->header_ok = 0; 1525 msg->question_ok = 0; 1526 1527 isc_buffer_remainingregion(source, &r); 1528 if (r.length < DNS_MESSAGE_HEADERLEN) 1529 return (ISC_R_UNEXPECTEDEND); 1530 1531 msg->id = isc_buffer_getuint16(source); 1532 tmpflags = isc_buffer_getuint16(source); 1533 msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK) 1534 >> DNS_MESSAGE_OPCODE_SHIFT); 1535 msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK); 1536 msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK); 1537 msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source); 1538 msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source); 1539 msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source); 1540 msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source); 1541 1542 msg->header_ok = 1; 1543 1544 /* 1545 * -1 means no EDNS. 1546 */ 1547 dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY); 1548 1549 dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14); 1550 1551 ret = getquestions(source, msg, &dctx, options); 1552 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) 1553 goto truncated; 1554 if (ret == DNS_R_RECOVERABLE) { 1555 seen_problem = ISC_TRUE; 1556 ret = ISC_R_SUCCESS; 1557 } 1558 if (ret != ISC_R_SUCCESS) 1559 return (ret); 1560 msg->question_ok = 1; 1561 1562 ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options); 1563 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) 1564 goto truncated; 1565 if (ret == DNS_R_RECOVERABLE) { 1566 seen_problem = ISC_TRUE; 1567 ret = ISC_R_SUCCESS; 1568 } 1569 if (ret != ISC_R_SUCCESS) 1570 return (ret); 1571 1572 ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options); 1573 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) 1574 goto truncated; 1575 if (ret == DNS_R_RECOVERABLE) { 1576 seen_problem = ISC_TRUE; 1577 ret = ISC_R_SUCCESS; 1578 } 1579 if (ret != ISC_R_SUCCESS) 1580 return (ret); 1581 1582 ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options); 1583 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) 1584 goto truncated; 1585 if (ret == DNS_R_RECOVERABLE) { 1586 seen_problem = ISC_TRUE; 1587 ret = ISC_R_SUCCESS; 1588 } 1589 if (ret != ISC_R_SUCCESS) 1590 return (ret); 1591 1592 isc_buffer_remainingregion(source, &r); 1593 if (r.length != 0) { 1594 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1595 DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3), 1596 "message has %u byte(s) of trailing garbage", 1597 r.length); 1598 } 1599 1600 truncated: 1601 if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0) 1602 isc_buffer_usedregion(&origsource, &msg->saved); 1603 else { 1604 msg->saved.length = isc_buffer_usedlength(&origsource); 1605 msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length); 1606 if (msg->saved.base == NULL) 1607 return (ISC_R_NOMEMORY); 1608 memcpy(msg->saved.base, isc_buffer_base(&origsource), 1609 msg->saved.length); 1610 msg->free_saved = 1; 1611 } 1612 1613 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) 1614 return (DNS_R_RECOVERABLE); 1615 if (seen_problem == ISC_TRUE) 1616 return (DNS_R_RECOVERABLE); 1617 return (ISC_R_SUCCESS); 1618} 1619 1620isc_result_t 1621dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx, 1622 isc_buffer_t *buffer) 1623{ 1624 isc_region_t r; 1625 1626 REQUIRE(DNS_MESSAGE_VALID(msg)); 1627 REQUIRE(buffer != NULL); 1628 REQUIRE(msg->buffer == NULL); 1629 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 1630 1631 msg->cctx = cctx; 1632 1633 /* 1634 * Erase the contents of this buffer. 1635 */ 1636 isc_buffer_clear(buffer); 1637 1638 /* 1639 * Make certain there is enough for at least the header in this 1640 * buffer. 1641 */ 1642 isc_buffer_availableregion(buffer, &r); 1643 if (r.length < DNS_MESSAGE_HEADERLEN) 1644 return (ISC_R_NOSPACE); 1645 1646 if (r.length < msg->reserved) 1647 return (ISC_R_NOSPACE); 1648 1649 /* 1650 * Reserve enough space for the header in this buffer. 1651 */ 1652 isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN); 1653 1654 msg->buffer = buffer; 1655 1656 return (ISC_R_SUCCESS); 1657} 1658 1659isc_result_t 1660dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) { 1661 isc_region_t r, rn; 1662 1663 REQUIRE(DNS_MESSAGE_VALID(msg)); 1664 REQUIRE(buffer != NULL); 1665 REQUIRE(msg->buffer != NULL); 1666 1667 /* 1668 * Ensure that the new buffer is empty, and has enough space to 1669 * hold the current contents. 1670 */ 1671 isc_buffer_clear(buffer); 1672 1673 isc_buffer_availableregion(buffer, &rn); 1674 isc_buffer_usedregion(msg->buffer, &r); 1675 REQUIRE(rn.length > r.length); 1676 1677 /* 1678 * Copy the contents from the old to the new buffer. 1679 */ 1680 isc_buffer_add(buffer, r.length); 1681 memcpy(rn.base, r.base, r.length); 1682 1683 msg->buffer = buffer; 1684 1685 return (ISC_R_SUCCESS); 1686} 1687 1688void 1689dns_message_renderrelease(dns_message_t *msg, unsigned int space) { 1690 REQUIRE(DNS_MESSAGE_VALID(msg)); 1691 REQUIRE(space <= msg->reserved); 1692 1693 msg->reserved -= space; 1694} 1695 1696isc_result_t 1697dns_message_renderreserve(dns_message_t *msg, unsigned int space) { 1698 isc_region_t r; 1699 1700 REQUIRE(DNS_MESSAGE_VALID(msg)); 1701 1702 if (msg->buffer != NULL) { 1703 isc_buffer_availableregion(msg->buffer, &r); 1704 if (r.length < (space + msg->reserved)) 1705 return (ISC_R_NOSPACE); 1706 } 1707 1708 msg->reserved += space; 1709 1710 return (ISC_R_SUCCESS); 1711} 1712 1713static inline isc_boolean_t 1714wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) { 1715 int pass_needed; 1716 1717 /* 1718 * If we are not rendering class IN, this ordering is bogus. 1719 */ 1720 if (rds->rdclass != dns_rdataclass_in) 1721 return (ISC_FALSE); 1722 1723 switch (rds->type) { 1724 case dns_rdatatype_a: 1725 case dns_rdatatype_aaaa: 1726 if (preferred_glue == rds->type) 1727 pass_needed = 4; 1728 else 1729 pass_needed = 3; 1730 break; 1731 case dns_rdatatype_rrsig: 1732 case dns_rdatatype_dnskey: 1733 pass_needed = 2; 1734 break; 1735 default: 1736 pass_needed = 1; 1737 } 1738 1739 if (pass_needed >= pass) 1740 return (ISC_FALSE); 1741 1742 return (ISC_TRUE); 1743} 1744 1745isc_result_t 1746dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid, 1747 unsigned int options) 1748{ 1749 dns_namelist_t *section; 1750 dns_name_t *name, *next_name; 1751 dns_rdataset_t *rdataset, *next_rdataset; 1752 unsigned int count, total; 1753 isc_result_t result; 1754 isc_buffer_t st; /* for rollbacks */ 1755 int pass; 1756 isc_boolean_t partial = ISC_FALSE; 1757 unsigned int rd_options; 1758 dns_rdatatype_t preferred_glue = 0; 1759 1760 REQUIRE(DNS_MESSAGE_VALID(msg)); 1761 REQUIRE(msg->buffer != NULL); 1762 REQUIRE(VALID_NAMED_SECTION(sectionid)); 1763 1764 section = &msg->sections[sectionid]; 1765 1766 if ((sectionid == DNS_SECTION_ADDITIONAL) 1767 && (options & DNS_MESSAGERENDER_ORDERED) == 0) { 1768 if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) { 1769 preferred_glue = dns_rdatatype_a; 1770 pass = 4; 1771 } else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) { 1772 preferred_glue = dns_rdatatype_aaaa; 1773 pass = 4; 1774 } else 1775 pass = 3; 1776 } else 1777 pass = 1; 1778 1779 if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0) 1780 rd_options = 0; 1781 else 1782 rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC; 1783 1784 /* 1785 * Shrink the space in the buffer by the reserved amount. 1786 */ 1787 msg->buffer->length -= msg->reserved; 1788 1789 total = 0; 1790 if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0) 1791 partial = ISC_TRUE; 1792 1793 /* 1794 * Render required glue first. Set TC if it won't fit. 1795 */ 1796 name = ISC_LIST_HEAD(*section); 1797 if (name != NULL) { 1798 rdataset = ISC_LIST_HEAD(name->list); 1799 if (rdataset != NULL && 1800 (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 0 && 1801 (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) { 1802 void *order_arg = msg->order_arg; 1803 st = *(msg->buffer); 1804 count = 0; 1805 if (partial) 1806 result = dns_rdataset_towirepartial(rdataset, 1807 name, 1808 msg->cctx, 1809 msg->buffer, 1810 msg->order, 1811 order_arg, 1812 rd_options, 1813 &count, 1814 NULL); 1815 else 1816 result = dns_rdataset_towiresorted(rdataset, 1817 name, 1818 msg->cctx, 1819 msg->buffer, 1820 msg->order, 1821 order_arg, 1822 rd_options, 1823 &count); 1824 total += count; 1825 if (partial && result == ISC_R_NOSPACE) { 1826 msg->flags |= DNS_MESSAGEFLAG_TC; 1827 msg->buffer->length += msg->reserved; 1828 msg->counts[sectionid] += total; 1829 return (result); 1830 } 1831 if (result != ISC_R_SUCCESS) { 1832 INSIST(st.used < 65536); 1833 dns_compress_rollback(msg->cctx, 1834 (isc_uint16_t)st.used); 1835 *(msg->buffer) = st; /* rollback */ 1836 msg->buffer->length += msg->reserved; 1837 msg->counts[sectionid] += total; 1838 return (result); 1839 } 1840 rdataset->attributes |= DNS_RDATASETATTR_RENDERED; 1841 } 1842 } 1843 1844 do { 1845 name = ISC_LIST_HEAD(*section); 1846 if (name == NULL) { 1847 msg->buffer->length += msg->reserved; 1848 msg->counts[sectionid] += total; 1849 return (ISC_R_SUCCESS); 1850 } 1851 1852 while (name != NULL) { 1853 next_name = ISC_LIST_NEXT(name, link); 1854 1855 rdataset = ISC_LIST_HEAD(name->list); 1856 while (rdataset != NULL) { 1857 next_rdataset = ISC_LIST_NEXT(rdataset, link); 1858 1859 if ((rdataset->attributes & 1860 DNS_RDATASETATTR_RENDERED) != 0) 1861 goto next; 1862 1863 if (((options & DNS_MESSAGERENDER_ORDERED) 1864 == 0) 1865 && (sectionid == DNS_SECTION_ADDITIONAL) 1866 && wrong_priority(rdataset, pass, 1867 preferred_glue)) 1868 goto next; 1869 1870 st = *(msg->buffer); 1871 1872 count = 0; 1873 if (partial) 1874 result = dns_rdataset_towirepartial( 1875 rdataset, 1876 name, 1877 msg->cctx, 1878 msg->buffer, 1879 msg->order, 1880 msg->order_arg, 1881 rd_options, 1882 &count, 1883 NULL); 1884 else 1885 result = dns_rdataset_towiresorted( 1886 rdataset, 1887 name, 1888 msg->cctx, 1889 msg->buffer, 1890 msg->order, 1891 msg->order_arg, 1892 rd_options, 1893 &count); 1894 1895 total += count; 1896 1897 /* 1898 * If out of space, record stats on what we 1899 * rendered so far, and return that status. 1900 * 1901 * XXXMLG Need to change this when 1902 * dns_rdataset_towire() can render partial 1903 * sets starting at some arbitary point in the 1904 * set. This will include setting a bit in the 1905 * rdataset to indicate that a partial 1906 * rendering was done, and some state saved 1907 * somewhere (probably in the message struct) 1908 * to indicate where to continue from. 1909 */ 1910 if (partial && result == ISC_R_NOSPACE) { 1911 msg->buffer->length += msg->reserved; 1912 msg->counts[sectionid] += total; 1913 return (result); 1914 } 1915 if (result != ISC_R_SUCCESS) { 1916 INSIST(st.used < 65536); 1917 dns_compress_rollback(msg->cctx, 1918 (isc_uint16_t)st.used); 1919 *(msg->buffer) = st; /* rollback */ 1920 msg->buffer->length += msg->reserved; 1921 msg->counts[sectionid] += total; 1922 return (result); 1923 } 1924 1925 /* 1926 * If we have rendered non-validated data, 1927 * ensure that the AD bit is not set. 1928 */ 1929 if (rdataset->trust != dns_trust_secure && 1930 (sectionid == DNS_SECTION_ANSWER || 1931 sectionid == DNS_SECTION_AUTHORITY)) 1932 msg->flags &= ~DNS_MESSAGEFLAG_AD; 1933 1934 rdataset->attributes |= 1935 DNS_RDATASETATTR_RENDERED; 1936 1937 next: 1938 rdataset = next_rdataset; 1939 } 1940 1941 name = next_name; 1942 } 1943 } while (--pass != 0); 1944 1945 msg->buffer->length += msg->reserved; 1946 msg->counts[sectionid] += total; 1947 1948 return (ISC_R_SUCCESS); 1949} 1950 1951void 1952dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) { 1953 isc_uint16_t tmp; 1954 isc_region_t r; 1955 1956 REQUIRE(DNS_MESSAGE_VALID(msg)); 1957 REQUIRE(target != NULL); 1958 1959 isc_buffer_availableregion(target, &r); 1960 REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN); 1961 1962 isc_buffer_putuint16(target, msg->id); 1963 1964 tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT) 1965 & DNS_MESSAGE_OPCODE_MASK); 1966 tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK); 1967 tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK); 1968 1969 INSIST(msg->counts[DNS_SECTION_QUESTION] < 65536 && 1970 msg->counts[DNS_SECTION_ANSWER] < 65536 && 1971 msg->counts[DNS_SECTION_AUTHORITY] < 65536 && 1972 msg->counts[DNS_SECTION_ADDITIONAL] < 65536); 1973 1974 isc_buffer_putuint16(target, tmp); 1975 isc_buffer_putuint16(target, 1976 (isc_uint16_t)msg->counts[DNS_SECTION_QUESTION]); 1977 isc_buffer_putuint16(target, 1978 (isc_uint16_t)msg->counts[DNS_SECTION_ANSWER]); 1979 isc_buffer_putuint16(target, 1980 (isc_uint16_t)msg->counts[DNS_SECTION_AUTHORITY]); 1981 isc_buffer_putuint16(target, 1982 (isc_uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]); 1983} 1984 1985isc_result_t 1986dns_message_renderend(dns_message_t *msg) { 1987 isc_buffer_t tmpbuf; 1988 isc_region_t r; 1989 int result; 1990 unsigned int count; 1991 1992 REQUIRE(DNS_MESSAGE_VALID(msg)); 1993 REQUIRE(msg->buffer != NULL); 1994 1995 if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) { 1996 /* 1997 * We have an extended rcode but are not using EDNS. 1998 */ 1999 return (DNS_R_FORMERR); 2000 } 2001 2002 /* 2003 * If we've got an OPT record, render it. 2004 */ 2005 if (msg->opt != NULL) { 2006 dns_message_renderrelease(msg, msg->opt_reserved); 2007 msg->opt_reserved = 0; 2008 /* 2009 * Set the extended rcode. 2010 */ 2011 msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK; 2012 msg->opt->ttl |= ((msg->rcode << 20) & 2013 DNS_MESSAGE_EDNSRCODE_MASK); 2014 /* 2015 * Render. 2016 */ 2017 count = 0; 2018 result = dns_rdataset_towire(msg->opt, dns_rootname, 2019 msg->cctx, msg->buffer, 0, 2020 &count); 2021 msg->counts[DNS_SECTION_ADDITIONAL] += count; 2022 if (result != ISC_R_SUCCESS) 2023 return (result); 2024 } 2025 2026 /* 2027 * If we're adding a TSIG or SIG(0) to a truncated message, 2028 * clear all rdatasets from the message except for the question 2029 * before adding the TSIG or SIG(0). If the question doesn't fit, 2030 * don't include it. 2031 */ 2032 if ((msg->tsigkey != NULL || msg->sig0key != NULL) && 2033 (msg->flags & DNS_MESSAGEFLAG_TC) != 0) 2034 { 2035 isc_buffer_t *buf; 2036 2037 msgresetnames(msg, DNS_SECTION_ANSWER); 2038 buf = msg->buffer; 2039 dns_message_renderreset(msg); 2040 msg->buffer = buf; 2041 isc_buffer_clear(msg->buffer); 2042 isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN); 2043 dns_compress_rollback(msg->cctx, 0); 2044 result = dns_message_rendersection(msg, DNS_SECTION_QUESTION, 2045 0); 2046 if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE) 2047 return (result); 2048 } 2049 2050 /* 2051 * If we're adding a TSIG record, generate and render it. 2052 */ 2053 if (msg->tsigkey != NULL) { 2054 dns_message_renderrelease(msg, msg->sig_reserved); 2055 msg->sig_reserved = 0; 2056 result = dns_tsig_sign(msg); 2057 if (result != ISC_R_SUCCESS) 2058 return (result); 2059 count = 0; 2060 result = dns_rdataset_towire(msg->tsig, msg->tsigname, 2061 msg->cctx, msg->buffer, 0, 2062 &count); 2063 msg->counts[DNS_SECTION_ADDITIONAL] += count; 2064 if (result != ISC_R_SUCCESS) 2065 return (result); 2066 } 2067 2068 /* 2069 * If we're adding a SIG(0) record, generate and render it. 2070 */ 2071 if (msg->sig0key != NULL) { 2072 dns_message_renderrelease(msg, msg->sig_reserved); 2073 msg->sig_reserved = 0; 2074 result = dns_dnssec_signmessage(msg, msg->sig0key); 2075 if (result != ISC_R_SUCCESS) 2076 return (result); 2077 count = 0; 2078 /* 2079 * Note: dns_rootname is used here, not msg->sig0name, since 2080 * the owner name of a SIG(0) is irrelevant, and will not 2081 * be set in a message being rendered. 2082 */ 2083 result = dns_rdataset_towire(msg->sig0, dns_rootname, 2084 msg->cctx, msg->buffer, 0, 2085 &count); 2086 msg->counts[DNS_SECTION_ADDITIONAL] += count; 2087 if (result != ISC_R_SUCCESS) 2088 return (result); 2089 } 2090 2091 isc_buffer_usedregion(msg->buffer, &r); 2092 isc_buffer_init(&tmpbuf, r.base, r.length); 2093 2094 dns_message_renderheader(msg, &tmpbuf); 2095 2096 msg->buffer = NULL; /* forget about this buffer only on success XXX */ 2097 2098 return (ISC_R_SUCCESS); 2099} 2100 2101void 2102dns_message_renderreset(dns_message_t *msg) { 2103 unsigned int i; 2104 dns_name_t *name; 2105 dns_rdataset_t *rds; 2106 2107 /* 2108 * Reset the message so that it may be rendered again. 2109 */ 2110 2111 REQUIRE(DNS_MESSAGE_VALID(msg)); 2112 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 2113 2114 msg->buffer = NULL; 2115 2116 for (i = 0; i < DNS_SECTION_MAX; i++) { 2117 msg->cursors[i] = NULL; 2118 msg->counts[i] = 0; 2119 for (name = ISC_LIST_HEAD(msg->sections[i]); 2120 name != NULL; 2121 name = ISC_LIST_NEXT(name, link)) { 2122 for (rds = ISC_LIST_HEAD(name->list); 2123 rds != NULL; 2124 rds = ISC_LIST_NEXT(rds, link)) { 2125 rds->attributes &= ~DNS_RDATASETATTR_RENDERED; 2126 } 2127 } 2128 } 2129 if (msg->tsigname != NULL) 2130 dns_message_puttempname(msg, &msg->tsigname); 2131 if (msg->tsig != NULL) { 2132 dns_rdataset_disassociate(msg->tsig); 2133 dns_message_puttemprdataset(msg, &msg->tsig); 2134 } 2135 if (msg->sig0 != NULL) { 2136 dns_rdataset_disassociate(msg->sig0); 2137 dns_message_puttemprdataset(msg, &msg->sig0); 2138 } 2139} 2140 2141isc_result_t 2142dns_message_firstname(dns_message_t *msg, dns_section_t section) { 2143 REQUIRE(DNS_MESSAGE_VALID(msg)); 2144 REQUIRE(VALID_NAMED_SECTION(section)); 2145 2146 msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]); 2147 2148 if (msg->cursors[section] == NULL) 2149 return (ISC_R_NOMORE); 2150 2151 return (ISC_R_SUCCESS); 2152} 2153 2154isc_result_t 2155dns_message_nextname(dns_message_t *msg, dns_section_t section) { 2156 REQUIRE(DNS_MESSAGE_VALID(msg)); 2157 REQUIRE(VALID_NAMED_SECTION(section)); 2158 REQUIRE(msg->cursors[section] != NULL); 2159 2160 msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link); 2161 2162 if (msg->cursors[section] == NULL) 2163 return (ISC_R_NOMORE); 2164 2165 return (ISC_R_SUCCESS); 2166} 2167 2168void 2169dns_message_currentname(dns_message_t *msg, dns_section_t section, 2170 dns_name_t **name) 2171{ 2172 REQUIRE(DNS_MESSAGE_VALID(msg)); 2173 REQUIRE(VALID_NAMED_SECTION(section)); 2174 REQUIRE(name != NULL && *name == NULL); 2175 REQUIRE(msg->cursors[section] != NULL); 2176 2177 *name = msg->cursors[section]; 2178} 2179 2180isc_result_t 2181dns_message_findname(dns_message_t *msg, dns_section_t section, 2182 dns_name_t *target, dns_rdatatype_t type, 2183 dns_rdatatype_t covers, dns_name_t **name, 2184 dns_rdataset_t **rdataset) 2185{ 2186 dns_name_t *foundname; 2187 isc_result_t result; 2188 2189 /* 2190 * XXX These requirements are probably too intensive, especially 2191 * where things can be NULL, but as they are they ensure that if 2192 * something is NON-NULL, indicating that the caller expects it 2193 * to be filled in, that we can in fact fill it in. 2194 */ 2195 REQUIRE(msg != NULL); 2196 REQUIRE(VALID_SECTION(section)); 2197 REQUIRE(target != NULL); 2198 if (name != NULL) 2199 REQUIRE(*name == NULL); 2200 if (type == dns_rdatatype_any) { 2201 REQUIRE(rdataset == NULL); 2202 } else { 2203 if (rdataset != NULL) 2204 REQUIRE(*rdataset == NULL); 2205 } 2206 2207 result = findname(&foundname, target, 2208 &msg->sections[section]); 2209 2210 if (result == ISC_R_NOTFOUND) 2211 return (DNS_R_NXDOMAIN); 2212 else if (result != ISC_R_SUCCESS) 2213 return (result); 2214 2215 if (name != NULL) 2216 *name = foundname; 2217 2218 /* 2219 * And now look for the type. 2220 */ 2221 if (type == dns_rdatatype_any) 2222 return (ISC_R_SUCCESS); 2223 2224 result = dns_message_findtype(foundname, type, covers, rdataset); 2225 if (result == ISC_R_NOTFOUND) 2226 return (DNS_R_NXRRSET); 2227 2228 return (result); 2229} 2230 2231void 2232dns_message_movename(dns_message_t *msg, dns_name_t *name, 2233 dns_section_t fromsection, 2234 dns_section_t tosection) 2235{ 2236 REQUIRE(msg != NULL); 2237 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 2238 REQUIRE(name != NULL); 2239 REQUIRE(VALID_NAMED_SECTION(fromsection)); 2240 REQUIRE(VALID_NAMED_SECTION(tosection)); 2241 2242 /* 2243 * Unlink the name from the old section 2244 */ 2245 ISC_LIST_UNLINK(msg->sections[fromsection], name, link); 2246 ISC_LIST_APPEND(msg->sections[tosection], name, link); 2247} 2248 2249void 2250dns_message_addname(dns_message_t *msg, dns_name_t *name, 2251 dns_section_t section) 2252{ 2253 REQUIRE(msg != NULL); 2254 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 2255 REQUIRE(name != NULL); 2256 REQUIRE(VALID_NAMED_SECTION(section)); 2257 2258 ISC_LIST_APPEND(msg->sections[section], name, link); 2259} 2260 2261isc_result_t 2262dns_message_gettempname(dns_message_t *msg, dns_name_t **item) { 2263 REQUIRE(DNS_MESSAGE_VALID(msg)); 2264 REQUIRE(item != NULL && *item == NULL); 2265 2266 *item = isc_mempool_get(msg->namepool); 2267 if (*item == NULL) 2268 return (ISC_R_NOMEMORY); 2269 dns_name_init(*item, NULL); 2270 2271 return (ISC_R_SUCCESS); 2272} 2273 2274isc_result_t 2275dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) { 2276 REQUIRE(DNS_MESSAGE_VALID(msg)); 2277 REQUIRE(item != NULL && *item == NULL); 2278 2279 *item = newoffsets(msg); 2280 if (*item == NULL) 2281 return (ISC_R_NOMEMORY); 2282 2283 return (ISC_R_SUCCESS); 2284} 2285 2286isc_result_t 2287dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) { 2288 REQUIRE(DNS_MESSAGE_VALID(msg)); 2289 REQUIRE(item != NULL && *item == NULL); 2290 2291 *item = newrdata(msg); 2292 if (*item == NULL) 2293 return (ISC_R_NOMEMORY); 2294 2295 return (ISC_R_SUCCESS); 2296} 2297 2298isc_result_t 2299dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) { 2300 REQUIRE(DNS_MESSAGE_VALID(msg)); 2301 REQUIRE(item != NULL && *item == NULL); 2302 2303 *item = isc_mempool_get(msg->rdspool); 2304 if (*item == NULL) 2305 return (ISC_R_NOMEMORY); 2306 2307 dns_rdataset_init(*item); 2308 2309 return (ISC_R_SUCCESS); 2310} 2311 2312isc_result_t 2313dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) { 2314 REQUIRE(DNS_MESSAGE_VALID(msg)); 2315 REQUIRE(item != NULL && *item == NULL); 2316 2317 *item = newrdatalist(msg); 2318 if (*item == NULL) 2319 return (ISC_R_NOMEMORY); 2320 2321 return (ISC_R_SUCCESS); 2322} 2323 2324void 2325dns_message_puttempname(dns_message_t *msg, dns_name_t **item) { 2326 REQUIRE(DNS_MESSAGE_VALID(msg)); 2327 REQUIRE(item != NULL && *item != NULL); 2328 2329 if (dns_name_dynamic(*item)) 2330 dns_name_free(*item, msg->mctx); 2331 isc_mempool_put(msg->namepool, *item); 2332 *item = NULL; 2333} 2334 2335void 2336dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) { 2337 REQUIRE(DNS_MESSAGE_VALID(msg)); 2338 REQUIRE(item != NULL && *item != NULL); 2339 2340 releaserdata(msg, *item); 2341 *item = NULL; 2342} 2343 2344void 2345dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) { 2346 REQUIRE(DNS_MESSAGE_VALID(msg)); 2347 REQUIRE(item != NULL && *item != NULL); 2348 2349 REQUIRE(!dns_rdataset_isassociated(*item)); 2350 isc_mempool_put(msg->rdspool, *item); 2351 *item = NULL; 2352} 2353 2354void 2355dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) { 2356 REQUIRE(DNS_MESSAGE_VALID(msg)); 2357 REQUIRE(item != NULL && *item != NULL); 2358 2359 releaserdatalist(msg, *item); 2360 *item = NULL; 2361} 2362 2363isc_result_t 2364dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp, 2365 unsigned int *flagsp) 2366{ 2367 isc_region_t r; 2368 isc_buffer_t buffer; 2369 dns_messageid_t id; 2370 unsigned int flags; 2371 2372 REQUIRE(source != NULL); 2373 2374 buffer = *source; 2375 2376 isc_buffer_remainingregion(&buffer, &r); 2377 if (r.length < DNS_MESSAGE_HEADERLEN) 2378 return (ISC_R_UNEXPECTEDEND); 2379 2380 id = isc_buffer_getuint16(&buffer); 2381 flags = isc_buffer_getuint16(&buffer); 2382 flags &= DNS_MESSAGE_FLAG_MASK; 2383 2384 if (flagsp != NULL) 2385 *flagsp = flags; 2386 if (idp != NULL) 2387 *idp = id; 2388 2389 return (ISC_R_SUCCESS); 2390} 2391 2392isc_result_t 2393dns_message_reply(dns_message_t *msg, isc_boolean_t want_question_section) { 2394 unsigned int first_section; 2395 isc_result_t result; 2396 2397 REQUIRE(DNS_MESSAGE_VALID(msg)); 2398 REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0); 2399 2400 if (!msg->header_ok) 2401 return (DNS_R_FORMERR); 2402 if (msg->opcode != dns_opcode_query && 2403 msg->opcode != dns_opcode_notify) 2404 want_question_section = ISC_FALSE; 2405 if (want_question_section) { 2406 if (!msg->question_ok) 2407 return (DNS_R_FORMERR); 2408 first_section = DNS_SECTION_ANSWER; 2409 } else 2410 first_section = DNS_SECTION_QUESTION; 2411 msg->from_to_wire = DNS_MESSAGE_INTENTRENDER; 2412 msgresetnames(msg, first_section); 2413 msgresetopt(msg); 2414 msgresetsigs(msg, ISC_TRUE); 2415 msginitprivate(msg); 2416 /* 2417 * We now clear most flags and then set QR, ensuring that the 2418 * reply's flags will be in a reasonable state. 2419 */ 2420 msg->flags &= DNS_MESSAGE_REPLYPRESERVE; 2421 msg->flags |= DNS_MESSAGEFLAG_QR; 2422 2423 /* 2424 * This saves the query TSIG status, if the query was signed, and 2425 * reserves space in the reply for the TSIG. 2426 */ 2427 if (msg->tsigkey != NULL) { 2428 unsigned int otherlen = 0; 2429 msg->querytsigstatus = msg->tsigstatus; 2430 msg->tsigstatus = dns_rcode_noerror; 2431 if (msg->querytsigstatus == dns_tsigerror_badtime) 2432 otherlen = 6; 2433 msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen); 2434 result = dns_message_renderreserve(msg, msg->sig_reserved); 2435 if (result != ISC_R_SUCCESS) { 2436 msg->sig_reserved = 0; 2437 return (result); 2438 } 2439 } 2440 if (msg->saved.base != NULL) { 2441 msg->query.base = msg->saved.base; 2442 msg->query.length = msg->saved.length; 2443 msg->free_query = msg->free_saved; 2444 msg->saved.base = NULL; 2445 msg->saved.length = 0; 2446 msg->free_saved = 0; 2447 } 2448 2449 return (ISC_R_SUCCESS); 2450} 2451 2452dns_rdataset_t * 2453dns_message_getopt(dns_message_t *msg) { 2454 2455 /* 2456 * Get the OPT record for 'msg'. 2457 */ 2458 2459 REQUIRE(DNS_MESSAGE_VALID(msg)); 2460 2461 return (msg->opt); 2462} 2463 2464isc_result_t 2465dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) { 2466 isc_result_t result; 2467 dns_rdata_t rdata = DNS_RDATA_INIT; 2468 2469 /* 2470 * Set the OPT record for 'msg'. 2471 */ 2472 2473 /* 2474 * The space required for an OPT record is: 2475 * 2476 * 1 byte for the name 2477 * 2 bytes for the type 2478 * 2 bytes for the class 2479 * 4 bytes for the ttl 2480 * 2 bytes for the rdata length 2481 * --------------------------------- 2482 * 11 bytes 2483 * 2484 * plus the length of the rdata. 2485 */ 2486 2487 REQUIRE(DNS_MESSAGE_VALID(msg)); 2488 REQUIRE(opt->type == dns_rdatatype_opt); 2489 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 2490 REQUIRE(msg->state == DNS_SECTION_ANY); 2491 2492 msgresetopt(msg); 2493 2494 result = dns_rdataset_first(opt); 2495 if (result != ISC_R_SUCCESS) 2496 goto cleanup; 2497 dns_rdataset_current(opt, &rdata); 2498 msg->opt_reserved = 11 + rdata.length; 2499 result = dns_message_renderreserve(msg, msg->opt_reserved); 2500 if (result != ISC_R_SUCCESS) { 2501 msg->opt_reserved = 0; 2502 goto cleanup; 2503 } 2504 2505 msg->opt = opt; 2506 2507 return (ISC_R_SUCCESS); 2508 2509 cleanup: 2510 dns_message_puttemprdataset(msg, &opt); 2511 return (result); 2512 2513} 2514 2515dns_rdataset_t * 2516dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) { 2517 2518 /* 2519 * Get the TSIG record and owner for 'msg'. 2520 */ 2521 2522 REQUIRE(DNS_MESSAGE_VALID(msg)); 2523 REQUIRE(owner == NULL || *owner == NULL); 2524 2525 if (owner != NULL) 2526 *owner = msg->tsigname; 2527 return (msg->tsig); 2528} 2529 2530isc_result_t 2531dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) { 2532 isc_result_t result; 2533 2534 /* 2535 * Set the TSIG key for 'msg' 2536 */ 2537 2538 REQUIRE(DNS_MESSAGE_VALID(msg)); 2539 REQUIRE(msg->state == DNS_SECTION_ANY); 2540 2541 if (key == NULL && msg->tsigkey != NULL) { 2542 if (msg->sig_reserved != 0) { 2543 dns_message_renderrelease(msg, msg->sig_reserved); 2544 msg->sig_reserved = 0; 2545 } 2546 dns_tsigkey_detach(&msg->tsigkey); 2547 } 2548 if (key != NULL) { 2549 REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL); 2550 dns_tsigkey_attach(key, &msg->tsigkey); 2551 if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) { 2552 msg->sig_reserved = spacefortsig(msg->tsigkey, 0); 2553 result = dns_message_renderreserve(msg, 2554 msg->sig_reserved); 2555 if (result != ISC_R_SUCCESS) { 2556 dns_tsigkey_detach(&msg->tsigkey); 2557 msg->sig_reserved = 0; 2558 return (result); 2559 } 2560 } 2561 } 2562 return (ISC_R_SUCCESS); 2563} 2564 2565dns_tsigkey_t * 2566dns_message_gettsigkey(dns_message_t *msg) { 2567 2568 /* 2569 * Get the TSIG key for 'msg' 2570 */ 2571 2572 REQUIRE(DNS_MESSAGE_VALID(msg)); 2573 2574 return (msg->tsigkey); 2575} 2576 2577isc_result_t 2578dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) { 2579 dns_rdata_t *rdata = NULL; 2580 dns_rdatalist_t *list = NULL; 2581 dns_rdataset_t *set = NULL; 2582 isc_buffer_t *buf = NULL; 2583 isc_region_t r; 2584 isc_result_t result; 2585 2586 REQUIRE(DNS_MESSAGE_VALID(msg)); 2587 REQUIRE(msg->querytsig == NULL); 2588 2589 if (querytsig == NULL) 2590 return (ISC_R_SUCCESS); 2591 2592 result = dns_message_gettemprdata(msg, &rdata); 2593 if (result != ISC_R_SUCCESS) 2594 goto cleanup; 2595 2596 result = dns_message_gettemprdatalist(msg, &list); 2597 if (result != ISC_R_SUCCESS) 2598 goto cleanup; 2599 result = dns_message_gettemprdataset(msg, &set); 2600 if (result != ISC_R_SUCCESS) 2601 goto cleanup; 2602 2603 isc_buffer_usedregion(querytsig, &r); 2604 result = isc_buffer_allocate(msg->mctx, &buf, r.length); 2605 if (result != ISC_R_SUCCESS) 2606 goto cleanup; 2607 isc_buffer_putmem(buf, r.base, r.length); 2608 isc_buffer_usedregion(buf, &r); 2609 dns_rdata_init(rdata); 2610 dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r); 2611 dns_message_takebuffer(msg, &buf); 2612 ISC_LIST_INIT(list->rdata); 2613 ISC_LIST_APPEND(list->rdata, rdata, link); 2614 result = dns_rdatalist_tordataset(list, set); 2615 if (result != ISC_R_SUCCESS) 2616 goto cleanup; 2617 2618 msg->querytsig = set; 2619 2620 return (result); 2621 2622 cleanup: 2623 if (rdata != NULL) 2624 dns_message_puttemprdata(msg, &rdata); 2625 if (list != NULL) 2626 dns_message_puttemprdatalist(msg, &list); 2627 if (set != NULL) 2628 dns_message_puttemprdataset(msg, &set); 2629 return (ISC_R_NOMEMORY); 2630} 2631 2632isc_result_t 2633dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx, 2634 isc_buffer_t **querytsig) { 2635 isc_result_t result; 2636 dns_rdata_t rdata = DNS_RDATA_INIT; 2637 isc_region_t r; 2638 2639 REQUIRE(DNS_MESSAGE_VALID(msg)); 2640 REQUIRE(mctx != NULL); 2641 REQUIRE(querytsig != NULL && *querytsig == NULL); 2642 2643 if (msg->tsig == NULL) 2644 return (ISC_R_SUCCESS); 2645 2646 result = dns_rdataset_first(msg->tsig); 2647 if (result != ISC_R_SUCCESS) 2648 return (result); 2649 dns_rdataset_current(msg->tsig, &rdata); 2650 dns_rdata_toregion(&rdata, &r); 2651 2652 result = isc_buffer_allocate(mctx, querytsig, r.length); 2653 if (result != ISC_R_SUCCESS) 2654 return (result); 2655 isc_buffer_putmem(*querytsig, r.base, r.length); 2656 return (ISC_R_SUCCESS); 2657} 2658 2659dns_rdataset_t * 2660dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) { 2661 2662 /* 2663 * Get the SIG(0) record for 'msg'. 2664 */ 2665 2666 REQUIRE(DNS_MESSAGE_VALID(msg)); 2667 REQUIRE(owner == NULL || *owner == NULL); 2668 2669 if (msg->sig0 != NULL && owner != NULL) { 2670 /* If dns_message_getsig0 is called on a rendered message 2671 * after the SIG(0) has been applied, we need to return the 2672 * root name, not NULL. 2673 */ 2674 if (msg->sig0name == NULL) 2675 *owner = dns_rootname; 2676 else 2677 *owner = msg->sig0name; 2678 } 2679 return (msg->sig0); 2680} 2681 2682isc_result_t 2683dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) { 2684 isc_region_t r; 2685 unsigned int x; 2686 isc_result_t result; 2687 2688 /* 2689 * Set the SIG(0) key for 'msg' 2690 */ 2691 2692 /* 2693 * The space required for an SIG(0) record is: 2694 * 2695 * 1 byte for the name 2696 * 2 bytes for the type 2697 * 2 bytes for the class 2698 * 4 bytes for the ttl 2699 * 2 bytes for the type covered 2700 * 1 byte for the algorithm 2701 * 1 bytes for the labels 2702 * 4 bytes for the original ttl 2703 * 4 bytes for the signature expiration 2704 * 4 bytes for the signature inception 2705 * 2 bytes for the key tag 2706 * n bytes for the signer's name 2707 * x bytes for the signature 2708 * --------------------------------- 2709 * 27 + n + x bytes 2710 */ 2711 REQUIRE(DNS_MESSAGE_VALID(msg)); 2712 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 2713 REQUIRE(msg->state == DNS_SECTION_ANY); 2714 2715 if (key != NULL) { 2716 REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL); 2717 dns_name_toregion(dst_key_name(key), &r); 2718 result = dst_key_sigsize(key, &x); 2719 if (result != ISC_R_SUCCESS) { 2720 msg->sig_reserved = 0; 2721 return (result); 2722 } 2723 msg->sig_reserved = 27 + r.length + x; 2724 result = dns_message_renderreserve(msg, msg->sig_reserved); 2725 if (result != ISC_R_SUCCESS) { 2726 msg->sig_reserved = 0; 2727 return (result); 2728 } 2729 msg->sig0key = key; 2730 } 2731 return (ISC_R_SUCCESS); 2732} 2733 2734dst_key_t * 2735dns_message_getsig0key(dns_message_t *msg) { 2736 2737 /* 2738 * Get the SIG(0) key for 'msg' 2739 */ 2740 2741 REQUIRE(DNS_MESSAGE_VALID(msg)); 2742 2743 return (msg->sig0key); 2744} 2745 2746void 2747dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) { 2748 REQUIRE(DNS_MESSAGE_VALID(msg)); 2749 REQUIRE(buffer != NULL); 2750 REQUIRE(ISC_BUFFER_VALID(*buffer)); 2751 2752 ISC_LIST_APPEND(msg->cleanup, *buffer, link); 2753 *buffer = NULL; 2754} 2755 2756isc_result_t 2757dns_message_signer(dns_message_t *msg, dns_name_t *signer) { 2758 isc_result_t result = ISC_R_SUCCESS; 2759 dns_rdata_t rdata = DNS_RDATA_INIT; 2760 2761 REQUIRE(DNS_MESSAGE_VALID(msg)); 2762 REQUIRE(signer != NULL); 2763 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE); 2764 2765 if (msg->tsig == NULL && msg->sig0 == NULL) 2766 return (ISC_R_NOTFOUND); 2767 2768 if (msg->verify_attempted == 0) 2769 return (DNS_R_NOTVERIFIEDYET); 2770 2771 if (!dns_name_hasbuffer(signer)) { 2772 isc_buffer_t *dynbuf = NULL; 2773 result = isc_buffer_allocate(msg->mctx, &dynbuf, 512); 2774 if (result != ISC_R_SUCCESS) 2775 return (result); 2776 dns_name_setbuffer(signer, dynbuf); 2777 dns_message_takebuffer(msg, &dynbuf); 2778 } 2779 2780 if (msg->sig0 != NULL) { 2781 dns_rdata_sig_t sig; 2782 2783 result = dns_rdataset_first(msg->sig0); 2784 INSIST(result == ISC_R_SUCCESS); 2785 dns_rdataset_current(msg->sig0, &rdata); 2786 2787 result = dns_rdata_tostruct(&rdata, &sig, NULL); 2788 if (result != ISC_R_SUCCESS) 2789 return (result); 2790 2791 if (msg->verified_sig && msg->sig0status == dns_rcode_noerror) 2792 result = ISC_R_SUCCESS; 2793 else 2794 result = DNS_R_SIGINVALID; 2795 dns_name_clone(&sig.signer, signer); 2796 dns_rdata_freestruct(&sig); 2797 } else { 2798 dns_name_t *identity; 2799 dns_rdata_any_tsig_t tsig; 2800 2801 result = dns_rdataset_first(msg->tsig); 2802 INSIST(result == ISC_R_SUCCESS); 2803 dns_rdataset_current(msg->tsig, &rdata); 2804 2805 result = dns_rdata_tostruct(&rdata, &tsig, NULL); 2806 if (msg->tsigstatus != dns_rcode_noerror) 2807 result = DNS_R_TSIGVERIFYFAILURE; 2808 else if (tsig.error != dns_rcode_noerror) 2809 result = DNS_R_TSIGERRORSET; 2810 else 2811 result = ISC_R_SUCCESS; 2812 dns_rdata_freestruct(&tsig); 2813 2814 if (msg->tsigkey == NULL) { 2815 /* 2816 * If msg->tsigstatus & tsig.error are both 2817 * dns_rcode_noerror, the message must have been 2818 * verified, which means msg->tsigkey will be 2819 * non-NULL. 2820 */ 2821 INSIST(result != ISC_R_SUCCESS); 2822 } else { 2823 identity = dns_tsigkey_identity(msg->tsigkey); 2824 if (identity == NULL) { 2825 if (result == ISC_R_SUCCESS) 2826 result = DNS_R_NOIDENTITY; 2827 identity = &msg->tsigkey->name; 2828 } 2829 dns_name_clone(identity, signer); 2830 } 2831 } 2832 2833 return (result); 2834} 2835 2836void 2837dns_message_resetsig(dns_message_t *msg) { 2838 REQUIRE(DNS_MESSAGE_VALID(msg)); 2839 msg->verified_sig = 0; 2840 msg->verify_attempted = 0; 2841 msg->tsigstatus = dns_rcode_noerror; 2842 msg->sig0status = dns_rcode_noerror; 2843 msg->timeadjust = 0; 2844 if (msg->tsigkey != NULL) { 2845 dns_tsigkey_detach(&msg->tsigkey); 2846 msg->tsigkey = NULL; 2847 } 2848} 2849 2850isc_result_t 2851dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) { 2852 dns_message_resetsig(msg); 2853 return (dns_message_checksig(msg, view)); 2854} 2855 2856isc_result_t 2857dns_message_checksig(dns_message_t *msg, dns_view_t *view) { 2858 isc_buffer_t b, msgb; 2859 2860 REQUIRE(DNS_MESSAGE_VALID(msg)); 2861 2862 if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL) 2863 return (ISC_R_SUCCESS); 2864 INSIST(msg->saved.base != NULL); 2865 isc_buffer_init(&msgb, msg->saved.base, msg->saved.length); 2866 isc_buffer_add(&msgb, msg->saved.length); 2867 if (msg->tsigkey != NULL || msg->tsig != NULL) { 2868 if (view != NULL) 2869 return (dns_view_checksig(view, &msgb, msg)); 2870 else 2871 return (dns_tsig_verify(&msgb, msg, NULL, NULL)); 2872 } else { 2873 dns_rdata_t rdata = DNS_RDATA_INIT; 2874 dns_rdata_sig_t sig; 2875 dns_rdataset_t keyset; 2876 isc_result_t result; 2877 2878 result = dns_rdataset_first(msg->sig0); 2879 INSIST(result == ISC_R_SUCCESS); 2880 dns_rdataset_current(msg->sig0, &rdata); 2881 2882 /* 2883 * This can occur when the message is a dynamic update, since 2884 * the rdata length checking is relaxed. This should not 2885 * happen in a well-formed message, since the SIG(0) is only 2886 * looked for in the additional section, and the dynamic update 2887 * meta-records are in the prerequisite and update sections. 2888 */ 2889 if (rdata.length == 0) 2890 return (ISC_R_UNEXPECTEDEND); 2891 2892 result = dns_rdata_tostruct(&rdata, &sig, msg->mctx); 2893 if (result != ISC_R_SUCCESS) 2894 return (result); 2895 2896 dns_rdataset_init(&keyset); 2897 if (view == NULL) 2898 return (DNS_R_KEYUNAUTHORIZED); 2899 result = dns_view_simplefind(view, &sig.signer, 2900 dns_rdatatype_key /* SIG(0) */, 2901 0, 0, ISC_FALSE, &keyset, NULL); 2902 2903 if (result != ISC_R_SUCCESS) { 2904 /* XXXBEW Should possibly create a fetch here */ 2905 result = DNS_R_KEYUNAUTHORIZED; 2906 goto freesig; 2907 } else if (keyset.trust < dns_trust_secure) { 2908 /* XXXBEW Should call a validator here */ 2909 result = DNS_R_KEYUNAUTHORIZED; 2910 goto freesig; 2911 } 2912 result = dns_rdataset_first(&keyset); 2913 INSIST(result == ISC_R_SUCCESS); 2914 for (; 2915 result == ISC_R_SUCCESS; 2916 result = dns_rdataset_next(&keyset)) 2917 { 2918 dst_key_t *key = NULL; 2919 2920 dns_rdataset_current(&keyset, &rdata); 2921 isc_buffer_init(&b, rdata.data, rdata.length); 2922 isc_buffer_add(&b, rdata.length); 2923 2924 result = dst_key_fromdns(&sig.signer, rdata.rdclass, 2925 &b, view->mctx, &key); 2926 if (result != ISC_R_SUCCESS) 2927 continue; 2928 if (dst_key_alg(key) != sig.algorithm || 2929 dst_key_id(key) != sig.keyid || 2930 !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC || 2931 dst_key_proto(key) == DNS_KEYPROTO_ANY)) 2932 { 2933 dst_key_free(&key); 2934 continue; 2935 } 2936 result = dns_dnssec_verifymessage(&msgb, msg, key); 2937 dst_key_free(&key); 2938 if (result == ISC_R_SUCCESS) 2939 break; 2940 } 2941 if (result == ISC_R_NOMORE) 2942 result = DNS_R_KEYUNAUTHORIZED; 2943 2944 freesig: 2945 if (dns_rdataset_isassociated(&keyset)) 2946 dns_rdataset_disassociate(&keyset); 2947 dns_rdata_freestruct(&sig); 2948 return (result); 2949 } 2950} 2951 2952isc_result_t 2953dns_message_sectiontotext(dns_message_t *msg, dns_section_t section, 2954 const dns_master_style_t *style, 2955 dns_messagetextflag_t flags, 2956 isc_buffer_t *target) { 2957 dns_name_t *name, empty_name; 2958 dns_rdataset_t *rdataset; 2959 isc_result_t result; 2960 2961 REQUIRE(DNS_MESSAGE_VALID(msg)); 2962 REQUIRE(target != NULL); 2963 REQUIRE(VALID_SECTION(section)); 2964 2965 if (ISC_LIST_EMPTY(msg->sections[section])) 2966 return (ISC_R_SUCCESS); 2967 2968 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) { 2969 ADD_STRING(target, ";; "); 2970 if (msg->opcode != dns_opcode_update) { 2971 ADD_STRING(target, sectiontext[section]); 2972 } 2973 else { 2974 ADD_STRING(target, updsectiontext[section]); 2975 } 2976 ADD_STRING(target, " SECTION:\n"); 2977 } 2978 2979 dns_name_init(&empty_name, NULL); 2980 result = dns_message_firstname(msg, section); 2981 if (result != ISC_R_SUCCESS) { 2982 return (result); 2983 } 2984 do { 2985 name = NULL; 2986 dns_message_currentname(msg, section, &name); 2987 for (rdataset = ISC_LIST_HEAD(name->list); 2988 rdataset != NULL; 2989 rdataset = ISC_LIST_NEXT(rdataset, link)) { 2990 if (section == DNS_SECTION_QUESTION) { 2991 ADD_STRING(target, ";"); 2992 result = dns_master_questiontotext(name, 2993 rdataset, 2994 style, 2995 target); 2996 } else { 2997 result = dns_master_rdatasettotext(name, 2998 rdataset, 2999 style, 3000 target); 3001 } 3002 if (result != ISC_R_SUCCESS) 3003 return (result); 3004 } 3005 result = dns_message_nextname(msg, section); 3006 } while (result == ISC_R_SUCCESS); 3007 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 && 3008 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 3009 ADD_STRING(target, "\n"); 3010 if (result == ISC_R_NOMORE) 3011 result = ISC_R_SUCCESS; 3012 return (result); 3013} 3014 3015isc_result_t 3016dns_message_pseudosectiontotext(dns_message_t *msg, 3017 dns_pseudosection_t section, 3018 const dns_master_style_t *style, 3019 dns_messagetextflag_t flags, 3020 isc_buffer_t *target) { 3021 dns_rdataset_t *ps = NULL; 3022 dns_name_t *name = NULL; 3023 isc_result_t result; 3024 char buf[sizeof("1234567890")]; 3025 isc_uint32_t mbz; 3026 3027 REQUIRE(DNS_MESSAGE_VALID(msg)); 3028 REQUIRE(target != NULL); 3029 REQUIRE(VALID_PSEUDOSECTION(section)); 3030 3031 switch (section) { 3032 case DNS_PSEUDOSECTION_OPT: 3033 ps = dns_message_getopt(msg); 3034 if (ps == NULL) 3035 return (ISC_R_SUCCESS); 3036 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 3037 ADD_STRING(target, ";; OPT PSEUDOSECTION:\n"); 3038 ADD_STRING(target, "; EDNS: version: "); 3039 snprintf(buf, sizeof(buf), "%u", 3040 (unsigned int)((ps->ttl & 0x00ff0000) >> 16)); 3041 ADD_STRING(target, buf); 3042 ADD_STRING(target, ", flags:"); 3043 if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0) 3044 ADD_STRING(target, " do"); 3045 mbz = ps->ttl & ~DNS_MESSAGEEXTFLAG_DO & 0xffff; 3046 if (mbz != 0) { 3047 ADD_STRING(target, "; MBZ: "); 3048 snprintf(buf, sizeof(buf), "%.4x ", mbz); 3049 ADD_STRING(target, buf); 3050 ADD_STRING(target, ", udp: "); 3051 } else 3052 ADD_STRING(target, "; udp: "); 3053 snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass); 3054 ADD_STRING(target, buf); 3055 return (ISC_R_SUCCESS); 3056 case DNS_PSEUDOSECTION_TSIG: 3057 ps = dns_message_gettsig(msg, &name); 3058 if (ps == NULL) 3059 return (ISC_R_SUCCESS); 3060 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 3061 ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n"); 3062 result = dns_master_rdatasettotext(name, ps, style, target); 3063 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 && 3064 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 3065 ADD_STRING(target, "\n"); 3066 return (result); 3067 case DNS_PSEUDOSECTION_SIG0: 3068 ps = dns_message_getsig0(msg, &name); 3069 if (ps == NULL) 3070 return (ISC_R_SUCCESS); 3071 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 3072 ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n"); 3073 result = dns_master_rdatasettotext(name, ps, style, target); 3074 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 && 3075 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 3076 ADD_STRING(target, "\n"); 3077 return (result); 3078 } 3079 return (ISC_R_UNEXPECTED); 3080} 3081 3082isc_result_t 3083dns_message_totext(dns_message_t *msg, const dns_master_style_t *style, 3084 dns_messagetextflag_t flags, isc_buffer_t *target) { 3085 char buf[sizeof("1234567890")]; 3086 isc_result_t result; 3087 3088 REQUIRE(DNS_MESSAGE_VALID(msg)); 3089 REQUIRE(target != NULL); 3090 3091 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) { 3092 ADD_STRING(target, ";; ->>HEADER<<- opcode: "); 3093 ADD_STRING(target, opcodetext[msg->opcode]); 3094 ADD_STRING(target, ", status: "); 3095 ADD_STRING(target, rcodetext[msg->rcode]); 3096 ADD_STRING(target, ", id: "); 3097 snprintf(buf, sizeof(buf), "%6u", msg->id); 3098 ADD_STRING(target, buf); 3099 ADD_STRING(target, "\n;; flags: "); 3100 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) 3101 ADD_STRING(target, "qr "); 3102 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) 3103 ADD_STRING(target, "aa "); 3104 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) 3105 ADD_STRING(target, "tc "); 3106 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) 3107 ADD_STRING(target, "rd "); 3108 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) 3109 ADD_STRING(target, "ra "); 3110 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) 3111 ADD_STRING(target, "ad "); 3112 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) 3113 ADD_STRING(target, "cd "); 3114 if (msg->opcode != dns_opcode_update) { 3115 ADD_STRING(target, "; QUESTION: "); 3116 } else { 3117 ADD_STRING(target, "; ZONE: "); 3118 } 3119 snprintf(buf, sizeof(buf), "%1u", 3120 msg->counts[DNS_SECTION_QUESTION]); 3121 ADD_STRING(target, buf); 3122 if (msg->opcode != dns_opcode_update) { 3123 ADD_STRING(target, ", ANSWER: "); 3124 } else { 3125 ADD_STRING(target, ", PREREQ: "); 3126 } 3127 snprintf(buf, sizeof(buf), "%1u", 3128 msg->counts[DNS_SECTION_ANSWER]); 3129 ADD_STRING(target, buf); 3130 if (msg->opcode != dns_opcode_update) { 3131 ADD_STRING(target, ", AUTHORITY: "); 3132 } else { 3133 ADD_STRING(target, ", UPDATE: "); 3134 } 3135 snprintf(buf, sizeof(buf), "%1u", 3136 msg->counts[DNS_SECTION_AUTHORITY]); 3137 ADD_STRING(target, buf); 3138 ADD_STRING(target, ", ADDITIONAL: "); 3139 snprintf(buf, sizeof(buf), "%1u", 3140 msg->counts[DNS_SECTION_ADDITIONAL]); 3141 ADD_STRING(target, buf); 3142 ADD_STRING(target, "\n"); 3143 } 3144 result = dns_message_pseudosectiontotext(msg, 3145 DNS_PSEUDOSECTION_OPT, 3146 style, flags, target); 3147 if (result != ISC_R_SUCCESS) 3148 return (result); 3149 3150 result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION, 3151 style, flags, target); 3152 if (result != ISC_R_SUCCESS) 3153 return (result); 3154 result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER, 3155 style, flags, target); 3156 if (result != ISC_R_SUCCESS) 3157 return (result); 3158 result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY, 3159 style, flags, target); 3160 if (result != ISC_R_SUCCESS) 3161 return (result); 3162 result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL, 3163 style, flags, target); 3164 if (result != ISC_R_SUCCESS) 3165 return (result); 3166 3167 result = dns_message_pseudosectiontotext(msg, 3168 DNS_PSEUDOSECTION_TSIG, 3169 style, flags, target); 3170 if (result != ISC_R_SUCCESS) 3171 return (result); 3172 3173 result = dns_message_pseudosectiontotext(msg, 3174 DNS_PSEUDOSECTION_SIG0, 3175 style, flags, target); 3176 if (result != ISC_R_SUCCESS) 3177 return (result); 3178 3179 return (ISC_R_SUCCESS); 3180} 3181 3182isc_region_t * 3183dns_message_getrawmessage(dns_message_t *msg) { 3184 REQUIRE(DNS_MESSAGE_VALID(msg)); 3185 return (&msg->saved); 3186} 3187 3188void 3189dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order, 3190 void *order_arg) 3191{ 3192 REQUIRE(DNS_MESSAGE_VALID(msg)); 3193 msg->order = order; 3194 msg->order_arg = order_arg; 3195} 3196 3197void 3198dns_message_settimeadjust(dns_message_t *msg, int timeadjust) { 3199 REQUIRE(DNS_MESSAGE_VALID(msg)); 3200 msg->timeadjust = timeadjust; 3201} 3202 3203int 3204dns_message_gettimeadjust(dns_message_t *msg) { 3205 REQUIRE(DNS_MESSAGE_VALID(msg)); 3206 return (msg->timeadjust); 3207} 3208 3209isc_result_t 3210dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) { 3211 3212 REQUIRE(opcode < 16); 3213 3214 if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode])) 3215 return (ISC_R_NOSPACE); 3216 isc_buffer_putstr(target, opcodetext[opcode]); 3217 return (ISC_R_SUCCESS); 3218} 3219