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

[or-cvs] r10781: Get the RESOLVE controller code working. (in tor/trunk: . doc doc/spec src/or)



Author: nickm
Date: 2007-07-10 13:14:51 -0400 (Tue, 10 Jul 2007)
New Revision: 10781

Modified:
   tor/trunk/
   tor/trunk/ChangeLog
   tor/trunk/doc/TODO
   tor/trunk/doc/spec/control-spec.txt
   tor/trunk/src/or/connection_edge.c
   tor/trunk/src/or/control.c
   tor/trunk/src/or/dnsserv.c
   tor/trunk/src/or/main.c
   tor/trunk/src/or/or.h
   tor/trunk/src/or/relay.c
Log:
 r13666@catbus:  nickm | 2007-07-10 13:10:00 -0400
 Get the RESOLVE controller code working.



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

Modified: tor/trunk/ChangeLog
===================================================================
--- tor/trunk/ChangeLog	2007-07-10 17:13:24 UTC (rev 10780)
+++ tor/trunk/ChangeLog	2007-07-10 17:14:51 UTC (rev 10781)
@@ -15,6 +15,8 @@
       match requests to applications. (Patch from Robert Hogan.)
     - Report address and port correctly on connections to DNSPort. (Patch
       from Robert Hogan.)
+    - Add a RESOLVE command to launch hostname lookups. (Original patch
+      from Robert Hogan.)
 
   o Performance improvements (win32):
     - Use Critical Sections rather than Mutexes for synchronizing threads

Modified: tor/trunk/doc/TODO
===================================================================
--- tor/trunk/doc/TODO	2007-07-10 17:13:24 UTC (rev 10780)
+++ tor/trunk/doc/TODO	2007-07-10 17:14:51 UTC (rev 10781)
@@ -206,7 +206,7 @@
       o Make it handle .onion and .exit correctly.
       - Document.
       - Handle TCP DNS requests too?
-    - Add a way to request DNS resolves from the controller.
+    o 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
       - Write a proposal

Modified: tor/trunk/doc/spec/control-spec.txt
===================================================================
--- tor/trunk/doc/spec/control-spec.txt	2007-07-10 17:13:24 UTC (rev 10780)
+++ tor/trunk/doc/spec/control-spec.txt	2007-07-10 17:14:51 UTC (rev 10781)
@@ -683,6 +683,18 @@
      stable releases after 0.1.2.2-alpha, the release where it was first
      available.)
 
+3.20. RESOLVE
+
+  The syntax is
+    "RESOLVE" *Option *Address CRLF
+    Option = "mode=reverse"
+    Address = a hostname or IPv4 address
+
+  This command launches a remote hostname lookup request for every specified
+  request (or reverse lookup if "mode=reverse" is specified).  Note that the
+  request is done in the background: to see the answers, your controller will
+  need to listen for ADDRMAP events; see 4.1.7 below.
+
 4. Replies
 
   Reply codes follow the same 3-character format as used by SMTP, with the
@@ -947,8 +959,8 @@
 
   Expiry is expressed as the local time (rather than GMT).
 
-  [XXX We should rename this to ADDRESSMAP. -RD]
-    [Why? Surely it can't be worth the compatibility issues. -NM]
+  These events are generated when a new address mapping is entered in the
+  cache, or when the answer for a RESOLVE command is found.
 
 4.1.8. Descriptors uploaded to us in our role as authoritative dirserver
 

Modified: tor/trunk/src/or/connection_edge.c
===================================================================
--- tor/trunk/src/or/connection_edge.c	2007-07-10 17:13:24 UTC (rev 10780)
+++ tor/trunk/src/or/connection_edge.c	2007-07-10 17:14:51 UTC (rev 10781)
@@ -59,7 +59,7 @@
     else if (SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command))
       connection_ap_handshake_socks_resolved(conn,
                                              RESOLVED_TYPE_ERROR_TRANSIENT,
-                                             0, NULL, -1);
+                                             0, NULL, -1, -1);
     else /* unknown or no handshake at all. send no response. */
       conn->socks_request->has_finished = 1;
   }
@@ -655,23 +655,30 @@
  * more rewrites; but don't get into an infinite loop.
  * Don't write more than maxlen chars into address.  Return true if the
  * address changed; false otherwise.
+ * DOCDOC expires_out
  */
 int
