[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r10317: Well, that was easier than I thought it would be. Tor is now (in tor/trunk: . doc src/or)



Author: nickm
Date: 2007-05-24 16:31:30 -0400 (Thu, 24 May 2007)
New Revision: 10317

Added:
   tor/trunk/src/or/dnsserv.c
Modified:
   tor/trunk/
   tor/trunk/ChangeLog
   tor/trunk/doc/TODO
   tor/trunk/src/or/Makefile.am
   tor/trunk/src/or/config.c
   tor/trunk/src/or/connection.c
   tor/trunk/src/or/connection_edge.c
   tor/trunk/src/or/or.h
Log:
 r12942@catbus:  nickm | 2007-05-24 16:31:22 -0400
 Well, that was easier than I thought it would be.  Tor is now a DNS proxy as well as a socks proxy.  Probably some bugs remain, but since it A) has managed to resolve one address for me successfully, and B) will not affect anybody who leaves DNSPort unset, it feel like a good time to commit.



Property changes on: tor/trunk
___________________________________________________________________
 svk:merge ticket from /tor/trunk [r12942] on 8246c3cf-6607-4228-993b-4d95d33730f1

Modified: tor/trunk/ChangeLog
===================================================================
--- tor/trunk/ChangeLog	2007-05-24 20:31:27 UTC (rev 10316)
+++ tor/trunk/ChangeLog	2007-05-24 20:31:30 UTC (rev 10317)
@@ -22,6 +22,12 @@
       logging information that would be very useful to an attacker.
     - Start work implementing proposal 103: Add a standalone tool to
       generate key certificates.
+    - Initial implementation of a client-side DNS proxy feature to replace
+      the need for dns-proxy-tor:  Just set "DNSPort 9999", and Tor will
+      now listen for DNS requests on port 9999, use the Tor network to
+      resolve them anonymously, and send the reply back like a regular DNS
+      server.  The code is still buggy, undocumented, and only implements
+      a subset of DNS.
 
   o Security fixes:
     - Directory authorities now call routers stable if they have an

Modified: tor/trunk/doc/TODO
===================================================================
--- tor/trunk/doc/TODO	2007-05-24 20:31:27 UTC (rev 10316)
+++ tor/trunk/doc/TODO	2007-05-24 20:31:30 UTC (rev 10317)
@@ -195,7 +195,13 @@
   - Features:
     - Traffic priorities (by Jun 1)
       - Ability to prioritize own traffic over relayed traffic.
-    - Implement a DNS proxy
+    o Implement a DNS proxy
+      o Make a listener type.
+      o Hook into connection_edge logic.
+      o Hook into evdns_server_* logic
+      - Actually send back a useful answer.
+      - Make i
+      - Document.
     - Add a way to request DNS resolves from the controller.
     - A better UI for authority ops.
       - Follow weasel's proposal, crossed with mixminion dir config format

Modified: tor/trunk/src/or/Makefile.am
===================================================================
--- tor/trunk/src/or/Makefile.am	2007-05-24 20:31:27 UTC (rev 10316)
+++ tor/trunk/src/or/Makefile.am	2007-05-24 20:31:30 UTC (rev 10317)
@@ -7,7 +7,7 @@
 tor_SOURCES = buffers.c circuitbuild.c circuitlist.c \
 	circuituse.c command.c config.c \
 	connection.c connection_edge.c connection_or.c control.c \
-	cpuworker.c directory.c dirserv.c dns.c hibernate.c main.c \
+	cpuworker.c directory.c dirserv.c dns.c dnsserv.c hibernate.c main.c \
 	onion.c policies.c relay.c rendcommon.c rendclient.c rendmid.c \
 	rendservice.c rephist.c router.c routerlist.c routerparse.c \
 	eventdns.c \
@@ -23,7 +23,7 @@
 test_SOURCES = buffers.c circuitbuild.c circuitlist.c \
 	circuituse.c command.c config.c \
 	connection.c connection_edge.c connection_or.c control.c \
-	cpuworker.c directory.c dirserv.c dns.c hibernate.c main.c \
+	cpuworker.c directory.c dirserv.c dns.c dnsserv.c hibernate.c main.c \
 	onion.c policies.c relay.c rendcommon.c rendclient.c rendmid.c \
 	rendservice.c rephist.c router.c routerlist.c routerparse.c \
 	eventdns.c \

