/* * Copyright (C) 1999 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void dump_packet(isc_mem_t *mctx, unsigned char *buf, u_int len); dns_result_t resolve_packet(dns_db_t *db, isc_buffer_t *source, isc_buffer_t *target); dns_result_t printmessage(dns_message_t *message); #define CHECKRESULT(result, msg) \ { \ if ((result) != DNS_R_SUCCESS) { \ printf("%s: %s\n", (msg), dns_result_totext(result)); \ return; \ } \ } void dump_packet(isc_mem_t *mctx, unsigned char *buf, u_int len) { dns_message_t *message; dns_result_t result; isc_buffer_t source; unsigned int i; for (i = 0 ; i < len ; /* */ ) { fprintf(stdout, "%02x", buf[i]); if ((++i % 20) == 0) fputs("\n", stdout); else if (i == len) fputs("\n", stdout); else fputs(" ", stdout); } isc_buffer_init(&source, buf, len, ISC_BUFFERTYPE_BINARY); isc_buffer_add(&source, len); result = dns_message_create(mctx, DNS_MESSAGE_INTENT_PARSE, &message); CHECKRESULT(result, "dns_message_create failed"); result = dns_message_parse(message, &source); CHECKRESULT(result, "dns_message_parse failed"); result = printmessage(message); CHECKRESULT(result, "printmessage() failed"); dns_message_destroy(&message); } static isc_uint16_t getshort(isc_buffer_t *buffer) { isc_region_t r; isc_buffer_remaining(buffer, &r); if (r.length < 2) { printf("not enough input\n"); exit(5); } return (isc_buffer_getuint16(buffer)); } dns_result_t resolve_packet(dns_db_t *db, dns_message_t *query, dns_message_t **reply, isc_buffer_t *target) { dns_decompress_t dctx; dns_compress_t cctx; dns_result_t result; unsigned int count; dns_name_t name; isc_uint16_t qtype; isc_uint16_t qclass; unsigned char t[256]; isc_buffer_t tbuf; isc_uint16_t status; dns_dbnode_t *node; dns_rdataset_t rdataset; isc_boolean_t authoritative = ISC_TRUE; isc_region_t r; count = 0; status = 0; message.id = getshort(source); message.flags = getshort(source); message.qcount = getshort(source); message.ancount = getshort(source); message.aucount = getshort(source); message.adcount = getshort(source); INSIST(message.qcount == 1); INSIST(message.ancount == 0); INSIST(message.aucount == 0); INSIST(message.adcount == 0); dns_decompress_init(&dctx, -1, ISC_FALSE); result = dns_compress_init(&cctx, -1, db->mctx); if (result != DNS_R_SUCCESS) return (result); /* * Expand the name requested into buffer (tbuf) */ isc_buffer_init(&tbuf, t, sizeof(t), ISC_BUFFERTYPE_BINARY); dns_name_init(&name, NULL); isc_buffer_remaining(source, &r); isc_buffer_setactive(source, r.length); if (!dns_decompress_strict(&dctx)) dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL); else dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14); result = dns_name_fromwire(&name, source, &dctx, ISC_FALSE, &tbuf); qtype = getshort(source); qclass = getshort(source); /* * Look it up in the database. XXX Uses many hard coded bits. */ if (!dns_name_issubdomain(&name, dns_db_origin(db))) { status = 3; /* NXDOMAIN */ authoritative = ISC_FALSE; goto out; } node = NULL; result = dns_db_findnode(db, &name, ISC_FALSE, &node); if (result == DNS_R_NOTFOUND) { status = 3; /* NXDOMAIN */ goto out; } if (result != DNS_R_SUCCESS) { status = 2; /* SERVFAIL */ goto out; } dns_rdataset_init(&rdataset); result = dns_db_findrdataset(db, node, NULL, qtype, 0, &rdataset); dns_db_detachnode(db, &node); if (result == DNS_R_NOTFOUND) { status = 3; /* NXDOMAIN */ goto out; } if (result != DNS_R_SUCCESS) { status = 2; /* SERVFAIL */ goto out; } out: /* * XXX This should really use the buffer functions correctly, but... */ /* * Write the header. */ isc_buffer_putuint16(target, message.id); message.flags |= DNS_FLAG_QR; if (authoritative) message.flags |= DNS_FLAG_AA; message.flags &= ~(DNS_FLAG_TC | DNS_FLAG_RA); message.flags &= ~(DNS_RCODE_MASK); message.flags |= status; isc_buffer_putuint16(target, message.flags); isc_buffer_putuint16(target, message.qcount); isc_buffer_putuint16(target, message.ancount); /* XXX fix up later */ isc_buffer_putuint16(target, message.aucount); isc_buffer_putuint16(target, message.adcount); /* * Write the question. Note that we reconstruct it... */ dns_name_towire(&name, &cctx, target); isc_buffer_putuint16(target, qtype); isc_buffer_putuint16(target, qclass); /* * Now, scribble out the answer. If this works we will update the * answer count. If it fails, we will update the status instead. */ if (status == 0) { unsigned int oldused; count = 0; result = dns_rdataset_towire(&rdataset, &name, &cctx, target, &count); if (result != DNS_R_SUCCESS) { /* Should just return fail? */ oldused = target->used; target->used = 2; /* Hack! XXX */ message.flags &= ~(DNS_FLAG_AA|DNS_RCODE_MASK); message.flags |= 2; /* SERVFAIL */ isc_buffer_putuint16(target, message.flags); target->used = oldused; } else { oldused = target->used; target->used = 6; /* Another hack! XXX */ isc_buffer_putuint16(target, count); target->used = oldused; } } dns_compress_invalidate(&cctx); return (DNS_R_SUCCESS); }