abuse_contact/error.rs
1//! Error types for the crate.
2
3/// A value that cannot be used as a query or as a result.
4///
5/// These come from the constructors of the newtypes in this crate. A lookup that is
6/// certain to fail never reaches the network, and a placeholder a registry sends in
7/// place of a real address never reaches the caller.
8#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
9#[non_exhaustive]
10pub enum ValidationError {
11 /// The domain name was empty.
12 #[error("the domain name is empty. Give a name such as \"example.com\"")]
13 EmptyDomain,
14
15 /// The domain name was not shaped like a domain name.
16 #[error("\"{value}\" is not a domain name: {problem}")]
17 InvalidDomain {
18 /// The rejected value.
19 value: String,
20 /// What is wrong with it.
21 problem: &'static str,
22 },
23
24 /// The email address was not shaped like an email address.
25 #[error("\"{value}\" is not an email address: {problem}")]
26 InvalidEmail {
27 /// The rejected value.
28 value: String,
29 /// What is wrong with it.
30 problem: &'static str,
31 },
32
33 /// A source sent a fixed address that stands for "no contact published".
34 ///
35 /// A regional registry that withholds the contact of a network answers with one
36 /// address for every network in the region. The address is a marker, not a
37 /// mailbox that reads reports.
38 #[error(
39 "\"{value}\" is the address a source returns when it has no contact for the \
40 network, not a contact. Ask the regional registry, or use the technical \
41 contact from RDAP"
42 )]
43 WithheldEmail {
44 /// The marker the source sent.
45 value: String,
46 },
47
48 /// The registry sent a placeholder in place of an address.
49 ///
50 /// A registry that hides contact data puts a fixed string such as
51 /// `DATA REDACTED` in the field. The string is not an address and must not be
52 /// used as one.
53 #[error(
54 "\"{value}\" is a placeholder the registry sends in place of an address, \
55 not an address. Look for the abuse contact of the network instead"
56 )]
57 RedactedEmail {
58 /// The placeholder the registry sent.
59 value: String,
60 },
61}
62
63/// A lookup that did not finish.
64#[derive(Debug, thiserror::Error)]
65#[non_exhaustive]
66pub enum Error {
67 /// The request did not complete: DNS, TLS, connection or timeout.
68 #[error("the request to {server} did not complete: {source}")]
69 Transport {
70 /// The server the request went to.
71 server: String,
72 /// What the HTTP layer reported.
73 #[source]
74 source: Box<dyn std::error::Error + Send + Sync>,
75 },
76
77 /// The body was not the RDAP this crate expects.
78 #[error("{server} answered with a body that is not RDAP: {source}")]
79 Decode {
80 /// The server that answered.
81 server: String,
82 /// What the reader reported.
83 #[source]
84 source: serde_json::Error,
85 },
86
87 /// The server answered, and the answer was not a record.
88 #[error("{server} answered {status} for {target}")]
89 Status {
90 /// The server that answered.
91 server: String,
92 /// The HTTP status it sent.
93 status: u16,
94 /// What was asked about.
95 target: String,
96 },
97
98 /// The client did not send the request, or did not follow a redirect.
99 ///
100 /// A link in a record and a redirect from a server come from outside the process.
101 /// The client refuses one that goes to an address that is not public, uses a
102 /// scheme other than HTTP or HTTPS, drops from HTTPS to HTTP, or redirects too
103 /// many times.
104 #[error("the client did not request {server}: {reason}")]
105 Refused {
106 /// The URL the client did not request.
107 server: String,
108 /// Why.
109 reason: String,
110 },
111
112 /// The server sent a body longer than the crate reads.
113 ///
114 /// A record is a few kilobytes. A body past the limit is a fault on the server, or
115 /// a server that tries to use up the memory of the process.
116 #[error("{server} sent a body longer than {limit} bytes, which is more than a record")]
117 TooLarge {
118 /// The server that answered.
119 server: String,
120 /// The most the crate reads, in bytes.
121 limit: usize,
122 },
123
124 /// No registry holds the address or the name.
125 ///
126 /// The bootstrap registry names a server for every range IANA has given out. A
127 /// target with no server is a private address, a reserved range, or a name under
128 /// a top-level domain that runs no RDAP server.
129 #[error(
130 "no RDAP server answers for {target}. Check that it is a public address or a \
131 registered name, and not a private or reserved range"
132 )]
133 NoServer {
134 /// What was asked about.
135 target: String,
136 },
137
138 /// The address is not one the public registries describe.
139 ///
140 /// A regional registry holds a record for the reserved block a private address
141 /// sits in, and that record names IANA. Answering with it gives a contact that
142 /// cannot act, so the lookup stops here instead.
143 #[error(
144 "{target} is a private, reserved or documentation address. The registries \
145 describe the reserved block, not the host, so a report about it has no \
146 owner. Use the public address that carried the traffic"
147 )]
148 NotPublic {
149 /// The address that was asked about.
150 target: String,
151 },
152
153 /// A DNS lookup did not finish.
154 ///
155 /// A name that does not exist, or that holds no records of the type asked for, is
156 /// an answer and not this error. This is a lookup that got no answer: a timeout, a
157 /// server that failed, or a resolver configuration the system could not read.
158 #[error(
159 "the DNS lookup for {name} did not finish: {source}. Check that the system \
160 resolver answers, or give nameservers to Resolver::with_nameservers"
161 )]
162 Dns {
163 /// The name that was looked up, or what was being read.
164 name: String,
165 /// What the resolver reported.
166 #[source]
167 source: Box<dyn std::error::Error + Send + Sync>,
168 },
169
170 /// A value did not satisfy a documented limit.
171 #[error(transparent)]
172 Validation(#[from] ValidationError),
173}