-addressmap_rewrite(char *address, size_t maxlen)
+addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out)
 {
   addressmap_entry_t *ent;
   int rewrites;
   char *cp;
+  time_t expires = TIME_MAX;
 
   for (rewrites = 0; rewrites < 16; rewrites++) {
     ent = strmap_get(addressmap, address);
 
-    if (!ent || !ent->new_address)
+    if (!ent || !ent->new_address) {
+      if (expires_out)
+        *expires_out = expires;
       return (rewrites > 0); /* done, no rewrite needed */
+    }
 
     cp = tor_strdup(escaped_safe_str(ent->new_address));
     log_info(LD_APP, "Addressmap: rewriting %s to %s",
              escaped_safe_str(address), cp);
+    if (ent->expires > 1 && ent->expires < expires)
+      expires = ent->expires;
     tor_free(cp);
     strlcpy(address, ent->new_address, maxlen);
   }
@@ -679,14 +686,17 @@
            "Loop detected: we've rewritten %s 16 times! Using it as-is.",
            escaped_safe_str(address));
   /* it's fine to rewrite a rewrite, but don't loop forever */
+  if (expires_out)
+    *expires_out = TIME_MAX;
   return 1;
 }
 
 /** If we have a cached reverse DNS entry for the address stored in the
  * <b>maxlen</b>-byte buffer <b>address</b> (typically, a dotted quad) then
- * rewrite to the cached value and return 1.  Otherwise return 0. */
+ * rewrite to the cached value and return 1.  Otherwise return 0.
+ * DOCDOC expires_out */
 static int
-addressmap_rewrite_reverse(char *address, size_t maxlen)
+addressmap_rewrite_reverse(char *address, size_t maxlen, time_t *expires_out)
 {
   size_t len = maxlen + 16;
   char *s = tor_malloc(len), *cp;
@@ -702,6 +712,10 @@
     strlcpy(address, ent->new_address, maxlen);
     r = 1;
   }
+
+  if (expires_out)
+    *expires_out = (ent && ent->expires > 1) ? ent->expires : TIME_MAX;
+
   tor_free(s);
   return r;
 }
@@ -765,7 +779,7 @@
 
   log_info(LD_CONFIG, "Addressmap: (re)mapped '%s' to '%s'",
            safe_str(address), safe_str(ent->new_address));
-  control_event_address_mapped(address, ent->new_address, expires);
+  control_event_address_mapped(address, ent->new_address, expires, NULL);
 }
 
 /** An attempt to resolve <b>address</b> failed at some OR.
@@ -1182,6 +1196,7 @@
   struct in_addr addr_tmp;
   int automap = 0;
   char orig_address[MAX_SOCKS_ADDR_LEN];
+  time_t map_expires = TIME_MAX;
 
   tor_strlower(socks->address); /* normalize it */
   strlcpy(orig_address, socks->address, sizeof(orig_address));
@@ -1209,12 +1224,14 @@
   }
 
   if (socks->command == SOCKS_COMMAND_RESOLVE_PTR) {
-    if (addressmap_rewrite_reverse(socks->address, sizeof(socks->address))) {
+    if (addressmap_rewrite_reverse(socks->address, sizeof(socks->address),
+                                   &map_expires)) {
       char *result = tor_strdup(socks->address);
       /* remember _what_ is supposed to have been resolved. */
       strlcpy(socks->address, orig_address, sizeof(socks->address));
       connection_ap_handshake_socks_resolved(conn, RESOLVED_TYPE_HOSTNAME,
-                                             strlen(result), result, -1);
+                                             strlen(result), result, -1,
+                                             map_expires);
       connection_mark_unattached_ap(conn,
                                  END_STREAM_REASON_DONE |
                                  END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
@@ -1222,7 +1239,8 @@
     }
   } else if (!automap) {
     /* For address map controls, remap the address. */
-    if (addressmap_rewrite(socks->address, sizeof(socks->address))) {
+    if (addressmap_rewrite(socks->address, sizeof(socks->address),
+                           &map_expires)) {
       control_event_stream_status(conn, STREAM_EVENT_REMAP,
                                   REMAP_STREAM_SOURCE_CACHE);
     }
@@ -1309,7 +1327,7 @@
                                     escaped(socks->address));
         connection_ap_handshake_socks_resolved(conn,
                                                RESOLVED_TYPE_ERROR_TRANSIENT,
-                                               0,NULL,-1);
+                                               0,NULL,-1,TIME_MAX);
         connection_mark_unattached_ap(conn,
                                 END_STREAM_REASON_SOCKSPROTOCOL |
                                 END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
@@ -1321,7 +1339,7 @@
         /* remember _what_ is supposed to have been resolved. */
         strlcpy(socks->address, orig_address, sizeof(socks->address));
         connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV4,4,
-                                               (char*)&answer,-1);
+                                               (char*)&answer,-1,map_expires);
         connection_mark_unattached_ap(conn,
                                 END_STREAM_REASON_DONE |
                                 END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
@@ -1382,7 +1400,7 @@
       log_warn(LD_APP,
                "Resolve requests to hidden services not allowed. Failing.");
       connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,
-                                             0,NULL,-1);
+                                             0,NULL,-1,TIME_MAX);
       connection_mark_unattached_ap(conn,
                                 END_STREAM_REASON_SOCKSPROTOCOL |
                                 END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
@@ -1962,17 +1980,52 @@
   return conn;
 }
 
