tor_error/lib.rs
1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![doc = include_str!("../README.md")]
3// @@ begin lint list maintained by maint/add_warning @@
4#![allow(renamed_and_removed_lints)] // @@REMOVE_WHEN(ci_arti_stable)
5#![allow(unknown_lints)] // @@REMOVE_WHEN(ci_arti_nightly)
6#![warn(missing_docs)]
7#![warn(noop_method_call)]
8#![warn(unreachable_pub)]
9#![warn(clippy::all)]
10#![deny(clippy::await_holding_lock)]
11#![deny(clippy::cargo_common_metadata)]
12#![deny(clippy::cast_lossless)]
13#![deny(clippy::checked_conversions)]
14#![warn(clippy::cognitive_complexity)]
15#![deny(clippy::debug_assert_with_mut_call)]
16#![deny(clippy::exhaustive_enums)]
17#![deny(clippy::exhaustive_structs)]
18#![deny(clippy::expl_impl_clone_on_copy)]
19#![deny(clippy::fallible_impl_from)]
20#![deny(clippy::implicit_clone)]
21#![deny(clippy::large_stack_arrays)]
22#![warn(clippy::manual_ok_or)]
23#![deny(clippy::missing_docs_in_private_items)]
24#![warn(clippy::needless_borrow)]
25#![warn(clippy::needless_pass_by_value)]
26#![warn(clippy::option_option)]
27#![deny(clippy::print_stderr)]
28#![deny(clippy::print_stdout)]
29#![warn(clippy::rc_buffer)]
30#![deny(clippy::ref_option_ref)]
31#![warn(clippy::semicolon_if_nothing_returned)]
32#![warn(clippy::trait_duplication_in_bounds)]
33#![deny(clippy::unchecked_time_subtraction)]
34#![deny(clippy::unnecessary_wraps)]
35#![warn(clippy::unseparated_literal_suffix)]
36#![deny(clippy::unwrap_used)]
37#![deny(clippy::mod_module_files)]
38#![allow(clippy::let_unit_value)] // This can reasonably be done for explicitness
39#![allow(clippy::uninlined_format_args)]
40#![allow(clippy::significant_drop_in_scrutinee)] // arti/-/merge_requests/588/#note_2812945
41#![allow(clippy::result_large_err)] // temporary workaround for arti#587
42#![allow(clippy::needless_raw_string_hashes)] // complained-about code is fine, often best
43#![allow(clippy::needless_lifetimes)] // See arti#1765
44#![allow(mismatched_lifetime_syntaxes)] // temporary workaround for arti#2060
45#![allow(clippy::collapsible_if)] // See arti#2342
46#![deny(clippy::unused_async)]
47//! <!-- @@ end lint list maintained by maint/add_warning @@ -->
48
49use derive_more::Display;
50
51mod internal;
52pub use internal::*;
53
54mod report;
55pub use report::*;
56
57mod retriable;
58pub use retriable::*;
59
60mod misc;
61pub use misc::*;
62
63#[cfg(feature = "tracing")]
64pub mod tracing;
65
66#[cfg(feature = "http")]
67mod http;
68
69/// Classification of an error arising from Arti's Tor operations
70///
71/// This `ErrorKind` should suffice for programmatic handling by most applications embedding Arti:
72/// get the kind via [`HasKind::kind`] and compare it to the expected value(s) with equality
73/// or by matching.
74///
75/// When forwarding or reporting errors, use the whole error (e.g., `TorError`), not just the kind:
76/// the error itself will contain more detail and context which is useful to humans.
77//
78// Splitting vs lumping guidelines:
79//
80// # Split on the place which caused the error
81//
82// Every ErrorKind should generally have an associated "location" in
83// which it occurred. If a problem can happen in two different
84// "locations", it should have two different ErrorKinds. (This goal
85// may be frustrated sometimes by difficulty in determining where exactly
86// a given error occurred.)
87//
88// The location of an ErrorKind should always be clear from its name. If is not
89// clear, add a location-related word to the name of the ErrorKind.
90//
91// For the purposes of this discussion, the following locations exist:
92// - Process: Our code, or the application code using it. These errors don't
93// usually need a special prefix.
94// - Host: A problem with our local computing environment. These errors
95// usually reflect trying to run under impossible circumstances (no file
96// system, no permissions, etc).
97// - Local: Another process on the same machine, or on the network between us
98// and the Tor network. Errors in this location often indicate an outage,
99// misconfiguration, or a censorship event.
100// - Tor: Anywhere within the Tor network, or connections between Tor relays.
101// The words "Exit" and "Relay" also indicate this location.
102// - Remote: Anywhere _beyond_ the Tor exit. Can be a problem in the Tor
103// exit's connection to the real internet, or with the remote host that the
104// exit is talking to. (This kind of error can also indicate that the exit
105// is lying.)
106//
107// ## Lump any locations more fine-grained than that.
108//
109// We do not split locations more finely unless there's a good reason to do so.
110// For example, we don't typically split errors within the "Tor" location based
111// on whether they happened at a guard, a directory, or an exit. (Errors with
112// "Exit" or "Guard" in their names are okay, so long as that kind of error can
113// _only_ occur at an Exit or Guard.)
114//
115// # Split based on reasonable response and semantics
116//
117// We also should split ErrorKinds based on what it's reasonable for the
118// receiver to do with them. Users may find more applications for our errors
119// than we do, so we shouldn't assume that we can predict every reasonable use
120// in advance.
121//
122// ErrorKinds should be more specific than just the locations in which they
123// happen: for example, there shouldn't be a `TorNetworkError` or
124// a `RemoteFailure`.
125//
126// # Avoid exposing implementation details
127//
128// ErrorKinds should not relate to particular code paths in the Arti codebase.
129
130#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)]
131#[non_exhaustive]
132pub enum ErrorKind {
133 /// Error connecting to the Tor network
134 ///
135 /// Perhaps the local network is not working,
136 /// or perhaps the chosen relay or bridge is not working properly.
137 /// Not used for errors that occur within the Tor network, or accessing the public
138 /// internet on the far side of Tor.
139 #[display("error connecting to Tor")]
140 TorAccessFailed,
141
142 /// An attempt was made to use a Tor client for something without bootstrapping it first.
143 #[display("attempted to use unbootstrapped client")]
144 BootstrapRequired,
145
146 /// Our network directory has expired before we were able to replace it.
147 ///
148 /// This kind of error can indicate one of several possible problems:
149 /// * It can occur if the client used to be on the network, but has been
150 /// unable to make directory connections for a while.
151 /// * It can occur if the client has been suspended or sleeping for a long
152 /// time, and has suddenly woken up without having a chance to replace its
153 /// network directory.
154 /// * It can happen if the client has a sudden clock jump.
155 ///
156 /// Often, retrying after a minute or so will resolve this issue.
157 ///
158 // TODO this is pretty shonky. "try again after a minute or so", seriously?
159 //
160 /// Future versions of Arti may resolve this situation automatically without caller
161 /// intervention, possibly depending on preferences and API usage, in which case this kind of
162 /// error will never occur.
163 //
164 // TODO: We should distinguish among the actual issues here, and report a
165 // real bootstrapping problem when it exists.
166 #[display("network directory is expired.")]
167 DirectoryExpired,
168
169 /// IO error accessing local persistent state
170 ///
171 /// For example, the disk might be full, or there may be a permissions problem.
172 /// Usually the source will be [`std::io::Error`].
173 ///
174 /// Note that this kind of error only applies to problems in your `state_dir`:
175 /// problems with your cache are another kind.
176 #[display("could not read/write persistent state")]
177 PersistentStateAccessFailed,
178
179 /// We could not start up because a local resource is already being used by someone else
180 ///
181 /// Local resources include things like listening ports and state lockfiles.
182 /// (We don't use this error for "out of disk space" and the like.)
183 ///
184 /// This can occur when another process
185 /// (or another caller of Arti APIs)
186 /// is already running a facility that overlaps with the one being requested.
187 ///
188 /// For example,
189 /// running multiple processes each containing instances of the same hidden service,
190 /// using the same state directories etc., is not supported.
191 ///
192 /// Another example:
193 /// if Arti is configured to listen on a particular port,
194 /// but another process on the system is already listening there,
195 /// the resulting error has kind `LocalResourceAlreadyInUse`.
196 // Actually, we only currently listen on ports in `arti` so we don't return
197 // any Rust errors for this situation at all, at the time of writing.
198 #[display("local resource (port, lockfile, etc.) already in use")]
199 LocalResourceAlreadyInUse,
200
201 /// We encountered a problem with filesystem permissions.
202 ///
203 /// This is likeliest to be caused by permissions on a file or directory
204 /// being too permissive; the next likeliest cause is that we were unable to
205 /// check the permissions on the file or directory, or on one of its
206 /// ancestors.
207 #[display("problem with filesystem permissions")]
208 FsPermissions,
209
210 /// Tor client's persistent state has been corrupted
211 ///
212 /// This could be because of a bug in the Tor code, or because something
213 /// else has been messing with the data.
214 ///
215 /// This might also occur if the Tor code was upgraded and the new Tor is
216 /// not compatible.
217 ///
218 /// Note that this kind of error only applies to problems in your
219 /// `state_dir`: problems with your cache are another kind.
220 #[display("corrupted data in persistent state")]
221 PersistentStateCorrupted,
222
223 /// Tor client's cache has been corrupted.
224 ///
225 /// This could be because of a bug in the Tor code, or because something else has been messing
226 /// with the data.
227 ///
228 /// This might also occur if the Tor code was upgraded and the new Tor is not compatible.
229 ///
230 /// Note that this kind of error only applies to problems in your `cache_dir`:
231 /// problems with your persistent state are another kind.
232 #[display("corrupted data in cache")]
233 CacheCorrupted,
234
235 /// We had a problem reading or writing to our data cache.
236 ///
237 /// This may be a disk error, a file permission error, or similar.
238 ///
239 /// Note that this kind of error only applies to problems in your `cache_dir`:
240 /// problems with your persistent state are another kind.
241 #[display("cache access problem")]
242 CacheAccessFailed,
243
244 /// The keystore has been corrupted
245 ///
246 /// This could be because of a bug in the Tor code, or because something else has been messing
247 /// with the data.
248 ///
249 /// Note that this kind of error only applies to problems in your `keystore_dir`:
250 /// problems with your cache or persistent state are another kind.
251 #[display("corrupted data in keystore")]
252 KeystoreCorrupted,
253
254 /// IO error accessing keystore
255 ///
256 /// For example, the disk might be full, or there may be a permissions problem.
257 /// The source is typically an [`std::io::Error`].
258 ///
259 /// Note that this kind of error only applies to problems in your `keystore_dir`:
260 /// problems with your cache or persistent state are another kind.
261 #[display("could not access keystore")]
262 KeystoreAccessFailed,
263
264 /// Tor client's Rust async reactor is shutting down.
265 ///
266 /// This likely indicates that the reactor has encountered a fatal error, or
267 /// has been told to do a clean shutdown, and it isn't possible to spawn new
268 /// tasks.
269 #[display("reactor is shutting down")]
270 ReactorShuttingDown,
271
272 /// Tor client is shutting down.
273 ///
274 /// This likely indicates that the last handle to the `TorClient` has been
275 /// dropped, and is preventing other operations from completing.
276 #[display("Tor client is shutting down.")]
277 ArtiShuttingDown,
278
279 /// This Tor client software is missing some feature that is recommended
280 /// (or required) for operation on the network.
281 ///
282 /// This occurs when the directory authorities tell us that we ought to have
283 /// a particular protocol feature that we do not support.
284 /// The correct solution is likely to upgrade to a more recent version of Arti.
285 #[display("Software version is deprecated")]
286 SoftwareDeprecated,
287
288 /// An operation failed because we waited too long for an exit to do
289 /// something.
290 ///
291 /// This error can happen if the host you're trying to connect to isn't
292 /// responding to traffic.
293 /// It can also happen if an exit, or hidden service, is overloaded, and
294 /// unable to answer your replies in a timely manner.
295 ///
296 /// And it might simply mean that the Tor network itself
297 /// (including possibly relays, or hidden service introduction or rendezvous points)
298 /// is not working properly
299 ///
300 /// In either case, trying later, or on a different circuit, might help.
301 //
302 // TODO: Say that this is distinct from the case where the exit _tells you_
303 // that there is a timeout.
304 #[display("operation timed out at exit")]
305 RemoteNetworkTimeout,
306
307 /// One or more configuration values were invalid or incompatible.
308 ///
309 /// This kind of error can happen if the user provides an invalid or badly
310 /// formatted configuration file, if some of the options in that file are
311 /// out of their ranges or unparsable, or if the options are not all
312 /// compatible with one another. It can also happen if configuration options
313 /// provided via APIs are out of range.
314 ///
315 /// If this occurs because of user configuration, it's probably best to tell
316 /// the user about the error. If it occurs because of API usage, it's
317 /// probably best to fix the code that causes the error.
318 #[display("invalid configuration")]
319 InvalidConfig,
320
321 /// Tried to change the configuration of a running Arti service in a way
322 /// that isn't supported.
323 ///
324 /// This kind of error can happen when you call a `reconfigure()` method on
325 /// a service (or part of a service) and the new configuration is not
326 /// compatible with the previous configuration.
327 ///
328 /// The only available remedy is to tear down the service and make a fresh
329 /// one (for example, by making a new `TorClient`).
330 #[display("invalid configuration transition")]
331 InvalidConfigTransition,
332
333 /// Tried to look up a directory depending on the user's home directory, but
334 /// the user's home directory isn't set or can't be found.
335 ///
336 /// This kind of error can also occur if we're running in an environment
337 /// where users don't have home directories.
338 ///
339 /// To resolve this kind of error, either move to an OS with home
340 /// directories, or make sure that all paths in the configuration are set
341 /// explicitly, and do not depend on any path variables.
342 #[display("could not find a home directory")]
343 NoHomeDirectory,
344
345 /// A requested operation was not implemented by Arti.
346 ///
347 /// This kind of error can happen when requesting a piece of protocol
348 /// functionality that has not (yet) been implemented in the Arti project.
349 ///
350 /// If it happens as a result of a user activity, it's fine to ignore, log,
351 /// or report the error. If it happens as a result of direct API usage, it
352 /// may indicate that you're using something that isn't implemented yet.
353 ///
354 /// This kind can relate both to operations which we plan to implement, and
355 /// to operations which we do not. It does not relate to facilities which
356 /// are disabled (e.g. at build time) or harmful.
357 ///
358 /// It can refer to facilities which were once implemented in Tor or Arti
359 /// but for which support has been removed.
360 #[display("operation not implemented")]
361 NotImplemented,
362
363 /// A feature was requested which has been disabled in this build of Arti.
364 ///
365 /// This kind of error happens when the running Arti was built without the
366 /// appropriate feature (usually, cargo feature) enabled.
367 ///
368 /// This might indicate that the overall running system has been
369 /// mis-configured at build-time. Alternatively, it can occur if the
370 /// running system is deliberately stripped down, in which case it might be
371 /// reasonable to simply report this error to a user.
372 #[display("operation not supported because Arti feature disabled")]
373 FeatureDisabled,
374
375 /// Someone or something local violated a network protocol.
376 ///
377 /// This kind of error can happen when a local program accessing us over some
378 /// other protocol violates the protocol's requirements.
379 ///
380 /// This usually indicates a programming error: either in that program's
381 /// implementation of the protocol, or in ours. In any case, the problem
382 /// is with software on the local system (or otherwise sharing a Tor client).
383 ///
384 /// It might also occur if the local system has an incompatible combination
385 /// of tools that we can't talk with.
386 ///
387 /// This error kind does *not* include situations that are better explained
388 /// by a local program simply crashing or terminating unexpectedly.
389 #[display("local protocol violation (local bug or incompatibility)")]
390 LocalProtocolViolation,
391
392 /// Someone or something on the Tor network violated the Tor protocols.
393 ///
394 /// This kind of error can happen when a remote Tor instance behaves in a
395 /// way we don't expect.
396 ///
397 /// It usually indicates a programming error: either in their implementation
398 /// of the protocol, or in ours. It can also indicate an attempted attack,
399 /// though that can be hard to diagnose.
400 #[display("Tor network protocol violation (bug, incompatibility, or attack)")]
401 TorProtocolViolation,
402
403 /// Something went wrong with a network connection or the local network.
404 ///
405 /// This kind of error is usually safe to retry, and shouldn't typically be
406 /// seen. By the time it reaches the caller, a more specific error type
407 /// should typically be available.
408 #[display("problem with network or connection")]
409 LocalNetworkError,
410
411 /// More of a local resource was needed, than is available (or than we are allowed)
412 ///
413 /// For example, we tried to use more memory than permitted by our memory quota.
414 #[display("local resource exhausted")]
415 LocalResourceExhausted,
416
417 /// A problem occurred when launching or communicating with an external
418 /// process running on this computer.
419 #[display("an externally launched plug-in tool failed")]
420 ExternalToolFailed,
421
422 /// A relay had an identity other than the one we expected.
423 ///
424 /// This could indicate a MITM attack, but more likely indicates that the
425 /// relay has changed its identity but the new identity hasn't propagated
426 /// through the directory system yet.
427 #[display("identity mismatch")]
428 RelayIdMismatch,
429
430 /// An attempt to do something remotely through the Tor network failed
431 /// because the circuit it was using shut down before the operation could
432 /// finish.
433 #[display("circuit collapsed")]
434 CircuitCollapse,
435
436 /// An operation timed out on the tor network.
437 ///
438 /// This may indicate a network problem, either with the local network
439 /// environment's ability to contact the Tor network, or with the Tor
440 /// network itself.
441 #[display("tor operation timed out")]
442 TorNetworkTimeout,
443
444 /// We tried but failed to download a piece of directory information.
445 ///
446 /// This is a lower-level kind of error; in general it should be retried
447 /// before the user can see it. In the future it is likely to be split
448 /// into several other kinds.
449 // TODO ^
450 #[display("directory fetch attempt failed")]
451 TorDirectoryError,
452
453 /// An operation finished because a remote stream was closed successfully.
454 ///
455 /// This can indicate that the target server closed the TCP connection,
456 /// or that the exit told us that it closed the TCP connection.
457 /// Callers should generally treat this like a closed TCP connection.
458 #[display("remote stream closed")]
459 RemoteStreamClosed,
460
461 /// An operation finished because the remote stream was closed abruptly.
462 ///
463 /// This kind of error is analogous to an ECONNRESET error; it indicates
464 /// that the exit reported that the stream was terminated without a clean
465 /// TCP shutdown.
466 ///
467 /// For most purposes, it's fine to treat this kind of error the same as
468 /// regular unexpected close.
469 #[display("remote stream reset")]
470 RemoteStreamReset,
471
472 /// An operation finished because a remote stream was closed unsuccessfully.
473 ///
474 /// This indicates that the exit reported some error message for the stream.
475 ///
476 /// We only provide this error kind when no more specific kind is available.
477 #[display("remote stream error")]
478 RemoteStreamError,
479
480 /// A stream failed, and the exit reports that the remote host refused
481 /// the connection.
482 ///
483 /// This is analogous to an ECONNREFUSED error.
484 #[display("remote host refused connection")]
485 RemoteConnectionRefused,
486
487 /// A stream was rejected by the exit relay because of that relay's exit
488 /// policy.
489 ///
490 /// (In Tor, exits have a set of policies declaring which addresses and
491 /// ports they're willing to connect to. Clients download only _summaries_
492 /// of these policies, so it's possible to be surprised by an exit's refusal
493 /// to connect somewhere.)
494 #[display("rejected by exit policy")]
495 ExitPolicyRejected,
496
497 /// An operation failed, and the exit reported that it waited too long for
498 /// the operation to finish.
499 ///
500 /// This kind of error is distinct from `RemoteNetworkTimeout`, which means
501 /// that _our own_ timeout threshold was violated.
502 #[display("timeout at exit relay")]
503 ExitTimeout,
504
505 /// An operation failed, and the exit reported a network failure of some
506 /// kind.
507 ///
508 /// This kind of error can occur for a number of reasons. If it happens
509 /// when trying to open a stream, it usually indicates a problem connecting,
510 /// such as an ENOROUTE error.
511 #[display("network failure at exit")]
512 RemoteNetworkFailed,
513
514 /// An operation finished because an exit failed to look up a hostname.
515 ///
516 /// Unfortunately, the Tor protocol does not distinguish failure of DNS
517 /// services ("we couldn't find out if this host exists and what its name is")
518 /// from confirmed denials ("this is not a hostname"). So this kind
519 /// conflates both those sorts of error.
520 ///
521 /// Trying at another exit might succeed, or the address might truly be
522 /// unresolvable.
523 #[display("remote hostname not found")]
524 RemoteHostNotFound,
525
526 /// The target hidden service (`.onion` service) was not found in the directory
527 ///
528 /// We successfully connected to at least one directory server,
529 /// but it didn't have a record of the hidden service.
530 ///
531 /// This probably means that the hidden service is not running, or does not exist.
532 /// (It might mean that the directory servers are faulty,
533 /// and that the hidden service was unable to publish its descriptor.)
534 #[display("Onion Service not found")]
535 OnionServiceNotFound,
536
537 /// The target hidden service (`.onion` service) seems to be down
538 ///
539 /// We successfully obtained a hidden service descriptor for the service,
540 /// so we know it is supposed to exist,
541 /// but we weren't able to communicate with it via any of its
542 /// introduction points.
543 ///
544 /// This probably means that the hidden service is not running.
545 /// (It might mean that the introduction point relays are faulty.)
546 #[display("Onion Service not running")]
547 OnionServiceNotRunning,
548
549 /// Protocol trouble involving the target hidden service (`.onion` service)
550 ///
551 /// Something unexpected happened when trying to connect to the selected hidden service.
552 /// It seems to have been due to the hidden service violating the Tor protocols somehow.
553 #[display("Onion Service protocol failed (apparently due to service behaviour)")]
554 OnionServiceProtocolViolation,
555
556 /// The target hidden service (`.onion` service) is running but we couldn't connect to it,
557 /// and we aren't sure whose fault that is
558 ///
559 /// This might be due to malfunction on the part of the service,
560 /// or a relay being used as an introduction point or relay,
561 /// or failure of the underlying Tor network.
562 #[display("Onion Service not reachable (due to service, or Tor network, behaviour)")]
563 OnionServiceConnectionFailed,
564
565 /// We tried to connect to an onion service without authentication,
566 /// but it apparently requires authentication.
567 #[display("Onion service required authentication, but none was provided.")]
568 OnionServiceMissingClientAuth,
569
570 /// We tried to connect to an onion service that requires authentication, and
571 /// ours is wrong.
572 ///
573 /// This likely means that we need to use a different key for talking to
574 /// this onion service, or that it has revoked our permissions to reach it.
575 #[display("Onion service required authentication, but provided authentication was incorrect.")]
576 OnionServiceWrongClientAuth,
577
578 /// We tried to parse a `.onion` address, and found that it was not valid.
579 ///
580 /// This likely means that it was corrupted somewhere along its way from its
581 /// origin to our API surface. It may be the wrong length, have invalid
582 /// characters, have an invalid version number, or have an invalid checksum.
583 #[display(".onion address was invalid.")]
584 OnionServiceAddressInvalid,
585
586 /// An resolve operation finished with an error.
587 ///
588 /// Contrary to [`RemoteHostNotFound`](ErrorKind::RemoteHostNotFound),
589 /// this can't mean "this is not a hostname".
590 /// This error should be retried.
591 #[display("remote hostname lookup failure")]
592 RemoteHostResolutionFailed,
593
594 /// Trouble involving a protocol we're using with a peer on the far side of the Tor network
595 ///
596 /// We were using a higher-layer protocol over a Tor connection,
597 /// and something went wrong.
598 /// This might be an error reported by the remote host within that higher protocol,
599 /// or a problem detected locally but relating to that higher protocol.
600 ///
601 /// The nature of the problem can vary:
602 /// examples could include:
603 /// failure to agree suitable parameters (incompatibility);
604 /// authentication problems (eg, TLS certificate trouble);
605 /// protocol violation by the peer;
606 /// peer refusing to provide service;
607 /// etc.
608 #[display("remote protocol violation")]
609 RemoteProtocolViolation,
610
611 /// An operation failed, and the relay in question reported that it's too
612 /// busy to answer our request.
613 #[display("relay too busy")]
614 RelayTooBusy,
615
616 /// We were asked to make an anonymous connection to a malformed address.
617 ///
618 /// This is probably because of a bad input from a user.
619 #[display("target address was invalid")]
620 InvalidStreamTarget,
621
622 /// We were asked to make an anonymous connection to a _locally_ disabled
623 /// address.
624 ///
625 /// For example, this kind of error can happen when try to connect to (e.g.)
626 /// `127.0.0.1` using a client that isn't configured with allow_local_addrs.
627 ///
628 /// Usually this means that you intended to reject the request as
629 /// nonsensical; but if you didn't, it probably means you should change your
630 /// configuration to allow what you want.
631 #[display("target address disabled locally")]
632 ForbiddenStreamTarget,
633
634 /// An operation failed in a transient way.
635 ///
636 /// This kind of error indicates that some kind of operation failed in a way
637 /// where retrying it again could likely have made it work.
638 ///
639 /// You should not generally see this kind of error returned directly to you
640 /// for high-level functions. It should only be returned from lower-level
641 /// crates that do not automatically retry these failures.
642 // Errors with this kind should generally not return a `HasRetryTime::retry_time()` of `Never`.
643 #[display("un-retried transient failure")]
644 TransientFailure,
645
646 /// Bug, for example calling a function with an invalid argument.
647 ///
648 /// This kind of error is usually a programming mistake on the caller's part.
649 /// This is usually a bug in code calling Arti, but it might be a bug in Arti itself.
650 //
651 // Usually, use `bad_api_usage!` and `into_bad_api_usage!` and thereby `InternalError`,
652 // rather than inventing a new type with this kind.
653 //
654 // Errors with this kind should generally include a stack trace. They are
655 // very like InternalError, in that they represent a bug in the program.
656 // The difference is that an InternalError, with kind `Internal`, represents
657 // a bug in arti, whereas errors with kind BadArgument represent bugs which
658 // could be (often, are likely to be) outside arti.
659 #[display("bad API usage (bug)")]
660 BadApiUsage,
661
662 /// We asked a relay to create or extend a circuit, and it declined.
663 ///
664 /// Either it gave an error message indicating that it refused to perform
665 /// the request, or the protocol gives it no room to explain what happened.
666 ///
667 /// This error is returned by higher-level functions only if it is the most informative
668 /// error after appropriate retries etc.
669 #[display("remote host refused our request")]
670 CircuitRefused,
671
672 /// We were unable to construct a path through the Tor network.
673 ///
674 /// Usually this indicates that there are too many user-supplied
675 /// restrictions for us to comply with.
676 ///
677 /// On test networks, it likely indicates that there aren't enough relays,
678 /// or that there aren't enough relays in distinct families.
679 //
680 // TODO: in the future, errors of this type should distinguish between
681 // cases where this happens because of a user restriction and cases where it
682 // happens because of a severely broken directory.
683 //
684 // The latter should be classified as TorDirectoryBroken.
685 #[display("could not construct a path")]
686 NoPath,
687
688 /// We were unable to find an exit relay with a certain set of desired
689 /// properties.
690 ///
691 /// Usually this indicates that there were too many user-supplied
692 /// restrictions on the exit for us to comply with, or that there was no
693 /// exit on the network supporting all of the ports that the user asked for.
694 //
695 // TODO: same as for NoPath.
696 #[display("no exit available for path")]
697 NoExit,
698
699 /// The Tor consensus directory is broken or unsuitable
700 ///
701 /// This could occur when running very old software
702 /// against the current Tor network,
703 /// so that the newer network is incompatible.
704 ///
705 /// It might also mean a catastrophic failure of the Tor network,
706 /// or that a deficient test network is in use.
707 ///
708 /// Currently some instances of this kind of problem
709 /// are reported as `NoPath` or `NoExit`.
710 #[display("Tor network consensus directory is not usable")]
711 TorDirectoryUnusable,
712
713 /// An operation failed because of _possible_ clock skew.
714 ///
715 /// The broken clock may be ours, or it may belong to another party on the
716 /// network. It's also possible that somebody else is lying about the time,
717 /// caching documents for far too long, or something like that.
718 #[display("possible clock skew detected")]
719 ClockSkew,
720
721 /// Internal error (bug) in Arti.
722 ///
723 /// A supposedly impossible problem has arisen. This indicates a bug in
724 /// Arti; if the Arti version is relatively recent, please report the bug on
725 /// our [bug tracker](https://gitlab.torproject.org/tpo/core/arti/-/issues).
726 #[display("internal error (bug)")]
727 Internal,
728
729 /// Unclassified error
730 ///
731 /// Some other error occurred, which does not fit into any of the other kinds.
732 ///
733 /// This kind is provided for use by external code
734 /// hooking into or replacing parts of Arti.
735 /// It is never returned by the code in Arti (`arti-*` and `tor-*` crates).
736 #[display("unclassified error")]
737 Other,
738}
739
740/// Errors that can be categorized as belonging to an [`ErrorKind`]
741///
742/// The most important implementation of this trait is
743/// `arti_client::TorError`; however, other internal errors throughout Arti
744/// also implement it.
745pub trait HasKind {
746 /// Return the kind of this error.
747 fn kind(&self) -> ErrorKind;
748}
749
750#[cfg(feature = "futures")]
751impl HasKind for futures::task::SpawnError {
752 fn kind(&self) -> ErrorKind {
753 use ErrorKind as EK;
754 if self.is_shutdown() {
755 EK::ReactorShuttingDown
756 } else {
757 EK::Internal
758 }
759 }
760}
761
762impl HasKind for void::Void {
763 fn kind(&self) -> ErrorKind {
764 void::unreachable(*self)
765 }
766}
767
768impl HasKind for std::convert::Infallible {
769 fn kind(&self) -> ErrorKind {
770 unreachable!()
771 }
772}
773
774/// Sealed
775mod sealed {
776 /// Sealed
777 pub trait Sealed {}
778}