Browse Source

Add TTLs to RESOLVED, CONNECTED, and END_REASON_EXITPOLICY cells. Also, add a missing ntohl in connection_ap_handshake_socks_resolved.

svn:r4894
Nick Mathewson 20 years ago
parent
commit
a6a45b7713
4 changed files with 76 additions and 29 deletions
  1. 13 3
      doc/tor-spec.txt
  2. 29 17
      src/or/connection_edge.c
  3. 12 5
      src/or/dns.c
  4. 22 4
      src/or/relay.c

+ 13 - 3
doc/tor-spec.txt

@@ -469,8 +469,16 @@ TODO: (very soon)
    address cannot be resolved, or a connection can't be established, the
    address cannot be resolved, or a connection can't be established, the
    exit node replies with a RELAY_END cell.  (See 5.4 below.)
    exit node replies with a RELAY_END cell.  (See 5.4 below.)
    Otherwise, the exit node replies with a RELAY_CONNECTED cell, whose
    Otherwise, the exit node replies with a RELAY_CONNECTED cell, whose
-   payload is the 4-byte IPv4 address or the 16-byte IPv6 address to which
-   the connection was made.
+   payload is in one of the following formats:
+       The IPv4 address to which the connection was made [4 octets]
+       A number of seconds (TTL) for which the address may be cached [4 octets]
+    or
+       Four zero-valued octets [4 octets]
+       An address type (6)     [1 octet]
+       The IPv6 address to which the connection was made [16 octets]
+       A number of seconds (TTL) for which the address may be cached [4 octets]
+   [XXXX Versions of Tor before 0.1.1.6 ignore and do not generate the TTL
+   field.  No version of Tor currently generates the IPv6 format.]
 
 
    The OP waits for a RELAY_CONNECTED cell before sending any data.
    The OP waits for a RELAY_CONNECTED cell before sending any data.
    Once a connection has been established, the OP and exit node
    Once a connection has been established, the OP and exit node
@@ -511,7 +519,8 @@ TODO: (very soon)
                                    Tor protocol violations.)
                                    Tor protocol violations.)
 
 
    (With REASON_EXITPOLICY, the 4-byte IPv4 address or 16-byte IPv6 address
    (With REASON_EXITPOLICY, the 4-byte IPv4 address or 16-byte IPv6 address
-   forms the optional data; no other reason currently has extra data.)
+   forms the optional data; no other reason currently has extra data.
+   As of 0.1.1.6, the body also contains a 4-byte TTL.)
 
 
    OPs and ORs MUST accept reasons not on the above list, since future
    OPs and ORs MUST accept reasons not on the above list, since future
    versions of Tor may provide more fine-grained reasons.
    versions of Tor may provide more fine-grained reasons.
@@ -558,6 +567,7 @@ TODO: (very soon)
        Type   (1 octet)
        Type   (1 octet)
        Length (1 octet)
        Length (1 octet)
        Value  (variable-width)
        Value  (variable-width)
+       TTL    (4 octets)
    "Length" is the length of the Value field.
    "Length" is the length of the Value field.
    "Type" is one of:
    "Type" is one of:
       0x00 -- Hostname
       0x00 -- Hostname

+ 29 - 17
src/or/connection_edge.c

@@ -48,7 +48,7 @@ _connection_mark_unattached_ap(connection_t *conn, int endreason,
     if (conn->socks_request->command == SOCKS_COMMAND_CONNECT)
     if (conn->socks_request->command == SOCKS_COMMAND_CONNECT)
       connection_ap_handshake_socks_reply(conn, NULL, 0, socksreason);
       connection_ap_handshake_socks_reply(conn, NULL, 0, socksreason);
     else
     else
-      connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL);
+      connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL,-1);
   }
   }
 
 
   _connection_mark_for_close(conn, line, file);
   _connection_mark_for_close(conn, line, file);
@@ -194,7 +194,8 @@ connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_layer)
     /* this is safe even for rend circs, because they never fail
     /* this is safe even for rend circs, because they never fail
      * because of exitpolicy */
      * because of exitpolicy */
     set_uint32(payload+1, htonl(conn->addr));
     set_uint32(payload+1, htonl(conn->addr));
-    payload_len += 4;
+    set_uint32(payload+5, htonl(MAX_DNS_ENTRY_AGE)); /* XXXXfill with a real TTL*/
+    payload_len += 8;
   }
   }
 
 
   circ = circuit_get_by_edge_conn(conn);
   circ = circuit_get_by_edge_conn(conn);
