1 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
2 * Copyright (c) 2007-2016, The Tor Project, Inc. */
3 /* See LICENSE for licensing information */
7 * \brief Convert circuit, stream, and orconn error reasons to and/or from
8 * strings and errno values.
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
21 /***************************** Edge (stream) reasons **********************/
23 /** Convert the reason for ending a stream <b>reason</b> into the format used
24 * in STREAM events. Return NULL if the reason is unrecognized. */
26 stream_end_reason_to_control_string(int reason
)
28 reason
&= END_STREAM_REASON_MASK
;
30 case END_STREAM_REASON_MISC
: return "MISC";
31 case END_STREAM_REASON_RESOLVEFAILED
: return "RESOLVEFAILED";
32 case END_STREAM_REASON_CONNECTREFUSED
: return "CONNECTREFUSED";
33 case END_STREAM_REASON_EXITPOLICY
: return "EXITPOLICY";
34 case END_STREAM_REASON_DESTROY
: return "DESTROY";
35 case END_STREAM_REASON_DONE
: return "DONE";
36 case END_STREAM_REASON_TIMEOUT
: return "TIMEOUT";
37 case END_STREAM_REASON_NOROUTE
: return "NOROUTE";
38 case END_STREAM_REASON_HIBERNATING
: return "HIBERNATING";
39 case END_STREAM_REASON_INTERNAL
: return "INTERNAL";
40 case END_STREAM_REASON_RESOURCELIMIT
: return "RESOURCELIMIT";
41 case END_STREAM_REASON_CONNRESET
: return "CONNRESET";
42 case END_STREAM_REASON_TORPROTOCOL
: return "TORPROTOCOL";
43 case END_STREAM_REASON_NOTDIRECTORY
: return "NOTDIRECTORY";
45 case END_STREAM_REASON_CANT_ATTACH
: return "CANT_ATTACH";
46 case END_STREAM_REASON_NET_UNREACHABLE
: return "NET_UNREACHABLE";
47 case END_STREAM_REASON_SOCKSPROTOCOL
: return "SOCKS_PROTOCOL";
49 case END_STREAM_REASON_PRIVATE_ADDR
: return "PRIVATE_ADDR";
55 /** Translate <b>reason</b>, which came from a relay 'end' cell,
56 * into a static const string describing why the stream is closing.
57 * <b>reason</b> is -1 if no reason was provided.
60 stream_end_reason_to_string(int reason
)
64 log_fn(LOG_PROTOCOL_WARN
, LD_PROTOCOL
,
65 "End cell arrived with length 0. Should be at least 1.");
67 case END_STREAM_REASON_MISC
: return "misc error";
68 case END_STREAM_REASON_RESOLVEFAILED
: return "resolve failed";
69 case END_STREAM_REASON_CONNECTREFUSED
: return "connection refused";
70 case END_STREAM_REASON_EXITPOLICY
: return "exit policy failed";
71 case END_STREAM_REASON_DESTROY
: return "destroyed";
72 case END_STREAM_REASON_DONE
: return "closed normally";
73 case END_STREAM_REASON_TIMEOUT
: return "gave up (timeout)";
74 case END_STREAM_REASON_NOROUTE
: return "no route to host";
75 case END_STREAM_REASON_HIBERNATING
: return "server is hibernating";
76 case END_STREAM_REASON_INTERNAL
: return "internal error at server";
77 case END_STREAM_REASON_RESOURCELIMIT
: return "server out of resources";
78 case END_STREAM_REASON_CONNRESET
: return "connection reset";
79 case END_STREAM_REASON_TORPROTOCOL
: return "Tor protocol error";
80 case END_STREAM_REASON_NOTDIRECTORY
: return "not a directory";
82 log_fn(LOG_PROTOCOL_WARN
, LD_PROTOCOL
,
83 "Reason for ending (%d) not recognized.",reason
);
88 /** Translate <b>reason</b> (as from a relay 'end' cell) into an
89 * appropriate SOCKS5 reply code.
91 * A reason of 0 means that we're not actually expecting to send
92 * this code back to the socks client; we just call it 'succeeded'
93 * to keep things simple.
96 stream_end_reason_to_socks5_response(int reason
)
98 switch (reason
& END_STREAM_REASON_MASK
) {
100 return SOCKS5_SUCCEEDED
;
101 case END_STREAM_REASON_MISC
:
102 return SOCKS5_GENERAL_ERROR
;
103 case END_STREAM_REASON_RESOLVEFAILED
:
104 return SOCKS5_HOST_UNREACHABLE
;
105 case END_STREAM_REASON_CONNECTREFUSED
:
106 return SOCKS5_CONNECTION_REFUSED
;
107 case END_STREAM_REASON_ENTRYPOLICY
:
108 return SOCKS5_NOT_ALLOWED
;
109 case END_STREAM_REASON_EXITPOLICY
:
110 return SOCKS5_NOT_ALLOWED
;
111 case END_STREAM_REASON_DESTROY
:
112 return SOCKS5_GENERAL_ERROR
;
113 case END_STREAM_REASON_DONE
:
114 /* Note that 'DONE' usually indicates a successful close from the other
115 * side of the stream... but if we receive it before a connected cell --
116 * that is, before we have sent a SOCKS reply -- that means that the
117 * other side of the circuit closed the connection before telling us it
119 return SOCKS5_CONNECTION_REFUSED
;
120 case END_STREAM_REASON_TIMEOUT
:
121 return SOCKS5_TTL_EXPIRED
;
122 case END_STREAM_REASON_NOROUTE
:
123 return SOCKS5_HOST_UNREACHABLE
;
124 case END_STREAM_REASON_RESOURCELIMIT
:
125 return SOCKS5_GENERAL_ERROR
;
126 case END_STREAM_REASON_HIBERNATING
:
127 return SOCKS5_GENERAL_ERROR
;
128 case END_STREAM_REASON_INTERNAL
:
129 return SOCKS5_GENERAL_ERROR
;
130 case END_STREAM_REASON_CONNRESET
:
131 return SOCKS5_CONNECTION_REFUSED
;
132 case END_STREAM_REASON_TORPROTOCOL
:
133 return SOCKS5_GENERAL_ERROR
;
135 case END_STREAM_REASON_CANT_ATTACH
:
136 return SOCKS5_GENERAL_ERROR
;
137 case END_STREAM_REASON_NET_UNREACHABLE
:
138 return SOCKS5_NET_UNREACHABLE
;
139 case END_STREAM_REASON_SOCKSPROTOCOL
:
140 return SOCKS5_GENERAL_ERROR
;
141 case END_STREAM_REASON_PRIVATE_ADDR
:
142 return SOCKS5_GENERAL_ERROR
;
145 log_fn(LOG_PROTOCOL_WARN
, LD_PROTOCOL
,
146 "Reason for ending (%d) not recognized; "
147 "sending generic socks error.", reason
);
148 return SOCKS5_GENERAL_ERROR
;
152 /* We need to use a few macros to deal with the fact that Windows
153 * decided that their sockets interface should be a permakludge.
154 * E_CASE is for errors where windows has both a EFOO and a WSAEFOO
155 * version, and S_CASE is for errors where windows has only a WSAEFOO
156 * version. (The E is for 'error', the S is for 'socket'). */
158 #define E_CASE(s) case s: case WSA ## s
159 #define S_CASE(s) case WSA ## s
161 #define E_CASE(s) case s
162 #define S_CASE(s) case s
165 /** Given an errno from a failed exit connection, return a reason code
166 * appropriate for use in a RELAY END cell. */
168 errno_to_stream_end_reason(int e
)
170 /* To add new errors here, find out if they exist on Windows, and if a WSA*
171 * equivalent exists on windows. Add a case, an S_CASE, or an E_CASE as
175 return END_STREAM_REASON_DONE
;
181 S_CASE(EPROTONOSUPPORT
):
182 S_CASE(EAFNOSUPPORT
):
184 return END_STREAM_REASON_INTERNAL
;
186 S_CASE(EHOSTUNREACH
):
189 return END_STREAM_REASON_NOROUTE
;
190 S_CASE(ECONNREFUSED
):
191 return END_STREAM_REASON_CONNECTREFUSED
;
193 return END_STREAM_REASON_CONNRESET
;
195 return END_STREAM_REASON_TIMEOUT
;
200 S_CASE(EADDRNOTAVAIL
):
202 return END_STREAM_REASON_RESOURCELIMIT
;
204 log_info(LD_EXIT
, "Didn't recognize errno %d (%s); telling the client "
205 "that we are ending a stream for 'misc' reason.",
206 e
, tor_socket_strerror(e
));
207 return END_STREAM_REASON_MISC
;
211 /***************************** ORConn reasons *****************************/
213 /** Convert the reason for ending an OR connection <b>r</b> into the format
214 * used in ORCONN events. Return "UNKNOWN" if the reason is unrecognized. */
216 orconn_end_reason_to_control_string(int r
)
218 /* To add new errors here, find out if they exist on Windows, and if a WSA*
219 * equivalent exists on windows. Add a case, an S_CASE, or an E_CASE as
222 case END_OR_CONN_REASON_DONE
:
224 case END_OR_CONN_REASON_REFUSED
:
225 return "CONNECTREFUSED";
226 case END_OR_CONN_REASON_OR_IDENTITY
:
228 case END_OR_CONN_REASON_CONNRESET
:
229 return "CONNECTRESET";
230 case END_OR_CONN_REASON_TIMEOUT
:
232 case END_OR_CONN_REASON_NO_ROUTE
:
234 case END_OR_CONN_REASON_IO_ERROR
:
236 case END_OR_CONN_REASON_RESOURCE_LIMIT
:
237 return "RESOURCELIMIT";
238 case END_OR_CONN_REASON_MISC
:
240 case END_OR_CONN_REASON_PT_MISSING
:
245 log_warn(LD_BUG
, "Unrecognized or_conn reason code %d", r
);
250 /** Convert a TOR_TLS_* error code into an END_OR_CONN_* reason. */
252 tls_error_to_orconn_end_reason(int e
)
255 case TOR_TLS_ERROR_IO
:
256 return END_OR_CONN_REASON_IO_ERROR
;
257 case TOR_TLS_ERROR_CONNREFUSED
:
258 return END_OR_CONN_REASON_REFUSED
;
259 case TOR_TLS_ERROR_CONNRESET
:
260 return END_OR_CONN_REASON_CONNRESET
;
261 case TOR_TLS_ERROR_NO_ROUTE
:
262 return END_OR_CONN_REASON_NO_ROUTE
;
263 case TOR_TLS_ERROR_TIMEOUT
:
264 return END_OR_CONN_REASON_TIMEOUT
;
265 case TOR_TLS_WANTREAD
:
266 case TOR_TLS_WANTWRITE
:
269 return END_OR_CONN_REASON_DONE
;
271 return END_OR_CONN_REASON_MISC
;
275 /** Given an errno from a failed ORConn connection, return a reason code
276 * appropriate for use in the controller orconn events. */
278 errno_to_orconn_end_reason(int e
)
282 return END_OR_CONN_REASON_DONE
;
286 S_CASE(EHOSTUNREACH
):
287 return END_OR_CONN_REASON_NO_ROUTE
;
288 S_CASE(ECONNREFUSED
):
289 return END_OR_CONN_REASON_REFUSED
;
291 return END_OR_CONN_REASON_CONNRESET
;
293 return END_OR_CONN_REASON_TIMEOUT
;
302 return END_OR_CONN_REASON_RESOURCE_LIMIT
;
304 log_info(LD_OR
, "Didn't recognize errno %d (%s).",
305 e
, tor_socket_strerror(e
));
306 return END_OR_CONN_REASON_MISC
;
310 /***************************** Circuit reasons *****************************/
312 /** Convert a numeric reason for destroying a circuit into a string for a
315 circuit_end_reason_to_control_string(int reason
)
319 if (reason
>= 0 && reason
& END_CIRC_REASON_FLAG_REMOTE
) {
320 reason
&= ~END_CIRC_REASON_FLAG_REMOTE
;
325 case END_CIRC_AT_ORIGIN
:
326 /* This shouldn't get passed here; it's a catch-all reason. */
328 case END_CIRC_REASON_NONE
:
329 /* This shouldn't get passed here; it's a catch-all reason. */
331 case END_CIRC_REASON_TORPROTOCOL
:
332 return "TORPROTOCOL";
333 case END_CIRC_REASON_INTERNAL
:
335 case END_CIRC_REASON_REQUESTED
:
337 case END_CIRC_REASON_HIBERNATING
:
338 return "HIBERNATING";
339 case END_CIRC_REASON_RESOURCELIMIT
:
340 return "RESOURCELIMIT";
341 case END_CIRC_REASON_CONNECTFAILED
:
342 return "CONNECTFAILED";
343 case END_CIRC_REASON_OR_IDENTITY
:
344 return "OR_IDENTITY";
345 case END_CIRC_REASON_CHANNEL_CLOSED
:
346 return "CHANNEL_CLOSED";
347 case END_CIRC_REASON_FINISHED
:
349 case END_CIRC_REASON_TIMEOUT
:
351 case END_CIRC_REASON_DESTROYED
:
353 case END_CIRC_REASON_NOPATH
:
355 case END_CIRC_REASON_NOSUCHSERVICE
:
356 return "NOSUCHSERVICE";
357 case END_CIRC_REASON_MEASUREMENT_EXPIRED
:
358 return "MEASUREMENT_EXPIRED";
359 case END_CIRC_REASON_IP_NOW_REDUNDANT
:
360 return "IP_NOW_REDUNDANT";
364 * If it's remote, it's not a bug *here*, so don't use LD_BUG, but
365 * do note that the someone we're talking to is speaking the Tor
366 * protocol with a weird accent.
368 log_warn(LD_PROTOCOL
,
369 "Remote server sent bogus reason code %d", reason
);
372 "Unrecognized reason code %d", reason
);
378 /** Return a string corresponding to a SOCKS4 response code. */
380 socks4_response_code_to_string(uint8_t code
)
384 return "connection accepted";
386 return "server rejected connection";
388 return "server cannot connect to identd on this client";
390 return "user id does not match identd";
392 return "invalid SOCKS 4 response code";
396 /** Return a string corresponding to a SOCKS5 response code. */
398 socks5_response_code_to_string(uint8_t code
)
402 return "connection accepted";
404 return "general SOCKS server failure";
406 return "connection not allowed by ruleset";
408 return "Network unreachable";
410 return "Host unreachable";
412 return "Connection refused";
414 return "TTL expired";
416 return "Command not supported";
418 return "Address type not supported";
420 return "unknown reason";
424 /** Return a string corresponding to a bandwidht_weight_rule_t */
426 bandwidth_weight_rule_to_string(bandwidth_weight_rule_t rule
)
431 return "no weighting";
432 case WEIGHT_FOR_EXIT
:
433 return "weight as exit";
435 return "weight as middle node";
436 case WEIGHT_FOR_GUARD
:
437 return "weight as guard";
439 return "weight as directory";
441 return "unknown rule";