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
//! Fetch user-supplied URLs from a server without letting them reach your
//! private network.
//!
//! When a server fetches a URL someone else gave it (a webhook, a link
//! preview, an uptime check), the URL can point at `127.0.0.1`, at the cloud
//! metadata service on `169.254.169.254`, or at a name that resolves to one
//! of them.
//!
//! A [`Fetcher`] resolves every hop itself and refuses the whole name if any
//! address is loopback, private, link-local or otherwise not public
//! ([`is_public`] has the list, IPv6 spellings included). It then connects
//! only to the addresses it checked. A DNS answer that changes afterwards
//! changes nothing. Redirects are followed by hand and checked again, a
//! redirect to another origin goes without the headers and body you set,
//! proxies from the environment are ignored, and one timeout covers the
//! whole chain.
//!
//! ```no_run
//! use ssrf_guard::{Fetcher, Policy};
//!
//! # async fn run() -> Result<(), ssrf_guard::Error> {
//! let fetcher = Fetcher::new(Policy::default());
//! let resp = fetcher.get("https://example.com/").await?;
//! println!("{} from {:?}", resp.status(), resp.remote_addr());
//! let body = resp.text().await?;
//! # Ok(())
//! # }
//! ```
//!
//! A redirect to `http://localhost/` or to a name that resolves to `10.1.2.3`
//! fails with [`Error::Denied`]. [`Fetcher::connect`] does the same checks
//! for a plain TCP connection, and [`Fetcher::resolve`] for anything else
//! you connect yourself.
//!
//! To refuse more, such as your own servers' public addresses, add blocks
//! with [`PolicyBuilder::deny`]. To let something through that the list refuses,
//! such as loopback in tests, use [`PolicyBuilder::allow`].
//!
//! # Platform notes
//!
//! Needs a tokio runtime. TLS is rustls with the platform verifier, which
//! checks certificates against the operating system's trust store. On
//! Linux that needs a CA bundle installed (`ca-certificates` on Debian and
//! Alpine), which slim container images often leave out. TLS session
//! resumption is off. A server can't use session tickets to tie one
//! caller's fetches to another's. HTTP/1.1 only.
//!
//! The system resolver blocks a thread per lookup, and the policy's timeout
//! can't stop it. See [`PolicyBuilder::timeout`].
//!
//! The checks run on the addresses this process connects to. They can't see
//! past a NAT64 gateway or a VPN that routes public addresses somewhere
//! private, and they don't stop a public server you fetch from doing
//! whatever it likes with the request.
pub use ;
pub use Error;
pub use ;
pub use ;
pub use Bytes;
pub use header;
pub use ;
pub use Url;
// Compiles the README's example with the doctests.
;