浏览代码

Actually send back correctly-formed IPv6 CONNECTED cells

We had some old code to send back connected cells for IPv6 addresses,
but it was wrong.  Fortunately, it was also unreachable.
Nick Mathewson 11 年之前
父节点
当前提交
882b389668
共有 3 个文件被更改,包括 94 次插入29 次删除
  1. 52 27
      src/or/connection_edge.c
  2. 3 1
      src/or/connection_edge.h
  3. 39 1
      src/test/test_cell_formats.c

+ 52 - 27
src/or/connection_edge.c

@@ -392,6 +392,38 @@ connection_edge_finished_flushing(edge_connection_t *conn)
   return 0;
   return 0;
 }
 }
 
 
+/** DOCDOC */
+#define MAX_CONNECTED_CELL_PAYLOAD_LEN 25
+
+/** DOCDOC */
+/* private */int
+connected_cell_format_payload(uint8_t *payload_out,
+                              const tor_addr_t *addr,
+                              uint32_t ttl)
+{
+  const sa_family_t family = tor_addr_family(addr);
+  int connected_payload_len;
+
+  if (family == AF_INET) {
+    set_uint32(payload_out, tor_addr_to_ipv4n(addr));
+    connected_payload_len = 4;
+  } else if (family == AF_INET6) {
+    set_uint32(payload_out, 0);
+    set_uint8(payload_out + 4, 6);
+    memcpy(payload_out + 5, tor_addr_to_in6_addr8(addr), 16);
+    connected_payload_len = 21;
+  } else {
+    return -1;
+  }
+
+  set_uint32(payload_out + connected_payload_len, htonl(dns_clip_ttl(ttl)));
+  connected_payload_len += 4;
+
+  tor_assert(connected_payload_len <= MAX_CONNECTED_CELL_PAYLOAD_LEN);
+
+  return connected_payload_len;
+}
+
 /** Connected handler for exit connections: start writing pending
 /** Connected handler for exit connections: start writing pending
  * data, deliver 'CONNECTED' relay cells as appropriate, and check
  * data, deliver 'CONNECTED' relay cells as appropriate, and check
  * any pending data that may have been received. */
  * any pending data that may have been received. */
@@ -423,22 +455,16 @@ connection_edge_finished_connecting(edge_connection_t *edge_conn)
                                      RELAY_COMMAND_CONNECTED, NULL, 0) < 0)
                                      RELAY_COMMAND_CONNECTED, NULL, 0) < 0)
       return 0; /* circuit is closed, don't continue */
       return 0; /* circuit is closed, don't continue */
   } else {
   } else {
-    char connected_payload[20];
-    int connected_payload_len;
-    if (tor_addr_family(&conn->addr) == AF_INET) {
-      set_uint32(connected_payload, tor_addr_to_ipv4n(&conn->addr));
-      set_uint32(connected_payload+4,
-                 htonl(dns_clip_ttl(edge_conn->address_ttl)));
-      connected_payload_len = 8;
-    } else {
-      memcpy(connected_payload, tor_addr_to_in6_addr8(&conn->addr), 16);
-      set_uint32(connected_payload+16,
-                 htonl(dns_clip_ttl(edge_conn->address_ttl)));
-      connected_payload_len = 20;
-    }
+    uint8_t connected_payload[MAX_CONNECTED_CELL_PAYLOAD_LEN];
+    int connected_payload_len =
+      connected_cell_format_payload(connected_payload, &conn->addr,
+                                    edge_conn->address_ttl);
+    if (connected_payload_len < 0)
+      return -1;
+
     if (connection_edge_send_command(edge_conn,
     if (connection_edge_send_command(edge_conn,
-                                 RELAY_COMMAND_CONNECTED,
-                                 connected_payload, connected_payload_len) < 0)
+                        RELAY_COMMAND_CONNECTED,
+                        (char*)connected_payload, connected_payload_len) < 0)
       return 0; /* circuit is closed, don't continue */
       return 0; /* circuit is closed, don't continue */
   }
   }
   tor_assert(edge_conn->package_window > 0);
   tor_assert(edge_conn->package_window > 0);
