1use std::env;
2
3pub const IANA_WHOIS_SERVER: &str = "whois.iana.org";
4pub const DEFAULT_WHOIS_SERVER: &str = "whois.ripe.net";
5pub const DEFAULT_WHOIS_PORT: u16 = 43;
6pub const DN42_WHOIS_SERVER: &str = "lantian.pub";
7pub const DN42_WHOIS_PORT: u16 = 43;
8pub const BGPTOOLS_WHOIS_SERVER: &str = "bgp.tools";
9pub const BGPTOOLS_WHOIS_PORT: u16 = 43;
10pub const RADB_WHOIS_SERVER: &str = "whois.radb.net";
11pub const RADB_WHOIS_PORT: u16 = 43;
12
13#[derive(Debug, Clone)]
14pub struct WhoisServer {
15 pub host: String,
16 pub port: u16,
17 pub name: String,
18}
19
20impl WhoisServer {
21 pub fn new(host: impl Into<String>, port: u16, name: impl Into<String>) -> Self {
22 Self {
23 host: host.into(),
24 port,
25 name: name.into(),
26 }
27 }
28
29 pub fn iana() -> Self {
30 Self::new(IANA_WHOIS_SERVER, DEFAULT_WHOIS_PORT, "IANA")
31 }
32
33 pub fn default() -> Self {
34 Self::new(DEFAULT_WHOIS_SERVER, DEFAULT_WHOIS_PORT, "RIPE")
35 }
36
37 pub fn dn42() -> Self {
38 Self::new(DN42_WHOIS_SERVER, DN42_WHOIS_PORT, "DN42")
39 }
40
41 pub fn bgptools() -> Self {
42 Self::new(BGPTOOLS_WHOIS_SERVER, BGPTOOLS_WHOIS_PORT, "BGP.tools")
43 }
44
45 pub fn radb() -> Self {
46 Self::new(RADB_WHOIS_SERVER, RADB_WHOIS_PORT, "RADB")
47 }
48
49 pub fn custom(host: impl Into<String>, port: u16) -> Self {
50 Self::new(host.into(), port, "Custom")
51 }
52
53 pub fn address(&self) -> String {
54 format!("{}:{}", self.host, self.port)
55 }
56}
57
58pub struct ServerSelector;
59
60impl ServerSelector {
61 pub fn extract_whois_server(response: &str) -> Option<String> {
63 for line in response.lines() {
64 let line = line.trim();
65
66 if line.starts_with("whois:") {
68 return Some(line.split_whitespace()
69 .nth(1)?
70 .trim()
71 .to_string());
72 }
73 if line.starts_with("refer:") {
75 return Some(line.split_whitespace()
76 .nth(1)?
77 .trim()
78 .to_string());
79 }
80 }
81 None
82 }
83
84 pub fn from_env() -> Option<String> {
86 env::var("WHOIS_SERVER").ok()
87 }
88
89 pub fn select_server(
91 domain: &str,
92 use_dn42: bool,
93 use_bgptools: bool,
94 explicit_server: Option<&str>,
95 port: u16,
96 ) -> WhoisServer {
97 if use_dn42 || domain.to_uppercase().starts_with("AS42424") {
99 return WhoisServer::dn42();
100 }
101
102 if use_bgptools {
103 return WhoisServer::bgptools();
104 }
105
106 if let Some(server) = explicit_server {
107 return WhoisServer::custom(server, port);
108 }
109
110 if let Some(env_server) = Self::from_env() {
111 return WhoisServer::custom(env_server, port);
112 }
113
114 WhoisServer::iana()
116 }
117}