tor

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

reasons.c (17124B)


      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 reasons.c
      7 * \brief Convert circuit, stream, and orconn error reasons to and/or from
      8 * strings and errno values.
      9 *
     10 * This module is just a bunch of functions full of case statements that
     11 * convert from one representation of our error codes to another. These are
     12 * mainly used in generating log messages, in sending messages to the
     13 * controller in control.c, and in converting errors from one protocol layer
     14 * to another.
     15 **/
     16 
     17 #include "core/or/or.h"
     18 #include "app/config/config.h"
     19 #include "core/or/reasons.h"
     20 #include "feature/nodelist/node_select.h"
     21 #include "lib/tls/tortls.h"
     22 
     23 /***************************** Edge (stream) reasons **********************/
     24 
     25 /** Convert the reason for ending a stream <b>reason</b> into the format used
     26 * in STREAM events. Return NULL if the reason is unrecognized.
     27 *
     28 * Note: For all specified remote reasons that can occur in a Relay END
     29 * message, these are the same as the specified name of the END reason.
     30 */
     31 const char *
     32 stream_end_reason_to_control_string(int reason)
     33 {
     34  reason &= END_STREAM_REASON_MASK;
     35  switch (reason) {
     36    case END_STREAM_REASON_MISC: return "MISC";
     37    case END_STREAM_REASON_RESOLVEFAILED: return "RESOLVEFAILED";
     38    case END_STREAM_REASON_CONNECTREFUSED: return "CONNECTREFUSED";
     39    case END_STREAM_REASON_EXITPOLICY: return "EXITPOLICY";
     40    case END_STREAM_REASON_DESTROY: return "DESTROY";
     41    case END_STREAM_REASON_DONE: return "DONE";
     42    case END_STREAM_REASON_TIMEOUT: return "TIMEOUT";
     43    case END_STREAM_REASON_NOROUTE: return "NOROUTE";
     44    case END_STREAM_REASON_HIBERNATING: return "HIBERNATING";
     45    case END_STREAM_REASON_INTERNAL: return "INTERNAL";
     46    case END_STREAM_REASON_RESOURCELIMIT: return "RESOURCELIMIT";
     47    case END_STREAM_REASON_CONNRESET: return "CONNRESET";
     48    case END_STREAM_REASON_TORPROTOCOL: return "TORPROTOCOL";
     49    case END_STREAM_REASON_NOTDIRECTORY: return "NOTDIRECTORY";
     50 
     51    case END_STREAM_REASON_CANT_ATTACH: return "CANT_ATTACH";
     52    case END_STREAM_REASON_NET_UNREACHABLE: return "NET_UNREACHABLE";
     53    case END_STREAM_REASON_SOCKSPROTOCOL: return "SOCKS_PROTOCOL";
     54    // XXXX Controlspec
     55    case END_STREAM_REASON_HTTPPROTOCOL: return "HTTP_PROTOCOL";
     56 
     57    case END_STREAM_REASON_PRIVATE_ADDR: return "PRIVATE_ADDR";
     58 
     59    default: return NULL;
     60  }
     61 }
     62 
     63 /** Translate <b>reason</b>, which came from a relay 'end' cell,
     64 * into a static const string describing why the stream is closing.
     65 * <b>reason</b> is -1 if no reason was provided.
     66 */
     67 const char *
     68 stream_end_reason_to_string(int reason)
     69 {
     70  switch (reason) {
     71    case -1:
     72      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
     73             "End cell arrived with length 0. Should be at least 1.");
     74      return "MALFORMED";
     75    case END_STREAM_REASON_MISC:           return "misc error";
     76    case END_STREAM_REASON_RESOLVEFAILED:  return "resolve failed";
     77    case END_STREAM_REASON_CONNECTREFUSED: return "connection refused";
     78    case END_STREAM_REASON_EXITPOLICY:     return "exit policy failed";
     79    case END_STREAM_REASON_DESTROY:        return "destroyed";
     80    case END_STREAM_REASON_DONE:           return "closed normally";
     81    case END_STREAM_REASON_TIMEOUT:        return "gave up (timeout)";
     82    case END_STREAM_REASON_NOROUTE:        return "no route to host";
     83    case END_STREAM_REASON_HIBERNATING:    return "server is hibernating";
     84    case END_STREAM_REASON_INTERNAL:       return "internal error at server";
     85    case END_STREAM_REASON_RESOURCELIMIT:  return "server out of resources";
     86    case END_STREAM_REASON_CONNRESET:      return "connection reset";
     87    case END_STREAM_REASON_TORPROTOCOL:    return "Tor protocol error";
     88    case END_STREAM_REASON_NOTDIRECTORY:   return "not a directory";
     89    default:
     90      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
     91             "Reason for ending (%d) not recognized.",reason);
     92      return "unknown";
     93  }
     94 }
     95 
     96 /** Translate <b>reason</b> (as from a relay 'end' cell) into an
     97 * appropriate SOCKS5 reply code.
     98 *
     99 * A reason of 0 means that we're not actually expecting to send
    100 * this code back to the socks client; we just call it 'succeeded'
    101 * to keep things simple.
    102 */
    103 socks5_reply_status_t
    104 stream_end_reason_to_socks5_response(int reason)
    105 {
    106  switch (reason & END_STREAM_REASON_MASK) {
    107    case 0:
    108      return SOCKS5_SUCCEEDED;
    109    case END_STREAM_REASON_MISC:
    110      return SOCKS5_GENERAL_ERROR;
    111    case END_STREAM_REASON_RESOLVEFAILED:
    112      return SOCKS5_HOST_UNREACHABLE;
    113    case END_STREAM_REASON_CONNECTREFUSED:
    114      return SOCKS5_CONNECTION_REFUSED;
    115    case END_STREAM_REASON_ENTRYPOLICY:
    116      return SOCKS5_NOT_ALLOWED;
    117    case END_STREAM_REASON_EXITPOLICY:
    118      return SOCKS5_NOT_ALLOWED;
    119    case END_STREAM_REASON_DESTROY:
    120      return SOCKS5_GENERAL_ERROR;
    121    case END_STREAM_REASON_DONE:
    122      /* Note that 'DONE' usually indicates a successful close from the other
    123       * side of the stream... but if we receive it before a connected cell --
    124       * that is, before we have sent a SOCKS reply -- that means that the
    125       * other side of the circuit closed the connection before telling us it
    126       * was complete. */
    127      return SOCKS5_CONNECTION_REFUSED;
    128    case END_STREAM_REASON_TIMEOUT:
    129      return SOCKS5_TTL_EXPIRED;
    130    case END_STREAM_REASON_NOROUTE:
    131      return SOCKS5_HOST_UNREACHABLE;
    132    case END_STREAM_REASON_RESOURCELIMIT:
    133      return SOCKS5_GENERAL_ERROR;
    134    case END_STREAM_REASON_HIBERNATING:
    135      return SOCKS5_GENERAL_ERROR;
    136    case END_STREAM_REASON_INTERNAL:
    137      return SOCKS5_GENERAL_ERROR;
    138    case END_STREAM_REASON_CONNRESET:
    139      return SOCKS5_CONNECTION_REFUSED;
    140    case END_STREAM_REASON_TORPROTOCOL:
    141      return SOCKS5_GENERAL_ERROR;
    142 
    143    case END_STREAM_REASON_CANT_ATTACH:
    144      return SOCKS5_GENERAL_ERROR;
    145    case END_STREAM_REASON_NET_UNREACHABLE:
    146      return SOCKS5_NET_UNREACHABLE;
    147    case END_STREAM_REASON_SOCKSPROTOCOL:
    148      return SOCKS5_GENERAL_ERROR;
    149    case END_STREAM_REASON_HTTPPROTOCOL:
    150      // LCOV_EXCL_START
    151      tor_assert_nonfatal_unreached();
    152      return SOCKS5_GENERAL_ERROR;
    153      // LCOV_EXCL_STOP
    154    case END_STREAM_REASON_PRIVATE_ADDR:
    155      return SOCKS5_GENERAL_ERROR;
    156 
    157    default:
    158      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
    159             "Reason for ending (%d) not recognized; "
    160             "sending generic socks error.", reason);
    161      return SOCKS5_GENERAL_ERROR;
    162  }
    163 }
    164 
    165 /* We need to use a few macros to deal with the fact that Windows
    166 * decided that their sockets interface should be a permakludge.
    167 * E_CASE is for errors where windows has both a EFOO and a WSAEFOO
    168 * version, and S_CASE is for errors where windows has only a WSAEFOO
    169 * version.  (The E is for 'error', the S is for 'socket'). */
    170 #ifdef _WIN32
    171 #define E_CASE(s) case s: case WSA ## s
    172 #define S_CASE(s) case WSA ## s
    173 #else
    174 #define E_CASE(s) case s
    175 #define S_CASE(s) case s
    176 #endif /* defined(_WIN32) */
    177 
    178 /** Given an errno from a failed exit connection, return a reason code
    179 * appropriate for use in a RELAY END cell. */
    180 uint8_t
    181 errno_to_stream_end_reason(int e)
    182 {
    183  /* To add new errors here, find out if they exist on Windows, and if a WSA*
    184   * equivalent exists on windows. Add a case, an S_CASE, or an E_CASE as
    185   * appropriate. */
    186  switch (e) {
    187    case EPIPE:
    188      return END_STREAM_REASON_DONE;
    189    E_CASE(EBADF):
    190    E_CASE(EFAULT):
    191    E_CASE(EINVAL):
    192    S_CASE(EISCONN):
    193    S_CASE(ENOTSOCK):
    194    S_CASE(EPROTONOSUPPORT):
    195    S_CASE(EAFNOSUPPORT):
    196    S_CASE(ENOTCONN):
    197      return END_STREAM_REASON_INTERNAL;
    198    S_CASE(ENETUNREACH):
    199    S_CASE(EHOSTUNREACH):
    200    E_CASE(EACCES):
    201    case EPERM:
    202      return END_STREAM_REASON_NOROUTE;
    203    S_CASE(ECONNREFUSED):
    204      return END_STREAM_REASON_CONNECTREFUSED;
    205    S_CASE(ECONNRESET):
    206      return END_STREAM_REASON_CONNRESET;
    207    S_CASE(ETIMEDOUT):
    208      return END_STREAM_REASON_TIMEOUT;
    209    S_CASE(ENOBUFS):
    210    case ENOMEM:
    211    case ENFILE:
    212    S_CASE(EADDRINUSE):
    213    S_CASE(EADDRNOTAVAIL):
    214    E_CASE(EMFILE):
    215      return END_STREAM_REASON_RESOURCELIMIT;
    216    default:
    217      log_info(LD_EXIT, "Didn't recognize errno %d (%s); telling the client "
    218               "that we are ending a stream for 'misc' reason.",
    219               e, tor_socket_strerror(e));
    220      return END_STREAM_REASON_MISC;
    221  }
    222 }
    223 
    224 /***************************** ORConn reasons *****************************/
    225 
    226 /** Convert the reason for ending an OR connection <b>r</b> into the format
    227 * used in ORCONN events. Return "UNKNOWN" if the reason is unrecognized. */
    228 const char *
    229 orconn_end_reason_to_control_string(int r)
    230 {
    231  /* To add new errors here, find out if they exist on Windows, and if a WSA*
    232   * equivalent exists on windows. Add a case, an S_CASE, or an E_CASE as
    233   * appropriate. */
    234  switch (r) {
    235    case END_OR_CONN_REASON_DONE:
    236      return "DONE";
    237    case END_OR_CONN_REASON_REFUSED:
    238      return "CONNECTREFUSED";
    239    case END_OR_CONN_REASON_OR_IDENTITY:
    240      return "IDENTITY";
    241    case END_OR_CONN_REASON_CONNRESET:
    242      return "CONNECTRESET";
    243    case END_OR_CONN_REASON_TIMEOUT:
    244      return "TIMEOUT";
    245    case END_OR_CONN_REASON_NO_ROUTE:
    246      return "NOROUTE";
    247    case END_OR_CONN_REASON_IO_ERROR:
    248      return "IOERROR";
    249    case END_OR_CONN_REASON_RESOURCE_LIMIT:
    250      return "RESOURCELIMIT";
    251    case END_OR_CONN_REASON_TLS_ERROR:
    252      return "TLS_ERROR";
    253    case END_OR_CONN_REASON_MISC:
    254      return "MISC";
    255    case END_OR_CONN_REASON_PT_MISSING:
    256      return "PT_MISSING";
    257    case 0:
    258      return "";
    259    default:
    260      log_warn(LD_BUG, "Unrecognized or_conn reason code %d", r);
    261      return "UNKNOWN";
    262  }
    263 }
    264 
    265 /** Convert a TOR_TLS_* error code into an END_OR_CONN_* reason. */
    266 int
    267 tls_error_to_orconn_end_reason(int e)
    268 {
    269  switch (e) {
    270    case TOR_TLS_ERROR_IO:
    271      return END_OR_CONN_REASON_IO_ERROR;
    272    case TOR_TLS_ERROR_CONNREFUSED:
    273      return END_OR_CONN_REASON_REFUSED;
    274    case TOR_TLS_ERROR_CONNRESET:
    275      return END_OR_CONN_REASON_CONNRESET;
    276    case TOR_TLS_ERROR_NO_ROUTE:
    277      return END_OR_CONN_REASON_NO_ROUTE;
    278    case TOR_TLS_ERROR_TIMEOUT:
    279      return END_OR_CONN_REASON_TIMEOUT;
    280    case TOR_TLS_WANTREAD:
    281    case TOR_TLS_WANTWRITE:
    282    case TOR_TLS_CLOSE:
    283    case TOR_TLS_DONE:
    284      return END_OR_CONN_REASON_DONE;
    285    case TOR_TLS_ERROR_MISC:
    286      return END_OR_CONN_REASON_TLS_ERROR;
    287    default:
    288      return END_OR_CONN_REASON_MISC;
    289  }
    290 }
    291 
    292 /** Given an errno from a failed ORConn connection, return a reason code
    293 * appropriate for use in the controller orconn events. */
    294 int
    295 errno_to_orconn_end_reason(int e)
    296 {
    297  switch (e) {
    298    case EPIPE:
    299      return END_OR_CONN_REASON_DONE;
    300    S_CASE(ENOTCONN):
    301    S_CASE(ENETUNREACH):
    302    S_CASE(ENETDOWN):
    303    S_CASE(EHOSTUNREACH):
    304      return END_OR_CONN_REASON_NO_ROUTE;
    305    S_CASE(ECONNREFUSED):
    306      return END_OR_CONN_REASON_REFUSED;
    307    S_CASE(ECONNRESET):
    308      return END_OR_CONN_REASON_CONNRESET;
    309    S_CASE(ETIMEDOUT):
    310      return END_OR_CONN_REASON_TIMEOUT;
    311    S_CASE(ENOBUFS):
    312    case ENOMEM:
    313    case ENFILE:
    314    E_CASE(EMFILE):
    315    E_CASE(EACCES):
    316    E_CASE(EBADF):
    317    E_CASE(EFAULT):
    318    E_CASE(EINVAL):
    319      return END_OR_CONN_REASON_RESOURCE_LIMIT;
    320    default:
    321      log_info(LD_OR, "Didn't recognize errno %d (%s).",
    322               e, tor_socket_strerror(e));
    323      return END_OR_CONN_REASON_MISC;
    324  }
    325 }
    326 
    327 /***************************** Circuit reasons *****************************/
    328 
    329 /** Convert a numeric reason for destroying a circuit into a string for a
    330 * CIRCUIT event. */
    331 const char *
    332 circuit_end_reason_to_control_string(int reason)
    333 {
    334  int is_remote = 0;
    335 
    336  if (reason >= 0 && reason & END_CIRC_REASON_FLAG_REMOTE) {
    337    reason &= ~END_CIRC_REASON_FLAG_REMOTE;
    338    is_remote = 1;
    339  }
    340 
    341  switch (reason) {
    342    case END_CIRC_AT_ORIGIN:
    343      /* This shouldn't get passed here; it's a catch-all reason. */
    344      return "ORIGIN";
    345    case END_CIRC_REASON_NONE:
    346      /* This shouldn't get passed here; it's a catch-all reason. */
    347      return "NONE";
    348    case END_CIRC_REASON_TORPROTOCOL:
    349      return "TORPROTOCOL";
    350    case END_CIRC_REASON_INTERNAL:
    351      return "INTERNAL";
    352    case END_CIRC_REASON_REQUESTED:
    353      return "REQUESTED";
    354    case END_CIRC_REASON_HIBERNATING:
    355      return "HIBERNATING";
    356    case END_CIRC_REASON_RESOURCELIMIT:
    357      return "RESOURCELIMIT";
    358    case END_CIRC_REASON_CONNECTFAILED:
    359      return "CONNECTFAILED";
    360    case END_CIRC_REASON_OR_IDENTITY:
    361      return "OR_IDENTITY";
    362    case END_CIRC_REASON_CHANNEL_CLOSED:
    363      return "CHANNEL_CLOSED";
    364    case END_CIRC_REASON_FINISHED:
    365      return "FINISHED";
    366    case END_CIRC_REASON_TIMEOUT:
    367      return "TIMEOUT";
    368    case END_CIRC_REASON_DESTROYED:
    369      return "DESTROYED";
    370    case END_CIRC_REASON_NOPATH:
    371      return "NOPATH";
    372    case END_CIRC_REASON_NOSUCHSERVICE:
    373      return "NOSUCHSERVICE";
    374    case END_CIRC_REASON_MEASUREMENT_EXPIRED:
    375      return "MEASUREMENT_EXPIRED";
    376    case END_CIRC_REASON_IP_NOW_REDUNDANT:
    377      return "IP_NOW_REDUNDANT";
    378    default:
    379      if (is_remote) {
    380        /*
    381         * If it's remote, it's not a bug *here*, so don't use LD_BUG, but
    382         * do note that the someone we're talking to is speaking the Tor
    383         * protocol with a weird accent.
    384         */
    385        log_warn(LD_PROTOCOL,
    386                 "Remote server sent bogus reason code %d", reason);
    387      } else {
    388        log_warn(LD_BUG,
    389                 "Unrecognized reason code %d", reason);
    390      }
    391      return NULL;
    392  }
    393 }
    394 
    395 /** Return a string corresponding to a SOCKS4 response code. */
    396 const char *
    397 socks4_response_code_to_string(uint8_t code)
    398 {
    399  switch (code) {
    400    case 0x5a:
    401      return "connection accepted";
    402    case 0x5b:
    403      return "server rejected connection";
    404    case 0x5c:
    405      return "server cannot connect to identd on this client";
    406    case 0x5d:
    407      return "user id does not match identd";
    408    default:
    409      return "invalid SOCKS 4 response code";
    410  }
    411 }
    412 
    413 /** Return a string corresponding to a SOCKS5 response code. */
    414 const char *
    415 socks5_response_code_to_string(uint8_t code)
    416 {
    417  switch (code) {
    418    case 0x00:
    419      return "connection accepted";
    420    case 0x01:
    421      return "general SOCKS server failure";
    422    case 0x02:
    423      return "connection not allowed by ruleset";
    424    case 0x03:
    425      return "Network unreachable";
    426    case 0x04:
    427      return "Host unreachable";
    428    case 0x05:
    429      return "Connection refused";
    430    case 0x06:
    431      return "TTL expired";
    432    case 0x07:
    433      return "Command not supported";
    434    case 0x08:
    435      return "Address type not supported";
    436    default:
    437      return "unknown reason";
    438  }
    439 }
    440 
    441 /** Return a string corresponding to a bandwidth_weight_rule_t */
    442 const char *
    443 bandwidth_weight_rule_to_string(bandwidth_weight_rule_t rule)
    444 {
    445  switch (rule)
    446    {
    447    case NO_WEIGHTING:
    448      return "no weighting";
    449    case WEIGHT_FOR_EXIT:
    450      return "weight as exit";
    451    case WEIGHT_FOR_MID:
    452      return "weight as middle node";
    453    case WEIGHT_FOR_GUARD:
    454      return "weight as guard";
    455    case WEIGHT_FOR_DIR:
    456      return "weight as directory";
    457    default:
    458      return "unknown rule";
    459  }
    460 }
    461 
    462 /** Given a RELAY_END reason value, convert it to an HTTP response to be
    463 * send over an HTTP tunnel connection. */
    464 const char *
    465 end_reason_to_http_connect_response_line(int endreason)
    466 {
    467  endreason &= END_STREAM_REASON_MASK;
    468  /* XXXX these are probably all wrong. Should they all be 502? */
    469  switch (endreason) {
    470    case 0:
    471      return "HTTP/1.0 200 OK\r\n";
    472    case END_STREAM_REASON_MISC:
    473      return "HTTP/1.0 500 Internal Server Error\r\n";
    474    case END_STREAM_REASON_RESOLVEFAILED:
    475      return "HTTP/1.0 503 Service Unavailable (resolve failed)\r\n";
    476    case END_STREAM_REASON_NOROUTE:
    477      return "HTTP/1.0 503 Service Unavailable (no route)\r\n";
    478    case END_STREAM_REASON_CONNECTREFUSED:
    479      return "HTTP/1.0 403 Forbidden (connection refused)\r\n";
    480    case END_STREAM_REASON_EXITPOLICY:
    481      return "HTTP/1.0 403 Forbidden (exit policy)\r\n";
    482    case END_STREAM_REASON_DESTROY:
    483      return "HTTP/1.0 502 Bad Gateway (destroy cell received)\r\n";
    484    case END_STREAM_REASON_DONE:
    485      return "HTTP/1.0 502 Bad Gateway (unexpected close)\r\n";
    486    case END_STREAM_REASON_TIMEOUT:
    487      return "HTTP/1.0 504 Gateway Timeout\r\n";
    488    case END_STREAM_REASON_HIBERNATING:
    489      return "HTTP/1.0 502 Bad Gateway (hibernating server)\r\n";
    490    case END_STREAM_REASON_INTERNAL:
    491      return "HTTP/1.0 502 Bad Gateway (internal error)\r\n";
    492    case END_STREAM_REASON_RESOURCELIMIT:
    493      return "HTTP/1.0 502 Bad Gateway (resource limit)\r\n";
    494    case END_STREAM_REASON_CONNRESET:
    495      return "HTTP/1.0 403 Forbidden (connection reset)\r\n";
    496    case END_STREAM_REASON_TORPROTOCOL:
    497      return "HTTP/1.0 502 Bad Gateway (tor protocol violation)\r\n";
    498    case END_STREAM_REASON_ENTRYPOLICY:
    499      return "HTTP/1.0 403 Forbidden (entry policy violation)\r\n";
    500    case END_STREAM_REASON_NOTDIRECTORY: FALLTHROUGH;
    501    default:
    502      tor_assert_nonfatal_unreached();
    503      return "HTTP/1.0 500 Internal Server Error (weird end reason)\r\n";
    504  }
    505 }