protover: Fix old tor hardcoded version check
[tor.git] / src / or / reasons.c
bloba1566e229989853889b1f7db29d2339aec6b568e
1 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
2 * Copyright (c) 2007-2016, The Tor Project, Inc. */
3 /* See LICENSE for licensing information */
5 /**
6 * \file reasons.c
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
14 * to another.
15 **/
17 #include "or.h"
18 #include "config.h"
19 #include "reasons.h"
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. */
25 const char *
26 stream_end_reason_to_control_string(int reason)
28 reason &= END_STREAM_REASON_MASK;
29 switch (reason) {
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";
51 default: return NULL;
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.
59 const char *
60 stream_end_reason_to_string(int reason)
62 switch (reason) {
63 case -1:
64 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
65 "End cell arrived with length 0. Should be at least 1.");
66 return "MALFORMED";
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";
81 default:
82 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
83 "Reason for ending (%d) not recognized.",reason);
84 return "unknown";
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.
95 socks5_reply_status_t
96 stream_end_reason_to_socks5_response(int reason)
98 switch (reason & END_STREAM_REASON_MASK) {
99 case 0:
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
118 * was complete. */
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;
144 default:
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'). */
157 #ifdef _WIN32
158 #define E_CASE(s) case s: case WSA ## s
159 #define S_CASE(s) case WSA ## s
160 #else
161 #define E_CASE(s) case s
162 #define S_CASE(s) case s
163 #endif
165 /** Given an errno from a failed exit connection, return a reason code
166 * appropriate for use in a RELAY END cell. */
167 uint8_t
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
172 * appropriate. */
173 switch (e) {
174 case EPIPE:
175 return END_STREAM_REASON_DONE;
176 E_CASE(EBADF):
177 E_CASE(EFAULT):
178 E_CASE(EINVAL):
179 S_CASE(EISCONN):
180 S_CASE(ENOTSOCK):
181 S_CASE(EPROTONOSUPPORT):
182 S_CASE(EAFNOSUPPORT):
183 S_CASE(ENOTCONN):
184 return END_STREAM_REASON_INTERNAL;
185 S_CASE(ENETUNREACH):
186 S_CASE(EHOSTUNREACH):
187 E_CASE(EACCES):
188 case EPERM:
189 return END_STREAM_REASON_NOROUTE;
190 S_CASE(ECONNREFUSED):
191 return END_STREAM_REASON_CONNECTREFUSED;
192 S_CASE(ECONNRESET):
193 return END_STREAM_REASON_CONNRESET;
194 S_CASE(ETIMEDOUT):
195 return END_STREAM_REASON_TIMEOUT;
196 S_CASE(ENOBUFS):
197 case ENOMEM:
198 case ENFILE:
199 S_CASE(EADDRINUSE):
200 S_CASE(EADDRNOTAVAIL):
201 E_CASE(EMFILE):
202 return END_STREAM_REASON_RESOURCELIMIT;
203 default:
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. */
215 const char *
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
220 * appropriate. */
221 switch (r) {
222 case END_OR_CONN_REASON_DONE:
223 return "DONE";
224 case END_OR_CONN_REASON_REFUSED:
225 return "CONNECTREFUSED";
226 case END_OR_CONN_REASON_OR_IDENTITY:
227 return "IDENTITY";
228 case END_OR_CONN_REASON_CONNRESET:
229 return "CONNECTRESET";
230 case END_OR_CONN_REASON_TIMEOUT:
231 return "TIMEOUT";
232 case END_OR_CONN_REASON_NO_ROUTE:
233 return "NOROUTE";
234 case END_OR_CONN_REASON_IO_ERROR:
235 return "IOERROR";
236 case END_OR_CONN_REASON_RESOURCE_LIMIT:
237 return "RESOURCELIMIT";
238 case END_OR_CONN_REASON_MISC:
239 return "MISC";
240 case END_OR_CONN_REASON_PT_MISSING:
241 return "PT_MISSING";
242 case 0:
243 return "";
244 default:
245 log_warn(LD_BUG, "Unrecognized or_conn reason code %d", r);
246 return "UNKNOWN";
250 /** Convert a TOR_TLS_* error code into an END_OR_CONN_* reason. */
252 tls_error_to_orconn_end_reason(int e)
254 switch (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:
267 case TOR_TLS_CLOSE:
268 case TOR_TLS_DONE:
269 return END_OR_CONN_REASON_DONE;
270 default:
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)
280 switch (e) {
281 case EPIPE:
282 return END_OR_CONN_REASON_DONE;
283 S_CASE(ENOTCONN):
284 S_CASE(ENETUNREACH):
285 S_CASE(ENETDOWN):
286 S_CASE(EHOSTUNREACH):
287 return END_OR_CONN_REASON_NO_ROUTE;
288 S_CASE(ECONNREFUSED):
289 return END_OR_CONN_REASON_REFUSED;
290 S_CASE(ECONNRESET):
291 return END_OR_CONN_REASON_CONNRESET;
292 S_CASE(ETIMEDOUT):
293 return END_OR_CONN_REASON_TIMEOUT;
294 S_CASE(ENOBUFS):
295 case ENOMEM:
296 case ENFILE:
297 E_CASE(EMFILE):
298 E_CASE(EACCES):
299 E_CASE(EBADF):
300 E_CASE(EFAULT):
301 E_CASE(EINVAL):
302 return END_OR_CONN_REASON_RESOURCE_LIMIT;
303 default:
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
313 * CIRCUIT event. */
314 const char *
315 circuit_end_reason_to_control_string(int reason)
317 int is_remote = 0;
319 if (reason >= 0 && reason & END_CIRC_REASON_FLAG_REMOTE) {
320 reason &= ~END_CIRC_REASON_FLAG_REMOTE;
321 is_remote = 1;
324 switch (reason) {
325 case END_CIRC_AT_ORIGIN:
326 /* This shouldn't get passed here; it's a catch-all reason. */
327 return "ORIGIN";
328 case END_CIRC_REASON_NONE:
329 /* This shouldn't get passed here; it's a catch-all reason. */
330 return "NONE";
331 case END_CIRC_REASON_TORPROTOCOL:
332 return "TORPROTOCOL";
333 case END_CIRC_REASON_INTERNAL:
334 return "INTERNAL";
335 case END_CIRC_REASON_REQUESTED:
336 return "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:
348 return "FINISHED";
349 case END_CIRC_REASON_TIMEOUT:
350 return "TIMEOUT";
351 case END_CIRC_REASON_DESTROYED:
352 return "DESTROYED";
353 case END_CIRC_REASON_NOPATH:
354 return "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";
361 default:
362 if (is_remote) {
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);
370 } else {
371 log_warn(LD_BUG,
372 "Unrecognized reason code %d", reason);
374 return NULL;
378 /** Return a string corresponding to a SOCKS4 response code. */
379 const char *
380 socks4_response_code_to_string(uint8_t code)
382 switch (code) {
383 case 0x5a:
384 return "connection accepted";
385 case 0x5b:
386 return "server rejected connection";
387 case 0x5c:
388 return "server cannot connect to identd on this client";
389 case 0x5d:
390 return "user id does not match identd";
391 default:
392 return "invalid SOCKS 4 response code";
396 /** Return a string corresponding to a SOCKS5 response code. */
397 const char *
398 socks5_response_code_to_string(uint8_t code)
400 switch (code) {
401 case 0x00:
402 return "connection accepted";
403 case 0x01:
404 return "general SOCKS server failure";
405 case 0x02:
406 return "connection not allowed by ruleset";
407 case 0x03:
408 return "Network unreachable";
409 case 0x04:
410 return "Host unreachable";
411 case 0x05:
412 return "Connection refused";
413 case 0x06:
414 return "TTL expired";
415 case 0x07:
416 return "Command not supported";
417 case 0x08:
418 return "Address type not supported";
419 default:
420 return "unknown reason";
424 /** Return a string corresponding to a bandwidht_weight_rule_t */
425 const char *
426 bandwidth_weight_rule_to_string(bandwidth_weight_rule_t rule)
428 switch (rule)
430 case NO_WEIGHTING:
431 return "no weighting";
432 case WEIGHT_FOR_EXIT:
433 return "weight as exit";
434 case WEIGHT_FOR_MID:
435 return "weight as middle node";
436 case WEIGHT_FOR_GUARD:
437 return "weight as guard";
438 case WEIGHT_FOR_DIR:
439 return "weight as directory";
440 default:
441 return "unknown rule";