+/** DOCDOC */
+static void
+tell_controller_about_resolved_result(edge_connection_t *conn,
+                                      int answer_type,
+                                      size_t answer_len,
+                                      const char *answer,
+                                      int ttl,
+                                      time_t expires)
+{
+
+  if (ttl >= 0 && (answer_type == RESOLVED_TYPE_IPV4 ||
+                   answer_type == RESOLVED_TYPE_HOSTNAME)) {
+    return; /* we already told the controller. */
+  } else if (answer_type == RESOLVED_TYPE_IPV4 && answer_len >= 4) {
+    struct in_addr in;
+    char buf[INET_NTOA_BUF_LEN];
+    in.s_addr = get_uint32(answer);
+    tor_inet_ntoa(&in, buf, sizeof(buf));
+    control_event_address_mapped(conn->socks_request->address,
+                                 buf, expires, NULL);
+  } else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len <256) {
+    char *cp = tor_strndup(answer, answer_len);
+    control_event_address_mapped(conn->socks_request->address,
+                                 cp, expires, NULL);
+    tor_free(cp);
+  } else {
+    control_event_address_mapped(conn->socks_request->address,
+                                 "<error>",
+                                 time(NULL)+ttl,
+                                 "error=yes");
+  }
+}
+
 /** Send an answer to an AP connection that has requested a DNS lookup
  * via SOCKS.  The type should be one of RESOLVED_TYPE_(IPV4|IPV6|HOSTNAME) or
  * -1 for unreachable; the answer should be in the format specified
  * in the socks extensions document.
+ * DOCDOC expires
  **/
 void
 connection_ap_handshake_socks_resolved(edge_connection_t *conn,
                                        int answer_type,
                                        size_t answer_len,
                                        const char *answer,
-                                       int ttl)
+                                       int ttl,
+                                       time_t expires)
 {
   char buf[384];
   size_t replylen;
@@ -1992,11 +2045,21 @@
     }
   }
 
