Tor 0.4.9.3-alpha-dev
Loading...
Searching...
No Matches
reasons.c
Go to the documentation of this file.
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"
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 */
31const char *
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 */
67const char *
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 */
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;
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
144 return SOCKS5_GENERAL_ERROR;
146 return SOCKS5_NET_UNREACHABLE;
148 return SOCKS5_GENERAL_ERROR;
150 // LCOV_EXCL_START
152 return SOCKS5_GENERAL_ERROR;
153 // LCOV_EXCL_STOP
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. */
180uint8_t
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. */
228const char *
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. */
266int
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. */
294int
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. */
331const char *
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) {
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";
371 return "NOPATH";
372 case END_CIRC_REASON_NOSUCHSERVICE:
373 return "NOSUCHSERVICE";
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. */
396const char *
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. */
414const char *
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 */
442const char *
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. */
464const char *
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";
499 return "HTTP/1.0 403 Forbidden (entry policy violation)\r\n";
500 case END_STREAM_REASON_NOTDIRECTORY: FALLTHROUGH;
501 default:
503 return "HTTP/1.0 500 Internal Server Error (weird end reason)\r\n";
504 }
505}
Header file for config.c.
#define log_fn(severity, domain, args,...)
Definition log.h:283
#define LD_PROTOCOL
Definition log.h:72
#define LD_OR
Definition log.h:92
#define LD_BUG
Definition log.h:86
Header file for node_select.c.
bandwidth_weight_rule_t
Definition node_select.h:43
Master header file for Tor-specific functionality.
#define END_STREAM_REASON_SOCKSPROTOCOL
Definition or.h:314
#define END_STREAM_REASON_HTTPPROTOCOL
Definition or.h:327
#define END_STREAM_REASON_CANT_ATTACH
Definition or.h:308
#define END_STREAM_REASON_PRIVATE_ADDR
Definition or.h:323
#define END_STREAM_REASON_ENTRYPOLICY
Definition or.h:332
#define END_CIRC_REASON_NOPATH
Definition or.h:368
#define END_CIRC_REASON_MEASUREMENT_EXPIRED
Definition or.h:365
#define END_CIRC_REASON_FLAG_REMOTE
Definition or.h:393
#define END_STREAM_REASON_MASK
Definition or.h:335
#define END_CIRC_AT_ORIGIN
Definition or.h:370
#define END_STREAM_REASON_NET_UNREACHABLE
Definition or.h:311
const char * end_reason_to_http_connect_response_line(int endreason)
Definition reasons.c:465
int tls_error_to_orconn_end_reason(int e)
Definition reasons.c:267
const char * stream_end_reason_to_string(int reason)
Definition reasons.c:68
const char * socks5_response_code_to_string(uint8_t code)
Definition reasons.c:415
int errno_to_orconn_end_reason(int e)
Definition reasons.c:295
const char * bandwidth_weight_rule_to_string(bandwidth_weight_rule_t rule)
Definition reasons.c:443
const char * socks4_response_code_to_string(uint8_t code)
Definition reasons.c:397
socks5_reply_status_t stream_end_reason_to_socks5_response(int reason)
Definition reasons.c:104
uint8_t errno_to_stream_end_reason(int e)
Definition reasons.c:181
const char * stream_end_reason_to_control_string(int reason)
Definition reasons.c:32
const char * orconn_end_reason_to_control_string(int r)
Definition reasons.c:229
const char * circuit_end_reason_to_control_string(int reason)
Definition reasons.c:332
Header file for reasons.c.
socks5_reply_status_t
Headers for tortls.c.
#define tor_assert_nonfatal_unreached()
Definition util_bug.h:177