📄 message.c
字号:
ISC_LIST_INIT(rdatalist->rdata); dns_rdataset_init(rdataset); result = dns_rdatalist_tordataset(rdatalist, rdataset); if (result != ISC_R_SUCCESS) goto cleanup; rdataset->attributes |= DNS_RDATASETATTR_QUESTION; ISC_LIST_APPEND(name->list, rdataset, link); rdataset = NULL; } if (seen_problem) return (DNS_R_RECOVERABLE); return (ISC_R_SUCCESS); cleanup: if (rdataset != NULL) { INSIST(!dns_rdataset_isassociated(rdataset)); isc_mempool_put(msg->rdspool, rdataset); }#if 0 if (rdatalist != NULL) isc_mempool_put(msg->rdlpool, rdatalist);#endif if (free_name) isc_mempool_put(msg->namepool, name); return (result);}static isc_boolean_tupdate(dns_section_t section, dns_rdataclass_t rdclass) { if (section == DNS_SECTION_PREREQUISITE) return (ISC_TF(rdclass == dns_rdataclass_any || rdclass == dns_rdataclass_none)); if (section == DNS_SECTION_UPDATE) return (ISC_TF(rdclass == dns_rdataclass_any)); return (ISC_FALSE);}static isc_result_tgetsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, dns_section_t sectionid, unsigned int options){ isc_region_t r; unsigned int count, rdatalen; dns_name_t *name; dns_name_t *name2; dns_offsets_t *offsets; dns_rdataset_t *rdataset; dns_rdatalist_t *rdatalist; isc_result_t result; dns_rdatatype_t rdtype, covers; dns_rdataclass_t rdclass; dns_rdata_t *rdata; dns_ttl_t ttl; dns_namelist_t *section; isc_boolean_t free_name, free_rdataset; isc_boolean_t preserve_order, best_effort, seen_problem; isc_boolean_t issigzero; preserve_order = ISC_TF(options & DNS_MESSAGEPARSE_PRESERVEORDER); best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT); seen_problem = ISC_FALSE; for (count = 0; count < msg->counts[sectionid]; count++) { int recstart = source->current; isc_boolean_t skip_name_search, skip_type_search; section = &msg->sections[sectionid]; skip_name_search = ISC_FALSE; skip_type_search = ISC_FALSE; free_name = ISC_FALSE; free_rdataset = ISC_FALSE; name = isc_mempool_get(msg->namepool); if (name == NULL) return (ISC_R_NOMEMORY); free_name = ISC_TRUE; offsets = newoffsets(msg); if (offsets == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } dns_name_init(name, *offsets); /* * Parse the name out of this packet. */ isc_buffer_remainingregion(source, &r); isc_buffer_setactive(source, r.length); result = getname(name, source, msg, dctx); if (result != ISC_R_SUCCESS) goto cleanup; /* * Get type, class, ttl, and rdatalen. Verify that at least * rdatalen bytes remain. (Some of this is deferred to * later.) */ isc_buffer_remainingregion(source, &r); if (r.length < 2 + 2 + 4 + 2) { result = ISC_R_UNEXPECTEDEND; goto cleanup; } rdtype = isc_buffer_getuint16(source); rdclass = isc_buffer_getuint16(source); /* * If there was no question section, we may not yet have * established a class. Do so now. */ if (msg->state == DNS_SECTION_ANY && rdtype != dns_rdatatype_opt && /* class is UDP SIZE */ rdtype != dns_rdatatype_tsig && /* class is ANY */ rdtype != dns_rdatatype_tkey) { /* class is undefined */ msg->rdclass = rdclass; msg->state = DNS_SECTION_QUESTION; } /* * If this class is different than the one in the question * section, bail. */ if (msg->opcode != dns_opcode_update && rdtype != dns_rdatatype_tsig && rdtype != dns_rdatatype_opt && rdtype != dns_rdatatype_dnskey /* in a TKEY query */ && rdtype != dns_rdatatype_sig /* SIG(0) */ && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */ && msg->rdclass != rdclass) DO_FORMERR; /* * Special type handling for TSIG, OPT, and TKEY. */ if (rdtype == dns_rdatatype_tsig) { /* * If it is a tsig, verify that it is in the * additional data section. */ if (sectionid != DNS_SECTION_ADDITIONAL || rdclass != dns_rdataclass_any || count != msg->counts[sectionid] - 1) DO_FORMERR; msg->sigstart = recstart; skip_name_search = ISC_TRUE; skip_type_search = ISC_TRUE; } else if (rdtype == dns_rdatatype_opt) { /* * The name of an OPT record must be ".", it * must be in the additional data section, and * it must be the first OPT we've seen. */ if (!dns_name_equal(dns_rootname, name) || msg->opt != NULL) DO_FORMERR; skip_name_search = ISC_TRUE; skip_type_search = ISC_TRUE; } else if (rdtype == dns_rdatatype_tkey) { /* * A TKEY must be in the additional section if this * is a query, and the answer section if this is a * response. Unless it's a Win2000 client. * * Its class is ignored. */ dns_section_t tkeysection; if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0) tkeysection = DNS_SECTION_ADDITIONAL; else tkeysection = DNS_SECTION_ANSWER; if (sectionid != tkeysection && sectionid != DNS_SECTION_ANSWER) DO_FORMERR; } /* * ... now get ttl and rdatalen, and check buffer. */ ttl = isc_buffer_getuint32(source); rdatalen = isc_buffer_getuint16(source); r.length -= (2 + 2 + 4 + 2); if (r.length < rdatalen) { result = ISC_R_UNEXPECTEDEND; goto cleanup; } /* * Read the rdata from the wire format. Interpret the * rdata according to its actual class, even if it had a * DynDNS meta-class in the packet (unless this is a TSIG). * Then put the meta-class back into the finished rdata. */ rdata = newrdata(msg); if (rdata == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } if (msg->opcode == dns_opcode_update && update(sectionid, rdclass)) { if (rdatalen != 0) { result = DNS_R_FORMERR; goto cleanup; } /* * When the rdata is empty, the data pointer is * never dereferenced, but it must still be non-NULL. * Casting 1 rather than "" avoids warnings about * discarding the const attribute of a string, * for compilers that would warn about such things. */ rdata->data = (unsigned char *)1; rdata->length = 0; rdata->rdclass = rdclass; rdata->type = rdtype; rdata->flags = DNS_RDATA_UPDATE; result = ISC_R_SUCCESS; } else if (rdtype == dns_rdatatype_tsig) result = getrdata(source, msg, dctx, rdclass, rdtype, rdatalen, rdata); else result = getrdata(source, msg, dctx, msg->rdclass, rdtype, rdatalen, rdata); if (result != ISC_R_SUCCESS) goto cleanup; rdata->rdclass = rdclass; issigzero = ISC_FALSE; if (rdtype == dns_rdatatype_rrsig && rdata->flags == 0) { covers = dns_rdata_covers(rdata); if (covers == 0) DO_FORMERR; } else if (rdtype == dns_rdatatype_sig /* SIG(0) */ && rdata->flags == 0) { covers = dns_rdata_covers(rdata); if (covers == 0) { if (sectionid != DNS_SECTION_ADDITIONAL || count != msg->counts[sectionid] - 1) DO_FORMERR; msg->sigstart = recstart; skip_name_search = ISC_TRUE; skip_type_search = ISC_TRUE; issigzero = ISC_TRUE; } } else covers = 0; /* * If we are doing a dynamic update or this is a meta-type, * don't bother searching for a name, just append this one * to the end of the message. */ if (preserve_order || msg->opcode == dns_opcode_update || skip_name_search) { if (rdtype != dns_rdatatype_opt && rdtype != dns_rdatatype_tsig && !issigzero) { ISC_LIST_APPEND(*section, name, link); free_name = ISC_FALSE; } } else { /* * Run through the section, looking to see if this name * is already there. If it is found, put back the * allocated name since we no longer need it, and set * our name pointer to point to the name we found. */ result = findname(&name2, name, section); /* * If it is a new name, append to the section. */ if (result == ISC_R_SUCCESS) { isc_mempool_put(msg->namepool, name); name = name2; } else { ISC_LIST_APPEND(*section, name, link); } free_name = ISC_FALSE; } /* * Search name for the particular type and class. * Skip this stage if in update mode or this is a meta-type. */ if (preserve_order || msg->opcode == dns_opcode_update || skip_type_search) result = ISC_R_NOTFOUND; else { /* * If this is a type that can only occur in * the question section, fail. */ if (dns_rdatatype_questiononly(rdtype)) DO_FORMERR; rdataset = NULL; result = dns_message_findtype(name, rdtype, covers, &rdataset); } /* * If we found an rdataset that matches, we need to * append this rdata to that set. If we did not, we need * to create a new rdatalist, store the important bits there, * convert it to an rdataset, and link the latter to the name. * Yuck. When appending, make certain that the type isn't * a singleton type, such as SOA or CNAME. * * Note that this check will be bypassed when preserving order, * the opcode is an update, or the type search is skipped. */ if (result == ISC_R_SUCCESS) { if (dns_rdatatype_issingleton(rdtype)) DO_FORMERR; } if (result == ISC_R_NOTFOUND) { rdataset = isc_mempool_get(msg->rdspool); if (rdataset == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } free_rdataset = ISC_TRUE; rdatalist = newrdatalist(msg); if (rdatalist == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } rdatalist->type = rdtype; rdatalist->covers = covers; rdatalist->rdclass = rdclass; rdatalist->ttl = ttl; ISC_LIST_INIT(rdatalist->rdata); dns_rdataset_init(rdataset); RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) == ISC_R_SUCCESS); if (rdtype != dns_rdatatype_opt && rdtype != dns_rdatatype_tsig && !issigzero) { ISC_LIST_APPEND(name->list, rdataset, link); free_rdataset = ISC_FALSE; } } /* * Minimize TTLs. * * Section 5.2 of RFC 2181 says we should drop * nonauthoritative rrsets where the TTLs differ, but we * currently treat them the as if they were authoritative and * minimize them. */ if (ttl != rdataset->ttl) { rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED; if (ttl < rdataset->ttl) rdataset->ttl = ttl; } /* * XXXMLG Perform a totally ugly hack here to pull * the rdatalist out of the private field in the rdataset, * and append this rdata to the rdatalist's linked list * of rdata. */ rdatalist = (dns_rdatalist_t *)(rdataset->private1); ISC_LIST_APPEND(rdatalist->rdata, rdata, link); /* * If this is an OPT record, remember it. Also, set * the extended rcode. Note that msg->opt will only be set * if best-effort parsing is enabled. */ if (rdtype == dns_rdatatype_opt && msg->opt == NULL) { dns_rcode_t ercode; msg->opt = rdataset; rdataset = NULL; free_rdataset = ISC_FALSE; ercode = (dns_rcode_t) ((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK) >> 20); msg->rcode |= ercode; isc_mempool_put(msg->namepool, name); free_name = ISC_FALSE; } /* * If this is an SIG(0) or TSIG record, remember it. Note * that msg->sig0 or msg->tsig will only be set if best-effort * parsing is enabled. */ if (issigzero && msg->sig0 == NULL) { msg->sig0 = rdataset; msg->sig0name = name; rdataset = NULL; free_rdataset = ISC_FALSE; free_name = ISC_FALSE; } else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) { msg->tsig = rdataset; msg->tsigname = name; rdataset = NULL; free_rdataset = ISC_FALSE; free_name = ISC_FALSE; } INSIST(free_name == ISC_FALSE); INSIST(free_rdataset == ISC_FALSE); } if (seen_problem) return (DNS_R_RECOVERABLE); return (ISC_R_SUCCESS); cleanup: if (free_name) isc_mempool_put(msg->namepool, name); if (free_rdataset) isc_mempool_put(msg->rdspool, rdataset); return (result);}isc_result_tdns_message_parse(dns_message_t *msg, isc_buffer_t *source, unsigned int options){ isc_region_t r; dns_decompress_t dctx; isc_result_t ret; isc_uint16_t tmpflags; isc_buffer_t origsource; isc_boolean_t seen_problem; isc_boolean_t ignore_tc; REQUIRE(DNS_MESSAGE_VALID(msg)); REQUIRE(source != NULL); REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE); seen_problem = ISC_FALSE; ignore_tc = ISC_TF(options & DNS_MESSAGEPARSE_IGNORETRUNCATION); origsource = *source; msg->header_ok = 0; msg->question_ok = 0; isc_buffer_remainingregion(source, &r); if (r.length < DNS_MESSAGE_HEADERLEN) return (ISC_R_UNEXPECTEDEND); msg->id = isc_buffer_getuint16(source); tmpflags = isc_buffer_getuint16(source); msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK) >> DNS_MESSAGE_OPCODE_SHIFT); msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK); msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK); msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source); msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source); msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source); msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source); msg->header_ok = 1; /* * -1 means no EDNS. */ dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY); dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14); ret = getquestions(source, msg, &dctx, options); if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) goto truncated; if (ret == DNS_R_RECOVERABLE) { seen_problem = ISC_TRUE; ret = ISC_R_SUCCESS; } if (ret != ISC_R_SUCCESS) return (ret); msg->question_ok = 1; ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options); if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) goto truncated; if (ret == DNS_R_RECOVERABLE) { seen_problem = ISC_TRUE; ret = ISC_R_SUCCESS; } if (ret != ISC_R_SUCCESS) return (ret); ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options); if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) goto truncated; if (ret == DNS_R_RECOVERABLE) { seen_problem = ISC_TRUE; ret = ISC_R_SUCCESS; } if (ret != ISC_R_SUCCESS) return (ret); ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options); if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) goto truncated; if (ret == DNS_R_RECOVERABLE) { seen_problem = ISC_TRUE; ret = ISC_R_SUCCESS; } if (ret != ISC_R_SUCCESS) return (ret); isc_buffer_remainingregion(source, &r); if (r.length != 0) { isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -