[tor-commits] [tor/master] relay: Split out relay-only circuit building

nickm at torproject.org nickm at torproject.org
Thu Apr 9 15:56:21 UTC 2020


commit 81687f5bc975842bb4d251881b04e19092ab336e
Author: teor <teor at torproject.org>
Date:   Tue Mar 17 17:18:40 2020 +1000

    relay: Split out relay-only circuit building
    
    Move the relay-only circuit building functions into a new file.
    
    Part of 33633.
---
 src/core/mainloop/cpuworker.c          |   2 +-
 src/core/or/circuitbuild.c             | 233 +-----------------------------
 src/core/or/circuitbuild.h             |  19 ++-
 src/core/or/command.c                  |   1 +
 src/core/or/relay.c                    |   1 +
 src/feature/relay/circuitbuild_relay.c | 253 +++++++++++++++++++++++++++++++++
 src/feature/relay/circuitbuild_relay.h |  60 ++++++++
 src/feature/relay/include.am           |   2 +
 8 files changed, 338 insertions(+), 233 deletions(-)

diff --git a/src/core/mainloop/cpuworker.c b/src/core/mainloop/cpuworker.c
index abd48f886..485ddb974 100644
--- a/src/core/mainloop/cpuworker.c
+++ b/src/core/mainloop/cpuworker.c
@@ -19,7 +19,6 @@
  **/
 #include "core/or/or.h"
 #include "core/or/channel.h"
-#include "core/or/circuitbuild.h"
 #include "core/or/circuitlist.h"
 #include "core/or/connection_or.h"
 #include "app/config/config.h"
@@ -27,6 +26,7 @@
 #include "lib/crypt_ops/crypto_rand.h"
 #include "lib/crypt_ops/crypto_util.h"
 #include "core/or/onion.h"
+#include "feature/relay/circuitbuild_relay.h"
 #include "feature/relay/onion_queue.h"
 #include "feature/stats/rephist.h"
 #include "feature/relay/router.h"
diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c
index ea51d7b9b..0527548f2 100644
--- a/src/core/or/circuitbuild.c
+++ b/src/core/or/circuitbuild.c
@@ -21,8 +21,7 @@
  * cells arrive, the client will invoke circuit_send_next_onion_skin() to send
  * CREATE or RELAY_EXTEND cells.
  *
- * On the server side, this module also handles the logic of responding to
- * RELAY_EXTEND requests, using circuit_extend().
+ * The server side is handled in feature/relay/circuitbuild_relay.c.
  **/
 
 #define CIRCUITBUILD_PRIVATE
@@ -35,7 +34,6 @@
 #include "core/crypto/onion_crypto.h"
 #include "core/crypto/onion_fast.h"
 #include "core/crypto/onion_tap.h"
-#include "core/crypto/relay_crypto.h"
 #include "core/mainloop/connection.h"
 #include "core/mainloop/mainloop.h"
 #include "core/or/channel.h"
@@ -84,13 +82,6 @@
 #include "feature/nodelist/routerinfo_st.h"
 #include "feature/nodelist/routerstatus_st.h"
 
