tor

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

control_fmt.c (11303B)


      1 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
      2 * Copyright (c) 2007-2021, The Tor Project, Inc. */
      3 /* See LICENSE for licensing information */
      4 
      5 /**
      6 * \file control_fmt.c
      7 * \brief Formatting functions for controller data.
      8 */
      9 
     10 #include "core/or/or.h"
     11 
     12 #include "core/mainloop/connection.h"
     13 #include "core/or/circuitbuild.h"
     14 #include "core/or/circuitlist.h"
     15 #include "core/or/connection_edge.h"
     16 #include "feature/control/control_fmt.h"
     17 #include "feature/control/control_proto.h"
     18 #include "feature/nodelist/nodelist.h"
     19 
     20 #include "core/or/cpath_build_state_st.h"
     21 #include "core/or/entry_connection_st.h"
     22 #include "core/or/or_connection_st.h"
     23 #include "core/or/origin_circuit_st.h"
     24 #include "core/or/conflux_util.h"
     25 #include "core/or/socks_request_st.h"
     26 #include "feature/control/control_connection_st.h"
     27 
     28 /** Given an AP connection <b>conn</b> and a <b>len</b>-character buffer
     29 * <b>buf</b>, determine the address:port combination requested on
     30 * <b>conn</b>, and write it to <b>buf</b>.  Return 0 on success, -1 on
     31 * failure. */
     32 int
     33 write_stream_target_to_buf(entry_connection_t *conn, char *buf, size_t len)
     34 {
     35  char buf2[256];
     36  if (conn->chosen_exit_name)
     37    if (tor_snprintf(buf2, sizeof(buf2), ".%s.exit", conn->chosen_exit_name)<0)
     38      return -1;
     39  if (!conn->socks_request)
     40    return -1;
     41  if (tor_snprintf(buf, len, "%s%s%s:%d",
     42               conn->socks_request->address,
     43               conn->chosen_exit_name ? buf2 : "",
     44               !conn->chosen_exit_name && connection_edge_is_rendezvous_stream(
     45                                     ENTRY_TO_EDGE_CONN(conn)) ? ".onion" : "",
     46               conn->socks_request->port)<0)
     47    return -1;
     48  return 0;
     49 }
     50 
     51 /** Figure out the best name for the target router of an OR connection
     52 * <b>conn</b>, and write it into the <b>len</b>-character buffer
     53 * <b>name</b>. */
     54 void
     55 orconn_target_get_name(char *name, size_t len, or_connection_t *conn)
     56 {
     57  const node_t *node = node_get_by_id(conn->identity_digest);
     58  if (node) {
     59    tor_assert(len > MAX_VERBOSE_NICKNAME_LEN);
     60    node_get_verbose_nickname(node, name);
     61  } else if (! tor_digest_is_zero(conn->identity_digest)) {
     62    name[0] = '$';
     63    base16_encode(name+1, len-1, conn->identity_digest,
     64                  DIGEST_LEN);
     65  } else {
     66    tor_snprintf(name, len, "%s:%d",
     67                 conn->base_.address, conn->base_.port);
     68  }
     69 }
     70 
     71 /** Allocate and return a description of <b>circ</b>'s current status,
     72 * including its path (if any). */
     73 char *
     74 circuit_describe_status_for_controller(origin_circuit_t *circ)
     75 {
     76  char *rv;
     77  smartlist_t *descparts = smartlist_new();
     78 
     79  {
     80    char *vpath = circuit_list_path_for_controller(circ);
     81    if (*vpath) {
     82      smartlist_add(descparts, vpath);
     83    } else {
     84      tor_free(vpath); /* empty path; don't put an extra space in the result */
     85    }
     86  }
     87 
     88  {
     89    cpath_build_state_t *build_state = circ->build_state;
     90    smartlist_t *flaglist = smartlist_new();
     91    char *flaglist_joined;
     92 
     93    if (build_state->onehop_tunnel)
     94      smartlist_add(flaglist, (void *)"ONEHOP_TUNNEL");
     95    if (build_state->is_internal)
     96      smartlist_add(flaglist, (void *)"IS_INTERNAL");
     97    if (build_state->need_capacity)
     98      smartlist_add(flaglist, (void *)"NEED_CAPACITY");
     99    if (build_state->need_uptime)
    100      smartlist_add(flaglist, (void *)"NEED_UPTIME");
    101 
    102    /* Only emit a BUILD_FLAGS argument if it will have a non-empty value. */
    103    if (smartlist_len(flaglist)) {
    104      flaglist_joined = smartlist_join_strings(flaglist, ",", 0, NULL);
    105 
    106      smartlist_add_asprintf(descparts, "BUILD_FLAGS=%s", flaglist_joined);
    107 
    108      tor_free(flaglist_joined);
    109    }
    110 
    111    smartlist_free(flaglist);
    112  }
    113 
    114  smartlist_add_asprintf(descparts, "PURPOSE=%s",
    115                    circuit_purpose_to_controller_string(circ->base_.purpose));
    116 
    117  {
    118    const char *hs_state =
    119      circuit_purpose_to_controller_hs_state_string(circ->base_.purpose);
    120 
    121    if (hs_state != NULL) {
    122      smartlist_add_asprintf(descparts, "HS_STATE=%s", hs_state);
    123    }
    124  }
    125 
    126  if (circ->hs_ident != NULL) {
    127    char addr[HS_SERVICE_ADDR_LEN_BASE32 + 1];
    128    const char *onion_address;
    129    hs_build_address(&circ->hs_ident->identity_pk, HS_VERSION_THREE, addr);
    130    onion_address = addr;
    131    smartlist_add_asprintf(descparts, "REND_QUERY=%s", onion_address);
    132  }
    133 
    134  {
    135    char tbuf[ISO_TIME_USEC_LEN+1];
    136    format_iso_time_nospace_usec(tbuf, &circ->base_.timestamp_created);
    137 
    138    smartlist_add_asprintf(descparts, "TIME_CREATED=%s", tbuf);
    139  }
    140 
    141  // Show username and/or password if available.
    142  if (circ->socks_username_len > 0) {
    143    char* socks_username_escaped = esc_for_log_len(circ->socks_username,
    144                                     (size_t) circ->socks_username_len);
    145    smartlist_add_asprintf(descparts, "SOCKS_USERNAME=%s",
    146                           socks_username_escaped);
    147    tor_free(socks_username_escaped);
    148  }
    149  if (circ->socks_password_len > 0) {
    150    char* socks_password_escaped = esc_for_log_len(circ->socks_password,
    151                                     (size_t) circ->socks_password_len);
    152    smartlist_add_asprintf(descparts, "SOCKS_PASSWORD=%s",
    153                           socks_password_escaped);
    154    tor_free(socks_password_escaped);
    155  }
    156 
    157  /* Attach the proof-of-work solution effort, if it's nonzero. Clients set
    158   * this to the effort they've chosen, services set this to a value that
    159   * was provided by the client and then verified by the service. */
    160  if (circ->hs_pow_effort > 0) {
    161    smartlist_add_asprintf(descparts, "HS_POW=v1,%u", circ->hs_pow_effort);
    162  }
    163 
    164  /* Add conflux id and RTT info, for accurate circuit display. The RTT is
    165   * provided to indicate the primary (preferred) circuit of a set
    166   * (which will have the lowest current RTT).
    167   *
    168   * NOTE: Because control port events can happen at arbitrary points, we
    169   * must specifically check exactly what we need from the conflux object.
    170   * We cannot use CIRCUIT_IS_CONFLUX() because this event may have been
    171   * emitted while a set was under partial construction or teardown. */
    172  if (TO_CIRCUIT(circ)->conflux || TO_CIRCUIT(circ)->conflux_pending_nonce) {
    173    const uint8_t *nonce = conflux_get_nonce(TO_CIRCUIT(circ));
    174    tor_assert(nonce);
    175 
    176    /* The conflux nonce is an ephemeral cryptographic secret that if known in
    177     * full, enables confirmation or data injection on a set by adding new legs
    178     * at an exit from elsewhere. Only output half of it. */
    179    smartlist_add_asprintf(descparts, "CONFLUX_ID=%s",
    180                           hex_str((const char *)nonce, DIGEST256_LEN/2));
    181 
    182    /* If we have a conflux object that is fully linked, the circ has an RTT */
    183    if (TO_CIRCUIT(circ)->conflux &&
    184        TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED) {
    185      uint64_t circ_rtt = conflux_get_circ_rtt(TO_CIRCUIT(circ));
    186      if (circ_rtt) {
    187        smartlist_add_asprintf(descparts, "CONFLUX_RTT=%" PRIu64, circ_rtt);
    188      }
    189    }
    190  }
    191 
    192  rv = smartlist_join_strings(descparts, " ", 0, NULL);
    193 
    194  SMARTLIST_FOREACH(descparts, char *, cp, tor_free(cp));
    195  smartlist_free(descparts);
    196 
    197  return rv;
    198 }
    199 
    200 /** Allocate and return a description of <b>conn</b>'s current status. */
    201 char *
    202 entry_connection_describe_status_for_controller(const entry_connection_t *conn)
    203 {
    204  char *rv;
    205  smartlist_t *descparts = smartlist_new();
    206 
    207  if (conn->socks_request != NULL) {
    208    // Show username and/or password if available; used by IsolateSOCKSAuth.
    209    if (conn->socks_request->usernamelen > 0) {
    210      char* username_escaped = esc_for_log_len(conn->socks_request->username,
    211                                 (size_t) conn->socks_request->usernamelen);
    212      smartlist_add_asprintf(descparts, "SOCKS_USERNAME=%s",
    213                             username_escaped);
    214      tor_free(username_escaped);
    215    }
    216    if (conn->socks_request->passwordlen > 0) {
    217      char* password_escaped = esc_for_log_len(conn->socks_request->password,
    218                                 (size_t) conn->socks_request->passwordlen);
    219      smartlist_add_asprintf(descparts, "SOCKS_PASSWORD=%s",
    220                             password_escaped);
    221      tor_free(password_escaped);
    222    }
    223 
    224    const char *client_protocol;
    225    // Show the client protocol; used by IsolateClientProtocol.
    226    switch (conn->socks_request->listener_type)
    227      {
    228      case CONN_TYPE_AP_LISTENER:
    229        switch (conn->socks_request->socks_version)
    230          {
    231          case 4: client_protocol = "SOCKS4"; break;
    232          case 5: client_protocol = "SOCKS5"; break;
    233          default: client_protocol = "UNKNOWN";
    234          }
    235        break;
    236      case CONN_TYPE_AP_TRANS_LISTENER: client_protocol = "TRANS"; break;
    237      case CONN_TYPE_AP_NATD_LISTENER: client_protocol = "NATD"; break;
    238      case CONN_TYPE_AP_DNS_LISTENER: client_protocol = "DNS"; break;
    239      case CONN_TYPE_AP_HTTP_CONNECT_LISTENER:
    240        client_protocol = "HTTPCONNECT"; break;
    241      case CONN_TYPE_METRICS_LISTENER:
    242        client_protocol = "METRICS"; break;
    243      default: client_protocol = "UNKNOWN";
    244      }
    245    smartlist_add_asprintf(descparts, "CLIENT_PROTOCOL=%s",
    246                           client_protocol);
    247  }
    248 
    249  // Show newnym epoch; used for stream isolation when NEWNYM is used.
    250  smartlist_add_asprintf(descparts, "NYM_EPOCH=%u",
    251                         conn->nym_epoch);
    252 
    253  // Show session group; used for stream isolation of multiple listener ports.
    254  smartlist_add_asprintf(descparts, "SESSION_GROUP=%d",
    255                         conn->entry_cfg.session_group);
    256 
    257  // Show isolation flags.
    258  smartlist_t *isoflaglist = smartlist_new();
    259  char *isoflaglist_joined;
    260  if (conn->entry_cfg.isolation_flags & ISO_DESTPORT) {
    261    smartlist_add(isoflaglist, (void *)"DESTPORT");
    262  }
    263  if (conn->entry_cfg.isolation_flags & ISO_DESTADDR) {
    264    smartlist_add(isoflaglist, (void *)"DESTADDR");
    265  }
    266  if (conn->entry_cfg.isolation_flags & ISO_SOCKSAUTH) {
    267    smartlist_add(isoflaglist, (void *)"SOCKS_USERNAME");
    268    smartlist_add(isoflaglist, (void *)"SOCKS_PASSWORD");
    269  }
    270  if (conn->entry_cfg.isolation_flags & ISO_CLIENTPROTO) {
    271    smartlist_add(isoflaglist, (void *)"CLIENT_PROTOCOL");
    272  }
    273  if (conn->entry_cfg.isolation_flags & ISO_CLIENTADDR) {
    274    smartlist_add(isoflaglist, (void *)"CLIENTADDR");
    275  }
    276  if (conn->entry_cfg.isolation_flags & ISO_SESSIONGRP) {
    277    smartlist_add(isoflaglist, (void *)"SESSION_GROUP");
    278  }
    279  if (conn->entry_cfg.isolation_flags & ISO_NYM_EPOCH) {
    280    smartlist_add(isoflaglist, (void *)"NYM_EPOCH");
    281  }
    282  isoflaglist_joined = smartlist_join_strings(isoflaglist, ",", 0, NULL);
    283  smartlist_add_asprintf(descparts, "ISO_FIELDS=%s", isoflaglist_joined);
    284  tor_free(isoflaglist_joined);
    285  smartlist_free(isoflaglist);
    286 
    287  rv = smartlist_join_strings(descparts, " ", 0, NULL);
    288 
    289  SMARTLIST_FOREACH(descparts, char *, cp, tor_free(cp));
    290  smartlist_free(descparts);
    291 
    292  return rv;
    293 }
    294 
    295 /** Return a longname the node whose identity is <b>id_digest</b>. If
    296 * node_get_by_id() returns NULL, base 16 encoding of <b>id_digest</b> is
    297 * returned instead.
    298 *
    299 * This function is not thread-safe.  Each call to this function invalidates
    300 * previous values returned by this function.
    301 */
    302 MOCK_IMPL(const char *,
    303 node_describe_longname_by_id,(const char *id_digest))
    304 {
    305  static char longname[MAX_VERBOSE_NICKNAME_LEN+1];
    306  node_get_verbose_nickname_by_id(id_digest, longname);
    307  return longname;
    308 }