Browse Source

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 years ago
parent
commit
882b389668
3 changed files with 94 additions and 29 deletions
  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;
 }
 
+/** 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
  * data, deliver 'CONNECTED' relay cells as appropriate, and check
  * 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)
       return 0; /* circuit is closed, don't continue */
   } 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,
-                                 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 */
   }
   tor_assert(edge_conn->package_window > 0);
@@ -2554,21 +2580,20 @@ connection_exit_connect(edge_connection_t *edge_conn)
                                  RELAY_COMMAND_CONNECTED,
                                  NULL, 0);
   } 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,
                                  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,
                      uint8_t *end_reason_out);
-
+int connected_cell_format_payload(uint8_t *payload_out,
+                                  const tor_addr_t *addr,
+                                  uint32_t ttl);
 #endif
 
 #endif

+ 39 - 1
src/test/test_cell_formats.c

@@ -231,6 +231,7 @@ test_cfmt_connected_cells(void *arg)
   cell_t cell;
   tor_addr_t addr;
   int ttl, r;
+  char *mem_op_hex_tmp = NULL;
   (void)arg;
 
   /* 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);
   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:
-  ;
+  tor_free(mem_op_hex_tmp);
 }
 
 #define TEST(name, flags)                                               \