message.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /*! \file */
00019 
00020 /***
00021  *** Imports
00022  ***/
00023 
00024 #include <config.h>
00025 #include <ctype.h>
00026 
00027 #include <isc/buffer.h>
00028 #include <isc/mem.h>
00029 #include <isc/print.h>
00030 #include <isc/string.h>         /* Required for HP/UX (and others?) */
00031 #include <isc/util.h>
00032 
00033 #include <dns/dnssec.h>
00034 #include <dns/keyvalues.h>
00035 #include <dns/log.h>
00036 #include <dns/masterdump.h>
00037 #include <dns/message.h>
00038 #include <dns/opcode.h>
00039 #include <dns/rdata.h>
00040 #include <dns/rdatalist.h>
00041 #include <dns/rdataset.h>
00042 #include <dns/rdatastruct.h>
00043 #include <dns/result.h>
00044 #include <dns/tsig.h>
00045 #include <dns/ttl.h>
00046 #include <dns/view.h>
00047 
00048 #ifdef SKAN_MSG_DEBUG
00049 static void
00050 hexdump(const char *msg, const char *msg2, void *base, size_t len) {
00051         unsigned char *p;
00052         unsigned int cnt;
00053 
00054         p = base;
00055         cnt = 0;
00056 
00057         printf("*** %s [%s] (%u bytes @ %p)\n", msg, msg2, len, base);
00058 
00059         while (cnt < len) {
00060                 if (cnt % 16 == 0)
00061                         printf("%p: ", p);
00062                 else if (cnt % 8 == 0)
00063                         printf(" |");
00064                 printf(" %02x %c", *p, (isprint(*p) ? *p : ' '));
00065                 p++;
00066                 cnt++;
00067 
00068                 if (cnt % 16 == 0)
00069                         printf("\n");
00070         }
00071 
00072         if (cnt % 16 != 0)
00073                 printf("\n");
00074 }
00075 #endif
00076 
00077 #define DNS_MESSAGE_OPCODE_MASK         0x7800U
00078 #define DNS_MESSAGE_OPCODE_SHIFT        11
00079 #define DNS_MESSAGE_RCODE_MASK          0x000fU
00080 #define DNS_MESSAGE_FLAG_MASK           0x8ff0U
00081 #define DNS_MESSAGE_EDNSRCODE_MASK      0xff000000U
00082 #define DNS_MESSAGE_EDNSRCODE_SHIFT     24
00083 #define DNS_MESSAGE_EDNSVERSION_MASK    0x00ff0000U
00084 #define DNS_MESSAGE_EDNSVERSION_SHIFT   16
00085 
00086 #define VALID_NAMED_SECTION(s)  (((s) > DNS_SECTION_ANY) \
00087                                  && ((s) < DNS_SECTION_MAX))
00088 #define VALID_SECTION(s)        (((s) >= DNS_SECTION_ANY) \
00089                                  && ((s) < DNS_SECTION_MAX))
00090 #define ADD_STRING(b, s)        {if (strlen(s) >= \
00091                                    isc_buffer_availablelength(b)) \
00092                                        return(ISC_R_NOSPACE); else \
00093                                        isc_buffer_putstr(b, s);}
00094 #define VALID_PSEUDOSECTION(s)  (((s) >= DNS_PSEUDOSECTION_ANY) \
00095                                  && ((s) < DNS_PSEUDOSECTION_MAX))
00096 
00097 #define OPTOUT(x) (((x)->attributes & DNS_RDATASETATTR_OPTOUT) != 0)
00098 
00099 /*%
00100  * This is the size of each individual scratchpad buffer, and the numbers
00101  * of various block allocations used within the server.
00102  * XXXMLG These should come from a config setting.
00103  */
00104 #define SCRATCHPAD_SIZE         512
00105 #define NAME_COUNT                8
00106 #define OFFSET_COUNT              4
00107 #define RDATA_COUNT               8
00108 #define RDATALIST_COUNT           8
00109 #define RDATASET_COUNT           RDATALIST_COUNT
00110 
00111 /*%
00112  * Text representation of the different items, for message_totext
00113  * functions.
00114  */
00115 static const char *sectiontext[] = {
00116         "QUESTION",
00117         "ANSWER",
00118         "AUTHORITY",
00119         "ADDITIONAL"
00120 };
00121 
00122 static const char *updsectiontext[] = {
00123         "ZONE",
00124         "PREREQUISITE",
00125         "UPDATE",
00126         "ADDITIONAL"
00127 };
00128 
00129 static const char *opcodetext[] = {
00130         "QUERY",
00131         "IQUERY",
00132         "STATUS",
00133         "RESERVED3",
00134         "NOTIFY",
00135         "UPDATE",
00136         "RESERVED6",
00137         "RESERVED7",
00138         "RESERVED8",
00139         "RESERVED9",
00140         "RESERVED10",
00141         "RESERVED11",
00142         "RESERVED12",
00143         "RESERVED13",
00144         "RESERVED14",
00145         "RESERVED15"
00146 };
00147 
00148 static const char *rcodetext[] = {
00149         "NOERROR",
00150         "FORMERR",
00151         "SERVFAIL",
00152         "NXDOMAIN",
00153         "NOTIMP",
00154         "REFUSED",
00155         "YXDOMAIN",
00156         "YXRRSET",
00157         "NXRRSET",
00158         "NOTAUTH",
00159         "NOTZONE",
00160         "RESERVED11",
00161         "RESERVED12",
00162         "RESERVED13",
00163         "RESERVED14",
00164         "RESERVED15",
00165         "BADVERS"
00166 };
00167 
00168 
00169 /*%
00170  * "helper" type, which consists of a block of some type, and is linkable.
00171  * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer
00172  * size, or the allocated elements will not be aligned correctly.
00173  */
00174 struct dns_msgblock {
00175         unsigned int                    count;
00176         unsigned int                    remaining;
00177         ISC_LINK(dns_msgblock_t)        link;
00178 }; /* dynamically sized */
00179 
00180 static inline dns_msgblock_t *
00181 msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
00182 
00183 #define msgblock_get(block, type) \
00184         ((type *)msgblock_internalget(block, sizeof(type)))
00185 
00186 static inline void *
00187 msgblock_internalget(dns_msgblock_t *, unsigned int);
00188 
00189 static inline void
00190 msgblock_reset(dns_msgblock_t *);
00191 
00192 static inline void
00193 msgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);
00194 
00195 static void
00196 logfmtpacket(dns_message_t *message, const char *description,
00197              isc_sockaddr_t *address, isc_logcategory_t *category,
00198              isc_logmodule_t *module, const dns_master_style_t *style,
00199              int level, isc_mem_t *mctx);
00200 
00201 /*
00202  * Allocate a new dns_msgblock_t, and return a pointer to it.  If no memory
00203  * is free, return NULL.
00204  */
00205 static inline dns_msgblock_t *
00206 msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
00207                   unsigned int count)
00208 {
00209         dns_msgblock_t *block;
00210         unsigned int length;
00211 
00212         length = sizeof(dns_msgblock_t) + (sizeof_type * count);
00213 
00214         block = isc_mem_get(mctx, length);
00215         if (block == NULL)
00216                 return (NULL);
00217 
00218         block->count = count;
00219         block->remaining = count;
00220 
00221         ISC_LINK_INIT(block, link);
00222 
00223         return (block);
00224 }
00225 
00226 /*
00227  * Return an element from the msgblock.  If no more are available, return
00228  * NULL.
00229  */
00230 static inline void *
00231 msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
00232         void *ptr;
00233 
00234         if (block == NULL || block->remaining == 0)
00235                 return (NULL);
00236 
00237         block->remaining--;
00238 
00239         ptr = (((unsigned char *)block)
00240                + sizeof(dns_msgblock_t)
00241                + (sizeof_type * block->remaining));
00242 
00243         return (ptr);
00244 }
00245 
00246 static inline void
00247 msgblock_reset(dns_msgblock_t *block) {
00248         block->remaining = block->count;
00249 }
00250 
00251 /*
00252  * Release memory associated with a message block.
00253  */
00254 static inline void
00255 msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, unsigned int sizeof_type)
00256 {
00257         unsigned int length;
00258 
00259         length = sizeof(dns_msgblock_t) + (sizeof_type * block->count);
00260 
00261         isc_mem_put(mctx, block, length);
00262 }
00263 
00264 /*
00265  * Allocate a new dynamic buffer, and attach it to this message as the
00266  * "current" buffer.  (which is always the last on the list, for our
00267  * uses)
00268  */
00269 static inline isc_result_t
00270 newbuffer(dns_message_t *msg, unsigned int size) {
00271         isc_result_t result;
00272         isc_buffer_t *dynbuf;
00273 
00274         dynbuf = NULL;
00275         result = isc_buffer_allocate(msg->mctx, &dynbuf, size);
00276         if (result != ISC_R_SUCCESS)
00277                 return (ISC_R_NOMEMORY);
00278 
00279         ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
00280         return (ISC_R_SUCCESS);
00281 }
00282 
00283 static inline isc_buffer_t *
00284 currentbuffer(dns_message_t *msg) {
00285         isc_buffer_t *dynbuf;
00286 
00287         dynbuf = ISC_LIST_TAIL(msg->scratchpad);
00288         INSIST(dynbuf != NULL);
00289 
00290         return (dynbuf);
00291 }
00292 
00293 static inline void
00294 releaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
00295         ISC_LIST_PREPEND(msg->freerdata, rdata, link);
00296 }
00297 
00298 static inline dns_rdata_t *
00299 newrdata(dns_message_t *msg) {
00300         dns_msgblock_t *msgblock;
00301         dns_rdata_t *rdata;
00302 
00303         rdata = ISC_LIST_HEAD(msg->freerdata);
00304         if (rdata != NULL) {
00305                 ISC_LIST_UNLINK(msg->freerdata, rdata, link);
00306                 return (rdata);
00307         }
00308 
00309         msgblock = ISC_LIST_TAIL(msg->rdatas);
00310         rdata = msgblock_get(msgblock, dns_rdata_t);
00311         if (rdata == NULL) {
00312                 msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t),
00313                                              RDATA_COUNT);
00314                 if (msgblock == NULL)
00315                         return (NULL);
00316 
00317                 ISC_LIST_APPEND(msg->rdatas, msgblock, link);
00318 
00319                 rdata = msgblock_get(msgblock, dns_rdata_t);
00320         }
00321 
00322         dns_rdata_init(rdata);
00323         return (rdata);
00324 }
00325 
00326 static inline void
00327 releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
00328         ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
00329 }
00330 
00331 static inline dns_rdatalist_t *
00332 newrdatalist(dns_message_t *msg) {
00333         dns_msgblock_t *msgblock;
00334         dns_rdatalist_t *rdatalist;
00335 
00336         rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
00337         if (rdatalist != NULL) {
00338                 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
00339                 goto out;
00340         }
00341 
00342         msgblock = ISC_LIST_TAIL(msg->rdatalists);
00343         rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
00344         if (rdatalist == NULL) {
00345                 msgblock = msgblock_allocate(msg->mctx,
00346                                              sizeof(dns_rdatalist_t),
00347                                              RDATALIST_COUNT);
00348                 if (msgblock == NULL)
00349                         return (NULL);
00350 
00351                 ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
00352 
00353                 rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
00354         }
00355  out:
00356         if (rdatalist != NULL)
00357                 dns_rdatalist_init(rdatalist);
00358 
00359         return (rdatalist);
00360 }
00361 
00362 static inline dns_offsets_t *
00363 newoffsets(dns_message_t *msg) {
00364         dns_msgblock_t *msgblock;
00365         dns_offsets_t *offsets;
00366 
00367         msgblock = ISC_LIST_TAIL(msg->offsets);
00368         offsets = msgblock_get(msgblock, dns_offsets_t);
00369         if (offsets == NULL) {
00370                 msgblock = msgblock_allocate(msg->mctx,
00371                                              sizeof(dns_offsets_t),
00372                                              OFFSET_COUNT);
00373                 if (msgblock == NULL)
00374                         return (NULL);
00375 
00376                 ISC_LIST_APPEND(msg->offsets, msgblock, link);
00377 
00378                 offsets = msgblock_get(msgblock, dns_offsets_t);
00379         }
00380 
00381         return (offsets);
00382 }
00383 
00384 static inline void
00385 msginitheader(dns_message_t *m) {
00386         m->id = 0;
00387         m->flags = 0;
00388         m->rcode = 0;
00389         m->opcode = 0;
00390         m->rdclass = 0;
00391 }
00392 
00393 static inline void
00394 msginitprivate(dns_message_t *m) {
00395         unsigned int i;
00396 
00397         for (i = 0; i < DNS_SECTION_MAX; i++) {
00398                 m->cursors[i] = NULL;
00399                 m->counts[i] = 0;
00400         }
00401         m->opt = NULL;
00402         m->sig0 = NULL;
00403         m->sig0name = NULL;
00404         m->tsig = NULL;
00405         m->tsigname = NULL;
00406         m->state = DNS_SECTION_ANY;  /* indicate nothing parsed or rendered */
00407         m->opt_reserved = 0;
00408         m->sig_reserved = 0;
00409         m->reserved = 0;
00410         m->buffer = NULL;
00411 }
00412 
00413 static inline void
00414 msginittsig(dns_message_t *m) {
00415         m->tsigstatus = dns_rcode_noerror;
00416         m->querytsigstatus = dns_rcode_noerror;
00417         m->tsigkey = NULL;
00418         m->tsigctx = NULL;
00419         m->sigstart = -1;
00420         m->sig0key = NULL;
00421         m->sig0status = dns_rcode_noerror;
00422         m->timeadjust = 0;
00423 }
00424 
00425 /*
00426  * Init elements to default state.  Used both when allocating a new element
00427  * and when resetting one.
00428  */
00429 static inline void
00430 msginit(dns_message_t *m) {
00431         msginitheader(m);
00432         msginitprivate(m);
00433         msginittsig(m);
00434         m->header_ok = 0;
00435         m->question_ok = 0;
00436         m->tcp_continuation = 0;
00437         m->verified_sig = 0;
00438         m->verify_attempted = 0;
00439         m->order = NULL;
00440         m->order_arg = NULL;
00441         m->query.base = NULL;
00442         m->query.length = 0;
00443         m->free_query = 0;
00444         m->saved.base = NULL;
00445         m->saved.length = 0;
00446         m->free_saved = 0;
00447         m->sitok = 0;
00448         m->sitbad = 0;
00449         m->querytsig = NULL;
00450 }
00451 
00452 static inline void
00453 msgresetnames(dns_message_t *msg, unsigned int first_section) {
00454         unsigned int i;
00455         dns_name_t *name, *next_name;
00456         dns_rdataset_t *rds, *next_rds;
00457 
00458         /*
00459          * Clean up name lists by calling the rdataset disassociate function.
00460          */
00461         for (i = first_section; i < DNS_SECTION_MAX; i++) {
00462                 name = ISC_LIST_HEAD(msg->sections[i]);
00463                 while (name != NULL) {
00464                         next_name = ISC_LIST_NEXT(name, link);
00465                         ISC_LIST_UNLINK(msg->sections[i], name, link);
00466 
00467                         rds = ISC_LIST_HEAD(name->list);
00468                         while (rds != NULL) {
00469                                 next_rds = ISC_LIST_NEXT(rds, link);
00470                                 ISC_LIST_UNLINK(name->list, rds, link);
00471 
00472                                 INSIST(dns_rdataset_isassociated(rds));
00473                                 dns_rdataset_disassociate(rds);
00474                                 isc_mempool_put(msg->rdspool, rds);
00475                                 rds = next_rds;
00476                         }
00477                         if (dns_name_dynamic(name))
00478                                 dns_name_free(name, msg->mctx);
00479                         isc_mempool_put(msg->namepool, name);
00480                         name = next_name;
00481                 }
00482         }
00483 }
00484 
00485 static void
00486 msgresetopt(dns_message_t *msg)
00487 {
00488         if (msg->opt != NULL) {
00489                 if (msg->opt_reserved > 0) {
00490                         dns_message_renderrelease(msg, msg->opt_reserved);
00491                         msg->opt_reserved = 0;
00492                 }
00493                 INSIST(dns_rdataset_isassociated(msg->opt));
00494                 dns_rdataset_disassociate(msg->opt);
00495                 isc_mempool_put(msg->rdspool, msg->opt);
00496                 msg->opt = NULL;
00497                 msg->sitok = 0;
00498                 msg->sitbad = 0;
00499         }
00500 }
00501 
00502 static void
00503 msgresetsigs(dns_message_t *msg, isc_boolean_t replying) {
00504         if (msg->sig_reserved > 0) {
00505                 dns_message_renderrelease(msg, msg->sig_reserved);
00506                 msg->sig_reserved = 0;
00507         }
00508         if (msg->tsig != NULL) {
00509                 INSIST(dns_rdataset_isassociated(msg->tsig));
00510                 INSIST(msg->namepool != NULL);
00511                 if (replying) {
00512                         INSIST(msg->querytsig == NULL);
00513                         msg->querytsig = msg->tsig;
00514                 } else {
00515                         dns_rdataset_disassociate(msg->tsig);
00516                         isc_mempool_put(msg->rdspool, msg->tsig);
00517                         if (msg->querytsig != NULL) {
00518                                 dns_rdataset_disassociate(msg->querytsig);
00519                                 isc_mempool_put(msg->rdspool, msg->querytsig);
00520                         }
00521                 }
00522                 if (dns_name_dynamic(msg->tsigname))
00523                         dns_name_free(msg->tsigname, msg->mctx);
00524                 isc_mempool_put(msg->namepool, msg->tsigname);
00525                 msg->tsig = NULL;
00526                 msg->tsigname = NULL;
00527         } else if (msg->querytsig != NULL && !replying) {
00528                 dns_rdataset_disassociate(msg->querytsig);
00529                 isc_mempool_put(msg->rdspool, msg->querytsig);
00530                 msg->querytsig = NULL;
00531         }
00532         if (msg->sig0 != NULL) {
00533                 INSIST(dns_rdataset_isassociated(msg->sig0));
00534                 dns_rdataset_disassociate(msg->sig0);
00535                 isc_mempool_put(msg->rdspool, msg->sig0);
00536                 if (msg->sig0name != NULL) {
00537                         if (dns_name_dynamic(msg->sig0name))
00538                                 dns_name_free(msg->sig0name, msg->mctx);
00539                         isc_mempool_put(msg->namepool, msg->sig0name);
00540                 }
00541                 msg->sig0 = NULL;
00542                 msg->sig0name = NULL;
00543         }
00544 }
00545 
00546 /*
00547  * Free all but one (or everything) for this message.  This is used by
00548  * both dns_message_reset() and dns_message_destroy().
00549  */
00550 static void
00551 msgreset(dns_message_t *msg, isc_boolean_t everything) {
00552         dns_msgblock_t *msgblock, *next_msgblock;
00553         isc_buffer_t *dynbuf, *next_dynbuf;
00554         dns_rdata_t *rdata;
00555         dns_rdatalist_t *rdatalist;
00556 
00557         msgresetnames(msg, 0);
00558         msgresetopt(msg);
00559         msgresetsigs(msg, ISC_FALSE);
00560 
00561         /*
00562          * Clean up linked lists.
00563          */
00564 
00565         /*
00566          * Run through the free lists, and just unlink anything found there.
00567          * The memory isn't lost since these are part of message blocks we
00568          * have allocated.
00569          */
00570         rdata = ISC_LIST_HEAD(msg->freerdata);
00571         while (rdata != NULL) {
00572                 ISC_LIST_UNLINK(msg->freerdata, rdata, link);
00573                 rdata = ISC_LIST_HEAD(msg->freerdata);
00574         }
00575         rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
00576         while (rdatalist != NULL) {
00577                 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
00578                 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
00579         }
00580 
00581         dynbuf = ISC_LIST_HEAD(msg->scratchpad);
00582         INSIST(dynbuf != NULL);
00583         if (!everything) {
00584                 isc_buffer_clear(dynbuf);
00585                 dynbuf = ISC_LIST_NEXT(dynbuf, link);
00586         }
00587         while (dynbuf != NULL) {
00588                 next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
00589                 ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
00590                 isc_buffer_free(&dynbuf);
00591                 dynbuf = next_dynbuf;
00592         }
00593 
00594         msgblock = ISC_LIST_HEAD(msg->rdatas);
00595         if (!everything && msgblock != NULL) {
00596                 msgblock_reset(msgblock);
00597                 msgblock = ISC_LIST_NEXT(msgblock, link);
00598         }
00599         while (msgblock != NULL) {
00600                 next_msgblock = ISC_LIST_NEXT(msgblock, link);
00601                 ISC_LIST_UNLINK(msg->rdatas, msgblock, link);
00602                 msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t));
00603                 msgblock = next_msgblock;
00604         }
00605 
00606         /*
00607          * rdatalists could be empty.
00608          */
00609 
00610         msgblock = ISC_LIST_HEAD(msg->rdatalists);
00611         if (!everything && msgblock != NULL) {
00612                 msgblock_reset(msgblock);
00613                 msgblock = ISC_LIST_NEXT(msgblock, link);
00614         }
00615         while (msgblock != NULL) {
00616                 next_msgblock = ISC_LIST_NEXT(msgblock, link);
00617                 ISC_LIST_UNLINK(msg->rdatalists, msgblock, link);
00618                 msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t));
00619                 msgblock = next_msgblock;
00620         }
00621 
00622         msgblock = ISC_LIST_HEAD(msg->offsets);
00623         if (!everything && msgblock != NULL) {
00624                 msgblock_reset(msgblock);
00625                 msgblock = ISC_LIST_NEXT(msgblock, link);
00626         }
00627         while (msgblock != NULL) {
00628                 next_msgblock = ISC_LIST_NEXT(msgblock, link);
00629                 ISC_LIST_UNLINK(msg->offsets, msgblock, link);
00630                 msgblock_free(msg->mctx, msgblock, sizeof(dns_offsets_t));
00631                 msgblock = next_msgblock;
00632         }
00633 
00634         if (msg->tsigkey != NULL) {
00635                 dns_tsigkey_detach(&msg->tsigkey);
00636                 msg->tsigkey = NULL;
00637         }
00638 
00639         if (msg->tsigctx != NULL)
00640                 dst_context_destroy(&msg->tsigctx);
00641 
00642         if (msg->query.base != NULL) {
00643                 if (msg->free_query != 0)
00644                         isc_mem_put(msg->mctx, msg->query.base,
00645                                     msg->query.length);
00646                 msg->query.base = NULL;
00647                 msg->query.length = 0;
00648         }
00649 
00650         if (msg->saved.base != NULL) {
00651                 if (msg->free_saved != 0)
00652                         isc_mem_put(msg->mctx, msg->saved.base,
00653                                     msg->saved.length);
00654                 msg->saved.base = NULL;
00655                 msg->saved.length = 0;
00656         }
00657 
00658         /*
00659          * cleanup the buffer cleanup list
00660          */
00661         dynbuf = ISC_LIST_HEAD(msg->cleanup);
00662         while (dynbuf != NULL) {
00663                 next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
00664                 ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
00665                 isc_buffer_free(&dynbuf);
00666                 dynbuf = next_dynbuf;
00667         }
00668 
00669         /*
00670          * Set other bits to normal default values.
00671          */
00672         if (!everything)
00673                 msginit(msg);
00674 
00675         ENSURE(isc_mempool_getallocated(msg->namepool) == 0);
00676         ENSURE(isc_mempool_getallocated(msg->rdspool) == 0);
00677 }
00678 
00679 static unsigned int
00680 spacefortsig(dns_tsigkey_t *key, int otherlen) {
00681         isc_region_t r1, r2;
00682         unsigned int x;
00683         isc_result_t result;
00684 
00685         /*
00686          * The space required for an TSIG record is:
00687          *
00688          *      n1 bytes for the name
00689          *      2 bytes for the type
00690          *      2 bytes for the class
00691          *      4 bytes for the ttl
00692          *      2 bytes for the rdlength
00693          *      n2 bytes for the algorithm name
00694          *      6 bytes for the time signed
00695          *      2 bytes for the fudge
00696          *      2 bytes for the MAC size
00697          *      x bytes for the MAC
00698          *      2 bytes for the original id
00699          *      2 bytes for the error
00700          *      2 bytes for the other data length
00701          *      y bytes for the other data (at most)
00702          * ---------------------------------
00703          *     26 + n1 + n2 + x + y bytes
00704          */
00705 
00706         dns_name_toregion(&key->name, &r1);
00707         dns_name_toregion(key->algorithm, &r2);
00708         if (key->key == NULL)
00709                 x = 0;
00710         else {
00711                 result = dst_key_sigsize(key->key, &x);
00712                 if (result != ISC_R_SUCCESS)
00713                         x = 0;
00714         }
00715         return (26 + r1.length + r2.length + x + otherlen);
00716 }
00717 
00718 isc_result_t
00719 dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
00720 {
00721         dns_message_t *m;
00722         isc_result_t result;
00723         isc_buffer_t *dynbuf;
00724         unsigned int i;
00725 
00726         REQUIRE(mctx != NULL);
00727         REQUIRE(msgp != NULL);
00728         REQUIRE(*msgp == NULL);
00729         REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
00730                 || intent == DNS_MESSAGE_INTENTRENDER);
00731 
00732         m = isc_mem_get(mctx, sizeof(dns_message_t));
00733         if (m == NULL)
00734                 return (ISC_R_NOMEMORY);
00735 
00736         /*
00737          * No allocations until further notice.  Just initialize all lists
00738          * and other members that are freed in the cleanup phase here.
00739          */
00740 
00741         m->magic = DNS_MESSAGE_MAGIC;
00742         m->from_to_wire = intent;
00743         msginit(m);
00744 
00745         for (i = 0; i < DNS_SECTION_MAX; i++)
00746                 ISC_LIST_INIT(m->sections[i]);
00747 
00748         m->mctx = NULL;
00749         isc_mem_attach(mctx, &m->mctx);
00750 
00751         ISC_LIST_INIT(m->scratchpad);
00752         ISC_LIST_INIT(m->cleanup);
00753         m->namepool = NULL;
00754         m->rdspool = NULL;
00755         ISC_LIST_INIT(m->rdatas);
00756         ISC_LIST_INIT(m->rdatalists);
00757         ISC_LIST_INIT(m->offsets);
00758         ISC_LIST_INIT(m->freerdata);
00759         ISC_LIST_INIT(m->freerdatalist);
00760 
00761         /*
00762          * Ok, it is safe to allocate (and then "goto cleanup" if failure)
00763          */
00764 
00765         result = isc_mempool_create(m->mctx, sizeof(dns_name_t), &m->namepool);
00766         if (result != ISC_R_SUCCESS)
00767                 goto cleanup;
00768         isc_mempool_setfreemax(m->namepool, NAME_COUNT);
00769         isc_mempool_setname(m->namepool, "msg:names");
00770 
00771         result = isc_mempool_create(m->mctx, sizeof(dns_rdataset_t),
00772                                     &m->rdspool);
00773         if (result != ISC_R_SUCCESS)
00774                 goto cleanup;
00775         isc_mempool_setfreemax(m->rdspool, NAME_COUNT);
00776         isc_mempool_setname(m->rdspool, "msg:rdataset");
00777 
00778         dynbuf = NULL;
00779         result = isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE);
00780         if (result != ISC_R_SUCCESS)
00781                 goto cleanup;
00782         ISC_LIST_APPEND(m->scratchpad, dynbuf, link);
00783 
00784         m->cctx = NULL;
00785 
00786         *msgp = m;
00787         return (ISC_R_SUCCESS);
00788 
00789         /*
00790          * Cleanup for error returns.
00791          */
00792  cleanup:
00793         dynbuf = ISC_LIST_HEAD(m->scratchpad);
00794         if (dynbuf != NULL) {
00795                 ISC_LIST_UNLINK(m->scratchpad, dynbuf, link);
00796                 isc_buffer_free(&dynbuf);
00797         }
00798         if (m->namepool != NULL)
00799                 isc_mempool_destroy(&m->namepool);
00800         if (m->rdspool != NULL)
00801                 isc_mempool_destroy(&m->rdspool);
00802         m->magic = 0;
00803         isc_mem_putanddetach(&mctx, m, sizeof(dns_message_t));
00804 
00805         return (ISC_R_NOMEMORY);
00806 }
00807 
00808 void
00809 dns_message_reset(dns_message_t *msg, unsigned int intent) {
00810         REQUIRE(DNS_MESSAGE_VALID(msg));
00811         REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
00812                 || intent == DNS_MESSAGE_INTENTRENDER);
00813 
00814         msgreset(msg, ISC_FALSE);
00815         msg->from_to_wire = intent;
00816 }
00817 
00818 void
00819 dns_message_destroy(dns_message_t **msgp) {
00820         dns_message_t *msg;
00821 
00822         REQUIRE(msgp != NULL);
00823         REQUIRE(DNS_MESSAGE_VALID(*msgp));
00824 
00825         msg = *msgp;
00826         *msgp = NULL;
00827 
00828         msgreset(msg, ISC_TRUE);
00829         isc_mempool_destroy(&msg->namepool);
00830         isc_mempool_destroy(&msg->rdspool);
00831         msg->magic = 0;
00832         isc_mem_putanddetach(&msg->mctx, msg, sizeof(dns_message_t));
00833 }
00834 
00835 static isc_result_t
00836 findname(dns_name_t **foundname, dns_name_t *target,
00837          dns_namelist_t *section)
00838 {
00839         dns_name_t *curr;
00840 
00841         for (curr = ISC_LIST_TAIL(*section);
00842              curr != NULL;
00843              curr = ISC_LIST_PREV(curr, link)) {
00844                 if (dns_name_equal(curr, target)) {
00845                         if (foundname != NULL)
00846                                 *foundname = curr;
00847                         return (ISC_R_SUCCESS);
00848                 }
00849         }
00850 
00851         return (ISC_R_NOTFOUND);
00852 }
00853 
00854 isc_result_t
00855 dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
00856                  dns_rdatatype_t type, dns_rdatatype_t covers,
00857                  dns_rdataset_t **rdataset)
00858 {
00859         dns_rdataset_t *curr;
00860 
00861         if (rdataset != NULL) {
00862                 REQUIRE(*rdataset == NULL);
00863         }
00864 
00865         for (curr = ISC_LIST_TAIL(name->list);
00866              curr != NULL;
00867              curr = ISC_LIST_PREV(curr, link)) {
00868                 if (curr->rdclass == rdclass &&
00869                     curr->type == type && curr->covers == covers) {
00870                         if (rdataset != NULL)
00871                                 *rdataset = curr;
00872                         return (ISC_R_SUCCESS);
00873                 }
00874         }
00875 
00876         return (ISC_R_NOTFOUND);
00877 }
00878 
00879 isc_result_t
00880 dns_message_findtype(dns_name_t *name, dns_rdatatype_t type,
00881                      dns_rdatatype_t covers, dns_rdataset_t **rdataset)
00882 {
00883         dns_rdataset_t *curr;
00884 
00885         REQUIRE(name != NULL);
00886         if (rdataset != NULL) {
00887                 REQUIRE(*rdataset == NULL);
00888         }
00889 
00890         for (curr = ISC_LIST_TAIL(name->list);
00891              curr != NULL;
00892              curr = ISC_LIST_PREV(curr, link)) {
00893                 if (curr->type == type && curr->covers == covers) {
00894                         if (rdataset != NULL)
00895                                 *rdataset = curr;
00896                         return (ISC_R_SUCCESS);
00897                 }
00898         }
00899 
00900         return (ISC_R_NOTFOUND);
00901 }
00902 
00903 /*
00904  * Read a name from buffer "source".
00905  */
00906 static isc_result_t
00907 getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
00908         dns_decompress_t *dctx)
00909 {
00910         isc_buffer_t *scratch;
00911         isc_result_t result;
00912         unsigned int tries;
00913 
00914         scratch = currentbuffer(msg);
00915 
00916         /*
00917          * First try:  use current buffer.
00918          * Second try:  allocate a new buffer and use that.
00919          */
00920         tries = 0;
00921         while (tries < 2) {
00922                 result = dns_name_fromwire(name, source, dctx, ISC_FALSE,
00923                                            scratch);
00924 
00925                 if (result == ISC_R_NOSPACE) {
00926                         tries++;
00927 
00928                         result = newbuffer(msg, SCRATCHPAD_SIZE);
00929                         if (result != ISC_R_SUCCESS)
00930                                 return (result);
00931 
00932                         scratch = currentbuffer(msg);
00933                         dns_name_reset(name);
00934                 } else {
00935                         return (result);
00936                 }
00937         }
00938 
00939         INSIST(0);  /* Cannot get here... */
00940         return (ISC_R_UNEXPECTED);
00941 }
00942 
00943 static isc_result_t
00944 getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
00945          dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
00946          unsigned int rdatalen, dns_rdata_t *rdata)
00947 {
00948         isc_buffer_t *scratch;
00949         isc_result_t result;
00950         unsigned int tries;
00951         unsigned int trysize;
00952 
00953         scratch = currentbuffer(msg);
00954 
00955         isc_buffer_setactive(source, rdatalen);
00956 
00957         /*
00958          * First try:  use current buffer.
00959          * Second try:  allocate a new buffer of size
00960          *     max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
00961          *     (the data will fit if it was not more than 50% compressed)
00962          * Subsequent tries: double buffer size on each try.
00963          */
00964         tries = 0;
00965         trysize = 0;
00966         /* XXX possibly change this to a while (tries < 2) loop */
00967         for (;;) {
00968                 result = dns_rdata_fromwire(rdata, rdclass, rdtype,
00969                                             source, dctx, 0,
00970                                             scratch);
00971 
00972                 if (result == ISC_R_NOSPACE) {
00973                         if (tries == 0) {
00974                                 trysize = 2 * rdatalen;
00975                                 if (trysize < SCRATCHPAD_SIZE)
00976                                         trysize = SCRATCHPAD_SIZE;
00977                         } else {
00978                                 INSIST(trysize != 0);
00979                                 if (trysize >= 65535)
00980                                         return (ISC_R_NOSPACE);
00981                                         /* XXX DNS_R_RRTOOLONG? */
00982                                 trysize *= 2;
00983                         }
00984                         tries++;
00985                         result = newbuffer(msg, trysize);
00986                         if (result != ISC_R_SUCCESS)
00987                                 return (result);
00988 
00989                         scratch = currentbuffer(msg);
00990                 } else {
00991                         return (result);
00992                 }
00993         }
00994 }
00995 
00996 #define DO_FORMERR                                      \
00997         do {                                            \
00998                 if (best_effort)                        \
00999                         seen_problem = ISC_TRUE;        \
01000                 else {                                  \
01001                         result = DNS_R_FORMERR;         \
01002                         goto cleanup;                   \
01003                 }                                       \
01004         } while (0)
01005 
01006 static isc_result_t
01007 getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
01008              unsigned int options)
01009 {
01010         isc_region_t r;
01011         unsigned int count;
01012         dns_name_t *name;
01013         dns_name_t *name2;
01014         dns_offsets_t *offsets;
01015         dns_rdataset_t *rdataset;
01016         dns_rdatalist_t *rdatalist;
01017         isc_result_t result;
01018         dns_rdatatype_t rdtype;
01019         dns_rdataclass_t rdclass;
01020         dns_namelist_t *section;
01021         isc_boolean_t free_name;
01022         isc_boolean_t best_effort;
01023         isc_boolean_t seen_problem;
01024 
01025         section = &msg->sections[DNS_SECTION_QUESTION];
01026 
01027         best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
01028         seen_problem = ISC_FALSE;
01029 
01030         name = NULL;
01031         rdataset = NULL;
01032         rdatalist = NULL;
01033 
01034         for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
01035                 name = isc_mempool_get(msg->namepool);
01036                 if (name == NULL)
01037                         return (ISC_R_NOMEMORY);
01038                 free_name = ISC_TRUE;
01039 
01040                 offsets = newoffsets(msg);
01041                 if (offsets == NULL) {
01042                         result = ISC_R_NOMEMORY;
01043                         goto cleanup;
01044                 }
01045                 dns_name_init(name, *offsets);
01046 
01047                 /*
01048                  * Parse the name out of this packet.
01049                  */
01050                 isc_buffer_remainingregion(source, &r);
01051                 isc_buffer_setactive(source, r.length);
01052                 result = getname(name, source, msg, dctx);
01053                 if (result != ISC_R_SUCCESS)
01054                         goto cleanup;
01055 
01056                 /*
01057                  * Run through the section, looking to see if this name
01058                  * is already there.  If it is found, put back the allocated
01059                  * name since we no longer need it, and set our name pointer
01060                  * to point to the name we found.
01061                  */
01062                 result = findname(&name2, name, section);
01063 
01064                 /*
01065                  * If it is the first name in the section, accept it.
01066                  *
01067                  * If it is not, but is not the same as the name already
01068                  * in the question section, append to the section.  Note that
01069                  * here in the question section this is illegal, so return
01070                  * FORMERR.  In the future, check the opcode to see if
01071                  * this should be legal or not.  In either case we no longer
01072                  * need this name pointer.
01073                  */
01074                 if (result != ISC_R_SUCCESS) {
01075                         if (!ISC_LIST_EMPTY(*section))
01076                                 DO_FORMERR;
01077                         ISC_LIST_APPEND(*section, name, link);
01078                         free_name = ISC_FALSE;
01079                 } else {
01080                         isc_mempool_put(msg->namepool, name);
01081                         name = name2;
01082                         name2 = NULL;
01083                         free_name = ISC_FALSE;
01084                 }
01085 
01086                 /*
01087                  * Get type and class.
01088                  */
01089                 isc_buffer_remainingregion(source, &r);
01090                 if (r.length < 4) {
01091                         result = ISC_R_UNEXPECTEDEND;
01092                         goto cleanup;
01093                 }
01094                 rdtype = isc_buffer_getuint16(source);
01095                 rdclass = isc_buffer_getuint16(source);
01096 
01097                 /*
01098                  * If this class is different than the one we already read,
01099                  * this is an error.
01100                  */
01101                 if (msg->state == DNS_SECTION_ANY) {
01102                         msg->state = DNS_SECTION_QUESTION;
01103                         msg->rdclass = rdclass;
01104                 } else if (msg->rdclass != rdclass)
01105                         DO_FORMERR;
01106 
01107                 /*
01108                  * Can't ask the same question twice.
01109                  */
01110                 result = dns_message_find(name, rdclass, rdtype, 0, NULL);
01111                 if (result == ISC_R_SUCCESS)
01112                         DO_FORMERR;
01113 
01114                 /*
01115                  * Allocate a new rdatalist.
01116                  */
01117                 rdatalist = newrdatalist(msg);
01118                 if (rdatalist == NULL) {
01119                         result = ISC_R_NOMEMORY;
01120                         goto cleanup;
01121                 }
01122                 rdataset =  isc_mempool_get(msg->rdspool);
01123                 if (rdataset == NULL) {
01124                         result = ISC_R_NOMEMORY;
01125                         goto cleanup;
01126                 }
01127 
01128                 /*
01129                  * Convert rdatalist to rdataset, and attach the latter to
01130                  * the name.
01131                  */
01132                 rdatalist->type = rdtype;
01133                 rdatalist->rdclass = rdclass;
01134 
01135                 dns_rdataset_init(rdataset);
01136                 result = dns_rdatalist_tordataset(rdatalist, rdataset);
01137                 if (result != ISC_R_SUCCESS)
01138                         goto cleanup;
01139 
01140                 rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
01141 
01142                 ISC_LIST_APPEND(name->list, rdataset, link);
01143                 rdataset = NULL;
01144         }
01145 
01146         if (seen_problem)
01147                 return (DNS_R_RECOVERABLE);
01148         return (ISC_R_SUCCESS);
01149 
01150  cleanup:
01151         if (rdataset != NULL) {
01152                 INSIST(!dns_rdataset_isassociated(rdataset));
01153                 isc_mempool_put(msg->rdspool, rdataset);
01154         }
01155 #if 0
01156         if (rdatalist != NULL)
01157                 isc_mempool_put(msg->rdlpool, rdatalist);
01158 #endif
01159         if (free_name)
01160                 isc_mempool_put(msg->namepool, name);
01161 
01162         return (result);
01163 }
01164 
01165 static isc_boolean_t
01166 update(dns_section_t section, dns_rdataclass_t rdclass) {
01167         if (section == DNS_SECTION_PREREQUISITE)
01168                 return (ISC_TF(rdclass == dns_rdataclass_any ||
01169                                rdclass == dns_rdataclass_none));
01170         if (section == DNS_SECTION_UPDATE)
01171                 return (ISC_TF(rdclass == dns_rdataclass_any));
01172         return (ISC_FALSE);
01173 }
01174 
01175 static isc_result_t
01176 getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
01177            dns_section_t sectionid, unsigned int options)
01178 {
01179         isc_region_t r;
01180         unsigned int count, rdatalen;
01181         dns_name_t *name;
01182         dns_name_t *name2;
01183         dns_offsets_t *offsets;
01184         dns_rdataset_t *rdataset;
01185         dns_rdatalist_t *rdatalist;
01186         isc_result_t result;
01187         dns_rdatatype_t rdtype, covers;
01188         dns_rdataclass_t rdclass;
01189         dns_rdata_t *rdata;
01190         dns_ttl_t ttl;
01191         dns_namelist_t *section;
01192         isc_boolean_t free_name, free_rdataset;
01193         isc_boolean_t preserve_order, best_effort, seen_problem;
01194         isc_boolean_t issigzero;
01195 
01196         preserve_order = ISC_TF(options & DNS_MESSAGEPARSE_PRESERVEORDER);
01197         best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
01198         seen_problem = ISC_FALSE;
01199 
01200         for (count = 0; count < msg->counts[sectionid]; count++) {
01201                 int recstart = source->current;
01202                 isc_boolean_t skip_name_search, skip_type_search;
01203 
01204                 section = &msg->sections[sectionid];
01205 
01206                 skip_name_search = ISC_FALSE;
01207                 skip_type_search = ISC_FALSE;
01208                 free_rdataset = ISC_FALSE;
01209 
01210                 name = isc_mempool_get(msg->namepool);
01211                 if (name == NULL)
01212                         return (ISC_R_NOMEMORY);
01213                 free_name = ISC_TRUE;
01214 
01215                 offsets = newoffsets(msg);
01216                 if (offsets == NULL) {
01217                         result = ISC_R_NOMEMORY;
01218                         goto cleanup;
01219                 }
01220                 dns_name_init(name, *offsets);
01221 
01222                 /*
01223                  * Parse the name out of this packet.
01224                  */
01225                 isc_buffer_remainingregion(source, &r);
01226                 isc_buffer_setactive(source, r.length);
01227                 result = getname(name, source, msg, dctx);
01228                 if (result != ISC_R_SUCCESS)
01229                         goto cleanup;
01230 
01231                 /*
01232                  * Get type, class, ttl, and rdatalen.  Verify that at least
01233                  * rdatalen bytes remain.  (Some of this is deferred to
01234                  * later.)
01235                  */
01236                 isc_buffer_remainingregion(source, &r);
01237                 if (r.length < 2 + 2 + 4 + 2) {
01238                         result = ISC_R_UNEXPECTEDEND;
01239                         goto cleanup;
01240                 }
01241                 rdtype = isc_buffer_getuint16(source);
01242                 rdclass = isc_buffer_getuint16(source);
01243 
01244                 /*
01245                  * If there was no question section, we may not yet have
01246                  * established a class.  Do so now.
01247                  */
01248                 if (msg->state == DNS_SECTION_ANY &&
01249                     rdtype != dns_rdatatype_opt &&      /* class is UDP SIZE */
01250                     rdtype != dns_rdatatype_tsig &&     /* class is ANY */
01251                     rdtype != dns_rdatatype_tkey) {     /* class is undefined */
01252                         msg->rdclass = rdclass;
01253                         msg->state = DNS_SECTION_QUESTION;
01254                 }
01255 
01256                 /*
01257                  * If this class is different than the one in the question
01258                  * section, bail.
01259                  */
01260                 if (msg->opcode != dns_opcode_update
01261                     && rdtype != dns_rdatatype_tsig
01262                     && rdtype != dns_rdatatype_opt
01263                     && rdtype != dns_rdatatype_dnskey /* in a TKEY query */
01264                     && rdtype != dns_rdatatype_sig /* SIG(0) */
01265                     && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
01266                     && msg->rdclass != dns_rdataclass_any
01267                     && msg->rdclass != rdclass)
01268                         DO_FORMERR;
01269 
01270                 /*
01271                  * Special type handling for TSIG, OPT, and TKEY.
01272                  */
01273                 if (rdtype == dns_rdatatype_tsig) {
01274                         /*
01275                          * If it is a tsig, verify that it is in the
01276                          * additional data section.
01277                          */
01278                         if (sectionid != DNS_SECTION_ADDITIONAL ||
01279                             rdclass != dns_rdataclass_any ||
01280                             count != msg->counts[sectionid]  - 1)
01281                                 DO_FORMERR;
01282                         msg->sigstart = recstart;
01283                         skip_name_search = ISC_TRUE;
01284                         skip_type_search = ISC_TRUE;
01285                 } else if (rdtype == dns_rdatatype_opt) {
01286                         /*
01287                          * The name of an OPT record must be ".", it
01288                          * must be in the additional data section, and
01289                          * it must be the first OPT we've seen.
01290                          */
01291                         if (!dns_name_equal(dns_rootname, name) ||
01292                             msg->opt != NULL)
01293                                 DO_FORMERR;
01294                         skip_name_search = ISC_TRUE;
01295                         skip_type_search = ISC_TRUE;
01296                 } else if (rdtype == dns_rdatatype_tkey) {
01297                         /*
01298                          * A TKEY must be in the additional section if this
01299                          * is a query, and the answer section if this is a
01300                          * response.  Unless it's a Win2000 client.
01301                          *
01302                          * Its class is ignored.
01303                          */
01304                         dns_section_t tkeysection;
01305 
01306                         if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
01307                                 tkeysection = DNS_SECTION_ADDITIONAL;
01308                         else
01309                                 tkeysection = DNS_SECTION_ANSWER;
01310                         if (sectionid != tkeysection &&
01311                             sectionid != DNS_SECTION_ANSWER)
01312                                 DO_FORMERR;
01313                 }
01314 
01315                 /*
01316                  * ... now get ttl and rdatalen, and check buffer.
01317                  */
01318                 ttl = isc_buffer_getuint32(source);
01319                 rdatalen = isc_buffer_getuint16(source);
01320                 r.length -= (2 + 2 + 4 + 2);
01321                 if (r.length < rdatalen) {
01322                         result = ISC_R_UNEXPECTEDEND;
01323                         goto cleanup;
01324                 }
01325 
01326                 /*
01327                  * Read the rdata from the wire format.  Interpret the
01328                  * rdata according to its actual class, even if it had a
01329                  * DynDNS meta-class in the packet (unless this is a TSIG).
01330                  * Then put the meta-class back into the finished rdata.
01331                  */
01332                 rdata = newrdata(msg);
01333                 if (rdata == NULL) {
01334                         result = ISC_R_NOMEMORY;
01335                         goto cleanup;
01336                 }
01337                 if (msg->opcode == dns_opcode_update &&
01338                     update(sectionid, rdclass)) {
01339                         if (rdatalen != 0) {
01340                                 result = DNS_R_FORMERR;
01341                                 goto cleanup;
01342                         }
01343                         /*
01344                          * When the rdata is empty, the data pointer is
01345                          * never dereferenced, but it must still be non-NULL.
01346                          * Casting 1 rather than "" avoids warnings about
01347                          * discarding the const attribute of a string,
01348                          * for compilers that would warn about such things.
01349                          */
01350                         rdata->data = (unsigned char *)1;
01351                         rdata->length = 0;
01352                         rdata->rdclass = rdclass;
01353                         rdata->type = rdtype;
01354                         rdata->flags = DNS_RDATA_UPDATE;
01355                         result = ISC_R_SUCCESS;
01356                 } else if (rdclass == dns_rdataclass_none &&
01357                            msg->opcode == dns_opcode_update &&
01358                            sectionid == DNS_SECTION_UPDATE) {
01359                         result = getrdata(source, msg, dctx, msg->rdclass,
01360                                           rdtype, rdatalen, rdata);
01361                 } else
01362                         result = getrdata(source, msg, dctx, rdclass,
01363                                           rdtype, rdatalen, rdata);
01364                 if (result != ISC_R_SUCCESS)
01365                         goto cleanup;
01366                 rdata->rdclass = rdclass;
01367                 issigzero = ISC_FALSE;
01368                 if (rdtype == dns_rdatatype_rrsig  &&
01369                     rdata->flags == 0) {
01370                         covers = dns_rdata_covers(rdata);
01371                         if (covers == 0)
01372                                 DO_FORMERR;
01373                 } else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
01374                            rdata->flags == 0) {
01375                         covers = dns_rdata_covers(rdata);
01376                         if (covers == 0) {
01377                                 if (sectionid != DNS_SECTION_ADDITIONAL ||
01378                                     count != msg->counts[sectionid]  - 1)
01379                                         DO_FORMERR;
01380                                 msg->sigstart = recstart;
01381                                 skip_name_search = ISC_TRUE;
01382                                 skip_type_search = ISC_TRUE;
01383                                 issigzero = ISC_TRUE;
01384                         }
01385                 } else
01386                         covers = 0;
01387 
01388                 /*
01389                  * Check the ownername of NSEC3 records
01390                  */
01391                 if (rdtype == dns_rdatatype_nsec3 &&
01392                     !dns_rdata_checkowner(name, msg->rdclass, rdtype,
01393                                           ISC_FALSE)) {
01394                         result = DNS_R_BADOWNERNAME;
01395                         goto cleanup;
01396                 }
01397 
01398                 /*
01399                  * If we are doing a dynamic update or this is a meta-type,
01400                  * don't bother searching for a name, just append this one
01401                  * to the end of the message.
01402                  */
01403                 if (preserve_order || msg->opcode == dns_opcode_update ||
01404                     skip_name_search) {
01405                         if (rdtype != dns_rdatatype_opt &&
01406                             rdtype != dns_rdatatype_tsig &&
01407                             !issigzero)
01408                         {
01409                                 ISC_LIST_APPEND(*section, name, link);
01410                                 free_name = ISC_FALSE;
01411                         }
01412                 } else {
01413                         /*
01414                          * Run through the section, looking to see if this name
01415                          * is already there.  If it is found, put back the
01416                          * allocated name since we no longer need it, and set
01417                          * our name pointer to point to the name we found.
01418                          */
01419                         result = findname(&name2, name, section);
01420 
01421                         /*
01422                          * If it is a new name, append to the section.
01423                          */
01424                         if (result == ISC_R_SUCCESS) {
01425                                 isc_mempool_put(msg->namepool, name);
01426                                 name = name2;
01427                         } else {
01428                                 ISC_LIST_APPEND(*section, name, link);
01429                         }
01430                         free_name = ISC_FALSE;
01431                 }
01432 
01433                 /*
01434                  * Search name for the particular type and class.
01435                  * Skip this stage if in update mode or this is a meta-type.
01436                  */
01437                 if (preserve_order || msg->opcode == dns_opcode_update ||
01438                     skip_type_search)
01439                         result = ISC_R_NOTFOUND;
01440                 else {
01441                         /*
01442                          * If this is a type that can only occur in
01443                          * the question section, fail.
01444                          */
01445                         if (dns_rdatatype_questiononly(rdtype))
01446                                 DO_FORMERR;
01447 
01448                         rdataset = NULL;
01449                         result = dns_message_find(name, rdclass, rdtype,
01450                                                    covers, &rdataset);
01451                 }
01452 
01453                 /*
01454                  * If we found an rdataset that matches, we need to
01455                  * append this rdata to that set.  If we did not, we need
01456                  * to create a new rdatalist, store the important bits there,
01457                  * convert it to an rdataset, and link the latter to the name.
01458                  * Yuck.  When appending, make certain that the type isn't
01459                  * a singleton type, such as SOA or CNAME.
01460                  *
01461                  * Note that this check will be bypassed when preserving order,
01462                  * the opcode is an update, or the type search is skipped.
01463                  */
01464                 if (result == ISC_R_SUCCESS) {
01465                         if (dns_rdatatype_issingleton(rdtype)) {
01466                                 dns_rdata_t *first;
01467                                 dns_rdatalist_fromrdataset(rdataset,
01468                                                            &rdatalist);
01469                                 first = ISC_LIST_HEAD(rdatalist->rdata);
01470                                 INSIST(first != NULL);
01471                                 if (dns_rdata_compare(rdata, first) != 0)
01472                                         DO_FORMERR;
01473                         }
01474                 }
01475 
01476                 if (result == ISC_R_NOTFOUND) {
01477                         rdataset = isc_mempool_get(msg->rdspool);
01478                         if (rdataset == NULL) {
01479                                 result = ISC_R_NOMEMORY;
01480                                 goto cleanup;
01481                         }
01482                         free_rdataset = ISC_TRUE;
01483 
01484                         rdatalist = newrdatalist(msg);
01485                         if (rdatalist == NULL) {
01486                                 result = ISC_R_NOMEMORY;
01487                                 goto cleanup;
01488                         }
01489 
01490                         rdatalist->type = rdtype;
01491                         rdatalist->covers = covers;
01492                         rdatalist->rdclass = rdclass;
01493                         rdatalist->ttl = ttl;
01494 
01495                         dns_rdataset_init(rdataset);
01496                         RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
01497                                                                rdataset)
01498                                       == ISC_R_SUCCESS);
01499                         dns_rdataset_setownercase(rdataset, name);
01500 
01501                         if (rdtype != dns_rdatatype_opt &&
01502                             rdtype != dns_rdatatype_tsig &&
01503                             !issigzero)
01504                         {
01505                                 ISC_LIST_APPEND(name->list, rdataset, link);
01506                                 free_rdataset = ISC_FALSE;
01507                         }
01508                 }
01509 
01510                 /*
01511                  * Minimize TTLs.
01512                  *
01513                  * Section 5.2 of RFC2181 says we should drop
01514                  * nonauthoritative rrsets where the TTLs differ, but we
01515                  * currently treat them the as if they were authoritative and
01516                  * minimize them.
01517                  */
01518                 if (ttl != rdataset->ttl) {
01519                         rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
01520                         if (ttl < rdataset->ttl)
01521                                 rdataset->ttl = ttl;
01522                 }
01523 
01524                 /* Append this rdata to the rdataset. */
01525                 dns_rdatalist_fromrdataset(rdataset, &rdatalist);
01526                 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
01527 
01528                 /*
01529                  * If this is an OPT record, remember it.  Also, set
01530                  * the extended rcode.  Note that msg->opt will only be set
01531                  * if best-effort parsing is enabled.
01532                  */
01533                 if (rdtype == dns_rdatatype_opt && msg->opt == NULL) {
01534                         dns_rcode_t ercode;
01535 
01536                         msg->opt = rdataset;
01537                         rdataset = NULL;
01538                         free_rdataset = ISC_FALSE;
01539                         ercode = (dns_rcode_t)
01540                                 ((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
01541                                  >> 20);
01542                         msg->rcode |= ercode;
01543                         isc_mempool_put(msg->namepool, name);
01544                         free_name = ISC_FALSE;
01545                 }
01546 
01547                 /*
01548                  * If this is an SIG(0) or TSIG record, remember it.  Note
01549                  * that msg->sig0 or msg->tsig will only be set if best-effort
01550                  * parsing is enabled.
01551                  */
01552                 if (issigzero && msg->sig0 == NULL) {
01553                         msg->sig0 = rdataset;
01554                         msg->sig0name = name;
01555                         rdataset = NULL;
01556                         free_rdataset = ISC_FALSE;
01557                         free_name = ISC_FALSE;
01558                 } else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) {
01559                         msg->tsig = rdataset;
01560                         msg->tsigname = name;
01561                         /* Windows doesn't like TSIG names to be compressed. */
01562                         msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
01563                         rdataset = NULL;
01564                         free_rdataset = ISC_FALSE;
01565                         free_name = ISC_FALSE;
01566                 }
01567 
01568                 if (seen_problem) {
01569                         if (free_name)
01570                                 isc_mempool_put(msg->namepool, name);
01571                         if (free_rdataset)
01572                                 isc_mempool_put(msg->rdspool, rdataset);
01573                         free_name = free_rdataset = ISC_FALSE;
01574                 }
01575                 INSIST(free_name == ISC_FALSE);
01576                 INSIST(free_rdataset == ISC_FALSE);
01577         }
01578 
01579         if (seen_problem)
01580                 return (DNS_R_RECOVERABLE);
01581         return (ISC_R_SUCCESS);
01582 
01583  cleanup:
01584         if (free_name)
01585                 isc_mempool_put(msg->namepool, name);
01586         if (free_rdataset)
01587                 isc_mempool_put(msg->rdspool, rdataset);
01588 
01589         return (result);
01590 }
01591 
01592 isc_result_t
01593 dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
01594                   unsigned int options)
01595 {
01596         isc_region_t r;
01597         dns_decompress_t dctx;
01598         isc_result_t ret;
01599         isc_uint16_t tmpflags;
01600         isc_buffer_t origsource;
01601         isc_boolean_t seen_problem;
01602         isc_boolean_t ignore_tc;
01603 
01604         REQUIRE(DNS_MESSAGE_VALID(msg));
01605         REQUIRE(source != NULL);
01606         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
01607 
01608         seen_problem = ISC_FALSE;
01609         ignore_tc = ISC_TF(options & DNS_MESSAGEPARSE_IGNORETRUNCATION);
01610 
01611         origsource = *source;
01612 
01613         msg->header_ok = 0;
01614         msg->question_ok = 0;
01615 
01616         isc_buffer_remainingregion(source, &r);
01617         if (r.length < DNS_MESSAGE_HEADERLEN)
01618                 return (ISC_R_UNEXPECTEDEND);
01619 
01620         msg->id = isc_buffer_getuint16(source);
01621         tmpflags = isc_buffer_getuint16(source);
01622         msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
01623                        >> DNS_MESSAGE_OPCODE_SHIFT);
01624         msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
01625         msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
01626         msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
01627         msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
01628         msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
01629         msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
01630 
01631         msg->header_ok = 1;
01632 
01633         /*
01634          * -1 means no EDNS.
01635          */
01636         dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
01637 
01638         dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
01639 
01640         ret = getquestions(source, msg, &dctx, options);
01641         if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
01642                 goto truncated;
01643         if (ret == DNS_R_RECOVERABLE) {
01644                 seen_problem = ISC_TRUE;
01645                 ret = ISC_R_SUCCESS;
01646         }
01647         if (ret != ISC_R_SUCCESS)
01648                 return (ret);
01649         msg->question_ok = 1;
01650 
01651         ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
01652         if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
01653                 goto truncated;
01654         if (ret == DNS_R_RECOVERABLE) {
01655                 seen_problem = ISC_TRUE;
01656                 ret = ISC_R_SUCCESS;
01657         }
01658         if (ret != ISC_R_SUCCESS)
01659                 return (ret);
01660 
01661         ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
01662         if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
01663                 goto truncated;
01664         if (ret == DNS_R_RECOVERABLE) {
01665                 seen_problem = ISC_TRUE;
01666                 ret = ISC_R_SUCCESS;
01667         }
01668         if (ret != ISC_R_SUCCESS)
01669                 return (ret);
01670 
01671         ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
01672         if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
01673                 goto truncated;
01674         if (ret == DNS_R_RECOVERABLE) {
01675                 seen_problem = ISC_TRUE;
01676                 ret = ISC_R_SUCCESS;
01677         }
01678         if (ret != ISC_R_SUCCESS)
01679                 return (ret);
01680 
01681         isc_buffer_remainingregion(source, &r);
01682         if (r.length != 0) {
01683                 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
01684                               DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
01685                               "message has %u byte(s) of trailing garbage",
01686                               r.length);
01687         }
01688 
01689  truncated:
01690         if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0)
01691                 isc_buffer_usedregion(&origsource, &msg->saved);
01692         else {
01693                 msg->saved.length = isc_buffer_usedlength(&origsource);
01694                 msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length);
01695                 if (msg->saved.base == NULL)
01696                         return (ISC_R_NOMEMORY);
01697                 memmove(msg->saved.base, isc_buffer_base(&origsource),
01698                         msg->saved.length);
01699                 msg->free_saved = 1;
01700         }
01701 
01702         if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
01703                 return (DNS_R_RECOVERABLE);
01704         if (seen_problem == ISC_TRUE)
01705                 return (DNS_R_RECOVERABLE);
01706         return (ISC_R_SUCCESS);
01707 }
01708 
01709 isc_result_t
01710 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
01711                         isc_buffer_t *buffer)
01712 {
01713         isc_region_t r;
01714 
01715         REQUIRE(DNS_MESSAGE_VALID(msg));
01716         REQUIRE(buffer != NULL);
01717         REQUIRE(msg->buffer == NULL);
01718         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
01719 
01720         msg->cctx = cctx;
01721 
01722         /*
01723          * Erase the contents of this buffer.
01724          */
01725         isc_buffer_clear(buffer);
01726 
01727         /*
01728          * Make certain there is enough for at least the header in this
01729          * buffer.
01730          */
01731         isc_buffer_availableregion(buffer, &r);
01732         if (r.length < DNS_MESSAGE_HEADERLEN)
01733                 return (ISC_R_NOSPACE);
01734 
01735         if (r.length < msg->reserved)
01736                 return (ISC_R_NOSPACE);
01737 
01738         /*
01739          * Reserve enough space for the header in this buffer.
01740          */
01741         isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
01742 
01743         msg->buffer = buffer;
01744 
01745         return (ISC_R_SUCCESS);
01746 }
01747 
01748 isc_result_t
01749 dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) {
01750         isc_region_t r, rn;
01751 
01752         REQUIRE(DNS_MESSAGE_VALID(msg));
01753         REQUIRE(buffer != NULL);
01754         REQUIRE(msg->buffer != NULL);
01755 
01756         /*
01757          * Ensure that the new buffer is empty, and has enough space to
01758          * hold the current contents.
01759          */
01760         isc_buffer_clear(buffer);
01761 
01762         isc_buffer_availableregion(buffer, &rn);
01763         isc_buffer_usedregion(msg->buffer, &r);
01764         REQUIRE(rn.length > r.length);
01765 
01766         /*
01767          * Copy the contents from the old to the new buffer.
01768          */
01769         isc_buffer_add(buffer, r.length);
01770         memmove(rn.base, r.base, r.length);
01771 
01772         msg->buffer = buffer;
01773 
01774         return (ISC_R_SUCCESS);
01775 }
01776 
01777 void
01778 dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
01779         REQUIRE(DNS_MESSAGE_VALID(msg));
01780         REQUIRE(space <= msg->reserved);
01781 
01782         msg->reserved -= space;
01783 }
01784 
01785 isc_result_t
01786 dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
01787         isc_region_t r;
01788 
01789         REQUIRE(DNS_MESSAGE_VALID(msg));
01790 
01791         if (msg->buffer != NULL) {
01792                 isc_buffer_availableregion(msg->buffer, &r);
01793                 if (r.length < (space + msg->reserved))
01794                         return (ISC_R_NOSPACE);
01795         }
01796 
01797         msg->reserved += space;
01798 
01799         return (ISC_R_SUCCESS);
01800 }
01801 
01802 static inline isc_boolean_t
01803 wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
01804         int pass_needed;
01805 
01806         /*
01807          * If we are not rendering class IN, this ordering is bogus.
01808          */
01809         if (rds->rdclass != dns_rdataclass_in)
01810                 return (ISC_FALSE);
01811 
01812         switch (rds->type) {
01813         case dns_rdatatype_a:
01814         case dns_rdatatype_aaaa:
01815                 if (preferred_glue == rds->type)
01816                         pass_needed = 4;
01817                 else
01818                         pass_needed = 3;
01819                 break;
01820         case dns_rdatatype_rrsig:
01821         case dns_rdatatype_dnskey:
01822                 pass_needed = 2;
01823                 break;
01824         default:
01825                 pass_needed = 1;
01826         }
01827 
01828         if (pass_needed >= pass)
01829                 return (ISC_FALSE);
01830 
01831         return (ISC_TRUE);
01832 }
01833 
01834 #ifdef ALLOW_FILTER_AAAA
01835 /*
01836  * Decide whether to not answer with an AAAA record and its RRSIG
01837  */
01838 static inline isc_boolean_t
01839 norender_rdataset(const dns_rdataset_t *rdataset, unsigned int options)
01840 {
01841         switch (rdataset->type) {
01842         case dns_rdatatype_aaaa:
01843                 if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0)
01844                         return (ISC_FALSE);
01845                 break;
01846 
01847         case dns_rdatatype_rrsig:
01848                 if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
01849                     rdataset->covers != dns_rdatatype_aaaa)
01850                         return (ISC_FALSE);
01851                 break;
01852 
01853         default:
01854                 return (ISC_FALSE);
01855         }
01856 
01857         if (rdataset->rdclass != dns_rdataclass_in)
01858                 return (ISC_FALSE);
01859 
01860         return (ISC_TRUE);
01861 }
01862 
01863 #endif
01864 isc_result_t
01865 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
01866                           unsigned int options)
01867 {
01868         dns_namelist_t *section;
01869         dns_name_t *name, *next_name;
01870         dns_rdataset_t *rdataset, *next_rdataset;
01871         unsigned int count, total;
01872         isc_result_t result;
01873         isc_buffer_t st; /* for rollbacks */
01874         int pass;
01875         isc_boolean_t partial = ISC_FALSE;
01876         unsigned int rd_options;
01877         dns_rdatatype_t preferred_glue = 0;
01878 
01879         REQUIRE(DNS_MESSAGE_VALID(msg));
01880         REQUIRE(msg->buffer != NULL);
01881         REQUIRE(VALID_NAMED_SECTION(sectionid));
01882 
01883         section = &msg->sections[sectionid];
01884 
01885         if ((sectionid == DNS_SECTION_ADDITIONAL)
01886             && (options & DNS_MESSAGERENDER_ORDERED) == 0) {
01887                 if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
01888                         preferred_glue = dns_rdatatype_a;
01889                         pass = 4;
01890                 } else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
01891                         preferred_glue = dns_rdatatype_aaaa;
01892                         pass = 4;
01893                 } else
01894                         pass = 3;
01895         } else
01896                 pass = 1;
01897 
01898         if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0)
01899                 rd_options = 0;
01900         else
01901                 rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC;
01902 
01903         /*
01904          * Shrink the space in the buffer by the reserved amount.
01905          */
01906         msg->buffer->length -= msg->reserved;
01907 
01908         total = 0;
01909         if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0)
01910                 partial = ISC_TRUE;
01911 
01912         /*
01913          * Render required glue first.  Set TC if it won't fit.
01914          */
01915         name = ISC_LIST_HEAD(*section);
01916         if (name != NULL) {
01917                 rdataset = ISC_LIST_HEAD(name->list);
01918                 if (rdataset != NULL &&
01919                     (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 0 &&
01920                     (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) {
01921                         const void *order_arg = msg->order_arg;
01922                         st = *(msg->buffer);
01923                         count = 0;
01924                         if (partial)
01925                                 result = dns_rdataset_towirepartial(rdataset,
01926                                                                     name,
01927                                                                     msg->cctx,
01928                                                                     msg->buffer,
01929                                                                     msg->order,
01930                                                                     order_arg,
01931                                                                     rd_options,
01932                                                                     &count,
01933                                                                     NULL);
01934                         else
01935                                 result = dns_rdataset_towiresorted(rdataset,
01936                                                                    name,
01937                                                                    msg->cctx,
01938                                                                    msg->buffer,
01939                                                                    msg->order,
01940                                                                    order_arg,
01941                                                                    rd_options,
01942                                                                    &count);
01943                         total += count;
01944                         if (partial && result == ISC_R_NOSPACE) {
01945                                 msg->flags |= DNS_MESSAGEFLAG_TC;
01946                                 msg->buffer->length += msg->reserved;
01947                                 msg->counts[sectionid] += total;
01948                                 return (result);
01949                         }
01950                         if (result == ISC_R_NOSPACE)
01951                                 msg->flags |= DNS_MESSAGEFLAG_TC;
01952                         if (result != ISC_R_SUCCESS) {
01953                                 INSIST(st.used < 65536);
01954                                 dns_compress_rollback(msg->cctx,
01955                                                       (isc_uint16_t)st.used);
01956                                 *(msg->buffer) = st;  /* rollback */
01957                                 msg->buffer->length += msg->reserved;
01958                                 msg->counts[sectionid] += total;
01959                                 return (result);
01960                         }
01961                         rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
01962                 }
01963         }
01964 
01965         do {
01966                 name = ISC_LIST_HEAD(*section);
01967                 if (name == NULL) {
01968                         msg->buffer->length += msg->reserved;
01969                         msg->counts[sectionid] += total;
01970                         return (ISC_R_SUCCESS);
01971                 }
01972 
01973                 while (name != NULL) {
01974                         next_name = ISC_LIST_NEXT(name, link);
01975 
01976                         rdataset = ISC_LIST_HEAD(name->list);
01977                         while (rdataset != NULL) {
01978                                 next_rdataset = ISC_LIST_NEXT(rdataset, link);
01979 
01980                                 if ((rdataset->attributes &
01981                                      DNS_RDATASETATTR_RENDERED) != 0)
01982                                         goto next;
01983 
01984                                 if (((options & DNS_MESSAGERENDER_ORDERED)
01985                                      == 0)
01986                                     && (sectionid == DNS_SECTION_ADDITIONAL)
01987                                     && wrong_priority(rdataset, pass,
01988                                                       preferred_glue))
01989                                         goto next;
01990 
01991 #ifdef ALLOW_FILTER_AAAA
01992                                 /*
01993                                  * Suppress AAAAs if asked and we are
01994                                  * not doing DNSSEC or are breaking DNSSEC.
01995                                  * Say so in the AD bit if we break DNSSEC.
01996                                  */
01997                                 if (norender_rdataset(rdataset, options) &&
01998                                     sectionid != DNS_SECTION_QUESTION) {
01999                                         if (sectionid == DNS_SECTION_ANSWER ||
02000                                             sectionid == DNS_SECTION_AUTHORITY)
02001                                             msg->flags &= ~DNS_MESSAGEFLAG_AD;
02002                                         if (OPTOUT(rdataset))
02003                                             msg->flags &= ~DNS_MESSAGEFLAG_AD;
02004                                         goto next;
02005                                 }
02006 
02007 #endif
02008                                 st = *(msg->buffer);
02009 
02010                                 count = 0;
02011                                 if (partial)
02012                                         result = dns_rdataset_towirepartial(
02013                                                           rdataset,
02014                                                           name,
02015                                                           msg->cctx,
02016                                                           msg->buffer,
02017                                                           msg->order,
02018                                                           msg->order_arg,
02019                                                           rd_options,
02020                                                           &count,
02021                                                           NULL);
02022                                 else
02023                                         result = dns_rdataset_towiresorted(
02024                                                           rdataset,
02025                                                           name,
02026                                                           msg->cctx,
02027                                                           msg->buffer,
02028                                                           msg->order,
02029                                                           msg->order_arg,
02030                                                           rd_options,
02031                                                           &count);
02032 
02033                                 total += count;
02034 
02035                                 /*
02036                                  * If out of space, record stats on what we
02037                                  * rendered so far, and return that status.
02038                                  *
02039                                  * XXXMLG Need to change this when
02040                                  * dns_rdataset_towire() can render partial
02041                                  * sets starting at some arbitrary point in the
02042                                  * set.  This will include setting a bit in the
02043                                  * rdataset to indicate that a partial
02044                                  * rendering was done, and some state saved
02045                                  * somewhere (probably in the message struct)
02046                                  * to indicate where to continue from.
02047                                  */
02048                                 if (partial && result == ISC_R_NOSPACE) {
02049                                         msg->buffer->length += msg->reserved;
02050                                         msg->counts[sectionid] += total;
02051                                         return (result);
02052                                 }
02053                                 if (result != ISC_R_SUCCESS) {
02054                                         INSIST(st.used < 65536);
02055                                         dns_compress_rollback(msg->cctx,
02056                                                         (isc_uint16_t)st.used);
02057                                         *(msg->buffer) = st;  /* rollback */
02058                                         msg->buffer->length += msg->reserved;
02059                                         msg->counts[sectionid] += total;
02060                                         return (result);
02061                                 }
02062 
02063                                 /*
02064                                  * If we have rendered non-validated data,
02065                                  * ensure that the AD bit is not set.
02066                                  */
02067                                 if (rdataset->trust != dns_trust_secure &&
02068                                     (sectionid == DNS_SECTION_ANSWER ||
02069                                      sectionid == DNS_SECTION_AUTHORITY))
02070                                         msg->flags &= ~DNS_MESSAGEFLAG_AD;
02071                                 if (OPTOUT(rdataset))
02072                                         msg->flags &= ~DNS_MESSAGEFLAG_AD;
02073 
02074                                 rdataset->attributes |=
02075                                         DNS_RDATASETATTR_RENDERED;
02076 
02077                         next:
02078                                 rdataset = next_rdataset;
02079                         }
02080 
02081                         name = next_name;
02082                 }
02083         } while (--pass != 0);
02084 
02085         msg->buffer->length += msg->reserved;
02086         msg->counts[sectionid] += total;
02087 
02088         return (ISC_R_SUCCESS);
02089 }
02090 
02091 void
02092 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
02093         isc_uint16_t tmp;
02094         isc_region_t r;
02095 
02096         REQUIRE(DNS_MESSAGE_VALID(msg));
02097         REQUIRE(target != NULL);
02098 
02099         isc_buffer_availableregion(target, &r);
02100         REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
02101 
02102         isc_buffer_putuint16(target, msg->id);
02103 
02104         tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
02105                & DNS_MESSAGE_OPCODE_MASK);
02106         tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
02107         tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
02108 
02109         INSIST(msg->counts[DNS_SECTION_QUESTION]  < 65536 &&
02110                msg->counts[DNS_SECTION_ANSWER]    < 65536 &&
02111                msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
02112                msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
02113 
02114         isc_buffer_putuint16(target, tmp);
02115         isc_buffer_putuint16(target,
02116                             (isc_uint16_t)msg->counts[DNS_SECTION_QUESTION]);
02117         isc_buffer_putuint16(target,
02118                             (isc_uint16_t)msg->counts[DNS_SECTION_ANSWER]);
02119         isc_buffer_putuint16(target,
02120                             (isc_uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
02121         isc_buffer_putuint16(target,
02122                             (isc_uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
02123 }
02124 
02125 isc_result_t
02126 dns_message_renderend(dns_message_t *msg) {
02127         isc_buffer_t tmpbuf;
02128         isc_region_t r;
02129         int result;
02130         unsigned int count;
02131 
02132         REQUIRE(DNS_MESSAGE_VALID(msg));
02133         REQUIRE(msg->buffer != NULL);
02134 
02135         if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
02136                 /*
02137                  * We have an extended rcode but are not using EDNS.
02138                  */
02139                 return (DNS_R_FORMERR);
02140         }
02141 
02142         /*
02143          * If we're adding a OPT, TSIG or SIG(0) to a truncated message,
02144          * clear all rdatasets from the message except for the question
02145          * before adding the OPT, TSIG or SIG(0).  If the question doesn't
02146          * fit, don't include it.
02147          */
02148         if ((msg->tsigkey != NULL || msg->sig0key != NULL || msg->opt) &&
02149             (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
02150         {
02151                 isc_buffer_t *buf;
02152 
02153                 msgresetnames(msg, DNS_SECTION_ANSWER);
02154                 buf = msg->buffer;
02155                 dns_message_renderreset(msg);
02156                 msg->buffer = buf;
02157                 isc_buffer_clear(msg->buffer);
02158                 isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
02159                 dns_compress_rollback(msg->cctx, 0);
02160                 result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
02161                                                    0);
02162                 if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
02163                         return (result);
02164         }
02165 
02166         /*
02167          * If we've got an OPT record, render it.
02168          */
02169         if (msg->opt != NULL) {
02170                 dns_message_renderrelease(msg, msg->opt_reserved);
02171                 msg->opt_reserved = 0;
02172                 /*
02173                  * Set the extended rcode.
02174                  */
02175                 msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
02176                 msg->opt->ttl |= ((msg->rcode << 20) &
02177                                   DNS_MESSAGE_EDNSRCODE_MASK);
02178                 /*
02179                  * Render.
02180                  */
02181                 count = 0;
02182                 result = dns_rdataset_towire(msg->opt, dns_rootname,
02183                                              msg->cctx, msg->buffer, 0,
02184                                              &count);
02185                 msg->counts[DNS_SECTION_ADDITIONAL] += count;
02186                 if (result != ISC_R_SUCCESS)
02187                         return (result);
02188         }
02189 
02190         /*
02191          * If we're adding a TSIG record, generate and render it.
02192          */
02193         if (msg->tsigkey != NULL) {
02194                 dns_message_renderrelease(msg, msg->sig_reserved);
02195                 msg->sig_reserved = 0;
02196                 result = dns_tsig_sign(msg);
02197                 if (result != ISC_R_SUCCESS)
02198                         return (result);
02199                 count = 0;
02200                 result = dns_rdataset_towire(msg->tsig, msg->tsigname,
02201                                              msg->cctx, msg->buffer, 0,
02202                                              &count);
02203                 msg->counts[DNS_SECTION_ADDITIONAL] += count;
02204                 if (result != ISC_R_SUCCESS)
02205                         return (result);
02206         }
02207 
02208         /*
02209          * If we're adding a SIG(0) record, generate and render it.
02210          */
02211         if (msg->sig0key != NULL) {
02212                 dns_message_renderrelease(msg, msg->sig_reserved);
02213                 msg->sig_reserved = 0;
02214                 result = dns_dnssec_signmessage(msg, msg->sig0key);
02215                 if (result != ISC_R_SUCCESS)
02216                         return (result);
02217                 count = 0;
02218                 /*
02219                  * Note: dns_rootname is used here, not msg->sig0name, since
02220                  * the owner name of a SIG(0) is irrelevant, and will not
02221                  * be set in a message being rendered.
02222                  */
02223                 result = dns_rdataset_towire(msg->sig0, dns_rootname,
02224                                              msg->cctx, msg->buffer, 0,
02225                                              &count);
02226                 msg->counts[DNS_SECTION_ADDITIONAL] += count;
02227                 if (result != ISC_R_SUCCESS)
02228                         return (result);
02229         }
02230 
02231         isc_buffer_usedregion(msg->buffer, &r);
02232         isc_buffer_init(&tmpbuf, r.base, r.length);
02233 
02234         dns_message_renderheader(msg, &tmpbuf);
02235 
02236         msg->buffer = NULL;  /* forget about this buffer only on success XXX */
02237 
02238         return (ISC_R_SUCCESS);
02239 }
02240 
02241 void
02242 dns_message_renderreset(dns_message_t *msg) {
02243         unsigned int i;
02244         dns_name_t *name;
02245         dns_rdataset_t *rds;
02246 
02247         /*
02248          * Reset the message so that it may be rendered again.
02249          */
02250 
02251         REQUIRE(DNS_MESSAGE_VALID(msg));
02252         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
02253 
02254         msg->buffer = NULL;
02255 
02256         for (i = 0; i < DNS_SECTION_MAX; i++) {
02257                 msg->cursors[i] = NULL;
02258                 msg->counts[i] = 0;
02259                 for (name = ISC_LIST_HEAD(msg->sections[i]);
02260                      name != NULL;
02261                      name = ISC_LIST_NEXT(name, link)) {
02262                         for (rds = ISC_LIST_HEAD(name->list);
02263                              rds != NULL;
02264                              rds = ISC_LIST_NEXT(rds, link)) {
02265                                 rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
02266                         }
02267                 }
02268         }
02269         if (msg->tsigname != NULL)
02270                 dns_message_puttempname(msg, &msg->tsigname);
02271         if (msg->tsig != NULL) {
02272                 dns_rdataset_disassociate(msg->tsig);
02273                 dns_message_puttemprdataset(msg, &msg->tsig);
02274         }
02275         if (msg->sig0 != NULL) {
02276                 dns_rdataset_disassociate(msg->sig0);
02277                 dns_message_puttemprdataset(msg, &msg->sig0);
02278         }
02279 }
02280 
02281 isc_result_t
02282 dns_message_firstname(dns_message_t *msg, dns_section_t section) {
02283         REQUIRE(DNS_MESSAGE_VALID(msg));
02284         REQUIRE(VALID_NAMED_SECTION(section));
02285 
02286         msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
02287 
02288         if (msg->cursors[section] == NULL)
02289                 return (ISC_R_NOMORE);
02290 
02291         return (ISC_R_SUCCESS);
02292 }
02293 
02294 isc_result_t
02295 dns_message_nextname(dns_message_t *msg, dns_section_t section) {
02296         REQUIRE(DNS_MESSAGE_VALID(msg));
02297         REQUIRE(VALID_NAMED_SECTION(section));
02298         REQUIRE(msg->cursors[section] != NULL);
02299 
02300         msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
02301 
02302         if (msg->cursors[section] == NULL)
02303                 return (ISC_R_NOMORE);
02304 
02305         return (ISC_R_SUCCESS);
02306 }
02307 
02308 void
02309 dns_message_currentname(dns_message_t *msg, dns_section_t section,
02310                         dns_name_t **name)
02311 {
02312         REQUIRE(DNS_MESSAGE_VALID(msg));
02313         REQUIRE(VALID_NAMED_SECTION(section));
02314         REQUIRE(name != NULL && *name == NULL);
02315         REQUIRE(msg->cursors[section] != NULL);
02316 
02317         *name = msg->cursors[section];
02318 }
02319 
02320 isc_result_t
02321 dns_message_findname(dns_message_t *msg, dns_section_t section,
02322                      dns_name_t *target, dns_rdatatype_t type,
02323                      dns_rdatatype_t covers, dns_name_t **name,
02324                      dns_rdataset_t **rdataset)
02325 {
02326         dns_name_t *foundname;
02327         isc_result_t result;
02328 
02329         /*
02330          * XXX These requirements are probably too intensive, especially
02331          * where things can be NULL, but as they are they ensure that if
02332          * something is NON-NULL, indicating that the caller expects it
02333          * to be filled in, that we can in fact fill it in.
02334          */
02335         REQUIRE(msg != NULL);
02336         REQUIRE(VALID_SECTION(section));
02337         REQUIRE(target != NULL);
02338         if (name != NULL)
02339                 REQUIRE(*name == NULL);
02340         if (type == dns_rdatatype_any) {
02341                 REQUIRE(rdataset == NULL);
02342         } else {
02343                 if (rdataset != NULL)
02344                         REQUIRE(*rdataset == NULL);
02345         }
02346 
02347         result = findname(&foundname, target,
02348                           &msg->sections[section]);
02349 
02350         if (result == ISC_R_NOTFOUND)
02351                 return (DNS_R_NXDOMAIN);
02352         else if (result != ISC_R_SUCCESS)
02353                 return (result);
02354 
02355         if (name != NULL)
02356                 *name = foundname;
02357 
02358         /*
02359          * And now look for the type.
02360          */
02361         if (type == dns_rdatatype_any)
02362                 return (ISC_R_SUCCESS);
02363 
02364         result = dns_message_findtype(foundname, type, covers, rdataset);
02365         if (result == ISC_R_NOTFOUND)
02366                 return (DNS_R_NXRRSET);
02367 
02368         return (result);
02369 }
02370 
02371 void
02372 dns_message_movename(dns_message_t *msg, dns_name_t *name,
02373                      dns_section_t fromsection,
02374                      dns_section_t tosection)
02375 {
02376         REQUIRE(msg != NULL);
02377         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
02378         REQUIRE(name != NULL);
02379         REQUIRE(VALID_NAMED_SECTION(fromsection));
02380         REQUIRE(VALID_NAMED_SECTION(tosection));
02381 
02382         /*
02383          * Unlink the name from the old section
02384          */
02385         ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
02386         ISC_LIST_APPEND(msg->sections[tosection], name, link);
02387 }
02388 
02389 void
02390 dns_message_addname(dns_message_t *msg, dns_name_t *name,
02391                     dns_section_t section)
02392 {
02393         REQUIRE(msg != NULL);
02394         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
02395         REQUIRE(name != NULL);
02396         REQUIRE(VALID_NAMED_SECTION(section));
02397 
02398         ISC_LIST_APPEND(msg->sections[section], name, link);
02399 }
02400 
02401 void
02402 dns_message_removename(dns_message_t *msg, dns_name_t *name,
02403                        dns_section_t section)
02404 {
02405         REQUIRE(msg != NULL);
02406         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
02407         REQUIRE(name != NULL);
02408         REQUIRE(VALID_NAMED_SECTION(section));
02409 
02410         ISC_LIST_UNLINK(msg->sections[section], name, link);
02411 }
02412 
02413 isc_result_t
02414 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
02415         REQUIRE(DNS_MESSAGE_VALID(msg));
02416         REQUIRE(item != NULL && *item == NULL);
02417 
02418         *item = isc_mempool_get(msg->namepool);
02419         if (*item == NULL)
02420                 return (ISC_R_NOMEMORY);
02421         dns_name_init(*item, NULL);
02422 
02423         return (ISC_R_SUCCESS);
02424 }
02425 
02426 isc_result_t
02427 dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) {
02428         REQUIRE(DNS_MESSAGE_VALID(msg));
02429         REQUIRE(item != NULL && *item == NULL);
02430 
02431         *item = newoffsets(msg);
02432         if (*item == NULL)
02433                 return (ISC_R_NOMEMORY);
02434 
02435         return (ISC_R_SUCCESS);
02436 }
02437 
02438 isc_result_t
02439 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
02440         REQUIRE(DNS_MESSAGE_VALID(msg));
02441         REQUIRE(item != NULL && *item == NULL);
02442 
02443         *item = newrdata(msg);
02444         if (*item == NULL)
02445                 return (ISC_R_NOMEMORY);
02446 
02447         return (ISC_R_SUCCESS);
02448 }
02449 
02450 isc_result_t
02451 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
02452         REQUIRE(DNS_MESSAGE_VALID(msg));
02453         REQUIRE(item != NULL && *item == NULL);
02454 
02455         *item = isc_mempool_get(msg->rdspool);
02456         if (*item == NULL)
02457                 return (ISC_R_NOMEMORY);
02458 
02459         dns_rdataset_init(*item);
02460 
02461         return (ISC_R_SUCCESS);
02462 }
02463 
02464 isc_result_t
02465 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
02466         REQUIRE(DNS_MESSAGE_VALID(msg));
02467         REQUIRE(item != NULL && *item == NULL);
02468 
02469         *item = newrdatalist(msg);
02470         if (*item == NULL)
02471                 return (ISC_R_NOMEMORY);
02472 
02473         return (ISC_R_SUCCESS);
02474 }
02475 
02476 void
02477 dns_message_puttempname(dns_message_t *msg, dns_name_t **item) {
02478         REQUIRE(DNS_MESSAGE_VALID(msg));
02479         REQUIRE(item != NULL && *item != NULL);
02480 
02481         if (dns_name_dynamic(*item))
02482                 dns_name_free(*item, msg->mctx);
02483         isc_mempool_put(msg->namepool, *item);
02484         *item = NULL;
02485 }
02486 
02487 void
02488 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
02489         REQUIRE(DNS_MESSAGE_VALID(msg));
02490         REQUIRE(item != NULL && *item != NULL);
02491 
02492         releaserdata(msg, *item);
02493         *item = NULL;
02494 }
02495 
02496 void
02497 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
02498         REQUIRE(DNS_MESSAGE_VALID(msg));
02499         REQUIRE(item != NULL && *item != NULL);
02500 
02501         REQUIRE(!dns_rdataset_isassociated(*item));
02502         isc_mempool_put(msg->rdspool, *item);
02503         *item = NULL;
02504 }
02505 
02506 void
02507 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
02508         REQUIRE(DNS_MESSAGE_VALID(msg));
02509         REQUIRE(item != NULL && *item != NULL);
02510 
02511         releaserdatalist(msg, *item);
02512         *item = NULL;
02513 }
02514 
02515 isc_result_t
02516 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
02517                        unsigned int *flagsp)
02518 {
02519         isc_region_t r;
02520         isc_buffer_t buffer;
02521         dns_messageid_t id;
02522         unsigned int flags;
02523 
02524         REQUIRE(source != NULL);
02525 
02526         buffer = *source;
02527 
02528         isc_buffer_remainingregion(&buffer, &r);
02529         if (r.length < DNS_MESSAGE_HEADERLEN)
02530                 return (ISC_R_UNEXPECTEDEND);
02531 
02532         id = isc_buffer_getuint16(&buffer);
02533         flags = isc_buffer_getuint16(&buffer);
02534         flags &= DNS_MESSAGE_FLAG_MASK;
02535 
02536         if (flagsp != NULL)
02537                 *flagsp = flags;
02538         if (idp != NULL)
02539                 *idp = id;
02540 
02541         return (ISC_R_SUCCESS);
02542 }
02543 
02544 isc_result_t
02545 dns_message_reply(dns_message_t *msg, isc_boolean_t want_question_section) {
02546         unsigned int clear_after;
02547         isc_result_t result;
02548 
02549         REQUIRE(DNS_MESSAGE_VALID(msg));
02550         REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
02551 
02552         if (!msg->header_ok)
02553                 return (DNS_R_FORMERR);
02554         if (msg->opcode != dns_opcode_query &&
02555             msg->opcode != dns_opcode_notify)
02556                 want_question_section = ISC_FALSE;
02557         if (msg->opcode == dns_opcode_update)
02558                 clear_after = DNS_SECTION_PREREQUISITE;
02559         else if (want_question_section) {
02560                 if (!msg->question_ok)
02561                         return (DNS_R_FORMERR);
02562                 clear_after = DNS_SECTION_ANSWER;
02563         } else
02564                 clear_after = DNS_SECTION_QUESTION;
02565         msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
02566         msgresetnames(msg, clear_after);
02567         msgresetopt(msg);
02568         msgresetsigs(msg, ISC_TRUE);
02569         msginitprivate(msg);
02570         /*
02571          * We now clear most flags and then set QR, ensuring that the
02572          * reply's flags will be in a reasonable state.
02573          */
02574         msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
02575         msg->flags |= DNS_MESSAGEFLAG_QR;
02576 
02577         /*
02578          * This saves the query TSIG status, if the query was signed, and
02579          * reserves space in the reply for the TSIG.
02580          */
02581         if (msg->tsigkey != NULL) {
02582                 unsigned int otherlen = 0;
02583                 msg->querytsigstatus = msg->tsigstatus;
02584                 msg->tsigstatus = dns_rcode_noerror;
02585                 if (msg->querytsigstatus == dns_tsigerror_badtime)
02586                         otherlen = 6;
02587                 msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen);
02588                 result = dns_message_renderreserve(msg, msg->sig_reserved);
02589                 if (result != ISC_R_SUCCESS) {
02590                         msg->sig_reserved = 0;
02591                         return (result);
02592                 }
02593         }
02594         if (msg->saved.base != NULL) {
02595                 msg->query.base = msg->saved.base;
02596                 msg->query.length = msg->saved.length;
02597                 msg->free_query = msg->free_saved;
02598                 msg->saved.base = NULL;
02599                 msg->saved.length = 0;
02600                 msg->free_saved = 0;
02601         }
02602 
02603         return (ISC_R_SUCCESS);
02604 }
02605 
02606 dns_rdataset_t *
02607 dns_message_getopt(dns_message_t *msg) {
02608 
02609         /*
02610          * Get the OPT record for 'msg'.
02611          */
02612 
02613         REQUIRE(DNS_MESSAGE_VALID(msg));
02614 
02615         return (msg->opt);
02616 }
02617 
02618 isc_result_t
02619 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
02620         isc_result_t result;
02621         dns_rdata_t rdata = DNS_RDATA_INIT;
02622 
02623         /*
02624          * Set the OPT record for 'msg'.
02625          */
02626 
02627         /*
02628          * The space required for an OPT record is:
02629          *
02630          *      1 byte for the name
02631          *      2 bytes for the type
02632          *      2 bytes for the class
02633          *      4 bytes for the ttl
02634          *      2 bytes for the rdata length
02635          * ---------------------------------
02636          *     11 bytes
02637          *
02638          * plus the length of the rdata.
02639          */
02640 
02641         REQUIRE(DNS_MESSAGE_VALID(msg));
02642         REQUIRE(opt->type == dns_rdatatype_opt);
02643         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
02644         REQUIRE(msg->state == DNS_SECTION_ANY);
02645 
02646         msgresetopt(msg);
02647 
02648         result = dns_rdataset_first(opt);
02649         if (result != ISC_R_SUCCESS)
02650                 goto cleanup;
02651         dns_rdataset_current(opt, &rdata);
02652         msg->opt_reserved = 11 + rdata.length;
02653         result = dns_message_renderreserve(msg, msg->opt_reserved);
02654         if (result != ISC_R_SUCCESS) {
02655                 msg->opt_reserved = 0;
02656                 goto cleanup;
02657         }
02658 
02659         msg->opt = opt;
02660 
02661         return (ISC_R_SUCCESS);
02662 
02663  cleanup:
02664         dns_rdataset_disassociate(opt);
02665         dns_message_puttemprdataset(msg, &opt);
02666         return (result);
02667 }
02668 
02669 dns_rdataset_t *
02670 dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) {
02671 
02672         /*
02673          * Get the TSIG record and owner for 'msg'.
02674          */
02675 
02676         REQUIRE(DNS_MESSAGE_VALID(msg));
02677         REQUIRE(owner == NULL || *owner == NULL);
02678 
02679         if (owner != NULL)
02680                 *owner = msg->tsigname;
02681         return (msg->tsig);
02682 }
02683 
02684 isc_result_t
02685 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
02686         isc_result_t result;
02687 
02688         /*
02689          * Set the TSIG key for 'msg'
02690          */
02691 
02692         REQUIRE(DNS_MESSAGE_VALID(msg));
02693         REQUIRE(msg->state == DNS_SECTION_ANY);
02694 
02695         if (key == NULL && msg->tsigkey != NULL) {
02696                 if (msg->sig_reserved != 0) {
02697                         dns_message_renderrelease(msg, msg->sig_reserved);
02698                         msg->sig_reserved = 0;
02699                 }
02700                 dns_tsigkey_detach(&msg->tsigkey);
02701         }
02702         if (key != NULL) {
02703                 REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
02704                 dns_tsigkey_attach(key, &msg->tsigkey);
02705                 if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
02706                         msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
02707                         result = dns_message_renderreserve(msg,
02708                                                            msg->sig_reserved);
02709                         if (result != ISC_R_SUCCESS) {
02710                                 dns_tsigkey_detach(&msg->tsigkey);
02711                                 msg->sig_reserved = 0;
02712                                 return (result);
02713                         }
02714                 }
02715         }
02716         return (ISC_R_SUCCESS);
02717 }
02718 
02719 dns_tsigkey_t *
02720 dns_message_gettsigkey(dns_message_t *msg) {
02721 
02722         /*
02723          * Get the TSIG key for 'msg'
02724          */
02725 
02726         REQUIRE(DNS_MESSAGE_VALID(msg));
02727 
02728         return (msg->tsigkey);
02729 }
02730 
02731 isc_result_t
02732 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
02733         dns_rdata_t *rdata = NULL;
02734         dns_rdatalist_t *list = NULL;
02735         dns_rdataset_t *set = NULL;
02736         isc_buffer_t *buf = NULL;
02737         isc_region_t r;
02738         isc_result_t result;
02739 
02740         REQUIRE(DNS_MESSAGE_VALID(msg));
02741         REQUIRE(msg->querytsig == NULL);
02742 
02743         if (querytsig == NULL)
02744                 return (ISC_R_SUCCESS);
02745 
02746         result = dns_message_gettemprdata(msg, &rdata);
02747         if (result != ISC_R_SUCCESS)
02748                 goto cleanup;
02749 
02750         result = dns_message_gettemprdatalist(msg, &list);
02751         if (result != ISC_R_SUCCESS)
02752                 goto cleanup;
02753         result = dns_message_gettemprdataset(msg, &set);
02754         if (result != ISC_R_SUCCESS)
02755                 goto cleanup;
02756 
02757         isc_buffer_usedregion(querytsig, &r);
02758         result = isc_buffer_allocate(msg->mctx, &buf, r.length);
02759         if (result != ISC_R_SUCCESS)
02760                 goto cleanup;
02761         isc_buffer_putmem(buf, r.base, r.length);
02762         isc_buffer_usedregion(buf, &r);
02763         dns_rdata_init(rdata);
02764         dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
02765         dns_message_takebuffer(msg, &buf);
02766         ISC_LIST_APPEND(list->rdata, rdata, link);
02767         result = dns_rdatalist_tordataset(list, set);
02768         if (result != ISC_R_SUCCESS)
02769                 goto cleanup;
02770 
02771         msg->querytsig = set;
02772 
02773         return (result);
02774 
02775  cleanup:
02776         if (rdata != NULL)
02777                 dns_message_puttemprdata(msg, &rdata);
02778         if (list != NULL)
02779                 dns_message_puttemprdatalist(msg, &list);
02780         if (set != NULL)
02781                 dns_message_puttemprdataset(msg, &set);
02782         return (ISC_R_NOMEMORY);
02783 }
02784 
02785 isc_result_t
02786 dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
02787                          isc_buffer_t **querytsig) {
02788         isc_result_t result;
02789         dns_rdata_t rdata = DNS_RDATA_INIT;
02790         isc_region_t r;
02791 
02792         REQUIRE(DNS_MESSAGE_VALID(msg));
02793         REQUIRE(mctx != NULL);
02794         REQUIRE(querytsig != NULL && *querytsig == NULL);
02795 
02796         if (msg->tsig == NULL)
02797                 return (ISC_R_SUCCESS);
02798 
02799         result = dns_rdataset_first(msg->tsig);
02800         if (result != ISC_R_SUCCESS)
02801                 return (result);
02802         dns_rdataset_current(msg->tsig, &rdata);
02803         dns_rdata_toregion(&rdata, &r);
02804 
02805         result = isc_buffer_allocate(mctx, querytsig, r.length);
02806         if (result != ISC_R_SUCCESS)
02807                 return (result);
02808         isc_buffer_putmem(*querytsig, r.base, r.length);
02809         return (ISC_R_SUCCESS);
02810 }
02811 
02812 dns_rdataset_t *
02813 dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) {
02814 
02815         /*
02816          * Get the SIG(0) record for 'msg'.
02817          */
02818 
02819         REQUIRE(DNS_MESSAGE_VALID(msg));
02820         REQUIRE(owner == NULL || *owner == NULL);
02821 
02822         if (msg->sig0 != NULL && owner != NULL) {
02823                 /* If dns_message_getsig0 is called on a rendered message
02824                  * after the SIG(0) has been applied, we need to return the
02825                  * root name, not NULL.
02826                  */
02827                 if (msg->sig0name == NULL)
02828                         *owner = dns_rootname;
02829                 else
02830                         *owner = msg->sig0name;
02831         }
02832         return (msg->sig0);
02833 }
02834 
02835 isc_result_t
02836 dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) {
02837         isc_region_t r;
02838         unsigned int x;
02839         isc_result_t result;
02840 
02841         /*
02842          * Set the SIG(0) key for 'msg'
02843          */
02844 
02845         /*
02846          * The space required for an SIG(0) record is:
02847          *
02848          *      1 byte for the name
02849          *      2 bytes for the type
02850          *      2 bytes for the class
02851          *      4 bytes for the ttl
02852          *      2 bytes for the type covered
02853          *      1 byte for the algorithm
02854          *      1 bytes for the labels
02855          *      4 bytes for the original ttl
02856          *      4 bytes for the signature expiration
02857          *      4 bytes for the signature inception
02858          *      2 bytes for the key tag
02859          *      n bytes for the signer's name
02860          *      x bytes for the signature
02861          * ---------------------------------
02862          *     27 + n + x bytes
02863          */
02864         REQUIRE(DNS_MESSAGE_VALID(msg));
02865         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
02866         REQUIRE(msg->state == DNS_SECTION_ANY);
02867 
02868         if (key != NULL) {
02869                 REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL);
02870                 dns_name_toregion(dst_key_name(key), &r);
02871                 result = dst_key_sigsize(key, &x);
02872                 if (result != ISC_R_SUCCESS) {
02873                         msg->sig_reserved = 0;
02874                         return (result);
02875                 }
02876                 msg->sig_reserved = 27 + r.length + x;
02877                 result = dns_message_renderreserve(msg, msg->sig_reserved);
02878                 if (result != ISC_R_SUCCESS) {
02879                         msg->sig_reserved = 0;
02880                         return (result);
02881                 }
02882                 msg->sig0key = key;
02883         }
02884         return (ISC_R_SUCCESS);
02885 }
02886 
02887 dst_key_t *
02888 dns_message_getsig0key(dns_message_t *msg) {
02889 
02890         /*
02891          * Get the SIG(0) key for 'msg'
02892          */
02893 
02894         REQUIRE(DNS_MESSAGE_VALID(msg));
02895 
02896         return (msg->sig0key);
02897 }
02898 
02899 void
02900 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
02901         REQUIRE(DNS_MESSAGE_VALID(msg));
02902         REQUIRE(buffer != NULL);
02903         REQUIRE(ISC_BUFFER_VALID(*buffer));
02904 
02905         ISC_LIST_APPEND(msg->cleanup, *buffer, link);
02906         *buffer = NULL;
02907 }
02908 
02909 isc_result_t
02910 dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
02911         isc_result_t result = ISC_R_SUCCESS;
02912         dns_rdata_t rdata = DNS_RDATA_INIT;
02913 
02914         REQUIRE(DNS_MESSAGE_VALID(msg));
02915         REQUIRE(signer != NULL);
02916         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
02917 
02918         if (msg->tsig == NULL && msg->sig0 == NULL)
02919                 return (ISC_R_NOTFOUND);
02920 
02921         if (msg->verify_attempted == 0)
02922                 return (DNS_R_NOTVERIFIEDYET);
02923 
02924         if (!dns_name_hasbuffer(signer)) {
02925                 isc_buffer_t *dynbuf = NULL;
02926                 result = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
02927                 if (result != ISC_R_SUCCESS)
02928                         return (result);
02929                 dns_name_setbuffer(signer, dynbuf);
02930                 dns_message_takebuffer(msg, &dynbuf);
02931         }
02932 
02933         if (msg->sig0 != NULL) {
02934                 dns_rdata_sig_t sig;
02935 
02936                 result = dns_rdataset_first(msg->sig0);
02937                 INSIST(result == ISC_R_SUCCESS);
02938                 dns_rdataset_current(msg->sig0, &rdata);
02939 
02940                 result = dns_rdata_tostruct(&rdata, &sig, NULL);
02941                 if (result != ISC_R_SUCCESS)
02942                         return (result);
02943 
02944                 if (msg->verified_sig && msg->sig0status == dns_rcode_noerror)
02945                         result = ISC_R_SUCCESS;
02946                 else
02947                         result = DNS_R_SIGINVALID;
02948                 dns_name_clone(&sig.signer, signer);
02949                 dns_rdata_freestruct(&sig);
02950         } else {
02951                 dns_name_t *identity;
02952                 dns_rdata_any_tsig_t tsig;
02953 
02954                 result = dns_rdataset_first(msg->tsig);
02955                 INSIST(result == ISC_R_SUCCESS);
02956                 dns_rdataset_current(msg->tsig, &rdata);
02957 
02958                 result = dns_rdata_tostruct(&rdata, &tsig, NULL);
02959                 INSIST(result == ISC_R_SUCCESS);
02960                 if (msg->tsigstatus != dns_rcode_noerror)
02961                         result = DNS_R_TSIGVERIFYFAILURE;
02962                 else if (tsig.error != dns_rcode_noerror)
02963                         result = DNS_R_TSIGERRORSET;
02964                 else
02965                         result = ISC_R_SUCCESS;
02966                 dns_rdata_freestruct(&tsig);
02967 
02968                 if (msg->tsigkey == NULL) {
02969                         /*
02970                          * If msg->tsigstatus & tsig.error are both
02971                          * dns_rcode_noerror, the message must have been
02972                          * verified, which means msg->tsigkey will be
02973                          * non-NULL.
02974                          */
02975                         INSIST(result != ISC_R_SUCCESS);
02976                 } else {
02977                         identity = dns_tsigkey_identity(msg->tsigkey);
02978                         if (identity == NULL) {
02979                                 if (result == ISC_R_SUCCESS)
02980                                         result = DNS_R_NOIDENTITY;
02981                                 identity = &msg->tsigkey->name;
02982                         }
02983                         dns_name_clone(identity, signer);
02984                 }
02985         }
02986 
02987         return (result);
02988 }
02989 
02990 void
02991 dns_message_resetsig(dns_message_t *msg) {
02992         REQUIRE(DNS_MESSAGE_VALID(msg));
02993         msg->verified_sig = 0;
02994         msg->verify_attempted = 0;
02995         msg->tsigstatus = dns_rcode_noerror;
02996         msg->sig0status = dns_rcode_noerror;
02997         msg->timeadjust = 0;
02998         if (msg->tsigkey != NULL) {
02999                 dns_tsigkey_detach(&msg->tsigkey);
03000                 msg->tsigkey = NULL;
03001         }
03002 }
03003 
03004 isc_result_t
03005 dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
03006         dns_message_resetsig(msg);
03007         return (dns_message_checksig(msg, view));
03008 }
03009 
03010 #ifdef SKAN_MSG_DEBUG
03011 void
03012 dns_message_dumpsig(dns_message_t *msg, char *txt1) {
03013         dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
03014         dns_rdata_any_tsig_t querytsig;
03015         isc_result_t result;
03016 
03017         if (msg->tsig != NULL) {
03018                 result = dns_rdataset_first(msg->tsig);
03019                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
03020                 dns_rdataset_current(msg->tsig, &querytsigrdata);
03021                 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
03022                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
03023                 hexdump(txt1, "TSIG", querytsig.signature,
03024                         querytsig.siglen);
03025         }
03026 
03027         if (msg->querytsig != NULL) {
03028                 result = dns_rdataset_first(msg->querytsig);
03029                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
03030                 dns_rdataset_current(msg->querytsig, &querytsigrdata);
03031                 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
03032                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
03033                 hexdump(txt1, "QUERYTSIG", querytsig.signature,
03034                         querytsig.siglen);
03035         }
03036 }
03037 #endif
03038 
03039 isc_result_t
03040 dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
03041         isc_buffer_t b, msgb;
03042 
03043         REQUIRE(DNS_MESSAGE_VALID(msg));
03044 
03045         if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL)
03046                 return (ISC_R_SUCCESS);
03047 
03048         INSIST(msg->saved.base != NULL);
03049         isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
03050         isc_buffer_add(&msgb, msg->saved.length);
03051         if (msg->tsigkey != NULL || msg->tsig != NULL) {
03052 #ifdef SKAN_MSG_DEBUG
03053                 dns_message_dumpsig(msg, "dns_message_checksig#1");
03054 #endif
03055                 if (view != NULL)
03056                         return (dns_view_checksig(view, &msgb, msg));
03057                 else
03058                         return (dns_tsig_verify(&msgb, msg, NULL, NULL));
03059         } else {
03060                 dns_rdata_t rdata = DNS_RDATA_INIT;
03061                 dns_rdata_sig_t sig;
03062                 dns_rdataset_t keyset;
03063                 isc_result_t result;
03064 
03065                 result = dns_rdataset_first(msg->sig0);
03066                 INSIST(result == ISC_R_SUCCESS);
03067                 dns_rdataset_current(msg->sig0, &rdata);
03068 
03069                 /*
03070                  * This can occur when the message is a dynamic update, since
03071                  * the rdata length checking is relaxed.  This should not
03072                  * happen in a well-formed message, since the SIG(0) is only
03073                  * looked for in the additional section, and the dynamic update
03074                  * meta-records are in the prerequisite and update sections.
03075                  */
03076                 if (rdata.length == 0)
03077                         return (ISC_R_UNEXPECTEDEND);
03078 
03079                 result = dns_rdata_tostruct(&rdata, &sig, msg->mctx);
03080                 if (result != ISC_R_SUCCESS)
03081                         return (result);
03082 
03083                 dns_rdataset_init(&keyset);
03084                 if (view == NULL)
03085                         return (DNS_R_KEYUNAUTHORIZED);
03086                 result = dns_view_simplefind(view, &sig.signer,
03087                                              dns_rdatatype_key /* SIG(0) */,
03088                                              0, 0, ISC_FALSE, &keyset, NULL);
03089 
03090                 if (result != ISC_R_SUCCESS) {
03091                         /* XXXBEW Should possibly create a fetch here */
03092                         result = DNS_R_KEYUNAUTHORIZED;
03093                         goto freesig;
03094                 } else if (keyset.trust < dns_trust_secure) {
03095                         /* XXXBEW Should call a validator here */
03096                         result = DNS_R_KEYUNAUTHORIZED;
03097                         goto freesig;
03098                 }
03099                 result = dns_rdataset_first(&keyset);
03100                 INSIST(result == ISC_R_SUCCESS);
03101                 for (;
03102                      result == ISC_R_SUCCESS;
03103                      result = dns_rdataset_next(&keyset))
03104                 {
03105                         dst_key_t *key = NULL;
03106 
03107                         dns_rdata_reset(&rdata);
03108                         dns_rdataset_current(&keyset, &rdata);
03109                         isc_buffer_init(&b, rdata.data, rdata.length);
03110                         isc_buffer_add(&b, rdata.length);
03111 
03112                         result = dst_key_fromdns(&sig.signer, rdata.rdclass,
03113                                                  &b, view->mctx, &key);
03114                         if (result != ISC_R_SUCCESS)
03115                                 continue;
03116                         if (dst_key_alg(key) != sig.algorithm ||
03117                             dst_key_id(key) != sig.keyid ||
03118                             !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
03119                               dst_key_proto(key) == DNS_KEYPROTO_ANY))
03120                         {
03121                                 dst_key_free(&key);
03122                                 continue;
03123                         }
03124                         result = dns_dnssec_verifymessage(&msgb, msg, key);
03125                         dst_key_free(&key);
03126                         if (result == ISC_R_SUCCESS)
03127                                 break;
03128                 }
03129                 if (result == ISC_R_NOMORE)
03130                         result = DNS_R_KEYUNAUTHORIZED;
03131 
03132  freesig:
03133                 if (dns_rdataset_isassociated(&keyset))
03134                         dns_rdataset_disassociate(&keyset);
03135                 dns_rdata_freestruct(&sig);
03136                 return (result);
03137         }
03138 }
03139 
03140 isc_result_t
03141 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
03142                           const dns_master_style_t *style,
03143                           dns_messagetextflag_t flags,
03144                           isc_buffer_t *target) {
03145         dns_name_t *name, empty_name;
03146         dns_rdataset_t *rdataset;
03147         isc_result_t result;
03148         isc_boolean_t seensoa = ISC_FALSE;
03149 
03150         REQUIRE(DNS_MESSAGE_VALID(msg));
03151         REQUIRE(target != NULL);
03152         REQUIRE(VALID_SECTION(section));
03153 
03154         if (ISC_LIST_EMPTY(msg->sections[section]))
03155                 return (ISC_R_SUCCESS);
03156 
03157         if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
03158                 ADD_STRING(target, ";; ");
03159                 if (msg->opcode != dns_opcode_update) {
03160                         ADD_STRING(target, sectiontext[section]);
03161                 } else {
03162                         ADD_STRING(target, updsectiontext[section]);
03163                 }
03164                 ADD_STRING(target, " SECTION:\n");
03165         }
03166 
03167         dns_name_init(&empty_name, NULL);
03168         result = dns_message_firstname(msg, section);
03169         if (result != ISC_R_SUCCESS) {
03170                 return (result);
03171         }
03172         do {
03173                 name = NULL;
03174                 dns_message_currentname(msg, section, &name);
03175                 for (rdataset = ISC_LIST_HEAD(name->list);
03176                      rdataset != NULL;
03177                      rdataset = ISC_LIST_NEXT(rdataset, link)) {
03178                         if (section == DNS_SECTION_ANSWER &&
03179                             rdataset->type == dns_rdatatype_soa) {
03180                                 if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0)
03181                                         continue;
03182                                 if (seensoa &&
03183                                     (flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0)
03184                                         continue;
03185                                 seensoa = ISC_TRUE;
03186                         }
03187                         if (section == DNS_SECTION_QUESTION) {
03188                                 ADD_STRING(target, ";");
03189                                 result = dns_master_questiontotext(name,
03190                                                                    rdataset,
03191                                                                    style,
03192                                                                    target);
03193                         } else {
03194                                 result = dns_master_rdatasettotext(name,
03195                                                                    rdataset,
03196                                                                    style,
03197                                                                    target);
03198                         }
03199                         if (result != ISC_R_SUCCESS)
03200                                 return (result);
03201                 }
03202                 result = dns_message_nextname(msg, section);
03203         } while (result == ISC_R_SUCCESS);
03204         if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
03205             (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
03206                 ADD_STRING(target, "\n");
03207         if (result == ISC_R_NOMORE)
03208                 result = ISC_R_SUCCESS;
03209         return (result);
03210 }
03211 
03212 static isc_result_t
03213 render_ecs(isc_buffer_t *optbuf, isc_buffer_t *target) {
03214         int i;
03215         char addr[16], addr_text[64];
03216         isc_uint16_t family;
03217         isc_uint8_t addrlen, addrbytes, scopelen;
03218 
03219         INSIST(isc_buffer_remaininglength(optbuf) >= 4);
03220         family = isc_buffer_getuint16(optbuf);
03221         addrlen = isc_buffer_getuint8(optbuf);
03222         scopelen = isc_buffer_getuint8(optbuf);
03223 
03224         addrbytes = (addrlen + 7) / 8;
03225         INSIST(isc_buffer_remaininglength(optbuf) >= addrbytes);
03226 
03227         memset(addr, 0, sizeof(addr));
03228         for (i = 0; i < addrbytes; i ++)
03229                 addr[i] = isc_buffer_getuint8(optbuf);
03230 
03231         if (family == 1)
03232                 inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text));
03233         else if (family == 2)
03234                 inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text));
03235         else {
03236                 snprintf(addr_text, sizeof(addr_text),
03237                          "Unsupported family %u", family);
03238                 ADD_STRING(target, addr_text);
03239                 return (ISC_R_SUCCESS);
03240         }
03241 
03242         ADD_STRING(target, addr_text);
03243         snprintf(addr_text, sizeof(addr_text), "/%d/%d", addrlen, scopelen);
03244         ADD_STRING(target, addr_text);
03245         return (ISC_R_SUCCESS);
03246 }
03247 
03248 isc_result_t
03249 dns_message_pseudosectiontotext(dns_message_t *msg,
03250                                 dns_pseudosection_t section,
03251                                 const dns_master_style_t *style,
03252                                 dns_messagetextflag_t flags,
03253                                 isc_buffer_t *target)
03254 {
03255         dns_rdataset_t *ps = NULL;
03256         dns_name_t *name = NULL;
03257         isc_result_t result;
03258         char buf[sizeof("1234567890")];
03259         isc_uint32_t mbz;
03260         dns_rdata_t rdata;
03261         isc_buffer_t optbuf;
03262         isc_uint16_t optcode, optlen;
03263         unsigned char *optdata;
03264 
03265         REQUIRE(DNS_MESSAGE_VALID(msg));
03266         REQUIRE(target != NULL);
03267         REQUIRE(VALID_PSEUDOSECTION(section));
03268 
03269         switch (section) {
03270         case DNS_PSEUDOSECTION_OPT:
03271                 ps = dns_message_getopt(msg);
03272                 if (ps == NULL)
03273                         return (ISC_R_SUCCESS);
03274                 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
03275                         ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
03276                 ADD_STRING(target, "; EDNS: version: ");
03277                 snprintf(buf, sizeof(buf), "%u",
03278                          (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
03279                 ADD_STRING(target, buf);
03280                 ADD_STRING(target, ", flags:");
03281                 if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
03282                         ADD_STRING(target, " do");
03283                 mbz = ps->ttl & 0xffff;
03284                 mbz &= ~DNS_MESSAGEEXTFLAG_DO;          /* Known Flags. */
03285                 if (mbz != 0) {
03286                         ADD_STRING(target, "; MBZ: ");
03287                         snprintf(buf, sizeof(buf), "%.4x ", mbz);
03288                         ADD_STRING(target, buf);
03289                         ADD_STRING(target, ", udp: ");
03290                 } else
03291                         ADD_STRING(target, "; udp: ");
03292                 snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
03293                 ADD_STRING(target, buf);
03294 
03295                 result = dns_rdataset_first(ps);
03296                 if (result != ISC_R_SUCCESS)
03297                         return (ISC_R_SUCCESS);
03298 
03299                 /* Print EDNS info, if any */
03300                 dns_rdata_init(&rdata);
03301                 dns_rdataset_current(ps, &rdata);
03302 
03303                 isc_buffer_init(&optbuf, rdata.data, rdata.length);
03304                 isc_buffer_add(&optbuf, rdata.length);
03305                 while (isc_buffer_remaininglength(&optbuf) != 0) {
03306                         INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
03307                         optcode = isc_buffer_getuint16(&optbuf);
03308                         optlen = isc_buffer_getuint16(&optbuf);
03309                         INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
03310 
03311                         if (optcode == DNS_OPT_NSID) {
03312                                 ADD_STRING(target, "; NSID");
03313                         } else if (optcode == DNS_OPT_SIT) {
03314                                 ADD_STRING(target, "; SIT");
03315                         } else if (optcode == DNS_OPT_CLIENT_SUBNET) {
03316                                 ADD_STRING(target, "; CLIENT-SUBNET: ");
03317                                 render_ecs(&optbuf, target);
03318                                 ADD_STRING(target, "\n");
03319                                 continue;
03320                         } else if (optcode == DNS_OPT_EXPIRE) {
03321                                 if (optlen == 4) {
03322                                         isc_uint32_t secs;
03323                                         secs = isc_buffer_getuint32(&optbuf);
03324                                         ADD_STRING(target, "; EXPIRE: ");
03325                                         snprintf(buf, sizeof(buf), "%u", secs);
03326                                         ADD_STRING(target, buf);
03327                                         ADD_STRING(target, " (");
03328                                         dns_ttl_totext(secs, ISC_TRUE, target);
03329                                         ADD_STRING(target, ")\n");
03330                                         continue;
03331                                 }
03332                                 ADD_STRING(target, "; EXPIRE");
03333                         } else {
03334                                 ADD_STRING(target, "; OPT=");
03335                                 snprintf(buf, sizeof(buf), "%u", optcode);
03336                                 ADD_STRING(target, buf);
03337                         }
03338 
03339                         if (optlen != 0) {
03340                                 int i;
03341                                 ADD_STRING(target, ": ");
03342 
03343                                 optdata = isc_buffer_current(&optbuf);
03344                                 for (i = 0; i < optlen; i++) {
03345                                         const char *sep;
03346                                         switch (optcode) {
03347                                         case DNS_OPT_SIT:
03348                                                 sep = "";
03349                                                 break;
03350                                         default:
03351                                                 sep = " ";
03352                                                 break;
03353                                         }
03354                                         snprintf(buf, sizeof(buf), "%02x%s",
03355                                                  optdata[i], sep);
03356                                         ADD_STRING(target, buf);
03357                                 }
03358 
03359                                 isc_buffer_forward(&optbuf, optlen);
03360 
03361                                 if (optcode == DNS_OPT_SIT) {
03362                                         if (msg->sitok)
03363                                                 ADD_STRING(target, " (good)");
03364                                         if (msg->sitbad)
03365                                                 ADD_STRING(target, " (bad)");
03366                                         ADD_STRING(target, "\n");
03367                                         continue;
03368                                 }
03369 
03370                                 /*
03371                                  * For non-SIT options, add a printable
03372                                  * version
03373                                  */
03374                                 ADD_STRING(target, "(\"");
03375                                 if (isc_buffer_availablelength(target) < optlen)
03376                                         return (ISC_R_NOSPACE);
03377                                 for (i = 0; i < optlen; i++) {
03378                                         if (isprint(optdata[i]))
03379                                                 isc_buffer_putmem(target,
03380                                                                   &optdata[i],
03381                                                                   1);
03382                                         else
03383                                                 isc_buffer_putstr(target, ".");
03384                                 }
03385                                 ADD_STRING(target, "\")");
03386                         }
03387                         ADD_STRING(target, "\n");
03388                 }
03389                 return (ISC_R_SUCCESS);
03390         case DNS_PSEUDOSECTION_TSIG:
03391                 ps = dns_message_gettsig(msg, &name);
03392                 if (ps == NULL)
03393                         return (ISC_R_SUCCESS);
03394                 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
03395                         ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
03396                 result = dns_master_rdatasettotext(name, ps, style, target);
03397                 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
03398                     (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
03399                         ADD_STRING(target, "\n");
03400                 return (result);
03401         case DNS_PSEUDOSECTION_SIG0:
03402                 ps = dns_message_getsig0(msg, &name);
03403                 if (ps == NULL)
03404                         return (ISC_R_SUCCESS);
03405                 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
03406                         ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
03407                 result = dns_master_rdatasettotext(name, ps, style, target);
03408                 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
03409                     (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
03410                         ADD_STRING(target, "\n");
03411                 return (result);
03412         }
03413         return (ISC_R_UNEXPECTED);
03414 }
03415 
03416 isc_result_t
03417 dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
03418                    dns_messagetextflag_t flags, isc_buffer_t *target) {
03419         char buf[sizeof("1234567890")];
03420         isc_result_t result;
03421 
03422         REQUIRE(DNS_MESSAGE_VALID(msg));
03423         REQUIRE(target != NULL);
03424 
03425         if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
03426                 ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
03427                 ADD_STRING(target, opcodetext[msg->opcode]);
03428                 ADD_STRING(target, ", status: ");
03429                 if (msg->rcode < (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
03430                         ADD_STRING(target, rcodetext[msg->rcode]);
03431                 } else {
03432                         snprintf(buf, sizeof(buf), "%4u", msg->rcode);
03433                         ADD_STRING(target, buf);
03434                 }
03435                 ADD_STRING(target, ", id: ");
03436                 snprintf(buf, sizeof(buf), "%6u", msg->id);
03437                 ADD_STRING(target, buf);
03438                 ADD_STRING(target, "\n;; flags:");
03439                 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
03440                         ADD_STRING(target, " qr");
03441                 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
03442                         ADD_STRING(target, " aa");
03443                 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
03444                         ADD_STRING(target, " tc");
03445                 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
03446                         ADD_STRING(target, " rd");
03447                 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
03448                         ADD_STRING(target, " ra");
03449                 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
03450                         ADD_STRING(target, " ad");
03451                 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
03452                         ADD_STRING(target, " cd");
03453                 /*
03454                  * The final unnamed flag must be zero.
03455                  */
03456                 if ((msg->flags & 0x0040U) != 0)
03457                         ADD_STRING(target, "; MBZ: 0x4");
03458                 if (msg->opcode != dns_opcode_update) {
03459                         ADD_STRING(target, "; QUESTION: ");
03460                 } else {
03461                         ADD_STRING(target, "; ZONE: ");
03462                 }
03463                 snprintf(buf, sizeof(buf), "%1u",
03464                          msg->counts[DNS_SECTION_QUESTION]);
03465                 ADD_STRING(target, buf);
03466                 if (msg->opcode != dns_opcode_update) {
03467                         ADD_STRING(target, ", ANSWER: ");
03468                 } else {
03469                         ADD_STRING(target, ", PREREQ: ");
03470                 }
03471                 snprintf(buf, sizeof(buf), "%1u",
03472                          msg->counts[DNS_SECTION_ANSWER]);
03473                 ADD_STRING(target, buf);
03474                 if (msg->opcode != dns_opcode_update) {
03475                         ADD_STRING(target, ", AUTHORITY: ");
03476                 } else {
03477                         ADD_STRING(target, ", UPDATE: ");
03478                 }
03479                 snprintf(buf, sizeof(buf), "%1u",
03480                         msg->counts[DNS_SECTION_AUTHORITY]);
03481                 ADD_STRING(target, buf);
03482                 ADD_STRING(target, ", ADDITIONAL: ");
03483                 snprintf(buf, sizeof(buf), "%1u",
03484                         msg->counts[DNS_SECTION_ADDITIONAL]);
03485                 ADD_STRING(target, buf);
03486                 ADD_STRING(target, "\n");
03487         }
03488         result = dns_message_pseudosectiontotext(msg,
03489                                                  DNS_PSEUDOSECTION_OPT,
03490                                                  style, flags, target);
03491         if (result != ISC_R_SUCCESS)
03492                 return (result);
03493 
03494         result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION,
03495                                            style, flags, target);
03496         if (result != ISC_R_SUCCESS)
03497                 return (result);
03498         result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER,
03499                                            style, flags, target);
03500         if (result != ISC_R_SUCCESS)
03501                 return (result);
03502         result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY,
03503                                            style, flags, target);
03504         if (result != ISC_R_SUCCESS)
03505                 return (result);
03506         result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL,
03507                                            style, flags, target);
03508         if (result != ISC_R_SUCCESS)
03509                 return (result);
03510 
03511         result = dns_message_pseudosectiontotext(msg,
03512                                                  DNS_PSEUDOSECTION_TSIG,
03513                                                  style, flags, target);
03514         if (result != ISC_R_SUCCESS)
03515                 return (result);
03516 
03517         result = dns_message_pseudosectiontotext(msg,
03518                                                  DNS_PSEUDOSECTION_SIG0,
03519                                                  style, flags, target);
03520         if (result != ISC_R_SUCCESS)
03521                 return (result);
03522 
03523         return (ISC_R_SUCCESS);
03524 }
03525 
03526 isc_region_t *
03527 dns_message_getrawmessage(dns_message_t *msg) {
03528         REQUIRE(DNS_MESSAGE_VALID(msg));
03529         return (&msg->saved);
03530 }
03531 
03532 void
03533 dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
03534                          const void *order_arg)
03535 {
03536         REQUIRE(DNS_MESSAGE_VALID(msg));
03537         msg->order = order;
03538         msg->order_arg = order_arg;
03539 }
03540 
03541 void
03542 dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
03543         REQUIRE(DNS_MESSAGE_VALID(msg));
03544         msg->timeadjust = timeadjust;
03545 }
03546 
03547 int
03548 dns_message_gettimeadjust(dns_message_t *msg) {
03549         REQUIRE(DNS_MESSAGE_VALID(msg));
03550         return (msg->timeadjust);
03551 }
03552 
03553 isc_result_t
03554 dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
03555 
03556         REQUIRE(opcode < 16);
03557 
03558         if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode]))
03559                 return (ISC_R_NOSPACE);
03560         isc_buffer_putstr(target, opcodetext[opcode]);
03561         return (ISC_R_SUCCESS);
03562 }
03563 
03564 void
03565 dns_message_logpacket(dns_message_t *message, const char *description,
03566                       isc_logcategory_t *category, isc_logmodule_t *module,
03567                       int level, isc_mem_t *mctx)
03568 {
03569         logfmtpacket(message, description, NULL, category, module,
03570                      &dns_master_style_debug, level, mctx);
03571 }
03572 
03573 void
03574 dns_message_logpacket2(dns_message_t *message,
03575                        const char *description, isc_sockaddr_t *address,
03576                        isc_logcategory_t *category, isc_logmodule_t *module,
03577                        int level, isc_mem_t *mctx)
03578 {
03579         REQUIRE(address != NULL);
03580 
03581         logfmtpacket(message, description, address, category, module,
03582                      &dns_master_style_debug, level, mctx);
03583 }
03584 
03585 void
03586 dns_message_logfmtpacket(dns_message_t *message, const char *description,
03587                          isc_logcategory_t *category, isc_logmodule_t *module,
03588                          const dns_master_style_t *style, int level,
03589                          isc_mem_t *mctx)
03590 {
03591         logfmtpacket(message, description, NULL, category, module, style,
03592                      level, mctx);
03593 }
03594 
03595 void
03596 dns_message_logfmtpacket2(dns_message_t *message,
03597                           const char *description, isc_sockaddr_t *address,
03598                           isc_logcategory_t *category, isc_logmodule_t *module,
03599                           const dns_master_style_t *style, int level,
03600                           isc_mem_t *mctx)
03601 {
03602         REQUIRE(address != NULL);
03603 
03604         logfmtpacket(message, description, address, category, module, style,
03605                      level, mctx);
03606 }
03607 
03608 static void
03609 logfmtpacket(dns_message_t *message, const char *description,
03610              isc_sockaddr_t *address, isc_logcategory_t *category,
03611              isc_logmodule_t *module, const dns_master_style_t *style,
03612              int level, isc_mem_t *mctx)
03613 {
03614         char addrbuf[ISC_SOCKADDR_FORMATSIZE] = { 0 };
03615         const char *newline = "\n";
03616         const char *space = " ";
03617         isc_buffer_t buffer;
03618         char *buf = NULL;
03619         int len = 1024;
03620         isc_result_t result;
03621 
03622         if (! isc_log_wouldlog(dns_lctx, level))
03623                 return;
03624 
03625         /*
03626          * Note that these are multiline debug messages.  We want a newline
03627          * to appear in the log after each message.
03628          */
03629 
03630         if (address != NULL)
03631                 isc_sockaddr_format(address, addrbuf, sizeof(addrbuf));
03632         else
03633                 newline = space = "";
03634 
03635         do {
03636                 buf = isc_mem_get(mctx, len);
03637                 if (buf == NULL)
03638                         break;
03639                 isc_buffer_init(&buffer, buf, len);
03640                 result = dns_message_totext(message, style, 0, &buffer);
03641                 if (result == ISC_R_NOSPACE) {
03642                         isc_mem_put(mctx, buf, len);
03643                         len += 1024;
03644                 } else if (result == ISC_R_SUCCESS)
03645                         isc_log_write(dns_lctx, category, module, level,
03646                                       "%s%s%s%s%.*s", description, space,
03647                                       addrbuf, newline,
03648                                       (int)isc_buffer_usedlength(&buffer),
03649                                       buf);
03650         } while (result == ISC_R_NOSPACE);
03651 
03652         if (buf != NULL)
03653                 isc_mem_put(mctx, buf, len);
03654 }
03655 
03656 isc_result_t
03657 dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp,
03658                      unsigned int version, isc_uint16_t udpsize,
03659                      unsigned int flags, dns_ednsopt_t *ednsopts, size_t count)
03660 {
03661         dns_rdataset_t *rdataset = NULL;
03662         dns_rdatalist_t *rdatalist = NULL;
03663         dns_rdata_t *rdata = NULL;
03664         isc_result_t result;
03665         unsigned int len = 0, i;
03666 
03667         REQUIRE(DNS_MESSAGE_VALID(message));
03668         REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
03669 
03670         result = dns_message_gettemprdatalist(message, &rdatalist);
03671         if (result != ISC_R_SUCCESS)
03672                 return (result);
03673         result = dns_message_gettemprdata(message, &rdata);
03674         if (result != ISC_R_SUCCESS)
03675                 goto cleanup;
03676         result = dns_message_gettemprdataset(message, &rdataset);
03677         if (result != ISC_R_SUCCESS)
03678                 goto cleanup;
03679         dns_rdataset_init(rdataset);
03680 
03681         rdatalist->type = dns_rdatatype_opt;
03682 
03683         /*
03684          * Set Maximum UDP buffer size.
03685          */
03686         rdatalist->rdclass = udpsize;
03687 
03688         /*
03689          * Set EXTENDED-RCODE and Z to 0.
03690          */
03691         rdatalist->ttl = (version << 16);
03692         rdatalist->ttl |= (flags & 0xffff);
03693 
03694         /*
03695          * Set EDNS options if applicable
03696          */
03697         if (count != 0U) {
03698                 isc_buffer_t *buf = NULL;
03699                 for (i = 0; i < count; i++)
03700                         len += ednsopts[i].length + 4;
03701 
03702                 if (len > 0xffffU) {
03703                         result = ISC_R_NOSPACE;
03704                         goto cleanup;
03705                 }
03706 
03707                 result = isc_buffer_allocate(message->mctx, &buf, len);
03708                 if (result != ISC_R_SUCCESS)
03709                         goto cleanup;
03710 
03711                 for (i = 0; i < count; i++)  {
03712                         isc_buffer_putuint16(buf, ednsopts[i].code);
03713                         isc_buffer_putuint16(buf, ednsopts[i].length);
03714                         isc_buffer_putmem(buf, ednsopts[i].value,
03715                                           ednsopts[i].length);
03716                 }
03717                 rdata->data = isc_buffer_base(buf);
03718                 rdata->length = len;
03719                 dns_message_takebuffer(message, &buf);
03720         } else {
03721                 rdata->data = NULL;
03722                 rdata->length = 0;
03723         }
03724 
03725         rdata->rdclass = rdatalist->rdclass;
03726         rdata->type = rdatalist->type;
03727         rdata->flags = 0;
03728 
03729         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
03730         result = dns_rdatalist_tordataset(rdatalist, rdataset);
03731         RUNTIME_CHECK(result == ISC_R_SUCCESS);
03732 
03733         *rdatasetp = rdataset;
03734         return (ISC_R_SUCCESS);
03735 
03736  cleanup:
03737         if (rdata != NULL)
03738                 dns_message_puttemprdata(message, &rdata);
03739         if (rdataset != NULL)
03740                 dns_message_puttemprdataset(message, &rdataset);
03741         if (rdatalist != NULL)
03742                 dns_message_puttemprdatalist(message, &rdatalist);
03743         return (result);
03744 }

Generated on Tue Apr 28 17:40:58 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha