diff --git a/bin/tests/wire_test.c b/bin/tests/wire_test.c index a15cbc021e54216fc7edf79524dc9ab17446b930..7cab0139be804a9075b1b88f3660713eb00976d8 100644 --- a/bin/tests/wire_test.c +++ b/bin/tests/wire_test.c @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -35,42 +36,26 @@ #include #include #include - -#define DNS_FLAG_QR 0x8000U -#define DNS_FLAG_AA 0x0400U -#define DNS_FLAG_TC 0x0200U -#define DNS_FLAG_RD 0x0100U -#define DNS_FLAG_RA 0x0080U - -#define DNS_OPCODE_MASK 0x7000U -#define DNS_OPCODE_SHIFT 11 -#define DNS_RCODE_MASK 0x000FU - -typedef struct dns_message { - unsigned int id; - unsigned int flags; - unsigned int qcount; - unsigned int ancount; - unsigned int aucount; - unsigned int adcount; - dns_namelist_t question; - dns_namelist_t answer; - dns_namelist_t authority; - dns_namelist_t additional; -} dns_message_t; - -#define MAX_PREALLOCATED 100 +#include dns_decompress_t dctx; unsigned int rdcount, rlcount, ncount; -dns_name_t names[MAX_PREALLOCATED]; -dns_rdata_t rdatas[MAX_PREALLOCATED]; -dns_rdatalist_t lists[MAX_PREALLOCATED]; void getmessage(dns_message_t *message, isc_buffer_t *source, isc_buffer_t *target); dns_result_t printmessage(dns_message_t *message); +static inline void +CHECKRESULT(dns_result_t result, char *msg) +{ + if (result != DNS_R_SUCCESS) { + printf("%s: %s\n", msg, dns_result_totext(result)); + + exit(1); + } +} + + #ifdef NOISY static void print_wirename(isc_region_t *name) { @@ -98,232 +83,6 @@ fromhex(char c) { /* NOTREACHED */ } -static isc_uint16_t -getshort(isc_buffer_t *buffer) { - isc_region_t r; - - isc_buffer_remaining(buffer, &r); - if (r.length < 2) { - printf("not enough input\n"); - exit(5); - } - - return (isc_buffer_getuint16(buffer)); -} - -static unsigned int -getname(dns_name_t *name, isc_buffer_t *source, isc_buffer_t *target) { - unsigned char c[255]; - dns_result_t result; - isc_buffer_t text; - unsigned int current; -#ifdef NOISY - isc_region_t r; -#endif - - isc_buffer_init(&text, c, 255, ISC_BUFFERTYPE_TEXT); - dns_name_init(name, NULL); - - current = source->current; - if (dns_decompress_edns(&dctx) > 1 || !dns_decompress_strict(&dctx)) - dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL); - else - dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14); - result = dns_name_fromwire(name, source, &dctx, ISC_FALSE, target); - -#ifdef NOISY - if (result == DNS_R_SUCCESS) { - dns_name_toregion(name, &r); - print_wirename(&r); - printf("%u labels, %u bytes.\n", - dns_name_countlabels(name), - r.length); - result = dns_name_totext(name, ISC_FALSE, &text); - if (result == DNS_R_SUCCESS) { - isc_buffer_used(&text, &r); - printf("%.*s\n", (int)r.length, r.base); - } else - printf("%s\n", dns_result_totext(result)); - } else - printf("%s\n", dns_result_totext(result)); -#else - if (result != DNS_R_SUCCESS) - printf("%s\n", dns_result_totext(result)); -#endif - - return (source->current - current); -} - -static void -getquestions(isc_buffer_t *source, dns_namelist_t *section, unsigned int count, - isc_buffer_t *target) -{ - unsigned int type, rdclass; - dns_name_t *name, *curr; - dns_rdatalist_t *rdatalist; - isc_region_t r; - - ISC_LIST_INIT(*section); - while (count > 0) { - count--; - - if (ncount == MAX_PREALLOCATED) { - printf("out of names\n"); - exit(1); - } - name = &names[ncount++]; - - isc_buffer_remaining(source, &r); - isc_buffer_setactive(source, r.length); - (void)getname(name, source, target); - for (curr = ISC_LIST_HEAD(*section); - curr != NULL; - curr = ISC_LIST_NEXT(curr, link)) { - if (dns_name_compare(curr, name) == 0) { - ncount--; - name = curr; - break; - } - } - if (name != curr) - ISC_LIST_APPEND(*section, name, link); - type = getshort(source); - rdclass = getshort(source); - for (rdatalist = ISC_LIST_HEAD(name->list); - rdatalist != NULL; - rdatalist = ISC_LIST_NEXT(rdatalist, link)) { - if (rdatalist->rdclass == rdclass && - rdatalist->type == type) - break; - } - if (rdatalist == NULL) { - if (rlcount == MAX_PREALLOCATED) { - printf("out of rdatalists\n"); - exit(1); - } - rdatalist = &lists[rlcount++]; - rdatalist->rdclass = rdclass; - rdatalist->type = type; - rdatalist->ttl = 0; - ISC_LIST_INIT(rdatalist->rdata); - ISC_LIST_APPEND(name->list, rdatalist, link); - } else - printf(";; duplicate question\n"); - } -} - -static void -getsection(isc_buffer_t *source, dns_namelist_t *section, unsigned int count, - isc_buffer_t *target) -{ - unsigned int type, rdclass, ttl, rdlength; - isc_region_t r; - dns_name_t *name, *curr; - dns_rdata_t *rdata; - dns_rdatalist_t *rdatalist; - dns_result_t result; - - ISC_LIST_INIT(*section); - while (count > 0) { - count--; - - if (ncount == MAX_PREALLOCATED) { - printf("out of names\n"); - exit(1); - } - name = &names[ncount++]; - isc_buffer_remaining(source, &r); - isc_buffer_setactive(source, r.length); - (void)getname(name, source, target); - for (curr = ISC_LIST_HEAD(*section); - curr != NULL; - curr = ISC_LIST_NEXT(curr, link)) { - if (dns_name_compare(curr, name) == 0) { - ncount--; - name = curr; - break; - } - } - if (name != curr) - ISC_LIST_APPEND(*section, name, link); - type = getshort(source); - rdclass = getshort(source); - ttl = getshort(source); - ttl *= 65536; - ttl += getshort(source); - rdlength = getshort(source); - isc_buffer_remaining(source, &r); - if (r.length < rdlength) { - printf("unexpected end of rdata\n"); - exit(7); - } - isc_buffer_setactive(source, rdlength); - if (rdcount == MAX_PREALLOCATED) { - printf("out of rdata\n"); - exit(1); - } - rdata = &rdatas[rdcount++]; - dns_decompress_localinit(&dctx, name, source); - result = dns_rdata_fromwire(rdata, rdclass, type, - source, &dctx, ISC_FALSE, - target); - dns_decompress_localinvalidate(&dctx); - if (result != DNS_R_SUCCESS) { - printf("%s\n", dns_result_totext(result)); - exit(1); - } - for (rdatalist = ISC_LIST_HEAD(name->list); - rdatalist != NULL; - rdatalist = ISC_LIST_NEXT(rdatalist, link)) { - if (rdatalist->rdclass == rdclass && - rdatalist->type == type) - break; - } - if (rdatalist == NULL) { - if (rlcount == MAX_PREALLOCATED) { - printf("out of rdatalists\n"); - exit(1); - } - rdatalist = &lists[rlcount++]; - rdatalist->rdclass = rdclass; - rdatalist->type = type; - rdatalist->ttl = ttl; - ISC_LIST_INIT(rdatalist->rdata); - ISC_LIST_APPEND(name->list, rdatalist, link); - } else { - if (ttl < rdatalist->ttl) - rdatalist->ttl = ttl; - } - - ISC_LIST_APPEND(rdatalist->rdata, rdata, link); - } -} - -void -getmessage(dns_message_t *message, isc_buffer_t *source, - isc_buffer_t *target) -{ - isc_region_t r; - - message->id = getshort(source); - message->flags = getshort(source); - message->qcount = getshort(source); - message->ancount = getshort(source); - message->aucount = getshort(source); - message->adcount = getshort(source); - - dns_decompress_init(&dctx, -1, ISC_FALSE); - getquestions(source, &message->question, message->qcount, target); - getsection(source, &message->answer, message->ancount, target); - getsection(source, &message->authority, message->aucount, target); - getsection(source, &message->additional, message->adcount, target); - dns_decompress_invalidate(&dctx); - - isc_buffer_remaining(source, &r); - if (r.length != 0) - printf("extra data at end of packet.\n"); -} - static char *opcodetext[] = { "QUERY", "IQUERY", @@ -362,85 +121,50 @@ static char *rcodetext[] = { "RESERVED15" }; -static void -printquestions(dns_namelist_t *section) { - dns_name_t *name; - dns_rdatalist_t *rdatalist; - char t[1000]; - isc_buffer_t target; - dns_result_t result; - - printf(";; QUERY SECTION:\n"); - for (name = ISC_LIST_HEAD(*section); - name != NULL; - name = ISC_LIST_NEXT(name, link)) { - isc_buffer_init(&target, t, sizeof t, ISC_BUFFERTYPE_TEXT); - result = dns_name_totext(name, ISC_FALSE, &target); - if (result != DNS_R_SUCCESS) { - printf("%s\n", dns_result_totext(result)); - exit(15); - } - for (rdatalist = ISC_LIST_HEAD(name->list); - rdatalist != NULL; - rdatalist = ISC_LIST_NEXT(rdatalist, link)) { - printf(";;\t%.*s, type = ", (int)target.used, - (char *)target.base); - isc_buffer_clear(&target); - result = dns_rdatatype_totext(rdatalist->type, - &target); - if (result != DNS_R_SUCCESS) { - printf("%s\n", - dns_result_totext(result)); - exit(16); - } - printf("%.*s, class = ", (int)target.used, - (char *)target.base); - isc_buffer_clear(&target); - result = dns_rdataclass_totext(rdatalist->rdclass, - &target); - if (result != DNS_R_SUCCESS) { - printf("%s\n", dns_result_totext(result)); - exit(17); - } - printf("%.*s\n", (int)target.used, - (char *)target.base); - } - } -} - static dns_result_t -printsection(dns_namelist_t *section, char *section_name) { +printsection(dns_message_t *msg, dns_section_t sectionid, char *section_name) +{ dns_name_t *name, *print_name; - dns_rdatalist_t *rdatalist; - dns_rdataset_t rdataset; + dns_rdataset_t *rdataset; isc_buffer_t target; dns_result_t result; isc_region_t r; dns_name_t empty_name; char t[1000]; isc_boolean_t first; + isc_boolean_t no_rdata; + + if (sectionid == DNS_SECTION_QUESTION) + no_rdata = ISC_TRUE; + else + no_rdata = ISC_FALSE; - dns_rdataset_init(&rdataset); - dns_name_init(&empty_name, NULL); printf("\n;; %s SECTION:\n", section_name); - for (name = ISC_LIST_HEAD(*section); - name != NULL; - name = ISC_LIST_NEXT(name, link)) { + + dns_name_init(&empty_name, NULL); + + result = dns_message_firstname(msg, sectionid); + if (result == DNS_R_NOMORE) + return (DNS_R_SUCCESS); + else if (result != DNS_R_SUCCESS) + return (result); + + for (;;) { + name = NULL; + dns_message_currentname(msg, sectionid, &name); + isc_buffer_init(&target, t, sizeof t, ISC_BUFFERTYPE_TEXT); first = ISC_TRUE; print_name = name; - for (rdatalist = ISC_LIST_HEAD(name->list); - rdatalist != NULL; - rdatalist = ISC_LIST_NEXT(rdatalist, link)) { - result = dns_rdatalist_tordataset(rdatalist, - &rdataset); - if (result != DNS_R_SUCCESS) - return (result); - result = dns_rdataset_totext(&rdataset, print_name, - ISC_FALSE, &target); + + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) { + result = dns_rdataset_totext(rdataset, print_name, + ISC_FALSE, &target, + no_rdata); if (result != DNS_R_SUCCESS) return (result); - dns_rdataset_disassociate(&rdataset); #ifdef USEINITALWS if (first) { print_name = &empty_name; @@ -450,53 +174,75 @@ printsection(dns_namelist_t *section, char *section_name) { } isc_buffer_used(&target, &r); printf("%.*s", (int)r.length, (char *)r.base); + + result = dns_message_nextname(msg, sectionid); + if (result == DNS_R_NOMORE) + break; + else if (result != DNS_R_SUCCESS) + return (result); } return (DNS_R_SUCCESS); } dns_result_t -printmessage(dns_message_t *message) { +printmessage(dns_message_t *msg) { isc_boolean_t did_flag = ISC_FALSE; - unsigned int opcode, rcode; dns_result_t result; - opcode = (message->flags & DNS_OPCODE_MASK) >> DNS_OPCODE_SHIFT; - rcode = message->flags & DNS_RCODE_MASK; + result = DNS_R_UNEXPECTED; + printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n", - opcodetext[opcode], rcodetext[rcode], message->id); + opcodetext[msg->opcode], rcodetext[msg->rcode], msg->id); + printf(";; flags: "); - if ((message->flags & DNS_FLAG_QR) != 0) { + if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) { printf("qr"); did_flag = ISC_TRUE; } - if ((message->flags & DNS_FLAG_AA) != 0) { + if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) { printf("%saa", did_flag ? " " : ""); did_flag = ISC_TRUE; } - if ((message->flags & DNS_FLAG_TC) != 0) { + if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) { printf("%stc", did_flag ? " " : ""); did_flag = ISC_TRUE; } - if ((message->flags & DNS_FLAG_RD) != 0) { + if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) { printf("%srd", did_flag ? " " : ""); did_flag = ISC_TRUE; } - if ((message->flags & DNS_FLAG_RA) != 0) { + if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) { printf("%sra", did_flag ? " " : ""); did_flag = ISC_TRUE; } printf("; QUERY: %u, ANSWER: %u, AUTHORITY: %u, ADDITIONAL: %u\n", - message->qcount, message->ancount, message->aucount, - message->adcount); - printquestions(&message->question); - result = printsection(&message->answer, "ANSWER"); + msg->counts[DNS_SECTION_QUESTION], + msg->counts[DNS_SECTION_ANSWER], + msg->counts[DNS_SECTION_AUTHORITY], + msg->counts[DNS_SECTION_ADDITIONAL]); + printf("; PSEUDOSECTIONS: OPT: %u, TSIG: %u\n", + msg->counts[DNS_SECTION_OPT], + msg->counts[DNS_SECTION_TSIG]); + + result = printsection(msg, DNS_SECTION_QUESTION, "QUESTION"); + if (result != DNS_R_SUCCESS) + return (result); + result = printsection(msg, DNS_SECTION_ANSWER, "ANSWER"); if (result != DNS_R_SUCCESS) return (result); - result = printsection(&message->authority, "AUTHORITY"); + result = printsection(msg, DNS_SECTION_AUTHORITY, "AUTHORITY"); + if (result != DNS_R_SUCCESS) + return (result); + result = printsection(msg, DNS_SECTION_ADDITIONAL, "ADDITIONAL"); + if (result != DNS_R_SUCCESS) + return (result); + result = printsection(msg, DNS_SECTION_OPT, "PSEUDOSECTION OPT"); + if (result != DNS_R_SUCCESS) + return (result); + result = printsection(msg, DNS_SECTION_TSIG, "PSEUDOSECTION TSIG"); if (result != DNS_R_SUCCESS) return (result); - result = printsection(&message->additional, "ADDITIONAL"); return (result); } @@ -506,16 +252,19 @@ int main(int argc, char *argv[]) { char *rp, *wp; unsigned char *bp; - isc_buffer_t source, target; + isc_buffer_t source; size_t len, i; int n; FILE *f; isc_boolean_t need_close = ISC_FALSE; unsigned char b[1000]; char s[1000]; - char t[5000]; - dns_message_t message; + dns_message_t *message; + dns_message_t *message2; dns_result_t result; + isc_mem_t *mctx; + + RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS); if (argc > 1) { f = fopen(argv[1], "r"); @@ -562,19 +311,26 @@ main(int argc, char *argv[]) { if (need_close) fclose(f); - rdcount = 0; - rlcount = 0; - ncount = 0; - + f = fopen("foo", "w"); + fwrite(b, bp - b, 1, f); + fclose(f); isc_buffer_init(&source, b, sizeof b, ISC_BUFFERTYPE_BINARY); isc_buffer_add(&source, bp - b); - isc_buffer_init(&target, t, sizeof t, ISC_BUFFERTYPE_BINARY); - getmessage(&message, &source, &target); - result = printmessage(&message); - if (result != DNS_R_SUCCESS) - printf("printmessage() failed: %s\n", - dns_result_totext(result)); + + result = dns_message_create(mctx, &message, DNS_MESSAGE_INTENT_PARSE); + CHECKRESULT(result, "dns_message_create failed"); + + result = dns_message_parse(message, &source); + CHECKRESULT(result, "dns_message_parse failed"); + + result = printmessage(message); + CHECKRESULT(result, "printmessage() failed"); + + dns_message_destroy(&message); + + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); return (0); } diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index 8f7dcb56a10e540d772074f89ed18a819b671601..e2d29f871ca851b1c2be9d357c16b3195b0822ee 100644 --- a/lib/dns/include/dns/message.h +++ b/lib/dns/include/dns/message.h @@ -56,15 +56,16 @@ ISC_LANG_BEGINDECLS -#define DNS_MESSAGE_QR 0x8000U -#define DNS_MESSAGE_AA 0x0400U -#define DNS_MESSAGE_TC 0x0200U -#define DNS_MESSAGE_RD 0x0100U -#define DNS_MESSAGE_RA 0x0080U +#define DNS_MESSAGEFLAG_QR 0x8000U +#define DNS_MESSAGEFLAG_AA 0x0400U +#define DNS_MESSAGEFLAG_TC 0x0200U +#define DNS_MESSAGEFLAG_RD 0x0100U +#define DNS_MESSAGEFLAG_RA 0x0080U #define DNS_MESSAGE_OPCODE_MASK 0x7000U #define DNS_MESSAGE_OPCODE_SHIFT 11 #define DNS_MESSAGE_RCODE_MASK 0x000fU +#define DNS_MESSAGE_FLAG_MASK 0x1ff0U #define DNS_MESSAGE_HEADER_LEN 12 /* 6 u_int16_t's */ diff --git a/lib/dns/message.c b/lib/dns/message.c index c73d000239b2c70091fa50b9eca628d395f2fc4c..07720a26de063f350c3cde26c829e1da51b60cc0 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -74,6 +75,7 @@ struct dns_msgblock { static inline void msgblock_free(isc_mem_t *, dns_msgblock_t *); + #define msgblock_get(block, type) \ ((type *)msgblock_internalget(block, sizeof(type))) @@ -375,6 +377,7 @@ msgreset(dns_message_t *msg, isc_boolean_t everything) dns_rdataset_disassociate(rds); rds = next_rds; } + name = next_name; } } @@ -508,7 +511,7 @@ dns_message_create(isc_mem_t *mctx, dns_message_t **msg, unsigned int intent) RDATASET_COUNT); if (msgblock == NULL) goto cleanup4; - ISC_LIST_APPEND(m->rdatas, msgblock, link); + ISC_LIST_APPEND(m->rdatasets, msgblock, link); if (intent == DNS_MESSAGE_INTENT_PARSE) { msgblock = msgblock_allocate(mctx, sizeof(dns_rdatalist_t), @@ -518,6 +521,7 @@ dns_message_create(isc_mem_t *mctx, dns_message_t **msg, unsigned int intent) ISC_LIST_APPEND(m->rdatalists, msgblock, link); } + *msg = m; return (DNS_R_SUCCESS); /* @@ -569,9 +573,11 @@ findname(dns_name_t **foundname, dns_name_t *target, dns_namelist_t *section) { dns_name_t *curr; + printf("-----\n"); for (curr = ISC_LIST_TAIL(*section) ; curr != NULL ; curr = ISC_LIST_PREV(curr, link)) { + printf("curr = %p\n", curr); if (dns_name_compare(curr, target) == 0) { if (foundname != NULL) *foundname = curr; @@ -641,6 +647,41 @@ getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg, return (DNS_R_UNEXPECTED); /* should never get here... XXXMLG */ } +static dns_result_t +getrdata(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg, + dns_decompress_t *dctx, dns_rdataclass_t rdclass, + dns_rdatatype_t rdtype, unsigned int rdatalen, dns_rdata_t *rdata) +{ + isc_buffer_t *scratch; + dns_result_t result; + unsigned int tries; + + scratch = currentbuffer(msg); + + isc_buffer_setactive(source, rdatalen); + dns_decompress_localinit(dctx, name, source); + + tries = 0; + while (tries < 2) { + result = dns_rdata_fromwire(rdata, rdclass, rdtype, + source, dctx, ISC_FALSE, + scratch); + + if (result == DNS_R_NOSPACE) { + tries++; + + result = newbuffer(msg); + if (result != DNS_R_SUCCESS) + return (result); + + scratch = currentbuffer(msg); + } else { + return (result); + } + } + + return (DNS_R_UNEXPECTED); /* should never get here... XXXMLG */ +} static dns_result_t getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx) @@ -666,6 +707,8 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx) /* * Parse the name out of this packet. */ + isc_buffer_remaining(source, &r); + isc_buffer_setactive(source, r.length); result = getname(name, source, msg, dctx); if (result != DNS_R_SUCCESS) return (result); @@ -679,17 +722,24 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx) result = findname(&name2, name, section); /* - * If it is a new name, append to the section. Note that + * If it is the first name in the section, accept it. + * + * If it is not, but is not the same as the name already + * in the question section, append to the section. Note that * here in the question section this is illegal, so return * FORMERR. In the future, check the opcode to see if * this should be legal or not. In either case we no longer * need this name pointer. */ - releasename(msg, name); - if (result != DNS_R_SUCCESS) - return (DNS_R_FORMERR); - name = name2; - ISC_LIST_APPEND(*section, name, link); + if (result != DNS_R_SUCCESS) { + if (ISC_LIST_EMPTY(*section)) { + ISC_LIST_APPEND(*section, name, link); + } else { + return (DNS_R_FORMERR); + } + } else { + name = name2; + } /* * Get type and class. @@ -734,6 +784,7 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx) rdatalist->ttl = 0; ISC_LIST_INIT(rdatalist->rdata); + dns_rdataset_init(rdataset); result = dns_rdatalist_tordataset(rdatalist, rdataset); if (result != DNS_R_SUCCESS) return (result); @@ -758,6 +809,7 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, dns_result_t result; dns_rdatatype_t rdtype; dns_rdataclass_t rdclass; + dns_rdata_t *rdata; dns_ttl_t ttl; dns_namelist_t *section; @@ -771,6 +823,8 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, /* * Parse the name out of this packet. */ + isc_buffer_remaining(source, &r); + isc_buffer_setactive(source, r.length); result = getname(name, source, msg, dctx); if (result != DNS_R_SUCCESS) return (result); @@ -789,10 +843,9 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, if (result == DNS_R_SUCCESS) { releasename(msg, name); name = name2; + } else { + ISC_LIST_APPEND(*section, name, link); } - name = name2; - ISC_LIST_APPEND(msg->sections[DNS_SECTION_QUESTION], - name, link); /* * Get type, class, ttl, and rdatalen. Verify that at least @@ -831,42 +884,51 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, result = findtype(&rdataset, name, rdtype); /* - * Oh hurt me... I need to add this name to the rdatalist, - * but I have to cheat to get at that given the rdataset... - * - * This sucks. XXXMLG stop point, code below probably wrong. + * 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. */ -#if 0 if (result != DNS_R_SUCCESS) { rdataset = newrdataset(msg); if (rdataset == NULL) return (DNS_R_NOMEMORY); + rdatalist = newrdatalist(msg); + if (rdatalist == NULL) + return (DNS_R_NOMEMORY); - ISC_LIST_APPEND(section, rdataset, - - return (DNS_R_FORMERR); -#endif + rdatalist->type = rdtype; + rdatalist->rdclass = rdclass; + rdatalist->ttl = ttl; + ISC_LIST_INIT(rdatalist->rdata); - /* - * Allocate a new rdatalist, rdata. - */ - rdatalist = newrdatalist(msg); - rdataset = newrdataset(msg); + dns_rdataset_init(rdataset); + dns_rdatalist_tordataset(rdatalist, rdataset); + + ISC_LIST_APPEND(name->list, rdataset, link); + } /* - * Convert rdatalist to rdataset, and attach the latter to - * the name. + * Read the rdata from the wire format. */ - rdatalist->type = rdtype; - rdatalist->rdclass = rdclass; - rdatalist->ttl = 0; - ISC_LIST_INIT(rdatalist->rdata); - - result = dns_rdatalist_tordataset(rdatalist, rdataset); + rdata = newrdata(msg); + if (rdata == NULL) + return (DNS_R_NOMEMORY); + result = getrdata(name, source, msg, dctx, + rdclass, rdtype, rdatalen, rdata); if (result != DNS_R_SUCCESS) return (result); - ISC_LIST_APPEND(name->list, rdataset, link); + /* + * XXX 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); } return (DNS_R_SUCCESS); @@ -878,16 +940,21 @@ dns_message_parse(dns_message_t *msg, isc_buffer_t *source) isc_region_t r; dns_decompress_t dctx; dns_result_t ret; + isc_uint16_t tmpflags; REQUIRE(VALID_MESSAGE(msg)); REQUIRE(source != NULL); isc_buffer_remaining(source, &r); - if (r.length >= DNS_MESSAGE_HEADER_LEN) + if (r.length < DNS_MESSAGE_HEADER_LEN) return (DNS_R_UNEXPECTEDEND); msg->id = isc_buffer_getuint16(source); - msg->flags = isc_buffer_getuint16(source); + tmpflags = isc_buffer_getuint16(source); + msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK) + >> DNS_MESSAGE_OPCODE_SHIFT); + msg->rcode = (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); @@ -911,6 +978,10 @@ dns_message_parse(dns_message_t *msg, isc_buffer_t *source) if (ret != DNS_R_SUCCESS) return (ret); + isc_buffer_remaining(source, &r); + if (r.length != 0) + return (DNS_R_FORMERR); + /* * XXXMLG Need to check the tsig(s) here... */ @@ -1024,7 +1095,7 @@ dns_message_currentname(dns_message_t *msg, dns_section_t section, { REQUIRE(VALID_MESSAGE(msg)); REQUIRE(VALID_NAMED_SECTION(section)); - REQUIRE(name != NULL && name == NULL); + REQUIRE(name != NULL && *name == NULL); REQUIRE(msg->cursors[section] != NULL); *name = msg->cursors[section];