Modified: tor/trunk/src/or/config.c
===================================================================
--- tor/trunk/src/or/config.c	2007-05-24 20:31:27 UTC (rev 10316)
+++ tor/trunk/src/or/config.c	2007-05-24 20:31:30 UTC (rev 10317)
@@ -155,6 +155,8 @@
   VAR("DirPort",             UINT,     DirPort,              "0"),
   OBSOLETE("DirPostPeriod"),
   VAR("DirServer",           LINELIST, DirServers,           NULL),
+  VAR("DNSPort",             UINT,     DNSPort,              "0"),
+  VAR("DNSListenAddress",    LINELIST, DNSListenAddress,     NULL),
   VAR("DownloadExtraInfo",   BOOL,     DownloadExtraInfo,    "0"),
   VAR("EnforceDistinctSubnets", BOOL,  EnforceDistinctSubnets,"1"),
   VAR("EntryNodes",          STRING,   EntryNodes,           NULL),
@@ -2415,6 +2417,9 @@
   if (options->DirPort == 0 && options->DirListenAddress != NULL)
     REJECT("DirPort must be defined if DirListenAddress is defined.");
 
+  if (options->DNSPort == 0 && options->DNSListenAddress != NULL)
+    REJECT("DirPort must be defined if DirListenAddress is defined.");
+
   if (options->ControlPort == 0 && options->ControlListenAddress != NULL)
     REJECT("ControlPort must be defined if ControlListenAddress is defined.");
 
@@ -2523,6 +2528,9 @@
   if (options->SocksPort < 0 || options->SocksPort > 65535)
     REJECT("SocksPort option out of bounds.");
 
+  if (options->DNSPort < 0 || options->DNSPort > 65535)
+    REJECT("DNSPort option out of bounds.");
+
   if (options->TransPort < 0 || options->TransPort > 65535)
     REJECT("TransPort option out of bounds.");
 

Modified: tor/trunk/src/or/connection.c
===================================================================
--- tor/trunk/src/or/connection.c	2007-05-24 20:31:27 UTC (rev 10316)
+++ tor/trunk/src/or/connection.c	2007-05-24 20:31:30 UTC (rev 10317)
@@ -48,6 +48,7 @@
     case CONN_TYPE_AP_TRANS_LISTENER:
       return "Transparent pf/netfilter listener";
     case CONN_TYPE_AP_NATD_LISTENER: return "Transparent natd listener";
+    case CONN_TYPE_AP_DNS_LISTENER: return "DNS listener";
     case CONN_TYPE_AP: return "Socks";
     case CONN_TYPE_DIR_LISTENER: return "Directory listener";
     case CONN_TYPE_DIR: return "Directory";
@@ -74,6 +75,7 @@
     case CONN_TYPE_AP_LISTENER:
     case CONN_TYPE_AP_TRANS_LISTENER:
     case CONN_TYPE_AP_NATD_LISTENER:
+    case CONN_TYPE_AP_DNS_LISTENER:
     case CONN_TYPE_DIR_LISTENER:
     case CONN_TYPE_CONTROL_LISTENER:
       if (state == LISTENER_STATE_READY)
@@ -240,6 +242,9 @@
       log_warn(LD_BUG, "Error removing write event for %d", conn->s);
     tor_free(conn->write_event);
   }