@@ -2554,21 +2580,20 @@ connection_exit_connect(edge_connection_t *edge_conn)
                                  RELAY_COMMAND_CONNECTED,
                                  RELAY_COMMAND_CONNECTED,
                                  NULL, 0);
                                  NULL, 0);
   } else { /* normal stream */
   } else { /* normal stream */
-    char connected_payload[20];
-    int connected_payload_len;
-    if (tor_addr_family(&conn->addr) == AF_INET) {
-      set_uint32(connected_payload, tor_addr_to_ipv4n(&conn->addr));
-      connected_payload_len = 4;
-    } else {
-      memcpy(connected_payload, tor_addr_to_in6_addr8(&conn->addr), 16);
-      connected_payload_len = 16;
+    uint8_t connected_payload[MAX_CONNECTED_CELL_PAYLOAD_LEN];
+    int connected_payload_len =
+      connected_cell_format_payload(connected_payload, &conn->addr,
+                                    edge_conn->address_ttl);
+    if (connected_payload_len < 0) {
+      connection_edge_end(edge_conn, END_STREAM_REASON_INTERNAL);
+      circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
+      connection_free(conn);
     }
     }
-    set_uint32(connected_payload+connected_payload_len,
-               htonl(dns_clip_ttl(edge_conn->address_ttl)));
-    connected_payload_len += 4;
+
     connection_edge_send_command(edge_conn,
     connection_edge_send_command(edge_conn,
                                  RELAY_COMMAND_CONNECTED,
                                  RELAY_COMMAND_CONNECTED,
-                                 connected_payload, connected_payload_len);
+                                 (char*)connected_payload,
+                                 connected_payload_len);
   }
   }
 }
 }
 
 

+ 3 - 1
src/or/connection_edge.h

@@ -109,7 +109,9 @@ typedef struct begin_cell_t {
 
 
 int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell,
 int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell,
                      uint8_t *end_reason_out);
                      uint8_t *end_reason_out);
-
+int connected_cell_format_payload(uint8_t *payload_out,
+                                  const tor_addr_t *addr,
+                                  uint32_t ttl);
 #endif
 #endif
 
 
 #endif
 #endif

+ 39 - 1
src/test/test_cell_formats.c

@@ -231,6 +231,7 @@ test_cfmt_connected_cells(void *arg)
   cell_t cell;
   cell_t cell;
   tor_addr_t addr;
   tor_addr_t addr;
   int ttl, r;
   int ttl, r;
+  char *mem_op_hex_tmp = NULL;
   (void)arg;
   (void)arg;
 
 
   /* Let's try an oldschool one with nothing in it. */
   /* Let's try an oldschool one with nothing in it. */
@@ -332,8 +333,45 @@ test_cfmt_connected_cells(void *arg)
   r = connected_cell_parse(&rh, &cell, &addr, &ttl);
   r = connected_cell_parse(&rh, &cell, &addr, &ttl);
   tt_int_op(r, ==, -1);
   tt_int_op(r, ==, -1);
 
 
+  /* Now make sure we can generate connected cells correctly. */
+  /* Try an IPv4 address */
+  memset(&rh, 0, sizeof(rh));
+  memset(&cell, 0, sizeof(cell));
+  tor_addr_parse(&addr, "30.40.50.60");
+  rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE,
+                                            &addr, 128);
+  tt_int_op(rh.length, ==, 8);
+  test_memeq_hex(cell.payload+RELAY_HEADER_SIZE, "1e28323c" "00000080");
+
+  /* Try parsing it. */
+  tor_addr_make_unspec(&addr);
+  r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+  tt_int_op(r, ==, 0);
+  tt_int_op(tor_addr_family(&addr), ==, AF_INET);
+  tt_str_op(fmt_addr(&addr), ==, "30.40.50.60");
+  tt_int_op(ttl, ==, 128);
+
+  /* Try an IPv6 address */
+  memset(&rh, 0, sizeof(rh));
+  memset(&cell, 0, sizeof(cell));
+  tor_addr_parse(&addr, "2620::6b0:b:1a1a:0:26e5:480e");
+  rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE,
+                                            &addr, 3600);
+  tt_int_op(rh.length, ==, 25);
+  test_memeq_hex(cell.payload + RELAY_HEADER_SIZE,
+                 "00000000" "06"
+                 "2620000006b0000b1a1a000026e5480e" "00000e10");
+
+  /* Try parsing it. */
+  tor_addr_make_unspec(&addr);
+  r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+  tt_int_op(r, ==, 0);
+  tt_int_op(tor_addr_family(&addr), ==, AF_INET6);
+  tt_str_op(fmt_addr(&addr), ==, "2620:0:6b0:b:1a1a:0:26e5:480e");
+  tt_int_op(ttl, ==, 3600);
+
  done:
  done:
-  ;
+  tor_free(mem_op_hex_tmp);
 }
 }
 
 
 #define TEST(name, flags)                                               \
 #define TEST(name, flags)                                               \