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
#![allow(clippy::cognitive_complexity)] // See arti#2556
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
#![warn(clippy::or_fun_call)]
28
#![deny(clippy::print_stderr)]
29
#![deny(clippy::print_stdout)]
30
#![warn(clippy::rc_buffer)]
31
#![deny(clippy::ref_option_ref)]
32
#![warn(clippy::semicolon_if_nothing_returned)]
33
#![warn(clippy::trait_duplication_in_bounds)]
34
#![deny(clippy::unchecked_time_subtraction)]
35
#![deny(clippy::unnecessary_wraps)]
36
#![warn(clippy::unseparated_literal_suffix)]
37
#![deny(clippy::unwrap_used)]
38
#![deny(clippy::mod_module_files)]
39
#![allow(clippy::let_unit_value)] // This can reasonably be done for explicitness
40
#![allow(clippy::uninlined_format_args)]
41
#![allow(clippy::significant_drop_in_scrutinee)] // arti/-/merge_requests/588/#note_2812945
42
#![allow(clippy::result_large_err)] // temporary workaround for arti#587
43
#![allow(clippy::needless_raw_string_hashes)] // complained-about code is fine, often best
44
#![allow(clippy::needless_lifetimes)] // See arti#1765
45
#![allow(mismatched_lifetime_syntaxes)] // temporary workaround for arti#2060
46
#![allow(clippy::collapsible_if)] // See arti#2342
47
#![deny(clippy::unused_async)]
48
#![deny(clippy::string_slice)] // See arti#2571
49
#![allow(recursion_depth_exceeding_limit)] // arti#2715, rust/issues/159228
50
//! <!-- @@ end lint list maintained by maint/add_warning @@ -->
51

            
52
use derive_more::Display;
53

            
54
mod internal;
55
pub use internal::*;
56

            
57
mod report;
58
pub use report::*;
59

            
60
mod retriable;
61
pub use retriable::*;
62

            
63
mod misc;
64
pub use misc::*;
65

            
66
#[cfg(feature = "tracing")]
67
pub mod tracing;
68

            
69
#[cfg(feature = "http")]
70
mod http;
71

            
72
/// Classification of an error arising from Arti's Tor operations
73
///
74
/// This `ErrorKind` should suffice for programmatic handling by most applications embedding Arti:
75
/// get the kind via [`HasKind::kind`] and compare it to the expected value(s) with equality
76
/// or by matching.
77
///
78
/// When forwarding or reporting errors, use the whole error (e.g., `TorError`), not just the kind:
79
/// the error itself will contain more detail and context which is useful to humans.
80
//
81
// Splitting vs lumping guidelines:
82
//
83
// # Split on the place which caused the error
84
//
85
// Every ErrorKind should generally have an associated "location" in
86
// which it occurred.  If a problem can happen in two different
87
// "locations", it should have two different ErrorKinds.  (This goal
88
// may be frustrated sometimes by difficulty in determining where exactly
89
// a given error occurred.)
90
//
91
// The location of an ErrorKind should always be clear from its name.  If is not
92
// clear, add a location-related word to the name of the ErrorKind.
93
//
94
// For the purposes of this discussion, the following locations exist:
95
//   - Process:  Our code, or the application code using it.  These errors don't
96
//     usually need a special prefix.
97
//   - Host: A problem with our local computing  environment.  These errors
98
//     usually reflect trying to run under impossible circumstances (no file
99
//     system, no permissions, etc).
100
//   - Local: Another process on the same machine, or on the network between us
101
//     and the Tor network.  Errors in this location often indicate an outage,
102
//     misconfiguration, or a censorship event.
103
//   - Tor: Anywhere within the Tor network, or connections between Tor relays.
104
//     The words "Exit" and "Relay" also indicate this location.
105
//   - Remote: Anywhere _beyond_ the Tor exit. Can be a problem in the Tor
106
//     exit's connection to the real internet,  or with the remote host that the
107
//     exit is talking to.  (This kind of error can also indicate that the exit
108
//     is lying.)
109
//
110
// ## Lump any locations more fine-grained than that.
111
//
112
// We do not split locations more finely unless there's a good reason to do so.
113
// For example, we don't typically split errors within the "Tor" location based
114
// on whether they happened at a guard, a directory, or an exit.  (Errors with
115
// "Exit" or "Guard" in their names are okay, so long as that kind of error can
116
// _only_ occur at an Exit or Guard.)
117
//
118
// # Split based on reasonable response and semantics
119
//
120
// We also should split ErrorKinds based on what it's reasonable for the
121
// receiver to do with them.  Users may find more applications for our errors
122
// than we do, so we shouldn't assume that we can predict every reasonable use
123
// in advance.
124
//
125
// ErrorKinds should be more specific than just the locations in which they
126
// happen: for example, there shouldn't be a `TorNetworkError` or
127
// a `RemoteFailure`.
128
//
129
// # Avoid exposing implementation details
130
//
131
// ErrorKinds should not relate to particular code paths in the Arti codebase.
132

            
133
#[derive(Debug, Clone, Copy, PartialEq, Eq, Display, Hash)]
134
#[non_exhaustive]
135
pub enum ErrorKind {
136
    /// Error connecting to the Tor network
137
    ///
138
    /// Perhaps the local network is not working,
139
    /// or perhaps the chosen relay or bridge is not working properly.
140
    /// Not used for errors that occur within the Tor network, or accessing the public
141
    /// internet on the far side of Tor.
142
    #[display("error connecting to Tor")]
143
    TorAccessFailed,
144

            
145
    /// An attempt was made to use a Tor client for something without bootstrapping it first.
146
    #[display("attempted to use unbootstrapped client")]
147
    BootstrapRequired,
148

            
149
    /// Our network directory has expired before we were able to replace it.
150
    ///
151
    /// This kind of error can indicate one of several possible problems:
152
    /// * It can occur if the client used to be on the network, but has been
153
    ///   unable to make directory connections for a while.
154
    /// * It can occur if the client has been suspended or sleeping for a long
155
    ///   time, and has suddenly woken up without having a chance to replace its
156
    ///   network directory.
157
    /// * It can happen if the client has a sudden clock jump.
158
    ///
159
    /// Often, retrying after a minute or so will resolve this issue.
160
    ///
161
    // TODO this is pretty shonky.  "try again after a minute or so", seriously?
162
    //
163
    /// Future versions of Arti may resolve this situation automatically without caller
164
    /// intervention, possibly depending on preferences and API usage, in which case this kind of
165
    /// error will never occur.
166
    //
167
    // TODO: We should distinguish among the actual issues here, and report a
168
    // real bootstrapping problem when it exists.
169
    #[display("network directory is expired.")]
170
    DirectoryExpired,
171

            
172
    /// IO error accessing local persistent state
173
    ///
174
    /// For example, the disk might be full, or there may be a permissions problem.
175
    /// Usually the source will be [`std::io::Error`].
176
    ///
177
    /// Note that this kind of error only applies to problems in your `state_dir`:
178
    /// problems with your cache are another kind.
179
    #[display("could not read/write persistent state")]
180
    PersistentStateAccessFailed,
181

            
182
    /// We could not start up because a local resource is already being used by someone else
183
    ///
184
    /// Local resources include things like listening ports and state lockfiles.
185
    /// (We don't use this error for "out of disk space" and the like.)
186
    ///
187
    /// This can occur when another process
188
    /// (or another caller of Arti APIs)
189
    /// is already running a facility that overlaps with the one being requested.
190
    ///
191
    /// For example,
192
    /// running multiple processes each containing instances of the same hidden service,
193
    /// using the same state directories etc., is not supported.
194
    ///
195
    /// Another example:
196
    /// if Arti is configured to listen on a particular port,
197
    /// but another process on the system is already listening there,
198
    /// the resulting error has kind `LocalResourceAlreadyInUse`.
199
    // Actually, we only currently listen on ports in `arti` so we don't return
200
    // any Rust errors for this situation at all, at the time of writing.
201
    #[display("local resource (port, lockfile, etc.) already in use")]
202
    LocalResourceAlreadyInUse,
203

            
204
    /// We encountered a problem with filesystem permissions.
205
    ///
206
    /// This is likeliest to be caused by permissions on a file or directory
207
    /// being too permissive; the next likeliest cause is that we were unable to
208
    /// check the permissions on the file or directory, or on one of its
209
    /// ancestors.
210
    #[display("problem with filesystem permissions")]
211
    FsPermissions,
212

            
213
    /// Tor client's persistent state has been corrupted
214
    ///
215
    /// This could be because of a bug in the Tor code, or because something
216
    /// else has been messing with the data.
217
    ///
218
    /// This might also occur if the Tor code was upgraded and the new Tor is
219
    /// not compatible.
220
    ///
221
    /// Note that this kind of error only applies to problems in your
222
    /// `state_dir`: problems with your cache are another kind.
223
    #[display("corrupted data in persistent state")]
224
    PersistentStateCorrupted,
225

            
226
    /// Tor client's cache has been corrupted.
227
    ///
228
    /// This could be because of a bug in the Tor code, or because something else has been messing
229
    /// with the data.
230
    ///
231
    /// This might also occur if the Tor code was upgraded and the new Tor is not compatible.
232
    ///
233
    /// Note that this kind of error only applies to problems in your `cache_dir`:
234
    /// problems with your persistent state are another kind.
235
    #[display("corrupted data in cache")]
236
    CacheCorrupted,
237

            
238
    /// We had a problem reading or writing to our data cache.
239
    ///
240
    /// This may be a disk error, a file permission error, or similar.
241
    ///
242
    /// Note that this kind of error only applies to problems in your `cache_dir`:
243
    /// problems with your persistent state are another kind.
244
    #[display("cache access problem")]
245
    CacheAccessFailed,
246

            
247
    /// The keystore has been corrupted
248
    ///
249
    /// This could be because of a bug in the Tor code, or because something else has been messing
250
    /// with the data.
251
    ///
252
    /// Note that this kind of error only applies to problems in your `keystore_dir`:
253
    /// problems with your cache or persistent state are another kind.
254
    #[display("corrupted data in keystore")]
255
    KeystoreCorrupted,
256

            
257
    /// IO error accessing keystore
258
    ///
259
    /// For example, the disk might be full, or there may be a permissions problem.
260
    /// The source is typically an [`std::io::Error`].
261
    ///
262
    /// Note that this kind of error only applies to problems in your `keystore_dir`:
263
    /// problems with your cache or persistent state are another kind.
264
    #[display("could not access keystore")]
265
    KeystoreAccessFailed,
266

            
267
    /// Tor client's Rust async reactor is shutting down.
268
    ///
269
    /// This likely indicates that the reactor has encountered a fatal error, or
270
    /// has been told to do a clean shutdown, and it isn't possible to spawn new
271
    /// tasks.
272
    #[display("reactor is shutting down")]
273
    ReactorShuttingDown,
274

            
275
    /// Tor client is shutting down.
276
    ///
277
    /// This likely indicates that the last handle to the `TorClient` has been
278
    /// dropped, and is preventing other operations from completing.
279
    #[display("Tor client is shutting down.")]
280
    ArtiShuttingDown,
281

            
282
    /// This Tor client software is missing some feature that is recommended
283
    /// (or required) for operation on the network.
284
    ///
285
    /// This occurs when the directory authorities tell us that we ought to have
286
    /// a particular protocol feature that we do not support.
287
    /// The correct solution is likely to upgrade to a more recent version of Arti.
288
    #[display("Software version is deprecated")]
289
    SoftwareDeprecated,
290

            
291
    /// An operation failed because we waited too long for an exit to do
292
    /// something.
293
    ///
294
    /// This error can happen if the host you're trying to connect to isn't
295
    /// responding to traffic.
296
    /// It can also happen if an exit, or hidden service, is overloaded, and
297
    /// unable to answer your replies in a timely manner.
298
    ///
299
    /// And it might simply mean that the Tor network itself
300
    /// (including possibly relays, or hidden service introduction or rendezvous points)
301
    /// is not working properly
302
    ///
303
    /// In either case, trying later, or on a different circuit, might help.
304
    //
305
    // TODO: Say that this is distinct from the case where the exit _tells you_
306
    // that there is a timeout.
307
    #[display("operation timed out at exit")]
308
    RemoteNetworkTimeout,
309

            
310
    /// One or more configuration values were invalid or incompatible.
311
    ///
312
    /// This kind of error can happen if the user provides an invalid or badly
313
    /// formatted configuration file, if some of the options in that file are
314
    /// out of their ranges or unparsable, or if the options are not all
315
    /// compatible with one another. It can also happen if configuration options
316
    /// provided via APIs are out of range.
317
    ///
318
    /// If this occurs because of user configuration, it's probably best to tell
319
    /// the user about the error. If it occurs because of API usage, it's
320
    /// probably best to fix the code that causes the error.
321
    #[display("invalid configuration")]
322
    InvalidConfig,
323

            
324
    /// Tried to change the configuration of a running Arti service in a way
325
    /// that isn't supported.
326
    ///
327
    /// This kind of error can happen when you call a `reconfigure()` method on
328
    /// a service (or part of a service) and the new configuration is not
329
    /// compatible with the previous configuration.
330
    ///
331
    /// The only available remedy is to tear down the service and make a fresh
332
    /// one (for example, by making a new `TorClient`).
333
    #[display("invalid configuration transition")]
334
    InvalidConfigTransition,
335

            
336
    /// Tried to look up a directory depending on the user's home directory, but
337
    /// the user's home directory isn't set or can't be found.
338
    ///
339
    /// This kind of error can also occur if we're running in an environment
340
    /// where users don't have home directories.
341
    ///
342
    /// To resolve this kind of error, either move to an OS with home
343
    /// directories, or make sure that all paths in the configuration are set
344
    /// explicitly, and do not depend on any path variables.
345
    #[display("could not find a home directory")]
346
    NoHomeDirectory,
347

            
348
    /// A requested operation was not implemented by Arti.
349
    ///
350
    /// This kind of error can happen when requesting a piece of protocol
351
    /// functionality that has not (yet) been implemented in the Arti project.
352
    ///
353
    /// If it happens as a result of a user activity, it's fine to ignore, log,
354
    /// or report the error. If it happens as a result of direct API usage, it
355
    /// may indicate that you're using something that isn't implemented yet.
356
    ///
357
    /// This kind can relate both to operations which we plan to implement, and
358
    /// to operations which we do not.  It does not relate to facilities which
359
    /// are disabled (e.g. at build time) or harmful.
360
    ///
361
    /// It can refer to facilities which were once implemented in Tor or Arti
362
    /// but for which support has been removed.
363
    #[display("operation not implemented")]
364
    NotImplemented,
365

            
366
    /// A feature was requested which has been disabled in this build of Arti.
367
    ///
368
    /// This kind of error happens when the running Arti was built without the
369
    /// appropriate feature (usually, cargo feature) enabled.
370
    ///
371
    /// This might indicate that the overall running system has been
372
    /// mis-configured at build-time.  Alternatively, it can occur if the
373
    /// running system is deliberately stripped down, in which case it might be
374
    /// reasonable to simply report this error to a user.
375
    #[display("operation not supported because Arti feature disabled")]
376
    FeatureDisabled,
377

            
378
    /// Someone or something local violated a network protocol.
379
    ///
380
    /// This kind of error can happen when a local program accessing us over some
381
    /// other protocol violates the protocol's requirements.
382
    ///
383
    /// This usually indicates a programming error: either in that program's
384
    /// implementation of the protocol, or in ours.  In any case, the problem
385
    /// is with software on the local system (or otherwise sharing a Tor client).
386
    ///
387
    /// It might also occur if the local system has an incompatible combination
388
    /// of tools that we can't talk with.
389
    ///
390
    /// This error kind does *not* include situations that are better explained
391
    /// by a local program simply crashing or terminating unexpectedly.
392
    #[display("local protocol violation (local bug or incompatibility)")]
393
    LocalProtocolViolation,
394

            
395
    /// Someone or something on the Tor network violated the Tor protocols.
396
    ///
397
    /// This kind of error can happen when a remote Tor instance behaves in a
398
    /// way we don't expect.
399
    ///
400
    /// It usually indicates a programming error: either in their implementation
401
    /// of the protocol, or in ours.  It can also indicate an attempted attack,
402
    /// though that can be hard to diagnose.
403
    #[display("Tor network protocol violation (bug, incompatibility, or attack)")]
404
    TorProtocolViolation,
405

            
406
    /// Something went wrong with a network connection or the local network.
407
    ///
408
    /// This kind of error is usually safe to retry, and shouldn't typically be
409
    /// seen.  By the time it reaches the caller, a more specific error type
410
    /// should typically be available.
411
    #[display("problem with network or connection")]
412
    LocalNetworkError,
413

            
414
    /// More of a local resource was needed, than is available (or than we are allowed)
415
    ///
416
    /// For example, we tried to use more memory than permitted by our memory quota.
417
    #[display("local resource exhausted")]
418
    LocalResourceExhausted,
419

            
420
    /// A problem occurred when launching or communicating with an external
421
    /// process running on this computer.
422
    #[display("an externally launched plug-in tool failed")]
423
    ExternalToolFailed,
424

            
425
    /// A relay had an identity other than the one we expected.
426
    ///
427
    /// This could indicate a MITM attack, but more likely indicates that the
428
    /// relay has changed its identity but the new identity hasn't propagated
429
    /// through the directory system yet.
430
    #[display("identity mismatch")]
431
    RelayIdMismatch,
432

            
433
    /// An attempt to do something remotely through the Tor network failed
434
    /// because the circuit it was using shut down before the operation could
435
    /// finish.
436
    #[display("circuit collapsed")]
437
    CircuitCollapse,
438

            
439
    /// An operation timed out on the tor network.
440
    ///
441
    /// This may indicate a network problem, either with the local network
442
    /// environment's ability to contact the Tor network, or with the Tor
443
    /// network itself.
444
    #[display("tor operation timed out")]
445
    TorNetworkTimeout,
446

            
447
    /// We tried but failed to download or upload a piece of directory information.
448
    ///
449
    /// This is a lower-level kind of error; in general it should be retried
450
    /// before the user can see it.   In the future it is likely to be split
451
    /// into several other kinds.
452
    // TODO ^
453
    #[display("directory fetch or upload attempt failed")]
454
    TorDirectoryError,
455

            
456
    /// An operation finished because a remote stream was closed successfully.
457
    ///
458
    /// This can indicate that the target server closed the TCP connection,
459
    /// or that the exit told us that it closed the TCP connection.
460
    /// Callers should generally treat this like a closed TCP connection.
461
    #[display("remote stream closed")]
462
    RemoteStreamClosed,
463

            
464
    /// An operation finished because the remote stream was closed abruptly.
465
    ///
466
    /// This kind of error is analogous to an ECONNRESET error; it indicates
467
    /// that the exit reported that the stream was terminated without a clean
468
    /// TCP shutdown.
469
    ///
470
    /// For most purposes, it's fine to treat this kind of error the same as
471
    /// regular unexpected close.
472
    #[display("remote stream reset")]
473
    RemoteStreamReset,
474

            
475
    /// An operation finished because a remote stream was closed unsuccessfully.
476
    ///
477
    /// This indicates that the exit reported some error message for the stream.
478
    ///
479
    /// We only provide this error kind when no more specific kind is available.
480
    #[display("remote stream error")]
481
    RemoteStreamError,
482

            
483
    /// A stream failed, and the exit reports that the remote host refused
484
    /// the connection.
485
    ///
486
    /// This is analogous to an ECONNREFUSED error.
487
    #[display("remote host refused connection")]
488
    RemoteConnectionRefused,
489

            
490
    /// A stream was rejected by the exit relay because of that relay's exit
491
    /// policy.
492
    ///
493
    /// (In Tor, exits have a set of policies declaring which addresses and
494
    /// ports they're willing to connect to.  Clients download only _summaries_
495
    /// of these policies, so it's possible to be surprised by an exit's refusal
496
    /// to connect somewhere.)
497
    #[display("rejected by exit policy")]
498
    ExitPolicyRejected,
499

            
500
    /// An operation failed, and the exit reported that it waited too long for
501
    /// the operation to finish.
502
    ///
503
    /// This kind of error is distinct from `RemoteNetworkTimeout`, which means
504
    /// that _our own_ timeout threshold was violated.
505
    #[display("timeout at exit relay")]
506
    ExitTimeout,
507

            
508
    /// An operation failed, and the exit reported a network failure of some
509
    /// kind.
510
    ///
511
    /// This kind of error can occur for a number of reasons.  If it happens
512
    /// when trying to open a stream, it usually indicates a problem connecting,
513
    /// such as an ENOROUTE error.
514
    #[display("network failure at exit")]
515
    RemoteNetworkFailed,
516

            
517
    /// An operation finished because an exit failed to look up a hostname.
518
    ///
519
    /// Unfortunately, the Tor protocol does not distinguish failure of DNS
520
    /// services ("we couldn't find out if this host exists and what its name is")
521
    /// from confirmed denials ("this is not a hostname").  So this kind
522
    /// conflates both those sorts of error.
523
    ///
524
    /// Trying at another exit might succeed, or the address might truly be
525
    /// unresolvable.
526
    #[display("remote hostname not found")]
527
    RemoteHostNotFound,
528

            
529
    /// The target hidden service (`.onion` service) was not found in the directory
530
    ///
531
    /// We successfully connected to at least one directory server,
532
    /// but it didn't have a record of the hidden service.
533
    ///
534
    /// This probably means that the hidden service is not running, or does not exist.
535
    /// (It might mean that the directory servers are faulty,
536
    /// and that the hidden service was unable to publish its descriptor.)
537
    #[display("Onion Service not found")]
538
    OnionServiceNotFound,
539

            
540
    /// The target hidden service (`.onion` service) seems to be down
541
    ///
542
    /// We successfully obtained a hidden service descriptor for the service,
543
    /// so we know it is supposed to exist,
544
    /// but we weren't able to communicate with it via any of its
545
    /// introduction points.
546
    ///
547
    /// This probably means that the hidden service is not running.
548
    /// (It might mean that the introduction point relays are faulty.)
549
    #[display("Onion Service not running")]
550
    OnionServiceNotRunning,
551

            
552
    /// Protocol trouble involving the target hidden service (`.onion` service)
553
    ///
554
    /// Something unexpected happened when trying to connect to the selected hidden service.
555
    /// It seems to have been due to the hidden service violating the Tor protocols somehow.
556
    #[display("Onion Service protocol failed (apparently due to service behaviour)")]
557
    OnionServiceProtocolViolation,
558

            
559
    /// The target hidden service (`.onion` service) is running but we couldn't connect to it,
560
    /// and we aren't sure whose fault that is
561
    ///
562
    /// This might be due to malfunction on the part of the service,
563
    /// or a relay being used as an introduction point or relay,
564
    /// or failure of the underlying Tor network.
565
    #[display("Onion Service not reachable (due to service, or Tor network, behaviour)")]
566
    OnionServiceConnectionFailed,
567

            
568
    /// We tried to connect to an onion service without authentication,
569
    /// but it apparently requires authentication.
570
    #[display("Onion service required authentication, but none was provided.")]
571
    OnionServiceMissingClientAuth,
572

            
573
    /// We tried to connect to an onion service that requires authentication, and
574
    /// ours is wrong.
575
    ///
576
    /// This likely means that we need to use a different key for talking to
577
    /// this onion service, or that it has revoked our permissions to reach it.
578
    #[display("Onion service required authentication, but provided authentication was incorrect.")]
579
    OnionServiceWrongClientAuth,
580

            
581
    /// We tried to parse a `.onion` address, and found that it was not valid.
582
    ///
583
    /// This likely means that it was corrupted somewhere along its way from its
584
    /// origin to our API surface.  It may be the wrong length, have invalid
585
    /// characters, have an invalid version number, or have an invalid checksum.
586
    #[display(".onion address was invalid.")]
587
    OnionServiceAddressInvalid,
588

            
589
    /// An resolve operation finished with an error.
590
    ///
591
    /// Contrary to [`RemoteHostNotFound`](ErrorKind::RemoteHostNotFound),
592
    /// this can't mean "this is not a hostname".
593
    /// This error should be retried.
594
    #[display("remote hostname lookup failure")]
595
    RemoteHostResolutionFailed,
596

            
597
    /// Trouble involving a protocol we're using with a peer on the far side of the Tor network
598
    ///
599
    /// We were using a higher-layer protocol over a Tor connection,
600
    /// and something went wrong.
601
    /// This might be an error reported by the remote host within that higher protocol,
602
    /// or a problem detected locally but relating to that higher protocol.
603
    ///
604
    /// The nature of the problem can vary:
605
    /// examples could include:
606
    /// failure to agree suitable parameters (incompatibility);
607
    /// authentication problems (eg, TLS certificate trouble);
608
    /// protocol violation by the peer;
609
    /// peer refusing to provide service;
610
    /// etc.
611
    #[display("remote protocol violation")]
612
    RemoteProtocolViolation,
613

            
614
    /// An operation failed, and the relay in question reported that it's too
615
    /// busy to answer our request.
616
    #[display("relay too busy")]
617
    RelayTooBusy,
618

            
619
    /// We were asked to make an anonymous connection to a malformed address.
620
    ///
621
    /// This is probably because of a bad input from a user.
622
    #[display("target address was invalid")]
623
    InvalidStreamTarget,
624

            
625
    /// We were asked to make an anonymous connection to a _locally_ disabled
626
    /// address.
627
    ///
628
    /// For example, this kind of error can happen when try to connect to (e.g.)
629
    /// `127.0.0.1` using a client that isn't configured with allow_local_addrs.
630
    ///
631
    /// Usually this means that you intended to reject the request as
632
    /// nonsensical; but if you didn't, it probably means you should change your
633
    /// configuration to allow what you want.
634
    #[display("target address disabled locally")]
635
    ForbiddenStreamTarget,
636

            
637
    /// An operation failed in a transient way.
638
    ///
639
    /// This kind of error indicates that some kind of operation failed in a way
640
    /// where retrying it again could likely have made it work.
641
    ///
642
    /// You should not generally see this kind of error returned directly to you
643
    /// for high-level functions.  It should only be returned from lower-level
644
    /// crates that do not automatically retry these failures.
645
    // Errors with this kind should generally not return a `HasRetryTime::retry_time()` of `Never`.
646
    #[display("un-retried transient failure")]
647
    TransientFailure,
648

            
649
    /// Bug, for example calling a function with an invalid argument.
650
    ///
651
    /// This kind of error is usually a programming mistake on the caller's part.
652
    /// This is usually a bug in code calling Arti, but it might be a bug in Arti itself.
653
    //
654
    // Usually, use `bad_api_usage!` and `into_bad_api_usage!` and thereby `InternalError`,
655
    // rather than inventing a new type with this kind.
656
    //
657
    // Errors with this kind should generally include a stack trace.  They are
658
    // very like InternalError, in that they represent a bug in the program.
659
    // The difference is that an InternalError, with kind `Internal`, represents
660
    // a bug in arti, whereas errors with kind BadArgument represent bugs which
661
    // could be (often, are likely to be) outside arti.
662
    #[display("bad API usage (bug)")]
663
    BadApiUsage,
664

            
665
    /// We asked a relay to create or extend a circuit, and it declined.
666
    ///
667
    /// Either it gave an error message indicating that it refused to perform
668
    /// the request, or the protocol gives it no room to explain what happened.
669
    ///
670
    /// This error is returned by higher-level functions only if it is the most informative
671
    /// error after appropriate retries etc.
672
    #[display("remote host refused our request")]
673
    CircuitRefused,
674

            
675
    /// We were unable to construct a path through the Tor network.
676
    ///
677
    /// Usually this indicates that there are too many user-supplied
678
    /// restrictions for us to comply with.
679
    ///
680
    /// On test networks, it likely indicates that there aren't enough relays,
681
    /// or that there aren't enough relays in distinct families.
682
    //
683
    // TODO: in the future, errors of this type should distinguish between
684
    // cases where this happens because of a user restriction and cases where it
685
    // happens because of a severely broken directory.
686
    //
687
    // The latter should be classified as TorDirectoryBroken.
688
    #[display("could not construct a path")]
689
    NoPath,
690

            
691
    /// We were unable to find an exit relay with a certain set of desired
692
    /// properties.
693
    ///
694
    /// Usually this indicates that there were too many user-supplied
695
    /// restrictions on the exit for us to comply with, or that there was no
696
    /// exit on the network supporting all of the ports that the user asked for.
697
    //
698
    // TODO: same as for NoPath.
699
    #[display("no exit available for path")]
700
    NoExit,
701

            
702
    /// The Tor consensus directory is broken or unsuitable
703
    ///
704
    /// This could occur when running very old software
705
    /// against the current Tor network,
706
    /// so that the newer network is incompatible.
707
    ///
708
    /// It might also mean a catastrophic failure of the Tor network,
709
    /// or that a deficient test network is in use.
710
    ///
711
    /// Currently some instances of this kind of problem
712
    /// are reported as `NoPath` or `NoExit`.
713
    #[display("Tor network consensus directory is not usable")]
714
    TorDirectoryUnusable,
715

            
716
    /// An operation failed because of _possible_ clock skew.
717
    ///
718
    /// The broken clock may be ours, or it may belong to another party on the
719
    /// network. It's also possible that somebody else is lying about the time,
720
    /// caching documents for far too long, or something like that.
721
    #[display("possible clock skew detected")]
722
    ClockSkew,
723

            
724
    /// A directory told us that some document we were trying to upload
725
    /// is not acceptable.
726
    ///
727
    /// This could be our fault (if we have a bug, if we're misconfigured,
728
    /// if we are running very old software, etc),
729
    /// or it could be the fault of the remote host
730
    /// (if it is running very old software).
731
    ///
732
    /// In the case of an upload over unencrypted HTTP, this error
733
    /// could also be the result of a MITM attacker impersonating the directory.
734
    TorDocumentRejected,
735

            
736
    /// Internal error (bug) in Arti.
737
    ///
738
    /// A supposedly impossible problem has arisen.  This indicates a bug in
739
    /// Arti; if the Arti version is relatively recent, please report the bug on
740
    /// our [bug tracker](https://gitlab.torproject.org/tpo/core/arti/-/issues).
741
    #[display("internal error (bug)")]
742
    Internal,
743

            
744
    /// Unclassified error
745
    ///
746
    /// Some other error occurred, which does not fit into any of the other kinds.
747
    ///
748
    /// This kind is provided for use by external code
749
    /// hooking into or replacing parts of Arti.
750
    /// It is never returned by the code in Arti (`arti-*` and `tor-*` crates).
751
    #[display("unclassified error")]
752
    Other,
753
}
754

            
755
/// Errors that can be categorized as belonging to an [`ErrorKind`]
756
///
757
/// The most important implementation of this trait is
758
/// `arti_client::TorError`; however, other internal errors throughout Arti
759
/// also implement it.
760
pub trait HasKind {
761
    /// Return the kind of this error.
762
    fn kind(&self) -> ErrorKind;
763
}
764

            
765
#[cfg(feature = "futures")]
766
impl HasKind for futures::task::SpawnError {
767
89
    fn kind(&self) -> ErrorKind {
768
        use ErrorKind as EK;
769
89
        if self.is_shutdown() {
770
89
            EK::ReactorShuttingDown
771
        } else {
772
            EK::Internal
773
        }
774
89
    }
775
}
776

            
777
impl HasKind for void::Void {
778
    fn kind(&self) -> ErrorKind {
779
        void::unreachable(*self)
780
    }
781
}
782

            
783
impl HasKind for std::convert::Infallible {
784
    fn kind(&self) -> ErrorKind {
785
        unreachable!()
786
    }
787
}
788

            
789
/// Sealed
790
mod sealed {
791
    /// Sealed
792
    pub trait Sealed {}
793
}