diff --git a/Makefile.in b/Makefile.in index bb16430..e19a9b6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -50,7 +50,7 @@ CC=@CC@ CPPFLAGS=-I. @CPPFLAGS@ CFLAGS=@CFLAGS@ LDFLAGS=@LDFLAGS@ -LIBS=@LIBS@ +LIBS=-lresolv @LIBS@ LIBOBJS=@LIBOBJS@ # filter out ctime_r from compat obj. LIBOBJ_WITHOUT_CTIME=@LIBOBJ_WITHOUT_CTIME@ diff --git a/README.tdns b/README.tdns new file mode 100644 index 0000000..7391fce --- /dev/null +++ b/README.tdns @@ -0,0 +1,54 @@ + +T-DNS: DNS over TCP and TLS + +Zi Hu, Liang Zhu, John Heidemann, Duane Wessels, Allison Mankin +USC/ISI and Verisign + + +ABOUT T-DNS + +DNS is the canonical example of a connectionless, single packet, +request/response protocol, with UDP as its dominant transport. Yet DNS +today is challenged by eavesdropping that compromises privacy, source +address spoofing that results in denial-of-service (DoS) attacks on +the server and third parties, injection attacks that exploit +fragmentation, and size limitations that constrain policy and +operational choices. We propose t-DNS to address these problems: it +combines TCP to smoothly support large payloads and mitigate spoofing +and amplification for DoS. T-DNS uses transport-layer security (TLS) +to provide privacy from users to their DNS resolvers and optionally to +authoritative servers. + + +OUR CHANGES + +1. we add TLS negotiation to current unbound implementation, +so we don't need a seperate port for DNS-over-TLS. +Full explanation of TLS negotiation over DNS is decribed here: +http://tools.ietf.org/html/draft-hzhwm-start-tls-for-dns-00 + +2. we make unbound to support concurrent processing of queries +from the same TCP connection. Although this hack still has some bugs: +e.g. some responses are not sent back to client, or are delayed for a long time. + + +HOW TO BUILD and RUN + +Our hacked unbound is built and started just like any other +unbound. However, here are our notes to help. + +1. compile: + +make sure you have the source code ldns-1.6.16 ready before compiling unbound. +add --with-ldns=ldns_dir option when you run ./configure, something like: configure --with-ldns=ldns_dir + + +2. run unbound in command line: + +a) in the unbound directory: chmod a+w .libs +b) you need you have a config file ready. +if you have unbound installed on your machine already, just use the configure file here /etc/unbound/unbound.conf. +start unbound by: +sudo ./unbound -d -c /etc/unbound/unbound.conf -v + +By the way, we only test our hacked unbound on Fedora19, so it might not work on other linux versions. diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c index 368faae..4d3cb03 100644 --- a/services/listen_dnsport.c +++ b/services/listen_dnsport.c @@ -784,12 +784,13 @@ listen_create(struct comm_base* base, struct listen_port* ports, if(ports->ftype == listen_type_udp) cp = comm_point_create_udp(base, ports->fd, front->udp_buff, cb, cb_arg); - else if(ports->ftype == listen_type_tcp) + else if(ports->ftype == listen_type_tcp){ cp = comm_point_create_tcp(base, ports->fd, - tcp_accept_count, bufsize, cb, cb_arg); + tcp_accept_count, bufsize, cb, cb_arg, sslctx); + } else if(ports->ftype == listen_type_ssl) { cp = comm_point_create_tcp(base, ports->fd, - tcp_accept_count, bufsize, cb, cb_arg); + tcp_accept_count, bufsize, cb, cb_arg, sslctx); cp->ssl = sslctx; } else if(ports->ftype == listen_type_udpancil) cp = comm_point_create_udp_ancil(base, ports->fd, diff --git a/util/netevent.c b/util/netevent.c index 193fa87..930d885 100644 --- a/util/netevent.c +++ b/util/netevent.c @@ -40,6 +40,8 @@ */ #include "config.h" #include +#include +#include #include "util/netevent.h" #include "util/log.h" #include "util/net_help.h" @@ -104,6 +106,9 @@ # endif #endif /* USE_MINI_EVENT */ +#define DNS_MESSAGEEXTFLAG_TLS 0x4000U +#define NS_T_TXT 16 +#define NS_CLASS_CH 3 /** * The internal event structure for keeping libevent info for the event. * Possibly other structures (list, tree) this is part of. @@ -158,8 +163,148 @@ static struct comm_point* comm_point_create_tcp_handler( struct comm_base *base, struct comm_point* parent, size_t bufsize, comm_point_callback_t* callback, void* callback_arg); +static int +comm_point_tcp_handle_write(int fd, struct comm_point* c); + /* -------- End of local definitions -------- */ + +/* + * print dns message ---zihu 2014-01-15 + */ +void print_section(ns_msg handle, int count, ns_sect sec_t, const char* sec_name) +{ + ns_rr rr; + char buf[1024]; + printf("%s:\n", sec_name); + int rrnum=0; + for (rrnum=0; rrnumssl); #endif } + else + { + //see if client ask for upgrade to TLS + //receive the first query + //check TO bit + //if TO bit set, upgrade to TLS + //else do normal recursive process and send response back. + } /* grab the tcp handler buffers */ c->tcp_free = c_hdl->tcp_free; @@ -866,6 +1019,9 @@ reclaim_tcp_handler(struct comm_point* c) c->ssl = NULL; #endif } + + /*reset the firstquery flag ---zihu 2014-01-15*/ + c->firstquery = true; comm_point_close(c); if(c->tcp_parent) { c->tcp_free = c->tcp_parent->tcp_free; @@ -900,12 +1056,14 @@ tcp_callback_reader(struct comm_point* c) if(c->tcp_do_toggle_rw) c->tcp_is_reading = 0; c->tcp_byte_count = 0; - if(c->type == comm_tcp) - comm_point_stop_listening(c); + //if(c->type == comm_tcp) + // comm_point_stop_listening(c); fptr_ok(fptr_whitelist_comm_point(c->callback)); if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo) ) { comm_point_start_listening(c, -1, TCP_QUERY_TIMEOUT); } + + c->tcp_is_reading = 1; } /** continue ssl handshake */ @@ -1154,6 +1312,8 @@ ssl_handle_it(struct comm_point* c) return ssl_handle_write(c); } + + /** Handle tcp reading callback. * @param fd: file descriptor of socket. * @param c: comm point to read from into buffer. @@ -1167,6 +1327,7 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok) log_assert(c->type == comm_tcp || c->type == comm_local); if(c->ssl) return ssl_handle_it(c); + if(!c->tcp_is_reading) return 0; @@ -1247,6 +1408,52 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok) c->repinfo.addrlen); return 0; } + + //first packet, we need to see if the client ask to upgrade to TLS + if(c->firstquery) + { + ldns_buffer* buffer = ldns_buffer_new(r); + ldns_buffer_copy(buffer, c->buffer); + //ldns_buffer_flip(buffer); + if(is_tls_set((char*)ldns_buffer_begin(buffer), r)) + { + print_dns_msg((char*)ldns_buffer_begin(buffer), r); + //send a reply + if(c->tcp_do_toggle_rw) + c->tcp_is_reading = 0; + c->tcp_byte_count = 0; + + //format a reply to the dummy query; + format_reply_to_dummy(buffer); + print_dns_msg((char*)ldns_buffer_begin(buffer), r); + + ldns_buffer_clear(c->buffer); + ldns_buffer_copy(c->buffer, buffer); + comm_point_tcp_handle_write(c->fd, c); + + //upgrade to SSL; + c->ssl = incoming_ssl_fd(c->upgrade_ssl, c->fd); + if(!c->ssl) + { + printf("incoming_ssl_fd error\n"); + return 0; + } + c->ssl_shake_state = comm_ssl_shake_read; +#ifdef USE_WINSOCK + comm_point_tcp_win_bio_cb(c, c->ssl); +#endif + c->firstquery=false; + ldns_buffer_free(buffer); + + return 1; + } + else + { + c->firstquery=false; + } + } + + printf("no tls upgrade, contiinue TCP\n"); ldns_buffer_skip(c->buffer, r); if(ldns_buffer_remaining(c->buffer) <= 0) { tcp_callback_reader(c); @@ -1597,6 +1804,8 @@ comm_point_create_tcp_handler(struct comm_base *base, free(c); return NULL; } + + c->firstquery = true; c->tcp_is_reading = 0; c->tcp_byte_count = 0; c->tcp_parent = parent; @@ -1630,7 +1839,7 @@ comm_point_create_tcp_handler(struct comm_base *base, struct comm_point* comm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize, - comm_point_callback_t* callback, void* callback_arg) + comm_point_callback_t* callback, void* callback_arg, void* sslctx) { struct comm_point* c = (struct comm_point*)calloc(1, sizeof(struct comm_point)); @@ -1687,6 +1896,7 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize, comm_point_delete(c); return NULL; } + (c->tcp_handlers[i])->upgrade_ssl = sslctx; } return c; @@ -1904,7 +2114,9 @@ comm_point_send_reply(struct comm_reply *repinfo) comm_point_send_udp_msg(repinfo->c, repinfo->c->buffer, (struct sockaddr*)&repinfo->addr, repinfo->addrlen); } else { - comm_point_start_listening(repinfo->c, -1, TCP_QUERY_TIMEOUT); + //comm_point_start_listening(repinfo->c, -1, TCP_QUERY_TIMEOUT); + (repinfo->c)->tcp_is_reading = 0; + comm_point_tcp_handle_write((repinfo->c)->fd, repinfo->c); } } diff --git a/util/netevent.h b/util/netevent.h index 86fa285..95a88dc 100644 --- a/util/netevent.h +++ b/util/netevent.h @@ -151,6 +151,9 @@ struct comm_point { /** buffer pointer. Either to perthread, or own buffer or NULL */ ldns_buffer* buffer; + /** is this the first query received*/ + bool firstquery; + /* -------- TCP Handler -------- */ /** Read/Write state for TCP */ int tcp_is_reading; @@ -174,6 +177,10 @@ struct comm_point { /* -------- SSL TCP DNS ------- */ /** the SSL object with rw bio (owned) or for commaccept ctx ref */ void* ssl; + + /** in case client want to upgrade to TLS*/ + void* upgrade_ssl; + /** handshake state for init and renegotiate */ enum { /** no handshake, it has been done */ @@ -390,7 +397,7 @@ struct comm_point* comm_point_create_udp_ancil(struct comm_base* base, */ struct comm_point* comm_point_create_tcp(struct comm_base* base, int fd, int num, size_t bufsize, - comm_point_callback_t* callback, void* callback_arg); + comm_point_callback_t* callback, void* callback_arg, void* sslctx); /** * Create an outgoing TCP commpoint. No file descriptor is opened, left at -1.