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