+  if (conn->dns_server_port) {
+    dnsserv_close_listener(conn);
+  }
 }
 
 /** Deallocate memory used by <b>conn</b>. Deallocate its buffers if
@@ -491,6 +496,12 @@
                  " set end_reason.",
                  conn->marked_for_close_file, conn->marked_for_close);
       }
+      if (edge_conn->dns_server_request) {
+        log_warn(LD_BUG,"Closing stream (marked at %s:%d) without having"
+                 " replied to DNS request.",
+                 conn->marked_for_close_file, conn->marked_for_close);
+        dnsserv_reject_request(edge_conn);
+      }
       control_event_stream_status(edge_conn, STREAM_EVENT_CLOSED,
                                   edge_conn->end_reason);
       circ = circuit_get_by_edge_conn(edge_conn);
@@ -632,6 +643,7 @@
 #ifndef MS_WINDOWS
   int one=1;
 #endif
+  int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER);
 
   memset(&listenaddr,0,sizeof(struct sockaddr_in));
   if (parse_addr_port(LOG_WARN, listenaddress, &address, &addr, &usePort)<0) {
@@ -658,7 +670,9 @@
     return NULL;
   }
 
-  s = tor_open_socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
+  s = tor_open_socket(PF_INET,
+                      is_tcp ? SOCK_STREAM : SOCK_DGRAM,
+                      is_tcp ? IPPROTO_TCP: IPPROTO_UDP);
   if (s < 0) {
     log_warn(LD_NET,"Socket creation failed.");
     goto err;
@@ -683,11 +697,13 @@
     goto err;
   }
 
-  if (listen(s,SOMAXCONN) < 0) {
-    log_warn(LD_NET, "Could not listen on %s:%u: %s", address, usePort,
-             tor_socket_strerror(tor_socket_errno(s)));
-    tor_close_socket(s);
-    goto err;
+  if (is_tcp) {
+    if (listen(s,SOMAXCONN) < 0) {
+      log_warn(LD_NET, "Could not listen on %s:%u: %s", address, usePort,
+               tor_socket_strerror(tor_socket_errno(s)));
+      tor_close_socket(s);
+      goto err;
+    }
   }
 
   set_socket_nonblocking(s);
@@ -708,7 +724,12 @@
             conn_type_to_string(type), usePort);
 
   conn->state = LISTENER_STATE_READY;
-  connection_start_reading(conn);
+  if (is_tcp) {
+    connection_start_reading(conn);
+  } else {
+    tor_assert(type == CONN_TYPE_AP_DNS_LISTENER);
+    dnsserv_configure_listener(conn);
+  }
 
   return conn;
 
@@ -1125,6 +1146,10 @@
                       options->NatdPort, "127.0.0.1", force,
                       replaced_conns, new_conns, 0)<0)
     return -1;
+  if (retry_listeners(CONN_TYPE_AP_DNS_LISTENER, options->DNSListenAddress,
+                      options->DNSPort, "127.0.0.1", force,
+                      replaced_conns, new_conns, 0)<0)
+    return -1;
   if (retry_listeners(CONN_TYPE_CONTROL_LISTENER,
                       options->ControlListenAddress,
                       options->ControlPort, "127.0.0.1", force,
@@ -1535,6 +1560,10 @@
       return connection_handle_listener_read(conn, CONN_TYPE_DIR);
     case CONN_TYPE_CONTROL_LISTENER:
       return connection_handle_listener_read(conn, CONN_TYPE_CONTROL);
+    case CONN_TYPE_AP_DNS_LISTENER:
+      /* This should never happen; eventdns.c handles the reads here. */
+      tor_fragile_assert();
+      return 0;
   }
 
 loop_again:

Modified: tor/trunk/src/or/connection_edge.c
===================================================================
--- tor/trunk/src/or/connection_edge.c	2007-05-24 20:31:27 UTC (rev 10316)
+++ tor/trunk/src/or/connection_edge.c	2007-05-24 20:31:30 UTC (rev 10317)
@@ -30,7 +30,6 @@
 static int connection_ap_handshake_process_socks(edge_connection_t *conn);
 static int connection_ap_process_natd(edge_connection_t *conn);
 static int connection_exit_connect_dir(edge_connection_t *exitconn);
-static int hostname_is_noconnect_address(const char *address);
 
 /** An AP stream has failed/finished. If it hasn't already sent back
  * a socks reply, send one now (based on endreason). Also set
@@ -1920,6 +1919,11 @@
   char buf[384];
   size_t replylen;
 
+  if (conn->dns_server_request) {
+    dnsserv_resolved(conn, answer_type, answer_len, answer, ttl);
+    return;
+  }
+
   if (ttl >= 0) {
     if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) {
       uint32_t a = ntohl(get_uint32(answer));
@@ -2551,7 +2555,7 @@
 
 /** Check if the address is of the form "y.noconnect"
  */
