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 }