-  if (conn->dns_server_request) {
-    /* We had a request on our DNS port: answer it. */
-    dnsserv_resolved(conn, answer_type, answer_len, answer, ttl);
-    conn->socks_request->has_finished = 1;
-    return;
+  if (conn->is_dns_request) {
+    if (conn->dns_server_request) {
+      /* We had a request on our DNS port: answer it. */
+      dnsserv_resolved(conn, answer_type, answer_len, answer, ttl);
+      conn->socks_request->has_finished = 1;
+      return;
+    } else {
+      /* This must be a request from the controller. We already sent
+       * a mapaddress if there's a ttl. */
+      tell_controller_about_resolved_result(conn, answer_type, answer_len,
+                                            answer, ttl, expires);
+      conn->socks_request->has_finished = 1;
+      return;
+    }
+    /* XXXX020 are we freeing conn anywhere? */
   }
 
   if (conn->socks_request->socks_version == 4) {

Modified: tor/trunk/src/or/control.c
===================================================================
--- tor/trunk/src/or/control.c	2007-07-10 17:13:24 UTC (rev 10780)
+++ tor/trunk/src/or/control.c	2007-07-10 17:14:51 UTC (rev 10781)
@@ -2221,9 +2221,10 @@
                        const char *body)
 {
   smartlist_t *args;
+  int is_reverse = 0;
   (void) len; /* body is nul-terminated; it's safe to ignore the length */
 
-  if (!(conn->event_mask & EVENT_ADDRMAP)) {
+  if (!(conn->event_mask & (1L<<EVENT_ADDRMAP))) {
     log_warn(LD_CONTROL, "Controller asked us to resolve an address, but "
              "isn't listening for ADDRMAP events.  It probably won't see "
              "the answer.");
@@ -2231,8 +2232,15 @@
   args = smartlist_create();
   smartlist_split_string(args, body, " ",
                          SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+  if (smartlist_len(args) &&
+      !strcasecmp(smartlist_get(args, 0), "mode=reverse")) {
+    char *cp = smartlist_get(args, 0);
+    smartlist_del_keeporder(args, 0);
+    tor_free(cp);
+    is_reverse = 1;
+  }
   SMARTLIST_FOREACH(args, const char *, arg, {
-    evdns_server_control(arg);
+      dnsserv_launch_request(arg, is_reverse);
   });
 
   SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
@@ -3058,22 +3066,25 @@
 }
 
 /** Called whenever an address mapping on <b>from<b> from changes to <b>to</b>.
- * <b>expires</b> values less than 3 are special; see connection_edge.c. */
+ * <b>expires</b> values less than 3 are special; see connection_edge.c.
+ * DOCDOC source. */
 int
-control_event_address_mapped(const char *from, const char *to, time_t expires)
+control_event_address_mapped(const char *from, const char *to, time_t expires,
+                             const char *error)
 {
   if (!EVENT_IS_INTERESTING(EVENT_ADDRMAP))
     return 0;
 
-  if (expires < 3)
-    send_control_event(EVENT_ADDRMAP, ALL_NAMES,
-                        "650 ADDRMAP %s %s NEVER\r\n", from, to);
+  if (expires < 3 || expires == TIME_MAX)
+    send_control_event_extended(EVENT_ADDRMAP, ALL_NAMES,
+                                "650 ADDRMAP %s %s NEVER@%s\r\n", from, to,
+                                error);
   else {
     char buf[ISO_TIME_LEN+1];
     format_local_iso_time(buf,expires);
-    send_control_event(EVENT_ADDRMAP, ALL_NAMES,
-                        "650 ADDRMAP %s %s \"%s\"\r\n",
-                        from, to, buf);
+    send_control_event_extended(EVENT_ADDRMAP, ALL_NAMES,
+                                "650 ADDRMAP %s %s \"%s\"@%s\r\n",
+                                from, to, buf, error);
   }
 
   return 0;

Modified: tor/trunk/src/or/dnsserv.c
===================================================================
--- tor/trunk/src/or/dnsserv.c	2007-07-10 17:13:24 UTC (rev 10780)
+++ tor/trunk/src/or/dnsserv.c	2007-07-10 17:14:51 UTC (rev 10781)
@@ -112,6 +112,7 @@
   /* Make a new dummy AP connection, and attach the request to it. */
   conn = TO_EDGE_CONN(connection_new(CONN_TYPE_AP, AF_INET));
   conn->_base.state = AP_CONN_STATE_RESOLVE_WAIT;
+  conn->is_dns_request = 1;
 
   TO_CONN(conn)->addr = ntohl(sin->sin_addr.s_addr);
   TO_CONN(conn)->port = ntohs(sin->sin_port);
@@ -149,58 +150,25 @@
  * controller.  We need to eventually answer the request <b>req</b>.
  */
 void
-dnsserv_launch_request(const char *name)
+dnsserv_launch_request(const char *name, int reverse)
 {
   edge_connection_t *conn;
-  struct evdns_server_request *server_req;
-  struct in_addr in;
   char *q_name;
-  int i;
-  int is_ip_address;
 
   /* Make a new dummy AP connection, and attach the request to it. */
   conn = TO_EDGE_CONN(connection_new(CONN_TYPE_AP, AF_INET));
   conn->_base.state = AP_CONN_STATE_RESOLVE_WAIT;
 
-  is_ip_address = tor_inet_aton(name, &in);
-
-  if (!is_ip_address)
-    conn->socks_request->command = SOCKS_COMMAND_RESOLVE_CONTROL;
+  if (reverse)
+    conn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR;
   else
-    conn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR_CONTROL;
+    conn->socks_request->command = SOCKS_COMMAND_RESOLVE;
 
+  conn->is_dns_request = 1;
+
   strlcpy(conn->socks_request->address, name,
           sizeof(conn->socks_request->address));
 
-  server_req = malloc(sizeof(struct evdns_server_request));
-  if (server_req == NULL) return;
-  memset(server_req, 0, sizeof(struct evdns_server_request));
-
-  server_req->flags = 0;
-  server_req->nquestions = 0;
-
-  server_req->questions = malloc(sizeof(struct evdns_server_question *) * 1);
-  if (server_req->questions == NULL)
-    return;
-
-  for ( i = 0; i < 1; ++i) {
-    struct evdns_server_question *q;
-    int namelen;
-    namelen = strlen(name);
-    q = malloc(sizeof(struct evdns_server_question) + namelen);
-    if (!q)
-        return;
-    if (!is_ip_address)
-      q->type = EVDNS_TYPE_A;
-    else
-      q->type = EVDNS_TYPE_PTR;
-    q->class = EVDNS_CLASS_INET;
-    memcpy(q->name, name, namelen+1);
-    server_req->questions[server_req->nquestions++] = q;
-  }
-
-  conn->dns_server_request = server_req;
-
   connection_add(TO_CONN(conn));
 
   /* Now, throw the connection over to get rewritten (which will answer it
@@ -296,6 +264,7 @@
   if (!SOCKS_COMMAND_IS_RESOLVE_CONTROL(conn->socks_request->command))
     evdns_server_request_respond(req, err);
 
+
   conn->dns_server_request = NULL;
 }
 

Modified: tor/trunk/src/or/main.c
===================================================================
--- tor/trunk/src/or/main.c	2007-07-10 17:13:24 UTC (rev 10780)
+++ tor/trunk/src/or/main.c	2007-07-10 17:14:51 UTC (rev 10781)
@@ -165,7 +165,7 @@
   tor_assert(conn->s >= 0 ||
              conn->linked ||
              (conn->type == CONN_TYPE_AP &&
-              TO_EDGE_CONN(conn)->dns_server_request));
+              TO_EDGE_CONN(conn)->is_dns_request));
 
   tor_assert(conn->conn_array_index == -1); /* can only connection_add once */
   conn->conn_array_index = smartlist_len(connection_array);

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2007-07-10 17:13:24 UTC (rev 10780)
+++ tor/trunk/src/or/or.h	2007-07-10 17:14:51 UTC (rev 10781)
@@ -910,6 +910,9 @@
    * already retried several times. */
   uint8_t num_socks_retries;
 
+  /** True iff this connection is for a dns request only. */
+  unsigned int is_dns_request : 1;
+
   /** If this is a DNSPort connection, this field holds the pending DNS
    * request that we're going to try to answer.  */
   struct evdns_server_request *dns_server_request;
@@ -2465,7 +2468,8 @@
                                             int answer_type,
                                             size_t answer_len,
                                             const char *answer,
-                                            int ttl);
+                                            int ttl,
+                                            time_t expires);
 
 int connection_exit_begin_conn(cell_t *cell, circuit_t *circ);
 int connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ);
@@ -2487,7 +2491,7 @@
 void addressmap_clear_configured(void);
 void addressmap_clear_transient(void);
 void addressmap_free_all(void);
-int addressmap_rewrite(char *address, size_t maxlen);
+int addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out);
 int addressmap_have_mapping(const char *address);
 void addressmap_register(const char *address, char *new_address,
                          time_t expires);
@@ -2614,7 +2618,7 @@
 void control_event_logmsg(int severity, unsigned int domain, const char *msg);
 int control_event_descriptors_changed(smartlist_t *routers);
 int control_event_address_mapped(const char *from, const char *to,
-                                 time_t expires);
+                                 time_t expires, const char *error);
 int control_event_or_authdir_new_descriptor(const char *action,
                                             const char *desc,
                                             size_t desclen,
@@ -2801,7 +2805,7 @@
                       const char *answer,
                       int ttl);
 void dnsserv_reject_request(edge_connection_t *conn);
-void dnsserv_launch_request(const char *name);
+void dnsserv_launch_request(const char *name, int is_reverse);
 
 /********************************* hibernate.c **********************/
 

Modified: tor/trunk/src/or/relay.c
===================================================================
--- tor/trunk/src/or/relay.c	2007-07-10 17:13:24 UTC (rev 10780)
+++ tor/trunk/src/or/relay.c	2007-07-10 17:14:51 UTC (rev 10781)
@@ -759,7 +759,8 @@
         }
         /* rewrite it to an IP if we learned one. */
         if (addressmap_rewrite(conn->socks_request->address,
-                               sizeof(conn->socks_request->address))) {
+                               sizeof(conn->socks_request->address),
+                               NULL)) {
           control_event_stream_status(conn, STREAM_EVENT_REMAP, 0);
         }
         if (conn->_base.chosen_exit_optional) {
@@ -946,7 +947,8 @@
                    answer_type,
                    cell->payload[RELAY_HEADER_SIZE+1], /*answer_len*/
                    cell->payload+RELAY_HEADER_SIZE+2, /*answer*/
-                   ttl);
+                   ttl,
+                   -1);
     if (answer_type == RESOLVED_TYPE_IPV4) {
       uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+2));
       remap_event_helper(conn, addr);