"Fossies" - the Fresh Open Source Software Archive

Member "tor-0.4.1.6/src/core/or/reasons.c" (10 Jun 2019, 16889 Bytes) of package /linux/misc/tor-0.4.1.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "reasons.c" see the Fossies "Dox" file reference documentation.

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