tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

ext_orport.c (22101B)


      1 /* Copyright (c) 2012-2021, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      4 /**
      5 * \file ext_orport.c
      6 * \brief Code implementing the Extended ORPort.
      7 *
      8 * The Extended ORPort interface is used by pluggable transports to
      9 * communicate additional information to a Tor bridge, including
     10 * address information. For more information on this interface,
     11 * see pt-spec.txt in torspec.git.
     12 *
     13 * There is no separate structure for extended ORPort connections; they use
     14 * or_connection_t objects, and share most of their implementation with
     15 * connection_or.c.  Once the handshake is done, an extended ORPort connection
     16 * turns into a regular OR connection, using connection_ext_or_transition().
     17 */
     18 
     19 #define EXT_ORPORT_PRIVATE
     20 #include "core/or/or.h"
     21 #include "core/mainloop/connection.h"
     22 #include "core/or/connection_or.h"
     23 #include "feature/control/control_events.h"
     24 #include "app/config/config.h"
     25 #include "lib/crypt_ops/crypto_rand.h"
     26 #include "lib/crypt_ops/crypto_util.h"
     27 #include "feature/relay/ext_orport.h"
     28 #include "core/mainloop/mainloop.h"
     29 #include "core/proto/proto_ext_or.h"
     30 
     31 #include "core/or/or_connection_st.h"
     32 
     33 /** Allocate and return a structure capable of holding an Extended
     34 *  ORPort message of body length <b>len</b>. */
     35 ext_or_cmd_t *
     36 ext_or_cmd_new(uint16_t len)
     37 {
     38  size_t size = offsetof(ext_or_cmd_t, body) + len;
     39  ext_or_cmd_t *cmd = tor_malloc(size);
     40  cmd->len = len;
     41  return cmd;
     42 }
     43 
     44 /** Deallocate the Extended ORPort message in <b>cmd</b>. */
     45 void
     46 ext_or_cmd_free_(ext_or_cmd_t *cmd)
     47 {
     48  tor_free(cmd);
     49 }
     50 
     51 /** Get an Extended ORPort message from <b>conn</b>, and place it in
     52 *  <b>out</b>. Return -1 on fail, 0 if we need more data, and 1 if we
     53 *  successfully extracted an Extended ORPort command from the
     54 *  buffer.  */
     55 static int
     56 connection_fetch_ext_or_cmd_from_buf(connection_t *conn, ext_or_cmd_t **out)
     57 {
     58  return fetch_ext_or_command_from_buf(conn->inbuf, out);
     59 }
     60 
     61 /** Write an Extended ORPort message to <b>conn</b>. Use
     62 *  <b>command</b> as the command type, <b>bodylen</b> as the body
     63 *  length, and <b>body</b>, if it's present, as the body of the
     64 *  message. */
     65 STATIC int
     66 connection_write_ext_or_command(connection_t *conn,
     67                                uint16_t command,
     68                                const char *body,
     69                                size_t bodylen)
     70 {
     71  char header[4];
     72  if (bodylen > UINT16_MAX)
     73    return -1;
     74  set_uint16(header, htons(command));
     75  set_uint16(header+2, htons(bodylen));
     76  connection_buf_add(header, 4, conn);
     77  if (bodylen) {
     78    tor_assert(body);
     79    connection_buf_add(body, bodylen, conn);
     80  }
     81  return 0;
     82 }
     83 
     84 /** Transition from an Extended ORPort which accepts Extended ORPort
     85 *  messages, to an Extended ORport which accepts OR traffic. */
     86 static void
     87 connection_ext_or_transition(or_connection_t *conn)
     88 {
     89  tor_assert(conn->base_.type == CONN_TYPE_EXT_OR);
     90 
     91  conn->base_.type = CONN_TYPE_OR;
     92  TO_CONN(conn)->state = 0; // set the state to a neutral value
     93  connection_or_event_status(conn, OR_CONN_EVENT_NEW, 0);
     94  connection_tls_start_handshake(conn, 1);
     95 }
     96 
     97 /** Length of authentication cookie. */
     98 #define EXT_OR_PORT_AUTH_COOKIE_LEN 32
     99 /** Length of the header of the cookie file. */
    100 #define EXT_OR_PORT_AUTH_COOKIE_HEADER_LEN 32
    101 /** Static cookie file header. */
    102 #define EXT_OR_PORT_AUTH_COOKIE_HEADER "! Extended ORPort Auth Cookie !\x0a"
    103 /** Length of safe-cookie protocol hashes. */
    104 #define EXT_OR_PORT_AUTH_HASH_LEN DIGEST256_LEN
    105 /** Length of safe-cookie protocol nonces. */
    106 #define EXT_OR_PORT_AUTH_NONCE_LEN 32
    107 /** Safe-cookie protocol constants. */
    108 #define EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST \
    109  "ExtORPort authentication server-to-client hash"
    110 #define EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST \
    111  "ExtORPort authentication client-to-server hash"
    112 
    113 /* Code to indicate cookie authentication */
    114 #define EXT_OR_AUTHTYPE_SAFECOOKIE 0x01
    115 
    116 /** If true, we've set ext_or_auth_cookie to a secret code and stored
    117 * it to disk. */
    118 STATIC int ext_or_auth_cookie_is_set = 0;
    119 /** If ext_or_auth_cookie_is_set, a secret cookie that we've stored to disk
    120 * and which we're using to authenticate controllers.  (If the controller can
    121 * read it off disk, it has permission to connect.) */
    122 STATIC uint8_t *ext_or_auth_cookie = NULL;
    123 
    124 /** Helper: Return a newly allocated string containing a path to the
    125 * file where we store our authentication cookie. */
    126 char *
    127 get_ext_or_auth_cookie_file_name(void)
    128 {
    129  const or_options_t *options = get_options();
    130  if (options->ExtORPortCookieAuthFile &&
    131      strlen(options->ExtORPortCookieAuthFile)) {
    132    return tor_strdup(options->ExtORPortCookieAuthFile);
    133  } else {
    134    return get_datadir_fname("extended_orport_auth_cookie");
    135  }
    136 }
    137 
    138 /* Initialize the cookie-based authentication system of the
    139 * Extended ORPort. If <b>is_enabled</b> is 0, then disable the cookie
    140 * authentication system. */
    141 int
    142 init_ext_or_cookie_authentication(int is_enabled)
    143 {
    144  char *fname = NULL;
    145  int retval;
    146 
    147  if (!is_enabled) {
    148    ext_or_auth_cookie_is_set = 0;
    149    return 0;
    150  }
    151 
    152  fname = get_ext_or_auth_cookie_file_name();
    153  retval = init_cookie_authentication(fname, EXT_OR_PORT_AUTH_COOKIE_HEADER,
    154                                      EXT_OR_PORT_AUTH_COOKIE_HEADER_LEN,
    155                           get_options()->ExtORPortCookieAuthFileGroupReadable,
    156                                      &ext_or_auth_cookie,
    157                                      &ext_or_auth_cookie_is_set);
    158  tor_free(fname);
    159  return retval;
    160 }
    161 
    162 /** Read data from <b>conn</b> and see if the client sent us the
    163 *  authentication type that they prefer to use in this session.
    164 *
    165 *  Return -1 if we received corrupted data or if we don't support the
    166 *  authentication type. Return 0 if we need more data in
    167 *  <b>conn</b>. Return 1 if the authentication type negotiation was
    168 *  successful. */
    169 static int
    170 connection_ext_or_auth_neg_auth_type(connection_t *conn)
    171 {
    172  char authtype[1] = {0};
    173 
    174  if (connection_get_inbuf_len(conn) < 1)
    175    return 0;
    176 
    177  if (connection_buf_get_bytes(authtype, 1, conn) < 0)
    178    return -1;
    179 
    180  log_debug(LD_GENERAL, "Client wants us to use %d auth type", authtype[0]);
    181  if (authtype[0] != EXT_OR_AUTHTYPE_SAFECOOKIE) {
    182    /* '1' is the only auth type supported atm */
    183    return -1;
    184  }
    185 
    186  conn->state = EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE;
    187  return 1;
    188 }
    189 
    190 /* DOCDOC */
    191 STATIC int
    192 handle_client_auth_nonce(const char *client_nonce, size_t client_nonce_len,
    193                         char **client_hash_out,
    194                         char **reply_out, size_t *reply_len_out)
    195 {
    196  char server_hash[EXT_OR_PORT_AUTH_HASH_LEN] = {0};
    197  char server_nonce[EXT_OR_PORT_AUTH_NONCE_LEN] = {0};
    198  char *reply;
    199  size_t reply_len;
    200 
    201  if (client_nonce_len != EXT_OR_PORT_AUTH_NONCE_LEN)
    202    return -1;
    203 
    204  /* Get our nonce */
    205  crypto_rand(server_nonce, EXT_OR_PORT_AUTH_NONCE_LEN);
    206 
    207  { /* set up macs */
    208    size_t hmac_s_msg_len = strlen(EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST) +
    209      2*EXT_OR_PORT_AUTH_NONCE_LEN;
    210    size_t hmac_c_msg_len = strlen(EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST) +
    211      2*EXT_OR_PORT_AUTH_NONCE_LEN;
    212 
    213    char *hmac_s_msg = tor_malloc_zero(hmac_s_msg_len);
    214    char *hmac_c_msg = tor_malloc_zero(hmac_c_msg_len);
    215    char *correct_client_hash = tor_malloc_zero(EXT_OR_PORT_AUTH_HASH_LEN);
    216 
    217    memcpy(hmac_s_msg,
    218           EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST,
    219           strlen(EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST));
    220    memcpy(hmac_s_msg + strlen(EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST),
    221           client_nonce, EXT_OR_PORT_AUTH_NONCE_LEN);
    222    memcpy(hmac_s_msg + strlen(EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST) +
    223           EXT_OR_PORT_AUTH_NONCE_LEN,
    224           server_nonce, EXT_OR_PORT_AUTH_NONCE_LEN);
    225 
    226    memcpy(hmac_c_msg,
    227           EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST,
    228           strlen(EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST));
    229    memcpy(hmac_c_msg + strlen(EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST),
    230           client_nonce, EXT_OR_PORT_AUTH_NONCE_LEN);
    231    memcpy(hmac_c_msg + strlen(EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST) +
    232           EXT_OR_PORT_AUTH_NONCE_LEN,
    233           server_nonce, EXT_OR_PORT_AUTH_NONCE_LEN);
    234 
    235    crypto_hmac_sha256(server_hash,
    236                       (char*)ext_or_auth_cookie,
    237                       EXT_OR_PORT_AUTH_COOKIE_LEN,
    238                       hmac_s_msg,
    239                       hmac_s_msg_len);
    240 
    241    crypto_hmac_sha256(correct_client_hash,
    242                       (char*)ext_or_auth_cookie,
    243                       EXT_OR_PORT_AUTH_COOKIE_LEN,
    244                       hmac_c_msg,
    245                       hmac_c_msg_len);
    246 
    247    /* Store the client hash we generated. We will need to compare it
    248       with the hash sent by the client. */
    249    *client_hash_out = correct_client_hash;
    250 
    251    memwipe(hmac_s_msg, 0, hmac_s_msg_len);
    252    memwipe(hmac_c_msg, 0, hmac_c_msg_len);
    253 
    254    tor_free(hmac_s_msg);
    255    tor_free(hmac_c_msg);
    256  }
    257 
    258  { /* debug logging */ /* XXX disable this codepath if not logging on debug?*/
    259    char server_hash_encoded[(2*EXT_OR_PORT_AUTH_HASH_LEN) + 1];
    260    char server_nonce_encoded[(2*EXT_OR_PORT_AUTH_NONCE_LEN) + 1];
    261    char client_nonce_encoded[(2*EXT_OR_PORT_AUTH_NONCE_LEN) + 1];
    262 
    263    base16_encode(server_hash_encoded, sizeof(server_hash_encoded),
    264                  server_hash, sizeof(server_hash));
    265    base16_encode(server_nonce_encoded, sizeof(server_nonce_encoded),
    266                  server_nonce, sizeof(server_nonce));
    267    base16_encode(client_nonce_encoded, sizeof(client_nonce_encoded),
    268                  client_nonce, EXT_OR_PORT_AUTH_NONCE_LEN);
    269 
    270    log_debug(LD_GENERAL,
    271              "server_hash: '%s'\nserver_nonce: '%s'\nclient_nonce: '%s'",
    272              server_hash_encoded, server_nonce_encoded, client_nonce_encoded);
    273 
    274    memwipe(server_hash_encoded, 0, sizeof(server_hash_encoded));
    275    memwipe(server_nonce_encoded, 0, sizeof(server_nonce_encoded));
    276    memwipe(client_nonce_encoded, 0, sizeof(client_nonce_encoded));
    277  }
    278 
    279  { /* write reply: (server_hash, server_nonce) */
    280 
    281    reply_len = EXT_OR_PORT_AUTH_COOKIE_LEN+EXT_OR_PORT_AUTH_NONCE_LEN;
    282    reply = tor_malloc_zero(reply_len);
    283    memcpy(reply, server_hash, EXT_OR_PORT_AUTH_HASH_LEN);
    284    memcpy(reply + EXT_OR_PORT_AUTH_HASH_LEN, server_nonce,
    285           EXT_OR_PORT_AUTH_NONCE_LEN);
    286  }
    287 
    288  *reply_out = reply;
    289  *reply_len_out = reply_len;
    290 
    291  return 0;
    292 }
    293 
    294 /** Read the client's nonce out of <b>conn</b>, setup the safe-cookie
    295 *  crypto, and then send our own hash and nonce to the client
    296 *
    297 *  Return -1 if there was an error; return 0 if we need more data in
    298 *  <b>conn</b>, and return 1 if we successfully retrieved the
    299 *  client's nonce and sent our own. */
    300 static int
    301 connection_ext_or_auth_handle_client_nonce(connection_t *conn)
    302 {
    303  char client_nonce[EXT_OR_PORT_AUTH_NONCE_LEN];
    304  char *reply=NULL;
    305  size_t reply_len=0;
    306 
    307  if (!ext_or_auth_cookie_is_set) { /* this should not happen */
    308    log_warn(LD_BUG, "Extended ORPort authentication cookie was not set. "
    309             "That's weird since we should have done that on startup. "
    310             "This might be a Tor bug, please file a bug report. ");
    311    return -1;
    312  }
    313 
    314  if (connection_get_inbuf_len(conn) < EXT_OR_PORT_AUTH_NONCE_LEN)
    315    return 0;
    316 
    317  if (connection_buf_get_bytes(client_nonce,
    318                                EXT_OR_PORT_AUTH_NONCE_LEN, conn) < 0)
    319    return -1;
    320 
    321  /* We extract the ClientNonce from the received data, and use it to
    322     calculate ServerHash and ServerNonce according to proposal 217.
    323 
    324     We also calculate our own ClientHash value and save it in the
    325     connection state. We validate it later against the ClientHash
    326     sent by the client.  */
    327  if (handle_client_auth_nonce(client_nonce, sizeof(client_nonce),
    328                            &TO_OR_CONN(conn)->ext_or_auth_correct_client_hash,
    329                            &reply, &reply_len) < 0)
    330    return -1;
    331 
    332  connection_buf_add(reply, reply_len, conn);
    333 
    334  memwipe(reply, 0, reply_len);
    335  tor_free(reply);
    336 
    337  log_debug(LD_GENERAL, "Got client nonce, and sent our own nonce and hash.");
    338 
    339  conn->state = EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH;
    340  return 1;
    341 }
    342 
    343 #define connection_ext_or_auth_send_result_success(c)  \
    344  connection_ext_or_auth_send_result(c, 1)
    345 #define connection_ext_or_auth_send_result_fail(c)  \
    346  connection_ext_or_auth_send_result(c, 0)
    347 
    348 /** Send authentication results to <b>conn</b>. Successful results if
    349 *  <b>success</b> is set; failure results otherwise. */
    350 static void
    351 connection_ext_or_auth_send_result(connection_t *conn, int success)
    352 {
    353  if (success)
    354    connection_buf_add("\x01", 1, conn);
    355  else
    356    connection_buf_add("\x00", 1, conn);
    357 }
    358 
    359 /** Receive the client's hash from <b>conn</b>, validate that it's
    360 *  correct, and then send the authentication results to the client.
    361 *
    362 *  Return -1 if there was an error during validation; return 0 if we
    363 *  need more data in <b>conn</b>, and return 1 if we successfully
    364 *  validated the client's hash and sent a happy authentication
    365 *  result. */
    366 static int
    367 connection_ext_or_auth_handle_client_hash(connection_t *conn)
    368 {
    369  char provided_client_hash[EXT_OR_PORT_AUTH_HASH_LEN] = {0};
    370 
    371  if (connection_get_inbuf_len(conn) < EXT_OR_PORT_AUTH_HASH_LEN)
    372    return 0;
    373 
    374  if (connection_buf_get_bytes(provided_client_hash,
    375                                EXT_OR_PORT_AUTH_HASH_LEN, conn) < 0)
    376    return -1;
    377 
    378  if (tor_memneq(TO_OR_CONN(conn)->ext_or_auth_correct_client_hash,
    379                 provided_client_hash, EXT_OR_PORT_AUTH_HASH_LEN)) {
    380    log_warn(LD_GENERAL, "Incorrect client hash. Authentication failed.");
    381    connection_ext_or_auth_send_result_fail(conn);
    382    return -1;
    383  }
    384 
    385  log_debug(LD_GENERAL, "Got client's hash and it was legit.");
    386 
    387  /* send positive auth result */
    388  connection_ext_or_auth_send_result_success(conn);
    389  conn->state = EXT_OR_CONN_STATE_OPEN;
    390  return 1;
    391 }
    392 
    393 /** Handle data from <b>or_conn</b> received on Extended ORPort.
    394 *  Return -1 on error. 0 on insufficient data. 1 on correct. */
    395 static int
    396 connection_ext_or_auth_process_inbuf(or_connection_t *or_conn)
    397 {
    398  connection_t *conn = TO_CONN(or_conn);
    399 
    400  /* State transitions of the Extended ORPort authentication protocol:
    401 
    402     EXT_OR_CONN_STATE_AUTH_WAIT_AUTH_TYPE (start state) ->
    403     EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE ->
    404     EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH ->
    405     EXT_OR_CONN_STATE_OPEN
    406 
    407     During EXT_OR_CONN_STATE_OPEN, data is handled by
    408     connection_ext_or_process_inbuf().
    409  */
    410 
    411  switch (conn->state) { /* Functionify */
    412  case EXT_OR_CONN_STATE_AUTH_WAIT_AUTH_TYPE:
    413    return connection_ext_or_auth_neg_auth_type(conn);
    414 
    415  case EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE:
    416    return connection_ext_or_auth_handle_client_nonce(conn);
    417 
    418  case EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH:
    419    return connection_ext_or_auth_handle_client_hash(conn);
    420 
    421  default:
    422    log_warn(LD_BUG, "Encountered unexpected connection state %d while trying "
    423             "to process Extended ORPort authentication data.", conn->state);
    424    return -1;
    425  }
    426 }
    427 
    428 /** Extended ORPort commands (Transport-to-Bridge) */
    429 #define EXT_OR_CMD_TB_DONE 0x0000
    430 #define EXT_OR_CMD_TB_USERADDR 0x0001
    431 #define EXT_OR_CMD_TB_TRANSPORT 0x0002
    432 
    433 /** Extended ORPort commands (Bridge-to-Transport) */
    434 #define EXT_OR_CMD_BT_OKAY 0x1000
    435 #define EXT_OR_CMD_BT_DENY 0x1001
    436 #define EXT_OR_CMD_BT_CONTROL 0x1002
    437 
    438 /** Process a USERADDR command from the Extended
    439 *  ORPort. <b>payload</b> is a payload of size <b>len</b>.
    440 *
    441 *  If the USERADDR command was well formed, change the address of
    442 *  <b>conn</b> to the address on the USERADDR command.
    443 *
    444 *  Return 0 on success and -1 on error. */
    445 static int
    446 connection_ext_or_handle_cmd_useraddr(connection_t *conn,
    447                                      const char *payload, uint16_t len)
    448 {
    449  /* Copy address string. */
    450  tor_addr_t addr;
    451  uint16_t port;
    452  char *addr_str;
    453  char *address_part=NULL;
    454  int res;
    455  if (memchr(payload, '\0', len)) {
    456    log_fn(LOG_PROTOCOL_WARN, LD_NET, "Unexpected NUL in ExtORPort UserAddr");
    457    return -1;
    458  }
    459 
    460  addr_str = tor_memdup_nulterm(payload, len);
    461 
    462  res = tor_addr_port_split(LOG_INFO, addr_str, &address_part, &port);
    463  tor_free(addr_str);
    464  if (res<0)
    465    return -1;
    466  if (port == 0) {
    467    log_warn(LD_GENERAL, "Server transport proxy gave us an empty port "
    468             "in ExtORPort UserAddr command.");
    469    // return -1; // enable this if nothing breaks after a while.
    470  }
    471 
    472  res = tor_addr_parse(&addr, address_part);
    473  tor_free(address_part);
    474  if (res<0)
    475    return -1;
    476 
    477  { /* do some logging */
    478    char *old_address = tor_addr_to_str_dup(&conn->addr);
    479    char *new_address = tor_addr_to_str_dup(&addr);
    480 
    481    log_debug(LD_NET, "Received USERADDR."
    482             "We rewrite our address from '%s:%u' to '%s:%u'.",
    483             safe_str(old_address), conn->port, safe_str(new_address), port);
    484 
    485    tor_free(old_address);
    486    tor_free(new_address);
    487  }
    488 
    489  /* record the address */
    490  tor_addr_copy(&conn->addr, &addr);
    491  conn->port = port;
    492  if (conn->address) {
    493    tor_free(conn->address);
    494  }
    495  conn->address = tor_addr_to_str_dup(&addr);
    496 
    497  /* Now that we know the address, we don't have to manually override rate
    498   * limiting. */
    499  conn->always_rate_limit_as_remote = 0;
    500 
    501  return 0;
    502 }
    503 
    504 /** Process a TRANSPORT command from the Extended
    505 *  ORPort. <b>payload</b> is a payload of size <b>len</b>.
    506 *
    507 *  If the TRANSPORT command was well formed, register the name of the
    508 *  transport on <b>conn</b>.
    509 *
    510 *  Return 0 on success and -1 on error. */
    511 static int
    512 connection_ext_or_handle_cmd_transport(or_connection_t *conn,
    513                                       const char *payload, uint16_t len)
    514 {
    515  char *transport_str;
    516  if (memchr(payload, '\0', len)) {
    517    log_fn(LOG_PROTOCOL_WARN, LD_NET, "Unexpected NUL in ExtORPort Transport");
    518    return -1;
    519  }
    520 
    521  transport_str = tor_memdup_nulterm(payload, len);
    522 
    523  /* Transport names MUST be C-identifiers. */
    524  if (!string_is_C_identifier(transport_str)) {
    525    tor_free(transport_str);
    526    return -1;
    527  }
    528 
    529  /* If ext_or_transport is already occupied (because the PT sent two
    530   *  TRANSPORT commands), deallocate the old name and keep the new
    531   *  one */
    532  if (conn->ext_or_transport)
    533    tor_free(conn->ext_or_transport);
    534 
    535  conn->ext_or_transport = transport_str;
    536  return 0;
    537 }
    538 
    539 #define EXT_OR_CONN_STATE_IS_AUTHENTICATING(st) \
    540  ((st) <= EXT_OR_CONN_STATE_AUTH_MAX)
    541 
    542 /** Process Extended ORPort messages from <b>or_conn</b>. */
    543 int
    544 connection_ext_or_process_inbuf(or_connection_t *or_conn)
    545 {
    546  connection_t *conn = TO_CONN(or_conn);
    547  ext_or_cmd_t *command;
    548  int r;
    549 
    550  /* DOCDOC Document the state machine and transitions in this function */
    551 
    552  /* If we are still in the authentication stage, process traffic as
    553     authentication data: */
    554  while (EXT_OR_CONN_STATE_IS_AUTHENTICATING(conn->state)) {
    555    log_debug(LD_GENERAL, "Got Extended ORPort authentication data (%u).",
    556              (unsigned int) connection_get_inbuf_len(conn));
    557    r = connection_ext_or_auth_process_inbuf(or_conn);
    558    if (r < 0) {
    559      connection_mark_for_close(conn);
    560      return -1;
    561    } else if (r == 0) {
    562      return 0;
    563    }
    564    /* if r > 0, loop and process more data (if any). */
    565  }
    566 
    567  while (1) {
    568    log_debug(LD_GENERAL, "Got Extended ORPort data.");
    569    command = NULL;
    570    r = connection_fetch_ext_or_cmd_from_buf(conn, &command);
    571    if (r < 0)
    572      goto err;
    573    else if (r == 0)
    574      return 0; /* need to wait for more data */
    575 
    576    /* Got a command! */
    577    tor_assert(command);
    578 
    579    if (command->cmd == EXT_OR_CMD_TB_DONE) {
    580      if (connection_get_inbuf_len(conn)) {
    581        /* The inbuf isn't empty; the client is misbehaving. */
    582        goto err;
    583      }
    584 
    585      log_debug(LD_NET, "Received DONE.");
    586 
    587      /* If the transport proxy did not use the TRANSPORT command to
    588       * specify the transport name, mark this as unknown transport. */
    589      if (!or_conn->ext_or_transport) {
    590        /* We write this string this way to avoid ??>, which is a C
    591         * trigraph. */
    592        or_conn->ext_or_transport = tor_strdup("<?" "?>");
    593      }
    594 
    595      connection_write_ext_or_command(conn, EXT_OR_CMD_BT_OKAY, NULL, 0);
    596 
    597      /* can't transition immediately; need to flush first. */
    598      conn->state = EXT_OR_CONN_STATE_FLUSHING;
    599      connection_stop_reading(conn);
    600    } else if (command->cmd == EXT_OR_CMD_TB_USERADDR) {
    601      if (connection_ext_or_handle_cmd_useraddr(conn,
    602                                            command->body, command->len) < 0)
    603        goto err;
    604    } else if (command->cmd == EXT_OR_CMD_TB_TRANSPORT) {
    605      if (connection_ext_or_handle_cmd_transport(or_conn,
    606                                             command->body, command->len) < 0)
    607        goto err;
    608    } else {
    609      log_notice(LD_NET,"Got Extended ORPort command we don't recognize (%u).",
    610                 command->cmd);
    611    }
    612 
    613    ext_or_cmd_free(command);
    614  }
    615 
    616  return 0;
    617 
    618 err:
    619  ext_or_cmd_free(command);
    620  connection_mark_for_close(conn);
    621  return -1;
    622 }
    623 
    624 /** <b>conn</b> finished flushing Extended ORPort messages to the
    625 *  network, and is now ready to accept OR traffic. This function
    626 *  does the transition. */
    627 int
    628 connection_ext_or_finished_flushing(or_connection_t *conn)
    629 {
    630  if (conn->base_.state == EXT_OR_CONN_STATE_FLUSHING) {
    631    connection_start_reading(TO_CONN(conn));
    632    connection_ext_or_transition(conn);
    633  }
    634  return 0;
    635 }
    636 
    637 /** Initiate Extended ORPort authentication, by sending the list of
    638 *  supported authentication types to the client. */
    639 int
    640 connection_ext_or_start_auth(or_connection_t *or_conn)
    641 {
    642  connection_t *conn = TO_CONN(or_conn);
    643  const uint8_t authtypes[] = {
    644    /* We only support authtype '1' for now. */
    645    EXT_OR_AUTHTYPE_SAFECOOKIE,
    646    /* Marks the end of the list. */
    647    0
    648  };
    649 
    650  log_debug(LD_GENERAL,
    651           "ExtORPort authentication: Sending supported authentication types");
    652 
    653  connection_buf_add((const char *)authtypes, sizeof(authtypes), conn);
    654  conn->state = EXT_OR_CONN_STATE_AUTH_WAIT_AUTH_TYPE;
    655 
    656  return 0;
    657 }
    658 
    659 /** Free any leftover allocated memory of the ext_orport.c subsystem. */
    660 void
    661 ext_orport_free_all(void)
    662 {
    663  if (ext_or_auth_cookie) /* Free the auth cookie */
    664    tor_free(ext_or_auth_cookie);
    665 }