use core::fmt; use hickory_resolver::proto::{ rr::{domain, rdata::name}, xfer::dns_handle, }; use regex::Regex; use whois_rust::{WhoIs, WhoIsLookupOptions}; #[derive(Debug, Clone)] enum RegistrantType { Registrant, Admin, Tech, Billing, } struct RegexQuery { re: Regex, } impl RegexQuery { fn new(expression: String) -> RegexQuery { let re = Regex::new(&expression).unwrap(); RegexQuery { re } } fn get_matches(&self, haystack: &str) -> Vec { let mut results = vec![]; for (_, [_, rex2]) in self.re.captures_iter(haystack).map(|c| c.extract()) { results.push(String::from(rex2.trim())); } results } } #[derive(Debug, Clone)] struct NameServer { host: String, } impl NameServer { fn new(host: String) -> NameServer { NameServer { host } } } #[derive(Debug, Clone)] struct Registrant { name: String, org: String, email: String, rtype: RegistrantType, } impl fmt::Display for Registrant { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "") } } impl Registrant { fn new(name: String, org: String, email: String, rtype: RegistrantType) -> Registrant { Registrant { name, org, email, rtype, } } } struct Eligibility { e_type: String, id: String, name: String, } pub struct WhoisData { registrar: Option, domain_status: Option, registrant: Option>, nameservers: Option>, dnssec: Option, eligibility_type: Option, } impl fmt::Display for WhoisData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "Registrar: {}\nStatus: {}\nRegistrant: {:?}\nNameservers: {:?}\nDNSSEC: {}", self.registrar.clone().unwrap(), self.domain_status.clone().unwrap(), self.registrant.clone().unwrap(), self.nameservers.clone().unwrap(), self.dnssec.clone().unwrap() ) } } impl WhoisData { pub fn new(domain: String) -> WhoisData { let whois = WhoIs::from_path("servers.json").unwrap(); let result: String = whois .lookup(WhoIsLookupOptions::from_string(domain).unwrap()) .unwrap(); let registrar_regex = RegexQuery::new(String::from(r"(?i)(.*registrar:|registrar *name:)(.*)")); let domain_status_regex = RegexQuery::new(String::from(r"(?i)(.*domain status:|.*status:)(.*)")); // TODO: Capture the registrant info for each type let registrant_name_regex = RegexQuery::new(String::from(r"(?i)(registrant.*name:)(.*)")); let registrant_org_regex = RegexQuery::new(String::from(r"(?i)(registrant org.*:|registrant:)(.*)")); let registrant_email_regex = RegexQuery::new(String::from(r"(?i)(registrant email:)(.*)")); let nameserver_regex = RegexQuery::new(String::from(r"(?i)(nameservers*:|name servers*:)(.*)")); let dnssec_regex = RegexQuery::new(String::from(r"(?i)(.*dnssec:)(.*)")); let registrar = WhoisData::return_regex(registrar_regex.get_matches(&result), 0); let domain_status = WhoisData::return_regex(domain_status_regex.get_matches(&result), 0); let reg_name = WhoisData::return_regex(registrant_name_regex.get_matches(&result), 0); let reg_org = WhoisData::return_regex(registrant_org_regex.get_matches(&result), 0); let reg_email = WhoisData::return_regex(registrant_email_regex.get_matches(&result), 0); let mut nameservers = vec![]; for nameserver in nameserver_regex.get_matches(&result) { nameservers.push(NameServer::new(nameserver)); } let mut dnssec = dnssec_regex.get_matches(&result); if dnssec.len() == 0 { dnssec = vec![String::from("Failed to get DNSSEC")]; } // println!("{:?}", registrar[0]); WhoisData { registrar: Some(registrar.clone()), domain_status: Some(domain_status.clone()), registrant: Some(vec![Registrant::new( reg_name.clone(), reg_org.clone(), reg_email, RegistrantType::Registrant, )]), nameservers: Some(nameservers), dnssec: Some(dnssec[0].clone()), eligibility_type: None, } } pub fn to_vec(&self) -> Vec { let mut ret_vec: Vec = vec![]; let mut registrar = String::from("Registrar: "); registrar.push_str(&self.registrar.clone().unwrap()); ret_vec.push(registrar); let mut domain_status = String::from("Status: "); domain_status.push_str(&self.domain_status.clone().unwrap()); ret_vec.push(domain_status); let mut dnssec = String::from("DNSSEC: "); dnssec.push_str(&self.dnssec.clone().unwrap()); ret_vec.push(dnssec); let mut registrant_type = String::new(); for registrant in &self.registrant.clone().unwrap() { match registrant.rtype { RegistrantType::Admin => { registrant_type.push_str("Admin "); } RegistrantType::Billing => { registrant_type.push_str("Billing "); } RegistrantType::Tech => { registrant_type.push_str("Tech "); } RegistrantType::Registrant => { registrant_type.push_str("Registrant "); } } let mut name = registrant_type.clone(); name.push_str("Name: "); name.push_str(®istrant.name); ret_vec.push(name); let mut org = registrant_type.clone(); org.push_str("Organisation: "); org.push_str(®istrant.org); ret_vec.push(org); let mut email = registrant_type.clone(); email.push_str("Email: "); email.push_str(®istrant.email); ret_vec.push(email); } for nameserver in &self.nameservers.clone().unwrap() { let mut tmp = String::from("Nameserver: "); tmp.push_str(&nameserver.host); ret_vec.push(tmp); } return ret_vec; } fn return_regex(caps: Vec, index: usize) -> String { let data: String; match caps.get(index) { Some(tmp) => { data = tmp.to_string(); } None => { data = String::from("None"); } } data } }