-static int
+int
 hostname_is_noconnect_address(const char *address)
 {
   return ! strcasecmpend(address, ".noconnect");

Added: tor/trunk/src/or/dnsserv.c
===================================================================
--- tor/trunk/src/or/dnsserv.c	                        (rev 0)
+++ tor/trunk/src/or/dnsserv.c	2007-05-24 20:31:30 UTC (rev 10317)
@@ -0,0 +1,177 @@
+/* Copyright 2007 Roger Dingledine, Nick Mathewson */
+/* See LICENSE for licensing information */
+/* $Id$ */
+const char dnsserv_c_id[] =
+  "$Id$";
+
+/**
+ * \file dnservs.c
+ * \brief Implements client-side DNS proxy server code.
+ **/
+
+#include "or.h"
+#include "eventdns.h"
+
+static void
+evdns_server_callback(struct evdns_server_request *req, void *_data)
+{
+  edge_connection_t *conn;
+  int i = 0;
+  struct evdns_server_question *q = NULL;
+  struct sockaddr_storage addr;
+  struct sockaddr *sa;
+  int addrlen;
+  uint32_t ipaddr;
+  int err = DNS_ERR_NONE;
+
+  tor_assert(req);
+  tor_assert(_data == NULL);
+  log_info(LD_APP, "Got a new DNS request!");
+
+  if ((addrlen = evdns_server_request_get_requesting_addr(req,
+                                (struct sockaddr*)&addr, sizeof(addr))) < 0) {
+    log_warn(LD_APP, "Couldn't get requesting address.");
+    evdns_server_request_respond(req, DNS_ERR_SERVERFAILED);
+    return;
+  }
+  sa = (struct sockaddr*) &addr;
+  if (sa->sa_family != AF_INET) {
+    /* XXXX020 Handle IPV6 */
+    log_warn(LD_APP, "Requesting address wasn't ipv4.");
+    evdns_server_request_respond(req, DNS_ERR_SERVERFAILED);
+    return;
+  } else {
+    struct sockaddr_in *sin = (struct sockaddr_in*)&addr;
+    ipaddr = ntohl(sin->sin_addr.s_addr);
+  }
+  if (!socks_policy_permits_address(ipaddr)) {
+    log_warn(LD_APP, "Rejecting DNS request from disallowed IP.");
+    evdns_server_request_respond(req, DNS_ERR_REFUSED);
+    return;
+  }
+  if (req->nquestions == 0) {
+    log_info(LD_APP, "No questions in DNS request; sending back nil reply.");
+    evdns_server_request_respond(req, 0);
+    return;
+  }
+  if (req->nquestions > 1) {
+    log_info(LD_APP, "Got a DNS request with more than one question; I only "
+             "handle one question at a time for now.  Skipping the extras.");
+  }
+  for (i = 0; i < req->nquestions; ++i) {
+    if (req->questions[i]->class != EVDNS_CLASS_INET)
+      continue;
+    switch (req->questions[i]->type) {
+      case EVDNS_TYPE_A:
+      case EVDNS_TYPE_PTR:
+        q = req->questions[i];
+      default:
+        break;
+      }
+  }
+  if (!q) {
+    log_info(LD_APP, "None of the questions we got were ones we're willing "
+             "to support. Sending error.");
+    evdns_server_request_respond(req, DNS_ERR_NOTIMPL);
+    return;
+  }
+  if (q->type == EVDNS_TYPE_A) {
+    if (hostname_is_noconnect_address(q->name)) {
+      err = DNS_ERR_REFUSED;
+    }
+  } else {
+    tor_assert(q->type == EVDNS_TYPE_PTR);
+  }
+  if (err == DNS_ERR_NONE && strlen(q->name) > MAX_SOCKS_ADDR_LEN-1)
+    err = DNS_ERR_FORMAT;
+
+  if (err != DNS_ERR_NONE) {
+    evdns_server_request_respond(req, err);
+    return;
+  }
+
+  /* XXXX020 Handle .onion and .exit. */
+  /* XXXX020 Send a stream event to the controller. */
+
+  conn = TO_EDGE_CONN(connection_new(CONN_TYPE_AP));
+  if (q->type == EVDNS_TYPE_A)
+    conn->socks_request->command = SOCKS_COMMAND_RESOLVE;
+  else
+    conn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR;
+
+  strlcpy(conn->socks_request->address, q->name,
+          sizeof(conn->socks_request->address));
+
+  conn->dns_server_request = req;
+
+  /* XXXX need to set state ?? */
+
+  log_info(LD_APP, "Passing request for %s to rewrite_and_attach.", q->name);
+  connection_ap_handshake_rewrite_and_attach(conn, NULL, NULL);
+  /* Now the connection is marked if it was bad. */
+
+  log_info(LD_APP, "Passed request for %s to rewrite_and_attach.", q->name);
+}
+
+void
+dnsserv_reject_request(edge_connection_t *conn)
+{
+  evdns_server_request_respond(conn->dns_server_request, DNS_ERR_SERVERFAILED);
+  conn->dns_server_request = NULL;
+}
+
+void
+dnsserv_resolved(edge_connection_t *conn,
+                 int answer_type,
+                 size_t answer_len,
+                 const char *answer,
+                 int ttl)
+{
+  struct evdns_server_request *req = conn->dns_server_request;
+  int err = DNS_ERR_NONE;
+  if (!req)
+    return;
+
+  /* XXXX Re-do. */
+  if (ttl < 60)
+    ttl = 60;
+
+  if (answer_type == RESOLVED_TYPE_IPV6) {
+    log_info(LD_APP, "Got an IPv6 answer; that's not implemented.");
+    err = DNS_ERR_NOTIMPL;
+  } else if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4 &&
+             conn->socks_request->command == SOCKS_COMMAND_RESOLVE) {
+    evdns_server_request_add_a_reply(req,
+                                     conn->socks_request->address,
+                                     1, (char*)answer, ttl);
+  } else if (answer_type == RESOLVED_TYPE_HOSTNAME &&
+             conn->socks_request->command == SOCKS_COMMAND_RESOLVE_PTR) {
+    char *ans = tor_strndup(answer, answer_len);
+    evdns_server_request_add_ptr_reply(req, NULL,
+                                       conn->socks_request->address,
+                                       (char*)answer, ttl);
+    tor_free(ans);
+  } else {
+    err = DNS_ERR_SERVERFAILED;
+  }
+
+  evdns_server_request_respond(req, err);
+  conn->dns_server_request = NULL;
+}
+
+void
+dnsserv_configure_listener(connection_t *conn)
+{
+  tor_assert(conn);
+  tor_assert(conn->s);
+
+  evdns_add_server_port(conn->s, 0, evdns_server_callback, NULL);
+}
+
+void
+dnsserv_close_listener(connection_t *conn)
+{
+  evdns_close_server_port(conn->dns_server_port);
+  conn->dns_server_port = NULL;
+}
+