@@ -266,7 +267,6 @@ connection_edge_finished_flushing(connection_t *conn)
 int
 int
 connection_edge_finished_connecting(connection_t *conn)
 connection_edge_finished_connecting(connection_t *conn)
 {
 {
-  char connected_payload[4];
   char valbuf[INET_NTOA_BUF_LEN];
   char valbuf[INET_NTOA_BUF_LEN];
   struct in_addr in;
   struct in_addr in;
 
 
@@ -289,9 +289,12 @@ connection_edge_finished_connecting(connection_t *conn)
                                      RELAY_COMMAND_CONNECTED, NULL, 0, conn->cpath_layer) < 0)
                                      RELAY_COMMAND_CONNECTED, NULL, 0, conn->cpath_layer) < 0)
       return 0; /* circuit is closed, don't continue */
       return 0; /* circuit is closed, don't continue */
   } else {
   } else {
-    *(uint32_t*)connected_payload = htonl(conn->addr);
+    char connected_payload[8];
+    set_uint32(connected_payload, htonl(htonl(conn->addr)));
+    set_uint32(connected_payload+4,
+               htonl(MAX_DNS_ENTRY_AGE)); /* XXXX fill with a real TTL */
     if (connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
     if (connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
-        RELAY_COMMAND_CONNECTED, connected_payload, 4, conn->cpath_layer) < 0)
+        RELAY_COMMAND_CONNECTED, connected_payload, 8, conn->cpath_layer) < 0)
       return 0; /* circuit is closed, don't continue */
       return 0; /* circuit is closed, don't continue */
   }
   }
   tor_assert(conn->package_window > 0);
   tor_assert(conn->package_window > 0);
@@ -683,9 +686,13 @@ client_dns_clear_failures(const char *address)
  *
  *
  * If <b>exitname</b> is defined, then append the addresses with
  * If <b>exitname</b> is defined, then append the addresses with
  * ".exitname.exit" before registering the mapping.
  * ".exitname.exit" before registering the mapping.
+ *
+ * If <b>ttl</b> is nonnegative, the mapping will be valid for
+ * <b>ttl</b>seconds.
  */
  */
 void
 void
-client_dns_set_addressmap(const char *address, uint32_t val, const char *exitname)
+client_dns_set_addressmap(const char *address, uint32_t val, const char *exitname,
+                          int ttl)
 {
 {
   struct in_addr in;
   struct in_addr in;
   char extendedaddress[MAX_SOCKS_ADDR_LEN+MAX_HEX_NICKNAME_LEN+10];
   char extendedaddress[MAX_SOCKS_ADDR_LEN+MAX_HEX_NICKNAME_LEN+10];
@@ -694,6 +701,9 @@ client_dns_set_addressmap(const char *address, uint32_t val, const char *exitnam
 
 
   tor_assert(address); tor_assert(val);
   tor_assert(address); tor_assert(val);
 
 
+  if (ttl<0 || ttl>MAX_DNS_ENTRY_AGE)
+    ttl = MAX_DNS_ENTRY_AGE;
+
   if (tor_inet_aton(address, &in))
   if (tor_inet_aton(address, &in))
     return; /* If address was an IP address already, don't add a mapping. */
     return; /* If address was an IP address already, don't add a mapping. */
   in.s_addr = htonl(val);
   in.s_addr = htonl(val);
@@ -709,8 +719,7 @@ client_dns_set_addressmap(const char *address, uint32_t val, const char *exitnam
     tor_snprintf(extendedval, sizeof(extendedval),
     tor_snprintf(extendedval, sizeof(extendedval),
                  "%s", valbuf);
                  "%s", valbuf);
   }
   }
-  addressmap_register(extendedaddress, tor_strdup(extendedval),
-                      time(NULL) + MAX_DNS_ENTRY_AGE);
+  addressmap_register(extendedaddress, tor_strdup(extendedval), time(NULL) + ttl);
 }
 }
 
 
 /* Currently, we hand out 127.192.0.1 through 127.254.254.254.
 /* Currently, we hand out 127.192.0.1 through 127.254.254.254.
@@ -1019,14 +1028,14 @@ connection_ap_handshake_process_socks(connection_t *conn)
       /* Reply to resolves immediately if we can. */
       /* Reply to resolves immediately if we can. */
       if (strlen(socks->address) > RELAY_PAYLOAD_SIZE) {
       if (strlen(socks->address) > RELAY_PAYLOAD_SIZE) {
         log_fn(LOG_WARN,"Address to be resolved is too large. Failing.");
         log_fn(LOG_WARN,"Address to be resolved is too large. Failing.");
-        connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL);
+        connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL,-1);
         connection_mark_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED);
         connection_mark_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED);
         return -1;
         return -1;
       }
       }
       if (tor_inet_aton(socks->address, &in)) { /* see if it's an IP already */
       if (tor_inet_aton(socks->address, &in)) { /* see if it's an IP already */
         answer = in.s_addr; /* leave it in network order */
         answer = in.s_addr; /* leave it in network order */
         connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV4,4,
         connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV4,4,
-                                               (char*)&answer);
+                                               (char*)&answer,-1);
         connection_mark_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED);
         connection_mark_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED);
         return 0;
         return 0;
       }
       }