-static channel_t * channel_connect_for_circuit(const tor_addr_t *addr,
-                                            uint16_t port,
-                                            const char *id_digest,
-                                            const ed25519_public_key_t *ed_id);
-static int circuit_deliver_create_cell(circuit_t *circ,
-                                       const create_cell_t *create_cell,
-                                       int relayed);
 static int circuit_send_first_onion_skin(origin_circuit_t *circ);
 static int circuit_build_no_more_hops(origin_circuit_t *circ);
 static int circuit_send_intermediate_onion_skin(origin_circuit_t *circ,
@@ -104,10 +95,10 @@ static const node_t *choose_good_middle_server(uint8_t purpose,
  * and then calls command_setup_channel() to give it the right
  * callbacks.
  */
-static channel_t *
+channel_t *
 channel_connect_for_circuit(const tor_addr_t *addr, uint16_t port,
                             const char *id_digest,
-                            const ed25519_public_key_t *ed_id)
+                            const struct ed25519_public_key_t *ed_id)
 {
   channel_t *chan;
 
@@ -707,8 +698,9 @@ circuit_n_chan_done(channel_t *chan, int status, int close_origin_circuits)
  * gave us via an EXTEND cell, so we shouldn't worry if we don't understand
  * it. Return -1 if we failed to find a suitable circid, else return 0.
  */
-static int
-circuit_deliver_create_cell(circuit_t *circ, const create_cell_t *create_cell,
+int
+circuit_deliver_create_cell(circuit_t *circ,
+                            const struct create_cell_t *create_cell,
                             int relayed)
 {
   cell_t cell;
@@ -1166,164 +1158,6 @@ circuit_note_clock_jumped(int64_t seconds_elapsed, bool was_idle)
   }
 }
 
-/** Take the 'extend' <b>cell</b>, pull out addr/port plus the onion
- * skin and identity digest for the next hop. If we're already connected,
- * pass the onion skin to the next hop using a create cell; otherwise
- * launch a new OR connection, and <b>circ</b> will notice when the
- * connection succeeds or fails.
- *
- * Return -1 if we want to warn and tear down the circuit, else return 0.
- */
-int
-circuit_extend(cell_t *cell, circuit_t *circ)
-{
-  channel_t *n_chan;
-  relay_header_t rh;
-  extend_cell_t ec;
-  const char *msg = NULL;
-  int should_launch = 0;
-
-  if (circ->n_chan) {
-    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
-           "n_chan already set. Bug/attack. Closing.");
-    return -1;
-  }
-  if (circ->n_hop) {
-    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
-           "conn to next hop already launched. Bug/attack. Closing.");
-    return -1;
-  }
-
-  if (!server_mode(get_options())) {
-    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
-           "Got an extend cell, but running as a client. Closing.");
-    return -1;
-  }
-
-  relay_header_unpack(&rh, cell->payload);
-
-  if (extend_cell_parse(&ec, rh.command,
-                        cell->payload+RELAY_HEADER_SIZE,
-                        rh.length) < 0) {
-    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
-           "Can't parse extend cell. Closing circuit.");
-    return -1;
-  }
-
-  if (!ec.orport_ipv4.port || tor_addr_is_null(&ec.orport_ipv4.addr)) {
-    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
-           "Client asked me to extend to zero destination port or addr.");
-    return -1;
-  }
-
-  if (tor_addr_is_internal(&ec.orport_ipv4.addr, 0) &&
-      !get_options()->ExtendAllowPrivateAddresses) {
-    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
-           "Client asked me to extend to a private address");
-    return -1;
-  }
-
-  /* Check if they asked us for 0000..0000. We support using
-   * an empty fingerprint for the first hop (e.g. for a bridge relay),
-   * but we don't want to let clients send us extend cells for empty
-   * fingerprints -- a) because it opens the user up to a mitm attack,
-   * and b) because it lets an attacker force the relay to hold open a
-   * new TLS connection for each extend request. */
-  if (tor_digest_is_zero((const char*)ec.node_id)) {
-    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
-           "Client asked me to extend without specifying an id_digest.");
-    return -1;
-  }
-
-  /* Fill in ed_pubkey if it was not provided and we can infer it from
-   * our networkstatus */
-  if (ed25519_public_key_is_zero(&ec.ed_pubkey)) {
-    const node_t *node = node_get_by_id((const char*)ec.node_id);
-    const ed25519_public_key_t *node_ed_id = NULL;
-    if (node &&
-        node_supports_ed25519_link_authentication(node, 1) &&
-        (node_ed_id = node_get_ed25519_id(node))) {
-      ed25519_pubkey_copy(&ec.ed_pubkey, node_ed_id);
-    }
-  }
-
-  /* Next, check if we're being asked to connect to the hop that the
-   * extend cell came from. There isn't any reason for that, and it can
-   * assist circular-path attacks. */
-  if (tor_memeq(ec.node_id,
-                TO_OR_CIRCUIT(circ)->p_chan->identity_digest,
-                DIGEST_LEN)) {
-    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
-           "Client asked me to extend back to the previous hop.");
-    return -1;
-  }
-
-  /* Check the previous hop Ed25519 ID too */
-  if (! ed25519_public_key_is_zero(&ec.ed_pubkey) &&
-      ed25519_pubkey_eq(&ec.ed_pubkey,
-                        &TO_OR_CIRCUIT(circ)->p_chan->ed25519_identity)) {
-    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
-           "Client asked me to extend back to the previous hop "
-           "(by Ed25519 ID).");
-    return -1;
-  }
-
-  n_chan = channel_get_for_extend((const char*)ec.node_id,
-                                  &ec.ed_pubkey,
-                                  &ec.orport_ipv4.addr,
-                                  &msg,
-                                  &should_launch);
-
-  if (!n_chan) {
-    log_debug(LD_CIRC|LD_OR,"Next router (%s): %s",
-              fmt_addrport(&ec.orport_ipv4.addr,ec.orport_ipv4.port),
-              msg?msg:"????");
-
-    circ->n_hop = extend_info_new(NULL /*nickname*/,
-                                  (const char*)ec.node_id,
-                                  &ec.ed_pubkey,
-                                  NULL, /*onion_key*/
-                                  NULL, /*curve25519_key*/
-                                  &ec.orport_ipv4.addr,
-                                  ec.orport_ipv4.port);
-
-    circ->n_chan_create_cell = tor_memdup(&ec.create_cell,
-                                          sizeof(ec.create_cell));
-
-    circuit_set_state(circ, CIRCUIT_STATE_CHAN_WAIT);
-
-    if (should_launch) {
-      /* we should try to open a connection */
-      n_chan = channel_connect_for_circuit(&ec.orport_ipv4.addr,
-                                           ec.orport_ipv4.port,
-                                           (const char*)ec.node_id,
-                                           &ec.ed_pubkey);
-      if (!n_chan) {
-        log_info(LD_CIRC,"Launching n_chan failed. Closing circuit.");
-        circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
-        return 0;
-      }
-      log_debug(LD_CIRC,"connecting in progress (or finished). Good.");
-    }
-    /* return success. The onion/circuit/etc will be taken care of
-     * automatically (may already have been) whenever n_chan reaches
-     * OR_CONN_STATE_OPEN.
-     */
-    return 0;
-  }
-
-  tor_assert(!circ->n_hop); /* Connection is already established. */
-  circ->n_chan = n_chan;
-  log_debug(LD_CIRC,
-            "n_chan is %s",
-            channel_get_canonical_remote_descr(n_chan));
-
-  if (circuit_deliver_create_cell(circ, &ec.create_cell, 1) < 0)
-    return -1;
-
-  return 0;
-}
-
 /** A "created" cell <b>reply</b> came back to us on circuit <b>circ</b>.
  * (The body of <b>reply</b> varies depending on what sort of handshake
  * this is.)
@@ -1433,61 +1267,6 @@ circuit_truncated(origin_circuit_t *circ, int reason)
 #endif /* 0 */
 }
 
