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