📄 message.c
字号:
/* * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. *//* $Id: message.c,v 1.194.2.10.2.17 2004/05/05 01:32:16 marka Exp $ *//*** *** Imports ***/#include <config.h>#include <isc/buffer.h>#include <isc/mem.h>#include <isc/print.h>#include <isc/string.h> /* Required for HP/UX (and others?) */#include <isc/util.h>#include <dns/dnssec.h>#include <dns/keyvalues.h>#include <dns/log.h>#include <dns/masterdump.h>#include <dns/message.h>#include <dns/opcode.h>#include <dns/rdata.h>#include <dns/rdatalist.h>#include <dns/rdataset.h>#include <dns/rdatastruct.h>#include <dns/result.h>#include <dns/tsig.h>#include <dns/view.h>#define DNS_MESSAGE_OPCODE_MASK 0x7800U#define DNS_MESSAGE_OPCODE_SHIFT 11#define DNS_MESSAGE_RCODE_MASK 0x000fU#define DNS_MESSAGE_FLAG_MASK 0x8ff0U#define DNS_MESSAGE_EDNSRCODE_MASK 0xff000000U#define DNS_MESSAGE_EDNSRCODE_SHIFT 24#define DNS_MESSAGE_EDNSVERSION_MASK 0x00ff0000U#define DNS_MESSAGE_EDNSVERSION_SHIFT 16#define VALID_NAMED_SECTION(s) (((s) > DNS_SECTION_ANY) \ && ((s) < DNS_SECTION_MAX))#define VALID_SECTION(s) (((s) >= DNS_SECTION_ANY) \ && ((s) < DNS_SECTION_MAX))#define ADD_STRING(b, s) {if (strlen(s) >= \ isc_buffer_availablelength(b)) \ return(ISC_R_NOSPACE); else \ isc_buffer_putstr(b, s);}#define VALID_PSEUDOSECTION(s) (((s) >= DNS_PSEUDOSECTION_ANY) \ && ((s) < DNS_PSEUDOSECTION_MAX))/* * This is the size of each individual scratchpad buffer, and the numbers * of various block allocations used within the server. * XXXMLG These should come from a config setting. */#define SCRATCHPAD_SIZE 512#define NAME_COUNT 8#define OFFSET_COUNT 4#define RDATA_COUNT 8#define RDATALIST_COUNT 8#define RDATASET_COUNT RDATALIST_COUNT/* * Text representation of the different items, for message_totext * functions. */static const char *sectiontext[] = { "QUESTION", "ANSWER", "AUTHORITY", "ADDITIONAL"};static const char *updsectiontext[] = { "ZONE", "PREREQUISITE", "UPDATE", "ADDITIONAL"};static const char *opcodetext[] = { "QUERY", "IQUERY", "STATUS", "RESERVED3", "NOTIFY", "UPDATE", "RESERVED6", "RESERVED7", "RESERVED8", "RESERVED9", "RESERVED10", "RESERVED11", "RESERVED12", "RESERVED13", "RESERVED14", "RESERVED15"};static const char *rcodetext[] = { "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED", "YXDOMAIN", "YXRRSET", "NXRRSET", "NOTAUTH", "NOTZONE", "RESERVED11", "RESERVED12", "RESERVED13", "RESERVED14", "RESERVED15", "BADVERS"};/* * "helper" type, which consists of a block of some type, and is linkable. * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer * size, or the allocated elements will not be alligned correctly. */struct dns_msgblock { unsigned int count; unsigned int remaining; ISC_LINK(dns_msgblock_t) link;}; /* dynamically sized */static inline dns_msgblock_t *msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);#define msgblock_get(block, type) \ ((type *)msgblock_internalget(block, sizeof(type)))static inline void *msgblock_internalget(dns_msgblock_t *, unsigned int);static inline voidmsgblock_reset(dns_msgblock_t *);static inline voidmsgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);/* * Allocate a new dns_msgblock_t, and return a pointer to it. If no memory * is free, return NULL. */static inline dns_msgblock_t *msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type, unsigned int count){ dns_msgblock_t *block; unsigned int length; length = sizeof(dns_msgblock_t) + (sizeof_type * count); block = isc_mem_get(mctx, length); if (block == NULL) return (NULL); block->count = count; block->remaining = count; ISC_LINK_INIT(block, link); return (block);}/* * Return an element from the msgblock. If no more are available, return * NULL. */static inline void *msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) { void *ptr; if (block == NULL || block->remaining == 0) return (NULL); block->remaining--; ptr = (((unsigned char *)block) + sizeof(dns_msgblock_t) + (sizeof_type * block->remaining)); return (ptr);}static inline voidmsgblock_reset(dns_msgblock_t *block) { block->remaining = block->count;}/* * Release memory associated with a message block. */static inline voidmsgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, unsigned int sizeof_type){ unsigned int length; length = sizeof(dns_msgblock_t) + (sizeof_type * block->count); isc_mem_put(mctx, block, length);}/* * Allocate a new dynamic buffer, and attach it to this message as the * "current" buffer. (which is always the last on the list, for our * uses) */static inline isc_result_tnewbuffer(dns_message_t *msg, unsigned int size) { isc_result_t result; isc_buffer_t *dynbuf; dynbuf = NULL; result = isc_buffer_allocate(msg->mctx, &dynbuf, size); if (result != ISC_R_SUCCESS) return (ISC_R_NOMEMORY); ISC_LIST_APPEND(msg->scratchpad, dynbuf, link); return (ISC_R_SUCCESS);}static inline isc_buffer_t *currentbuffer(dns_message_t *msg) { isc_buffer_t *dynbuf; dynbuf = ISC_LIST_TAIL(msg->scratchpad); INSIST(dynbuf != NULL); return (dynbuf);}static inline voidreleaserdata(dns_message_t *msg, dns_rdata_t *rdata) { ISC_LIST_PREPEND(msg->freerdata, rdata, link);}static inline dns_rdata_t *newrdata(dns_message_t *msg) { dns_msgblock_t *msgblock; dns_rdata_t *rdata; rdata = ISC_LIST_HEAD(msg->freerdata); if (rdata != NULL) { ISC_LIST_UNLINK(msg->freerdata, rdata, link); return (rdata); } msgblock = ISC_LIST_TAIL(msg->rdatas); rdata = msgblock_get(msgblock, dns_rdata_t); if (rdata == NULL) { msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t), RDATA_COUNT); if (msgblock == NULL) return (NULL); ISC_LIST_APPEND(msg->rdatas, msgblock, link); rdata = msgblock_get(msgblock, dns_rdata_t); } dns_rdata_init(rdata); return (rdata);}static inline voidreleaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) { ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);}static inline dns_rdatalist_t *newrdatalist(dns_message_t *msg) { dns_msgblock_t *msgblock; dns_rdatalist_t *rdatalist; rdatalist = ISC_LIST_HEAD(msg->freerdatalist); if (rdatalist != NULL) { ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link); return (rdatalist); } msgblock = ISC_LIST_TAIL(msg->rdatalists); rdatalist = msgblock_get(msgblock, dns_rdatalist_t); if (rdatalist == NULL) { msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdatalist_t), RDATALIST_COUNT); if (msgblock == NULL) return (NULL); ISC_LIST_APPEND(msg->rdatalists, msgblock, link); rdatalist = msgblock_get(msgblock, dns_rdatalist_t); } return (rdatalist);}static inline dns_offsets_t *newoffsets(dns_message_t *msg) { dns_msgblock_t *msgblock; dns_offsets_t *offsets; msgblock = ISC_LIST_TAIL(msg->offsets); offsets = msgblock_get(msgblock, dns_offsets_t); if (offsets == NULL) { msgblock = msgblock_allocate(msg->mctx, sizeof(dns_offsets_t), OFFSET_COUNT); if (msgblock == NULL) return (NULL); ISC_LIST_APPEND(msg->offsets, msgblock, link); offsets = msgblock_get(msgblock, dns_offsets_t); } return (offsets);}static inline voidmsginitheader(dns_message_t *m) { m->id = 0; m->flags = 0; m->rcode = 0; m->opcode = 0; m->rdclass = 0;}static inline voidmsginitprivate(dns_message_t *m) { unsigned int i; for (i = 0; i < DNS_SECTION_MAX; i++) { m->cursors[i] = NULL; m->counts[i] = 0; } m->opt = NULL; m->sig0 = NULL; m->sig0name = NULL; m->tsig = NULL; m->tsigname = NULL; m->state = DNS_SECTION_ANY; /* indicate nothing parsed or rendered */ m->opt_reserved = 0; m->sig_reserved = 0; m->reserved = 0; m->buffer = NULL;}static inline voidmsginittsig(dns_message_t *m) { m->tsigstatus = dns_rcode_noerror; m->querytsigstatus = dns_rcode_noerror; m->tsigkey = NULL; m->tsigctx = NULL; m->sigstart = -1; m->sig0key = NULL; m->sig0status = dns_rcode_noerror; m->timeadjust = 0;}/* * Init elements to default state. Used both when allocating a new element * and when resetting one. */static inline voidmsginit(dns_message_t *m) { msginitheader(m); msginitprivate(m); msginittsig(m); m->header_ok = 0; m->question_ok = 0; m->tcp_continuation = 0; m->verified_sig = 0; m->verify_attempted = 0; m->order = NULL; m->order_arg = NULL; m->query.base = NULL; m->query.length = 0; m->free_query = 0; m->saved.base = NULL; m->saved.length = 0; m->free_saved = 0; m->querytsig = NULL;}static inline voidmsgresetnames(dns_message_t *msg, unsigned int first_section) { unsigned int i; dns_name_t *name, *next_name; dns_rdataset_t *rds, *next_rds; /* * Clean up name lists by calling the rdataset disassociate function. */ for (i = first_section; i < DNS_SECTION_MAX; i++) { name = ISC_LIST_HEAD(msg->sections[i]); while (name != NULL) { next_name = ISC_LIST_NEXT(name, link); ISC_LIST_UNLINK(msg->sections[i], name, link); rds = ISC_LIST_HEAD(name->list); while (rds != NULL) { next_rds = ISC_LIST_NEXT(rds, link); ISC_LIST_UNLINK(name->list, rds, link); INSIST(dns_rdataset_isassociated(rds)); dns_rdataset_disassociate(rds); isc_mempool_put(msg->rdspool, rds); rds = next_rds; } if (dns_name_dynamic(name)) dns_name_free(name, msg->mctx); isc_mempool_put(msg->namepool, name); name = next_name; } }}static voidmsgresetopt(dns_message_t *msg){ if (msg->opt != NULL) { if (msg->opt_reserved > 0) { dns_message_renderrelease(msg, msg->opt_reserved); msg->opt_reserved = 0; } INSIST(dns_rdataset_isassociated(msg->opt)); dns_rdataset_disassociate(msg->opt); isc_mempool_put(msg->rdspool, msg->opt); msg->opt = NULL; }}static voidmsgresetsigs(dns_message_t *msg, isc_boolean_t replying) { if (msg->sig_reserved > 0) { dns_message_renderrelease(msg, msg->sig_reserved); msg->sig_reserved = 0; } if (msg->tsig != NULL) { INSIST(dns_rdataset_isassociated(msg->tsig)); INSIST(msg->namepool != NULL); if (replying) { INSIST(msg->querytsig == NULL); msg->querytsig = msg->tsig; } else { dns_rdataset_disassociate(msg->tsig); isc_mempool_put(msg->rdspool, msg->tsig); if (msg->querytsig != NULL) { dns_rdataset_disassociate(msg->querytsig); isc_mempool_put(msg->rdspool, msg->querytsig); } } if (dns_name_dynamic(msg->tsigname)) dns_name_free(msg->tsigname, msg->mctx); isc_mempool_put(msg->namepool, msg->tsigname); msg->tsig = NULL; msg->tsigname = NULL; } else if (msg->querytsig != NULL && !replying) { dns_rdataset_disassociate(msg->querytsig); isc_mempool_put(msg->rdspool, msg->querytsig); msg->querytsig = NULL; } if (msg->sig0 != NULL) { INSIST(dns_rdataset_isassociated(msg->sig0)); dns_rdataset_disassociate(msg->sig0); isc_mempool_put(msg->rdspool, msg->sig0); if (msg->sig0name != NULL) { if (dns_name_dynamic(msg->sig0name)) dns_name_free(msg->sig0name, msg->mctx); isc_mempool_put(msg->namepool, msg->sig0name); } msg->sig0 = NULL; msg->sig0name = NULL; }}/* * Free all but one (or everything) for this message. This is used by * both dns_message_reset() and dns_message_destroy(). */static voidmsgreset(dns_message_t *msg, isc_boolean_t everything) { dns_msgblock_t *msgblock, *next_msgblock; isc_buffer_t *dynbuf, *next_dynbuf; dns_rdata_t *rdata; dns_rdatalist_t *rdatalist; msgresetnames(msg, 0); msgresetopt(msg); msgresetsigs(msg, ISC_FALSE); /* * Clean up linked lists. */ /* * Run through the free lists, and just unlink anything found there. * The memory isn't lost since these are part of message blocks we * have allocated. */ rdata = ISC_LIST_HEAD(msg->freerdata); while (rdata != NULL) { ISC_LIST_UNLINK(msg->freerdata, rdata, link); rdata = ISC_LIST_HEAD(msg->freerdata); } rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -