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
//! Version banner output.
//!
//! `print_full` matches curl's `--version` format so existing curl tooling
//! (e.g. `grep -q HTTP2 <(curl --version)`) works against recon output.
//! `print_short` prints just `recon <version>` for scripts that only want
//! the number.
const RELEASE_DATE: &str = "2026-05-29";
// Update these when the corresponding Cargo.toml entries change majors/minors.
// Patch-version drift is not reflected — the banner reports the API surface.
const REQWEST_VERSION: &str = "0.12";
const RUSTLS_VERSION: &str = "0.23";
/// Protocols recon can speak. Keep this list in sync with the URL-scheme
/// dispatch in `main.rs` (and the `source::resolve_file_url` branch for
/// `file://`). When adding or removing protocol support, update this list
/// so `recon --version | grep <proto>` stays accurate. Rendered sorted
/// case-insensitively in `print_full`.
// scp / sftp / ssh are gated behind the `ssh` feature (default-on, dropped
// in the impersonate variant — see GitHub issue #1). They are appended
// conditionally in `print_full` rather than listed here.
const PROTOCOLS: &[&str] = &[
"dict", "dig", "dns", "drill", "file", "ftp", "ftps", "gopher", "gophers",
"http", "https", "imap", "imaps", "ipfs", "ipns", "ldap", "ldaps", "memcached",
"mqtt", "mqtts", "ntp", "ping", "pop3", "pop3s", "redis", "rtsp", "rtsps",
"smtp", "smtps", "tcp", "telnet", "tftp", "tls",
"traceroute", "udp", "whois", "ws", "wss",
];
/// Feature tokens. Kept curl-compatible where the concept overlaps (HTTP2,
/// HTTPS, IPv6, SSL, gzip, deflate, brotli, zstd) and recon-specific
/// otherwise (rustls-tls, charset, DKIM-signing, JWT, etc.). Rendered
/// sorted case-insensitively in `print_full` so the output scans easily.
const FEATURES: &[&str] = &[
"age-encrypt",
"archive",
"AsynchDNS",
"browser",
"brotli",
"aztec",
"charset",
"checkdigit",
"client-cert",
"compare",
"compression",
"decode",
"decode-all",
"flag-listing",
"interface-name-resolution",
"latam-tax-ids",
"mqtt-mtls",
"range",
"conditional-get",
"spider",
"xattr",
"multipart",
"netrc",
"http-version-pinning",
"retry",
"proto-filter",
"input-file",
"resume",
"config-file",
"DKIM-signing",
"email-dns",
"encode",
"gzip",
"deflate",
"hashes",
"HSTS",
"HTTP2",
"HTTPS",
"HTTPS-proxy",
"IPv6",
"JWT",
"Largefile",
"libz",
"markdown",
"maxicode-decode",
"MQTT5",
"pdf-cover-page",
"pdf-export",
"netstatus",
"pdf417",
"PGP-shellout",
"sample",
"script-concurrency",
"script-servers",
"SOCKS5",
"sqlite",
"SSL",
"rustls-tls",
"threadsafe",
"UnixSockets",
"zstd",
];
pub fn print_full() {
let mut protocols: Vec<&str> = PROTOCOLS.to_vec();
#[cfg(feature = "ssh")]
protocols.extend_from_slice(&["scp", "sftp", "ssh"]);
protocols.sort_by_key(|s| s.to_ascii_lowercase());
// ssh-pinning / ssh-compress are libssh2 transport capabilities;
// only present when the `ssh` feature is compiled in.
let mut features: Vec<&str> = FEATURES.to_vec();
#[cfg(feature = "ssh")]
features.extend_from_slice(&["ssh-pinning", "ssh-compress"]);
#[cfg(feature = "impersonate")]
features.push("TLS-impersonation");
features.sort_by_key(|s| s.to_ascii_lowercase());
println!(
"recon {} (reqwest/{} rustls/{})",
env!("CARGO_PKG_VERSION"),
REQWEST_VERSION,
RUSTLS_VERSION,
);
println!("Release-Date: {}", RELEASE_DATE);
println!("Protocols: {}", protocols.join(" "));
println!("Features: {}", features.join(" "));
}
pub fn print_short() {
println!("recon {}", env!("CARGO_PKG_VERSION"));
}