@@ -1075,7 +1084,7 @@ connection_ap_handshake_process_socks(connection_t *conn)
       /* if it's a resolve request, fail it right now, rather than
       /* if it's a resolve request, fail it right now, rather than
        * building all the circuits and then realizing it won't work. */
        * building all the circuits and then realizing it won't work. */
       log_fn(LOG_WARN,"Resolve requests to hidden services not allowed. Failing.");
       log_fn(LOG_WARN,"Resolve requests to hidden services not allowed. Failing.");
-      connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL);
+      connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL,-1);
       connection_mark_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED);
       connection_mark_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED);
       return -1;
       return -1;
     }
     }
@@ -1299,16 +1308,17 @@ void
 connection_ap_handshake_socks_resolved(connection_t *conn,
 connection_ap_handshake_socks_resolved(connection_t *conn,
                                        int answer_type,
                                        int answer_type,
                                        size_t answer_len,
                                        size_t answer_len,
-                                       const char *answer)
+                                       const char *answer,
+                                       int ttl)
 {
 {
   char buf[256];
   char buf[256];
   size_t replylen;
   size_t replylen;
 
 
   if (answer_type == RESOLVED_TYPE_IPV4) {
   if (answer_type == RESOLVED_TYPE_IPV4) {
-    uint32_t a = get_uint32(answer);
+    uint32_t a = ntohl(get_uint32(answer));
     if (a)
     if (a)
       client_dns_set_addressmap(conn->socks_request->address, ntohl(a),
       client_dns_set_addressmap(conn->socks_request->address, ntohl(a),
-                                conn->chosen_exit_name);
+                                conn->chosen_exit_name, ttl);
   }
   }
 
 
   if (conn->socks_request->socks_version == 4) {
   if (conn->socks_request->socks_version == 4) {
@@ -1581,7 +1591,6 @@ connection_exit_begin_resolve(cell_t *cell, circuit_t *circ)
 void
 void
 connection_exit_connect(connection_t *conn)
 connection_exit_connect(connection_t *conn)
 {
 {
-  char connected_payload[4];
   uint32_t addr;
   uint32_t addr;
   uint16_t port;
   uint16_t port;
 
 
@@ -1649,10 +1658,13 @@ connection_exit_connect(connection_t *conn)
                                  NULL, 0, conn->cpath_layer);
                                  NULL, 0, conn->cpath_layer);
   } else { /* normal stream */
   } else { /* normal stream */
     /* This must be the original address, not the redirected address. */
     /* This must be the original address, not the redirected address. */
-    *(uint32_t*)connected_payload = htonl(conn->addr);
+    char connected_payload[8];
+    set_uint32(connected_payload, htonl(htonl(conn->addr)));
+    set_uint32(connected_payload+4,
+               htonl(MAX_DNS_ENTRY_AGE)); /* XXXX fill with a real TTL */
     connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
     connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
                                  RELAY_COMMAND_CONNECTED,
                                  RELAY_COMMAND_CONNECTED,
-                                 connected_payload, 4, conn->cpath_layer);
+                                 connected_payload, 8, conn->cpath_layer);
   }
   }
 }
 }
 
 

+ 12 - 5
src/or/dns.c

@@ -192,14 +192,21 @@ send_resolved_cell(connection_t *conn, uint8_t answer_type)
     case RESOLVED_TYPE_IPV4:
     case RESOLVED_TYPE_IPV4:
       buf[1] = 4;
       buf[1] = 4;
       set_uint32(buf+2, htonl(conn->addr));
       set_uint32(buf+2, htonl(conn->addr));
-      buflen = 6;
+      set_uint32(buf+6, htonl(MAX_DNS_ENTRY_AGE)); /*XXXX send a real TTL*/
+      buflen = 10;
       break;
       break;
     case RESOLVED_TYPE_ERROR_TRANSIENT:
     case RESOLVED_TYPE_ERROR_TRANSIENT:
     case RESOLVED_TYPE_ERROR:
     case RESOLVED_TYPE_ERROR:
-      buf[1] = 24; /* length of "error resolving hostname" */
-      strlcpy(buf+2, "error resolving hostname", sizeof(buf)-2);
-      buflen = 26;
-      break;
+      {
+        const char *errmsg = "Error resolving hostname";
+        int msglen = strlen(errmsg);
+        int ttl = (answer_type == RESOLVED_TYPE_ERROR ? MAX_DNS_ENTRY_AGE : 0);
+        buf[1] = msglen;
+        strlcpy(buf+2, errmsg, sizeof(buf)-2);
+        set_uint32(buf+2+msglen, htonl((uint32_t)ttl));
+        buflen = 6+msglen;
+        break;
+      }
     default:
     default:
       tor_assert(0);
       tor_assert(0);
     }
     }