Property changes on: tor/trunk/src/or/dnsserv.c
___________________________________________________________________
Name: svn:eolstyle
   + native
Name: svn:keywords
   + Author Date Id Revision

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2007-05-24 20:31:27 UTC (rev 10316)
+++ tor/trunk/src/or/or.h	2007-05-24 20:31:30 UTC (rev 10317)
@@ -237,7 +237,9 @@
 /** Type for sockets listening for transparent connections redirected by
  * natd. */
 #define CONN_TYPE_AP_NATD_LISTENER 14
-#define _CONN_TYPE_MAX 14
+/** Type for sockets listening for DNS requests. */
+#define CONN_TYPE_AP_DNS_LISTENER 15
+#define _CONN_TYPE_MAX 15
 
 #define CONN_IS_EDGE(x) \
   ((x)->type == CONN_TYPE_EXIT || (x)->type == CONN_TYPE_AP)
@@ -813,6 +815,9 @@
    * read_event should be made active with libevent. */
   unsigned int active_on_link:1;
 
+  /* XXXX020 move this into a subtype!!! */
+  struct evdns_server_port *dns_server_port;
+
 } connection_t;
 
 /** Subtype of connection_t for an "OR connection" -- that is, one that speaks
@@ -905,6 +910,9 @@
    * already retried several times. */
   uint8_t num_socks_retries;
 
+  /** DOCDOC */
+  struct evdns_server_request *dns_server_request;
+
 } edge_connection_t;
 
 /** Subtype of connection_t for an "directory connection" -- that is, an HTTP
@@ -1728,6 +1736,8 @@
   config_line_t *TransListenAddress;
   /** Addresses to bind for listening for transparent natd connections */
   config_line_t *NatdListenAddress;
+  /** Addresses to bind for listening for SOCKS connections. */
+  config_line_t *DNSListenAddress;
   /** Addresses to bind for listening for OR connections. */
   config_line_t *ORListenAddress;
   /** Addresses to bind for listening for directory connections. */
@@ -1752,6 +1762,7 @@
   int NatdPort; /**< Port to listen on for transparent natd connections. */
   int ControlPort; /**< Port to listen on for control connections. */
   int DirPort; /**< Port to listen on for directory connections. */
+  int DNSPort; /**< Port to listen on for DNS requests. */
   int AssumeReachable; /**< Whether to publish our descriptor regardless. */
   int AuthoritativeDir; /**< Boolean: is this an authoritative directory? */
   int V1AuthoritativeDir; /**< Boolean: is this an authoritative directory
@@ -2403,6 +2414,7 @@
 int connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
                                                origin_circuit_t *circ,
                                                crypt_path_t *cpath);
+int hostname_is_noconnect_address(const char *address);
 
 void set_exit_redirects(smartlist_t *lst);
 typedef enum hostname_type_t {
@@ -2655,6 +2667,17 @@
 int dns_seems_to_be_broken(void);
 void dns_reset_correctness_checks(void);
 
+/********************************* dnsserv.c ************************/
+
+void dnsserv_configure_listener(connection_t *conn);
+void dnsserv_close_listener(connection_t *conn);
+void dnsserv_resolved(edge_connection_t *conn,
+                      int answer_type,
+                      size_t answer_len,
+                      const char *answer,
+                      int ttl);
+void dnsserv_reject_request(edge_connection_t *conn);
+
 /********************************* hibernate.c **********************/
 
 int accounting_parse_options(or_options_t *options, int validate_only);