-/** Given a response payload and keys, initialize, then send a created
- * cell back.
- */
-int
-onionskin_answer(or_circuit_t *circ,
-                 const created_cell_t *created_cell,
-                 const char *keys, size_t keys_len,
-                 const uint8_t *rend_circ_nonce)
-{
-  cell_t cell;
-
-  tor_assert(keys_len == CPATH_KEY_MATERIAL_LEN);
-
-  if (created_cell_format(&cell, created_cell) < 0) {
-    log_warn(LD_BUG,"couldn't format created cell (type=%d, len=%d)",
-             (int)created_cell->cell_type, (int)created_cell->handshake_len);
-    return -1;
-  }
-  cell.circ_id = circ->p_circ_id;
-
-  circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
-
-  log_debug(LD_CIRC,"init digest forward 0x%.8x, backward 0x%.8x.",
-            (unsigned int)get_uint32(keys),
-            (unsigned int)get_uint32(keys+20));
-  if (relay_crypto_init(&circ->crypto, keys, keys_len, 0, 0)<0) {
-    log_warn(LD_BUG,"Circuit initialization failed");
-    return -1;
-  }
-
-  memcpy(circ->rend_circ_nonce, rend_circ_nonce, DIGEST_LEN);
-
-  int used_create_fast = (created_cell->cell_type == CELL_CREATED_FAST);
-
-  append_cell_to_circuit_queue(TO_CIRCUIT(circ),
-                               circ->p_chan, &cell, CELL_DIRECTION_IN, 0);
-  log_debug(LD_CIRC,"Finished sending '%s' cell.",
-            used_create_fast ? "created_fast" : "created");
-
-  /* Ignore the local bit when ExtendAllowPrivateAddresses is set:
-   * it violates the assumption that private addresses are local.
-   * Also, many test networks run on local addresses, and
-   * TestingTorNetwork sets ExtendAllowPrivateAddresses. */
-  if ((!channel_is_local(circ->p_chan)
-       || get_options()->ExtendAllowPrivateAddresses)
-      && !channel_is_outgoing(circ->p_chan)) {
-    /* record that we could process create cells from a non-local conn
-     * that we didn't initiate; presumably this means that create cells
-     * can reach us too. */
-    router_orport_found_reachable();
-  }
-
-  return 0;
-}
-
 /** Helper for new_route_len().  Choose a circuit length for purpose
  * <b>purpose</b>: DEFAULT_ROUTE_LEN (+ 1 if someone else chose the
  * exit).  If someone else chose the exit, they could be colluding
diff --git a/src/core/or/circuitbuild.h b/src/core/or/circuitbuild.h
index 9a35c36ac..c66c0dc75 100644
--- a/src/core/or/circuitbuild.h
+++ b/src/core/or/circuitbuild.h
@@ -32,15 +32,10 @@ void circuit_n_chan_done(channel_t *chan, int status,
 int circuit_timeout_want_to_count_circ(const origin_circuit_t *circ);
 int circuit_send_next_onion_skin(origin_circuit_t *circ);
 void circuit_note_clock_jumped(int64_t seconds_elapsed, bool was_idle);
-int circuit_extend(cell_t *cell, circuit_t *circ);
 struct created_cell_t;
 int circuit_finish_handshake(origin_circuit_t *circ,
                              const struct created_cell_t *created_cell);
 int circuit_truncated(origin_circuit_t *circ, int reason);
-int onionskin_answer(or_circuit_t *circ,
-                     const struct created_cell_t *created_cell,
-                     const char *keys, size_t keys_len,
-                     const uint8_t *rend_circ_nonce);
 MOCK_DECL(int, circuit_all_predicted_ports_handled, (time_t now,
                                                      int *need_uptime,
                                                      int *need_capacity));
@@ -76,6 +71,20 @@ const node_t *choose_good_entry_server(uint8_t purpose,
                            struct circuit_guard_state_t **guard_state_out);
 void circuit_upgrade_circuits_from_guard_wait(void);
 
+struct ed25519_public_key_t;
+
+channel_t *
+channel_connect_for_circuit(const tor_addr_t *addr,
+                            uint16_t port,
+                            const char *id_digest,
+                            const struct ed25519_public_key_t *ed_id);
+struct create_cell_t;
+
+int
+circuit_deliver_create_cell(circuit_t *circ,
+                            const struct create_cell_t *create_cell,
+                            int relayed);
+
 #ifdef CIRCUITBUILD_PRIVATE
 STATIC circid_t get_unique_circ_id_by_chan(channel_t *chan);
 STATIC int new_route_len(uint8_t purpose, extend_info_t *exit_ei,
diff --git a/src/core/or/command.c b/src/core/or/command.c
index 9d946974b..8a1d2066c 100644
--- a/src/core/or/command.c
+++ b/src/core/or/command.c
@@ -54,6 +54,7 @@
 #include "feature/nodelist/describe.h"
 #include "feature/nodelist/nodelist.h"
 #include "feature/nodelist/routerlist.h"
+#include "feature/relay/circuitbuild_relay.h"
 #include "feature/relay/routermode.h"
 #include "feature/stats/rephist.h"
 #include "lib/crypt_ops/crypto_util.h"
diff --git a/src/core/or/relay.c b/src/core/or/relay.c
index 5ddabf347..00bbf77b9 100644
--- a/src/core/or/relay.c
+++ b/src/core/or/relay.c
@@ -66,6 +66,7 @@
 #include "lib/crypt_ops/crypto_util.h"
 #include "feature/dircommon/directory.h"
 #include "feature/relay/dns.h"
+#include "feature/relay/circuitbuild_relay.h"
 #include "feature/stats/geoip_stats.h"
 #include "feature/hs/hs_cache.h"
 #include "core/mainloop/mainloop.h"
diff --git a/src/feature/relay/circuitbuild_relay.c b/src/feature/relay/circuitbuild_relay.c
new file mode 100644
index 000000000..f167d0a8e
--- /dev/null
+++ b/src/feature/relay/circuitbuild_relay.c
@@ -0,0 +1,253 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file circuitbuild_relay.c
+ * @brief Implements the details of exteding circuits (by relaying extend
+ * cells as create cells, and answering create cells).
+ *
+ * On the server side, this module handles the logic of responding to
+ * RELAY_EXTEND requests, using circuit_extend() and onionskin_answer().
+ *
+ * The shared client and server code is in core/or/circuitbuild.c.
+ **/
+
+#include "orconfig.h"
+#include "feature/relay/circuitbuild_relay.h"
+
+#include "core/or/or.h"
+#include "app/config/config.h"
+
+#include "core/crypto/relay_crypto.h"
+
+#include "core/or/cell_st.h"
+#include "core/or/circuit_st.h"
+#include "core/or/extend_info_st.h"
+#include "core/or/or_circuit_st.h"
+
+#include "core/or/channel.h"
+#include "core/or/circuitbuild.h"
+#include "core/or/circuitlist.h"
+#include "core/or/onion.h"
+#include "core/or/relay.h"
+
+#include "feature/nodelist/nodelist.h"
+
+#include "feature/relay/routermode.h"
+#include "feature/relay/selftest.h"
+
+/** Take the 'extend' <b>cell</b>, pull out addr/port plus the onion
+ * skin and identity digest for the next hop. If we're already connected,
+ * pass the onion skin to the next hop using a create cell; otherwise
+ * launch a new OR connection, and <b>circ</b> will notice when the
+ * connection succeeds or fails.
+ *
+ * Return -1 if we want to warn and tear down the circuit, else return 0.
+ */
+int
+circuit_extend(struct cell_t *cell, struct circuit_t *circ)
+{
+  channel_t *n_chan;
+  relay_header_t rh;
+  extend_cell_t ec;
+  const char *msg = NULL;
+  int should_launch = 0;
+
+  if (circ->n_chan) {
+    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+           "n_chan already set. Bug/attack. Closing.");
+    return -1;
+  }
+  if (circ->n_hop) {
+    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+           "conn to next hop already launched. Bug/attack. Closing.");
+    return -1;
+  }
+
+  if (!server_mode(get_options())) {
+    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+           "Got an extend cell, but running as a client. Closing.");
+    return -1;
+  }
+
+  relay_header_unpack(&rh, cell->payload);
+
+  if (extend_cell_parse(&ec, rh.command,
+                        cell->payload+RELAY_HEADER_SIZE,
+                        rh.length) < 0) {
+    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+           "Can't parse extend cell. Closing circuit.");
+    return -1;
+  }
+
+  if (!ec.orport_ipv4.port || tor_addr_is_null(&ec.orport_ipv4.addr)) {
+    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+           "Client asked me to extend to zero destination port or addr.");
+    return -1;
+  }
+
+  if (tor_addr_is_internal(&ec.orport_ipv4.addr, 0) &&
+      !get_options()->ExtendAllowPrivateAddresses) {
+    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+           "Client asked me to extend to a private address");
+    return -1;
+  }
+
+  /* Check if they asked us for 0000..0000. We support using
+   * an empty fingerprint for the first hop (e.g. for a bridge relay),
+   * but we don't want to let clients send us extend cells for empty
+   * fingerprints -- a) because it opens the user up to a mitm attack,
+   * and b) because it lets an attacker force the relay to hold open a
+   * new TLS connection for each extend request. */
+  if (tor_digest_is_zero((const char*)ec.node_id)) {
+    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+           "Client asked me to extend without specifying an id_digest.");
+    return -1;
+  }
+
+  /* Fill in ed_pubkey if it was not provided and we can infer it from
+   * our networkstatus */
+  if (ed25519_public_key_is_zero(&ec.ed_pubkey)) {
+    const node_t *node = node_get_by_id((const char*)ec.node_id);
+    const ed25519_public_key_t *node_ed_id = NULL;
+    if (node &&
+        node_supports_ed25519_link_authentication(node, 1) &&
+        (node_ed_id = node_get_ed25519_id(node))) {
+      ed25519_pubkey_copy(&ec.ed_pubkey, node_ed_id);
+    }
+  }
+
+  /* Next, check if we're being asked to connect to the hop that the
+   * extend cell came from. There isn't any reason for that, and it can
+   * assist circular-path attacks. */
+  if (tor_memeq(ec.node_id,
+                TO_OR_CIRCUIT(circ)->p_chan->identity_digest,
+                DIGEST_LEN)) {
+    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+           "Client asked me to extend back to the previous hop.");
+    return -1;
+  }
+
+  /* Check the previous hop Ed25519 ID too */
+  if (! ed25519_public_key_is_zero(&ec.ed_pubkey) &&
+      ed25519_pubkey_eq(&ec.ed_pubkey,
+                        &TO_OR_CIRCUIT(circ)->p_chan->ed25519_identity)) {
+    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+           "Client asked me to extend back to the previous hop "
+           "(by Ed25519 ID).");
+    return -1;
+  }
+
+  n_chan = channel_get_for_extend((const char*)ec.node_id,
+                                  &ec.ed_pubkey,
+                                  &ec.orport_ipv4.addr,
+                                  &msg,
+                                  &should_launch);
+
+  if (!n_chan) {
+    log_debug(LD_CIRC|LD_OR,"Next router (%s): %s",
+              fmt_addrport(&ec.orport_ipv4.addr,ec.orport_ipv4.port),
+              msg?msg:"????");
+
+    circ->n_hop = extend_info_new(NULL /*nickname*/,
+                                  (const char*)ec.node_id,
+                                  &ec.ed_pubkey,
+                                  NULL, /*onion_key*/
+                                  NULL, /*curve25519_key*/
+                                  &ec.orport_ipv4.addr,
+                                  ec.orport_ipv4.port);
+
+    circ->n_chan_create_cell = tor_memdup(&ec.create_cell,
+                                          sizeof(ec.create_cell));
+
+    circuit_set_state(circ, CIRCUIT_STATE_CHAN_WAIT);
+
+    if (should_launch) {
+      /* we should try to open a connection */
+      n_chan = channel_connect_for_circuit(&ec.orport_ipv4.addr,
+                                           ec.orport_ipv4.port,
+                                           (const char*)ec.node_id,
+                                           &ec.ed_pubkey);
+      if (!n_chan) {
+        log_info(LD_CIRC,"Launching n_chan failed. Closing circuit.");
+        circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
+        return 0;
+      }
+      log_debug(LD_CIRC,"connecting in progress (or finished). Good.");
+    }
+    /* return success. The onion/circuit/etc will be taken care of
+     * automatically (may already have been) whenever n_chan reaches
+     * OR_CONN_STATE_OPEN.
+     */
+    return 0;
+  }
+
+  tor_assert(!circ->n_hop); /* Connection is already established. */
+  circ->n_chan = n_chan;
+  log_debug(LD_CIRC,
+            "n_chan is %s",
+            channel_get_canonical_remote_descr(n_chan));
+
+  if (circuit_deliver_create_cell(circ, &ec.create_cell, 1) < 0)
+    return -1;
+
+  return 0;
+}
+
+/** Given a response payload and keys, initialize, then send a created
+ * cell back.
+ */
+int
+onionskin_answer(struct or_circuit_t *circ,
+                 const created_cell_t *created_cell,
+                 const char *keys, size_t keys_len,
+                 const uint8_t *rend_circ_nonce)
+{
+  cell_t cell;
+
+  tor_assert(keys_len == CPATH_KEY_MATERIAL_LEN);
+
+  if (created_cell_format(&cell, created_cell) < 0) {
+    log_warn(LD_BUG,"couldn't format created cell (type=%d, len=%d)",
+             (int)created_cell->cell_type, (int)created_cell->handshake_len);
+    return -1;
+  }
+  cell.circ_id = circ->p_circ_id;
+
+  circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
+
+  log_debug(LD_CIRC,"init digest forward 0x%.8x, backward 0x%.8x.",
+            (unsigned int)get_uint32(keys),
+            (unsigned int)get_uint32(keys+20));
+  if (relay_crypto_init(&circ->crypto, keys, keys_len, 0, 0)<0) {
+    log_warn(LD_BUG,"Circuit initialization failed");
+    return -1;
+  }
+
+  memcpy(circ->rend_circ_nonce, rend_circ_nonce, DIGEST_LEN);
+
+  int used_create_fast = (created_cell->cell_type == CELL_CREATED_FAST);
+
+  append_cell_to_circuit_queue(TO_CIRCUIT(circ),
+                               circ->p_chan, &cell, CELL_DIRECTION_IN, 0);
+  log_debug(LD_CIRC,"Finished sending '%s' cell.",
+            used_create_fast ? "created_fast" : "created");
+
+  /* Ignore the local bit when ExtendAllowPrivateAddresses is set:
+   * it violates the assumption that private addresses are local.
+   * Also, many test networks run on local addresses, and
+   * TestingTorNetwork sets ExtendAllowPrivateAddresses. */
+  if ((!channel_is_local(circ->p_chan)
+       || get_options()->ExtendAllowPrivateAddresses)
+      && !channel_is_outgoing(circ->p_chan)) {
+    /* record that we could process create cells from a non-local conn
+     * that we didn't initiate; presumably this means that create cells
+     * can reach us too. */
+    router_orport_found_reachable();
+  }
+
+  return 0;
+}
diff --git a/src/feature/relay/circuitbuild_relay.h b/src/feature/relay/circuitbuild_relay.h
new file mode 100644
index 000000000..decc28d3a
--- /dev/null
+++ b/src/feature/relay/circuitbuild_relay.h
@@ -0,0 +1,60 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file circuitbuild_relay.h
+ * @brief Header for feature/relay/circuitbuild_relay.c
+ **/
+
+#ifndef TOR_FEATURE_RELAY_CIRCUITBUILD_RELAY_H
+#define TOR_FEATURE_RELAY_CIRCUITBUILD_RELAY_H
+
+#include "lib/cc/torint.h"
+
+struct cell_t;
+struct created_cell_t;
+
+struct circuit_t;
+struct or_circuit_t;
+
+#ifdef HAVE_MODULE_RELAY
+
+int circuit_extend(struct cell_t *cell, struct circuit_t *circ);
+
+int onionskin_answer(struct or_circuit_t *circ,
+                     const struct created_cell_t *created_cell,
+                     const char *keys, size_t keys_len,
+                     const uint8_t *rend_circ_nonce);
+
+#else
+
+static inline int
+circuit_extend(struct cell_t *cell, struct circuit_t *circ)
+{
+  (void)cell;
+  (void)circ;
+  tor_assert_nonfatal_unreached();
+  return -1;
+}
+
+static inline int
+onionskin_answer(struct or_circuit_t *circ,
+                 const struct created_cell_t *created_cell,
+                 const char *keys, size_t keys_len,
+                 const uint8_t *rend_circ_nonce)
+{
+  (void)circ;
+  (void)created_cell;
+  (void)keys;
+  (void)keys_len;
+  (void)rend_circ_nonce;
+  tor_assert_nonfatal_unreached();
+  return -1;
+}
+
+#endif
+
+#endif /* !defined(TOR_FEATURE_RELAY_CIRCUITBUILD_RELAY_H) */
diff --git a/src/feature/relay/include.am b/src/feature/relay/include.am
index 813ddb8fb..654432c34 100644
--- a/src/feature/relay/include.am
+++ b/src/feature/relay/include.am
@@ -8,6 +8,7 @@ LIBTOR_APP_A_SOURCES += 			\
 
 # ADD_C_FILE: INSERT SOURCES HERE.
 MODULE_RELAY_SOURCES = 						\
+	src/feature/relay/circuitbuild_relay.c			\
 	src/feature/relay/dns.c					\
 	src/feature/relay/ext_orport.c		                \
 	src/feature/relay/routermode.c				\
@@ -21,6 +22,7 @@ MODULE_RELAY_SOURCES = 						\
 
 # ADD_C_FILE: INSERT HEADERS HERE.
 noinst_HEADERS +=					\
+	src/feature/relay/circuitbuild_relay.h		\
 	src/feature/relay/dns.h				\
 	src/feature/relay/dns_structs.h			\
 	src/feature/relay/ext_orport.h			\





More information about the tor-commits mailing list