+ 22 - 4
src/or/relay.c

@@ -640,14 +640,19 @@ connection_edge_process_end_not_open(
       case END_STREAM_REASON_EXITPOLICY:
       case END_STREAM_REASON_EXITPOLICY:
         if (rh->length >= 5) {
         if (rh->length >= 5) {
           uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+1));
           uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+1));
+          int ttl;
           if (!addr) {
           if (!addr) {
             log_fn(LOG_INFO,"Address '%s' resolved to 0.0.0.0. Closing,",
             log_fn(LOG_INFO,"Address '%s' resolved to 0.0.0.0. Closing,",
                    safe_str(conn->socks_request->address));
                    safe_str(conn->socks_request->address));
             connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
             connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
             return 0;
             return 0;
           }
           }
+          if (rh->length >= 9)
+            ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+5));
+          else
+            ttl = -1;
           client_dns_set_addressmap(conn->socks_request->address, addr,
           client_dns_set_addressmap(conn->socks_request->address, addr,
-                                    conn->chosen_exit_name);
+                                    conn->chosen_exit_name, ttl);
         }
         }
         /* check if he *ought* to have allowed it */
         /* check if he *ought* to have allowed it */
         if (exitrouter &&
         if (exitrouter &&
@@ -735,14 +740,19 @@ connection_edge_process_relay_cell_not_open(
            (int)(time(NULL) - conn->timestamp_lastread));
            (int)(time(NULL) - conn->timestamp_lastread));
     if (rh->length >= 4) {
     if (rh->length >= 4) {
       uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE));
       uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE));
+      int ttl;
       if (!addr) {
       if (!addr) {
         log_fn(LOG_INFO,"...but it claims the IP address was 0.0.0.0. Closing.");
         log_fn(LOG_INFO,"...but it claims the IP address was 0.0.0.0. Closing.");
         connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL, conn->cpath_layer);
         connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL, conn->cpath_layer);
         connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
         connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
         return 0;
         return 0;
       }
       }
+      if (rh->length >= 8)
+        ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+8));
+      else
+        ttl = -1;
       client_dns_set_addressmap(conn->socks_request->address, addr,
       client_dns_set_addressmap(conn->socks_request->address, addr,
-                                conn->chosen_exit_name);
+                                conn->chosen_exit_name, ttl);
     }
     }
     circuit_log_path(LOG_INFO,circ);
     circuit_log_path(LOG_INFO,circ);
     connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_SUCCEEDED);
     connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_SUCCEEDED);
@@ -755,20 +765,28 @@ connection_edge_process_relay_cell_not_open(
     return 0;
     return 0;
   }
   }
   if (conn->type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_RESOLVED) {
   if (conn->type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_RESOLVED) {
+    int ttl;
+    int answer_len;
     if (conn->state != AP_CONN_STATE_RESOLVE_WAIT) {
     if (conn->state != AP_CONN_STATE_RESOLVE_WAIT) {
       log_fn(LOG_WARN,"Got a 'resolved' cell while not in state resolve_wait. Dropping.");
       log_fn(LOG_WARN,"Got a 'resolved' cell while not in state resolve_wait. Dropping.");
       return 0;
       return 0;
     }
     }
     tor_assert(conn->socks_request->command == SOCKS_COMMAND_RESOLVE);
     tor_assert(conn->socks_request->command == SOCKS_COMMAND_RESOLVE);
-    if (rh->length < 2 || cell->payload[RELAY_HEADER_SIZE+1]+2>rh->length) {
+    answer_len = cell->payload[RELAY_HEADER_SIZE+1];
+    if (rh->length < 2 || answer_len+2>rh->length) {
       log_fn(LOG_WARN, "Dropping malformed 'resolved' cell");
       log_fn(LOG_WARN, "Dropping malformed 'resolved' cell");
       connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
       connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
       return 0;
       return 0;
     }
     }
+    if (rh->length >= answer_len+6)
+      ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+6));
+    else
+      ttl = -1;
     connection_ap_handshake_socks_resolved(conn,
     connection_ap_handshake_socks_resolved(conn,
                    cell->payload[RELAY_HEADER_SIZE], /*answer_type*/
                    cell->payload[RELAY_HEADER_SIZE], /*answer_type*/
                    cell->payload[RELAY_HEADER_SIZE+1], /*answer_len*/
                    cell->payload[RELAY_HEADER_SIZE+1], /*answer_len*/
-                   cell->payload+RELAY_HEADER_SIZE+2); /* answer */
+                   cell->payload+RELAY_HEADER_SIZE+2,
+                   ttl); /* answer */
     connection_mark_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED);
     connection_mark_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED);
     return 0;
     return 0;
   }
   }