Compare commits
No commits in common. "feature/server-mode" and "master" have entirely different histories.
feature/se
...
master
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1 @@
|
|||||||
/target
|
/target
|
||||||
*.log
|
|
||||||
7
.vscode/launch.json
vendored
7
.vscode/launch.json
vendored
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": []
|
|
||||||
}
|
|
||||||
1283
Cargo.lock
generated
1283
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
13
Cargo.toml
13
Cargo.toml
@ -6,14 +6,7 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
configparser = "*"
|
configparser = "3.0.4"
|
||||||
crossterm = "*"
|
|
||||||
hickory-resolver = { version = "0.24.0" }
|
hickory-resolver = { version = "0.24.0" }
|
||||||
ratatui = "*"
|
regex = "1.10.3"
|
||||||
regex = "*"
|
whois-rust = "1.6.0"
|
||||||
whois-rust = "*"
|
|
||||||
serde = { version = "*", features = ["derive"] }
|
|
||||||
serde_json = "*"
|
|
||||||
chrono = "*"
|
|
||||||
addr = { version = "0.15.6", features = ["publicsuffix"] }
|
|
||||||
rocket = "0.5.1"
|
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
HelpMeDig
|
|
||||||
45
src/app.rs
45
src/app.rs
@ -1,45 +0,0 @@
|
|||||||
use ratatui::widgets::ListState;
|
|
||||||
|
|
||||||
use crate::config::*;
|
|
||||||
use crate::logger::*;
|
|
||||||
|
|
||||||
pub enum AppRenderDir {
|
|
||||||
Vertical,
|
|
||||||
Horizontal,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum MenuState {
|
|
||||||
Main,
|
|
||||||
List,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum CurrentState {
|
|
||||||
Lookup,
|
|
||||||
Menu,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct App {
|
|
||||||
pub domain_input: String,
|
|
||||||
pub whois_info: Vec<String>,
|
|
||||||
pub dns_info: Vec<String>,
|
|
||||||
pub render_direction: AppRenderDir,
|
|
||||||
pub current_state: CurrentState,
|
|
||||||
pub menu_state: MenuState,
|
|
||||||
pub config: Config,
|
|
||||||
pub state: ListState,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl App {
|
|
||||||
pub fn new() -> App {
|
|
||||||
App {
|
|
||||||
domain_input: String::new(),
|
|
||||||
whois_info: vec![],
|
|
||||||
dns_info: vec![],
|
|
||||||
render_direction: AppRenderDir::Vertical,
|
|
||||||
current_state: CurrentState::Lookup,
|
|
||||||
menu_state: MenuState::Main,
|
|
||||||
config: Config::load(),
|
|
||||||
state: ListState::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,36 +1,22 @@
|
|||||||
use configparser::ini::Ini;
|
use configparser::ini::Ini;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use std::env;
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub subdomains: Vec<String>,
|
pub subdomains: Vec<String>,
|
||||||
pub wildcard_test: String,
|
pub wildcard_test: String,
|
||||||
pub data_dir: String,
|
|
||||||
pub mode: ApplicationMode,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ApplicationMode {
|
|
||||||
UI,
|
|
||||||
SERVER,
|
|
||||||
ERROR,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Config {
|
impl fmt::Display for Config {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(f, "Subdomains: {:?}\nWildcard Test: {}", self.subdomains, self.wildcard_test)
|
||||||
f,
|
|
||||||
"Subdomains: {:?}\nWildcard Test: {}",
|
|
||||||
self.subdomains, self.wildcard_test
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn from_file(file_path: String) -> Config {
|
pub fn from_file(file_path: String) -> Config {
|
||||||
let mut config = Ini::new();
|
let mut config = Ini::new();
|
||||||
match config.load(file_path) {
|
config.load(file_path).unwrap();
|
||||||
Ok(_) => {
|
|
||||||
let subdomains = config.get("General", "subdomains").unwrap();
|
let subdomains = config.get("General", "subdomains").unwrap();
|
||||||
let mut subvec: Vec<String> = vec![];
|
let mut subvec: Vec<String> = vec![];
|
||||||
|
|
||||||
@ -38,71 +24,10 @@ impl Config {
|
|||||||
subvec.push(x.to_string());
|
subvec.push(x.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
let wildcard_test = config.get("General", "wildcard");
|
let wildcard_test = config.get("General", "wildcard_test");
|
||||||
let datadir = config.get("General", "data_directory");
|
|
||||||
|
|
||||||
let mode = match config.get("General", "mode").unwrap().as_str() {
|
|
||||||
"UI" => ApplicationMode::UI,
|
|
||||||
"SERVER" => ApplicationMode::SERVER,
|
|
||||||
_ => ApplicationMode::ERROR,
|
|
||||||
};
|
|
||||||
|
|
||||||
Config {
|
Config {
|
||||||
subdomains: subvec,
|
subdomains: subvec,
|
||||||
wildcard_test: wildcard_test.unwrap(),
|
wildcard_test: wildcard_test.unwrap()
|
||||||
data_dir: datadir.unwrap(),
|
|
||||||
mode: mode,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
println!("{:?}", err);
|
|
||||||
Config::new()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new() -> Config {
|
|
||||||
let mut config = Ini::new();
|
|
||||||
let mut default_path = env::var_os("HOME").unwrap();
|
|
||||||
default_path.push("/.config/dnslookup");
|
|
||||||
|
|
||||||
// Create the directories if they don't exist
|
|
||||||
match fs::create_dir_all(&default_path) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(err) => {
|
|
||||||
println!("Unable to create directories, got {}", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config.set(
|
|
||||||
"General",
|
|
||||||
"wildcard",
|
|
||||||
Some(String::from("dfjgnkdfjngkdfngjkd")),
|
|
||||||
);
|
|
||||||
config.set(
|
|
||||||
"General",
|
|
||||||
"subdomains",
|
|
||||||
Some(String::from("www,ftp,mail,files")),
|
|
||||||
);
|
|
||||||
config.set(
|
|
||||||
"General",
|
|
||||||
"data_directory",
|
|
||||||
Some(String::from(default_path.to_str().unwrap())),
|
|
||||||
);
|
|
||||||
config.set("General", "mode", Some(String::from("UI")));
|
|
||||||
|
|
||||||
let mut conf_path = default_path.clone();
|
|
||||||
conf_path.push("/config.ini");
|
|
||||||
|
|
||||||
config.write(&conf_path.clone()).unwrap();
|
|
||||||
Config::from_file(conf_path.into_string().unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load() -> Config {
|
|
||||||
// Default path is $HOME/.config/dnslookup/config.ini
|
|
||||||
let mut conf_path = env::var_os("HOME").unwrap();
|
|
||||||
conf_path.push("/.config/dnslookup/config.ini");
|
|
||||||
|
|
||||||
Config::from_file(conf_path.into_string().unwrap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -53,9 +53,9 @@ impl fmt::Display for Domain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Domain {
|
impl Domain {
|
||||||
pub fn new(domain: &String) -> Domain {
|
pub fn new(domain: String) -> Domain {
|
||||||
Domain {
|
Domain {
|
||||||
domain_name: String::from(domain),
|
domain_name: domain,
|
||||||
subdomains: vec![],
|
subdomains: vec![],
|
||||||
a_records: vec![],
|
a_records: vec![],
|
||||||
aaaa_records: vec![],
|
aaaa_records: vec![],
|
||||||
@ -67,56 +67,11 @@ impl Domain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_vec(&self) -> Vec<String> {
|
|
||||||
let mut ret_vec: Vec<String> = vec![];
|
|
||||||
for rec in &self.a_records {
|
|
||||||
let mut tmp = String::from("A: ");
|
|
||||||
tmp.push_str(rec.to_string().as_ref());
|
|
||||||
ret_vec.push(tmp);
|
|
||||||
}
|
|
||||||
for rec in &self.aaaa_records {
|
|
||||||
let mut tmp = String::from("AAAA: ");
|
|
||||||
tmp.push_str(rec.to_string().as_ref());
|
|
||||||
ret_vec.push(tmp);
|
|
||||||
}
|
|
||||||
for rec in &self.mx_records {
|
|
||||||
let mut tmp = String::from("MX: ");
|
|
||||||
tmp.push_str(rec.to_string().as_ref());
|
|
||||||
ret_vec.push(tmp);
|
|
||||||
}
|
|
||||||
for rec in &self.txt_records {
|
|
||||||
let mut tmp = String::from("TXT: ");
|
|
||||||
tmp.push_str(rec.to_string().as_ref());
|
|
||||||
ret_vec.push(tmp);
|
|
||||||
}
|
|
||||||
for rec in &self.ns_records {
|
|
||||||
let mut tmp = String::from("NS: ");
|
|
||||||
tmp.push_str(rec.to_string().as_ref());
|
|
||||||
ret_vec.push(tmp);
|
|
||||||
}
|
|
||||||
for rec in &self.soa_records {
|
|
||||||
let mut tmp = String::from("SOA: ");
|
|
||||||
tmp.push_str(rec.to_string().as_ref());
|
|
||||||
ret_vec.push(tmp);
|
|
||||||
}
|
|
||||||
for subdomain in &self.subdomains {
|
|
||||||
let mut subdomain_name = String::from(subdomain.domain_name.clone());
|
|
||||||
subdomain_name.push_str("\t");
|
|
||||||
for rec in &subdomain.a_records {
|
|
||||||
let mut tmp = String::from(&subdomain_name);
|
|
||||||
tmp.push_str(" A: ");
|
|
||||||
tmp.push_str(rec.to_string().as_ref());
|
|
||||||
ret_vec.push(tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret_vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn append_subdomain(&mut self, subdomain: String) {
|
pub fn append_subdomain(&mut self, subdomain: String) {
|
||||||
let mut new_domain = String::from(subdomain);
|
let mut new_domain = String::from(subdomain);
|
||||||
new_domain.push_str(".");
|
new_domain.push_str(".");
|
||||||
new_domain.push_str(&self.domain_name);
|
new_domain.push_str(&self.domain_name);
|
||||||
let subdomain = Domain::new(&new_domain);
|
let subdomain = Domain::new(new_domain);
|
||||||
self.subdomains.push(subdomain);
|
self.subdomains.push(subdomain);
|
||||||
// println!("Added: {}", new_domain);
|
// println!("Added: {}", new_domain);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,67 +0,0 @@
|
|||||||
use chrono::Local;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::error::Error;
|
|
||||||
use std::fs;
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use ratatui::{
|
|
||||||
style::{Modifier, Style},
|
|
||||||
text::{Line, Span},
|
|
||||||
widgets::ListItem,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::config::Config;
|
|
||||||
|
|
||||||
#[derive(Serialize)]
|
|
||||||
pub struct DomainData {
|
|
||||||
name: String,
|
|
||||||
dns_records: Vec<String>,
|
|
||||||
whois_info: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DomainData {
|
|
||||||
pub fn new(domain: String, dns: Vec<String>, whois_data: Vec<String>) -> DomainData {
|
|
||||||
DomainData {
|
|
||||||
name: domain,
|
|
||||||
dns_records: dns,
|
|
||||||
whois_info: whois_data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn save_lookup(&self, config: &Config) -> Result<(), Box<dyn Error>> {
|
|
||||||
let output = serde_json::to_string(&self).unwrap();
|
|
||||||
let date = Local::now();
|
|
||||||
let filepath = format!(
|
|
||||||
"{}/lookups/{}-{}.json",
|
|
||||||
config.data_dir,
|
|
||||||
date.format("%Y-%m-%d_%H-%M-%S"),
|
|
||||||
self.name
|
|
||||||
);
|
|
||||||
let path = format!("{}/lookups", config.data_dir);
|
|
||||||
let data_dir = Path::new(&path).exists();
|
|
||||||
if data_dir != true {
|
|
||||||
match fs::create_dir_all(format!("{}/lookups", config.data_dir)) {
|
|
||||||
Ok(_val) => {}
|
|
||||||
Err(_err) => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fs::write(filepath, output)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
// println!("{}", output);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn list_lookups(config: &Config) -> Vec<String> {
|
|
||||||
let mut items: Vec<String> = vec![];
|
|
||||||
for item in fs::read_dir(format!("{}/lookups", config.data_dir)).unwrap() {
|
|
||||||
let item_name = item.unwrap();
|
|
||||||
// items.push(ListItem::new(Line::from(Span::styled(
|
|
||||||
// String::from(item_name.path().to_string_lossy().clone()),
|
|
||||||
// Style::default(),
|
|
||||||
// ))));
|
|
||||||
items.push(String::from(item_name.path().to_string_lossy().clone()))
|
|
||||||
}
|
|
||||||
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
use std::fs::OpenOptions;
|
|
||||||
use std::io::prelude::*;
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
enum LoggerType {
|
|
||||||
Local(&'static str),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Logger {
|
|
||||||
l_type: LoggerType,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Logger {
|
|
||||||
pub fn new(path: &'static str) -> Logger {
|
|
||||||
Logger {
|
|
||||||
l_type: LoggerType::Local(path),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_log_line(&self, data: String) {
|
|
||||||
match self.l_type {
|
|
||||||
LoggerType::Local(path) => {
|
|
||||||
let mut file = OpenOptions::new()
|
|
||||||
.write(true)
|
|
||||||
.append(true)
|
|
||||||
.create(true)
|
|
||||||
.open(path)
|
|
||||||
.unwrap();
|
|
||||||
writeln!(file, "{}", data).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
177
src/main.rs
177
src/main.rs
@ -1,157 +1,44 @@
|
|||||||
#[macro_use]
|
|
||||||
extern crate rocket;
|
|
||||||
|
|
||||||
mod domain;
|
mod domain;
|
||||||
use crate::domain::Domain;
|
use crate::domain::Domain;
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
|
|
||||||
mod app;
|
|
||||||
use crate::app::*;
|
|
||||||
|
|
||||||
mod ui;
|
|
||||||
use crate::ui::*;
|
|
||||||
|
|
||||||
mod fsutil;
|
|
||||||
use crate::fsutil::*;
|
|
||||||
|
|
||||||
mod whois;
|
mod whois;
|
||||||
use whois::default;
|
use crate::whois::WhoisData;
|
||||||
use whois::selector::*;
|
|
||||||
|
|
||||||
mod logger;
|
use std::io;
|
||||||
mod server;
|
use std::io::Write;
|
||||||
use server::*;
|
|
||||||
|
|
||||||
use crossterm::event::{
|
fn main() {
|
||||||
self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEventKind,
|
// let mut running = true;
|
||||||
};
|
let config = Config::from_file("test.ini".to_string());
|
||||||
use crossterm::execute;
|
|
||||||
use crossterm::terminal::{
|
|
||||||
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
|
|
||||||
};
|
|
||||||
use ratatui::backend::{Backend, CrosstermBackend};
|
|
||||||
use ratatui::Terminal;
|
|
||||||
use std::error::Error;
|
|
||||||
use std::io::{self, stdout};
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
|
||||||
let init_config = Config::load();
|
|
||||||
match init_config.mode {
|
|
||||||
config::ApplicationMode::UI => run_tui(),
|
|
||||||
config::ApplicationMode::SERVER => run_server(),
|
|
||||||
config::ApplicationMode::ERROR => {
|
|
||||||
println!("Failed to parse mode in INI file");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/")]
|
|
||||||
pub fn hello() -> &'static str {
|
|
||||||
"This is a test"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_server() -> Result<(), Box<dyn Error>> {
|
|
||||||
// let server = server::Server::new();
|
|
||||||
let _rocket = rocket::build().mount("/", routes![hello]).launch();
|
|
||||||
Ok(())
|
|
||||||
// server.run()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_tui() -> Result<(), Box<dyn Error>> {
|
|
||||||
enable_raw_mode()?;
|
|
||||||
let mut stdout = stdout();
|
|
||||||
execute!(stdout, EnterAlternateScreen)?;
|
|
||||||
|
|
||||||
let backend = CrosstermBackend::new(stdout);
|
|
||||||
let mut terminal = Terminal::new(backend)?;
|
|
||||||
|
|
||||||
// Initialise the App
|
|
||||||
let mut app = App::new();
|
|
||||||
|
|
||||||
// Run the app
|
|
||||||
let _res = run_app(&mut terminal, &mut app);
|
|
||||||
|
|
||||||
disable_raw_mode()?;
|
|
||||||
execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
|
|
||||||
terminal.show_cursor()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_app<B: Backend>(terminal: &mut Terminal<B>, app: &mut App) -> io::Result<bool> {
|
|
||||||
loop {
|
loop {
|
||||||
terminal.draw(|f| ui(f, app))?;
|
let mut domain = String::new();
|
||||||
|
print!("Enter domain name: ");
|
||||||
|
io::stdout().flush().expect("Failed to flush buffer");
|
||||||
|
match io::stdin().read_line(&mut domain) {
|
||||||
|
Ok(_n) => {
|
||||||
|
if domain.trim() == "q" {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let mut dns = Domain::new(String::from(domain.trim()));
|
||||||
|
dns.apply_config(&config);
|
||||||
|
dns.lookup_all_records();
|
||||||
|
let whois = WhoisData::new(String::from(domain.trim()));
|
||||||
|
println!("DNS: {}\n\n\nWhois: {}", dns, whois);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
println!("{}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// let mut test = Domain::new("ventraip.com.au".to_string());
|
||||||
|
// let config = Config::from_file("test.ini".to_string());
|
||||||
|
// test.apply_config(&config);
|
||||||
|
|
||||||
if let Event::Key(key) = event::read()? {
|
// test.lookup_all_records();
|
||||||
if key.kind == event::KeyEventKind::Release {
|
// let whois = WhoisData::new(test.domain_name.clone());
|
||||||
continue;
|
|
||||||
}
|
// println!("Domain: {}\n{}", test.domain_name.clone(), whois);
|
||||||
match app.current_state {
|
|
||||||
CurrentState::Lookup => match key.code {
|
|
||||||
KeyCode::Esc => {
|
|
||||||
app.current_state = CurrentState::Menu;
|
|
||||||
}
|
|
||||||
KeyCode::Backspace => {
|
|
||||||
app.domain_input.pop();
|
|
||||||
}
|
|
||||||
KeyCode::Char(char) => {
|
|
||||||
app.domain_input.push(char);
|
|
||||||
}
|
|
||||||
KeyCode::Enter => {
|
|
||||||
// This will do the lookup and populate the UI with the info
|
|
||||||
if &app.domain_input == "" {
|
|
||||||
// Ignore empty input
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let mut domain = Domain::new(&app.domain_input);
|
|
||||||
domain.apply_config(&app.config);
|
|
||||||
domain.lookup_all_records();
|
|
||||||
app.dns_info = domain.to_vec();
|
|
||||||
let whois_server = select_whois_server(app.domain_input.clone());
|
|
||||||
match whois_server {
|
|
||||||
Ok(mut whois_data) => {
|
|
||||||
app.whois_info = whois_data.lookup(app.domain_input.clone());
|
|
||||||
}
|
|
||||||
Err(_) => {}
|
|
||||||
}
|
|
||||||
// let whois = WhoisData::new(app.domain_input.clone());
|
|
||||||
// app.whois_info = whois.to_vec();
|
|
||||||
}
|
|
||||||
KeyCode::Delete => {
|
|
||||||
app.domain_input = String::new();
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
CurrentState::Menu => match app.menu_state {
|
|
||||||
MenuState::Main => match key.code {
|
|
||||||
KeyCode::Esc => {
|
|
||||||
app.current_state = CurrentState::Lookup;
|
|
||||||
}
|
|
||||||
KeyCode::Char('s') => {
|
|
||||||
let domain_data = DomainData::new(
|
|
||||||
app.domain_input.clone(),
|
|
||||||
app.dns_info.clone(),
|
|
||||||
app.whois_info.clone(),
|
|
||||||
);
|
|
||||||
domain_data.save_lookup(&app.config).unwrap();
|
|
||||||
app.current_state = CurrentState::Lookup;
|
|
||||||
}
|
|
||||||
KeyCode::Char('l') => {
|
|
||||||
app.menu_state = MenuState::List;
|
|
||||||
}
|
|
||||||
KeyCode::Char('q') => return Ok(false),
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
MenuState::List => match key.code {
|
|
||||||
KeyCode::Esc => {
|
|
||||||
app.menu_state = MenuState::Main;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,26 +0,0 @@
|
|||||||
use rocket::*;
|
|
||||||
use std::error::Error;
|
|
||||||
|
|
||||||
// Initiate server here and have main loop here similar to how UI is done
|
|
||||||
pub struct Server {
|
|
||||||
listen_addr: String,
|
|
||||||
listen_port: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Server {
|
|
||||||
pub fn new() -> Server {
|
|
||||||
Server {
|
|
||||||
listen_addr: String::from("0.0.0.0"),
|
|
||||||
listen_port: 60009,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run(&self) -> Result<(), Box<dyn Error>> {
|
|
||||||
println!(
|
|
||||||
"Starting server on {}:{}",
|
|
||||||
self.listen_addr, self.listen_port
|
|
||||||
);
|
|
||||||
// rocket::build().mount("/", routes![Server::hello]);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
362
src/ui.rs
362
src/ui.rs
@ -1,362 +0,0 @@
|
|||||||
use ratatui::{
|
|
||||||
layout::{Constraint, Direction, Layout, Rect},
|
|
||||||
prelude::*,
|
|
||||||
style::{Color, Modifier, Style, Styled},
|
|
||||||
text::{Line, Span, Text},
|
|
||||||
widgets::{
|
|
||||||
Block, Borders, Clear, HighlightSpacing, List, ListDirection, ListItem, ListState, Padding,
|
|
||||||
Paragraph, Wrap,
|
|
||||||
},
|
|
||||||
Frame,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
app::{App, AppRenderDir},
|
|
||||||
CurrentState, DomainData, MenuState,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct StatefulList<'a> {
|
|
||||||
state: ListState,
|
|
||||||
items: Vec<ListItem<'a>>,
|
|
||||||
last_selected: Option<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StatefulList<'_> {
|
|
||||||
fn with_items<'a>(items: Vec<String>) -> StatefulList<'a> {
|
|
||||||
let mut veclist = Vec::<ListItem>::new();
|
|
||||||
for item in items {
|
|
||||||
veclist.push(ListItem::new(Line::from(item)));
|
|
||||||
}
|
|
||||||
StatefulList {
|
|
||||||
state: ListState::default(),
|
|
||||||
items: veclist,
|
|
||||||
last_selected: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&mut self) {
|
|
||||||
let i = match self.state.selected() {
|
|
||||||
Some(i) => {
|
|
||||||
if i >= self.items.len() - 1 {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
i + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => self.last_selected.unwrap_or(0),
|
|
||||||
};
|
|
||||||
self.state.select(Some(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn previous(&mut self) {
|
|
||||||
let i = match self.state.selected() {
|
|
||||||
Some(i) => {
|
|
||||||
if i == 0 {
|
|
||||||
self.items.len() - 1
|
|
||||||
} else {
|
|
||||||
i - 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => self.last_selected.unwrap_or(0),
|
|
||||||
};
|
|
||||||
self.state.select(Some(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unselect(&mut self) {
|
|
||||||
let offset = self.state.offset();
|
|
||||||
self.last_selected = self.state.selected();
|
|
||||||
self.state.select(None);
|
|
||||||
*self.state.offset_mut() = offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ui(f: &mut Frame, app: &mut App) {
|
|
||||||
if f.size().width > 100 {
|
|
||||||
app.render_direction = AppRenderDir::Horizontal;
|
|
||||||
} else {
|
|
||||||
app.render_direction = AppRenderDir::Vertical;
|
|
||||||
}
|
|
||||||
match app.current_state {
|
|
||||||
CurrentState::Lookup => {
|
|
||||||
match app.render_direction {
|
|
||||||
/*
|
|
||||||
Initial contianer is vertical but we have the large center Rect that we will split horizontally
|
|
||||||
Constraint 1: 30px title bar
|
|
||||||
Constraint 2: Rest of unused space
|
|
||||||
Constraint 3: 30px input / key hints
|
|
||||||
|
|
||||||
Constraint 2.a: 50% of usable space for whois
|
|
||||||
Constraint 2.b: 50% of usable space for dns
|
|
||||||
*/
|
|
||||||
AppRenderDir::Horizontal => {
|
|
||||||
let chunks = Layout::default()
|
|
||||||
.direction(Direction::Vertical)
|
|
||||||
.constraints([
|
|
||||||
Constraint::Length(3),
|
|
||||||
Constraint::Min(1),
|
|
||||||
Constraint::Length(3),
|
|
||||||
])
|
|
||||||
.split(f.size());
|
|
||||||
|
|
||||||
let title_block = Block::default()
|
|
||||||
.borders(Borders::ALL)
|
|
||||||
.style(Style::default())
|
|
||||||
.padding(Padding::horizontal(2));
|
|
||||||
|
|
||||||
let title = Paragraph::new(Span::styled(
|
|
||||||
"Dns Lookup tool",
|
|
||||||
Style::default().fg(Color::Yellow),
|
|
||||||
))
|
|
||||||
.block(title_block);
|
|
||||||
|
|
||||||
f.render_widget(title, chunks[0]);
|
|
||||||
|
|
||||||
let data_layout = Layout::default()
|
|
||||||
.direction(Direction::Horizontal)
|
|
||||||
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
|
|
||||||
.split(chunks[1]);
|
|
||||||
|
|
||||||
// Whois list
|
|
||||||
let mut whois_list_items = Vec::<ListItem>::new();
|
|
||||||
for record in &app.whois_info {
|
|
||||||
whois_list_items.push(ListItem::new(Line::from(Span::styled(
|
|
||||||
record,
|
|
||||||
Style::default(),
|
|
||||||
))))
|
|
||||||
}
|
|
||||||
let whois_list = List::new(whois_list_items);
|
|
||||||
|
|
||||||
f.render_widget(whois_list, data_layout[0]);
|
|
||||||
|
|
||||||
// DNS list
|
|
||||||
let mut dns_list_items = Vec::<ListItem>::new();
|
|
||||||
|
|
||||||
for record in &app.dns_info {
|
|
||||||
dns_list_items.push(ListItem::new(Line::from(Span::styled(
|
|
||||||
record,
|
|
||||||
Style::default(),
|
|
||||||
))))
|
|
||||||
}
|
|
||||||
let dns_list = List::new(dns_list_items);
|
|
||||||
|
|
||||||
f.render_widget(dns_list, data_layout[1]);
|
|
||||||
|
|
||||||
let footer_chunks = Layout::default()
|
|
||||||
.direction(Direction::Horizontal)
|
|
||||||
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
|
|
||||||
.split(chunks[2]);
|
|
||||||
|
|
||||||
let domain_block = Block::new().borders(Borders::ALL).style(Style::default());
|
|
||||||
let mut domain_string = String::from("Domain: ");
|
|
||||||
domain_string.push_str(&app.domain_input);
|
|
||||||
let domain_text = Paragraph::new(Text::styled(
|
|
||||||
domain_string,
|
|
||||||
Style::default().fg(Color::Blue),
|
|
||||||
))
|
|
||||||
.block(domain_block);
|
|
||||||
f.render_widget(domain_text, footer_chunks[0]);
|
|
||||||
|
|
||||||
let key_hint_block = Block::default()
|
|
||||||
.borders(Borders::ALL)
|
|
||||||
.style(Style::default());
|
|
||||||
|
|
||||||
let key_hint = Paragraph::new(Text::styled(
|
|
||||||
"[ESC] Menu / [Enter] Check domain / [Del] Clear Input",
|
|
||||||
Style::default().fg(Color::Red),
|
|
||||||
))
|
|
||||||
.block(key_hint_block);
|
|
||||||
f.render_widget(key_hint, footer_chunks[1]);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
Constraint 1: 30px title bar
|
|
||||||
Constraint 2: 50% of unused space for whois
|
|
||||||
Constraint 3: 50% of unused space for dns
|
|
||||||
Constraint 4: 30px input / key hints
|
|
||||||
*/
|
|
||||||
AppRenderDir::Vertical => {
|
|
||||||
let chunks = Layout::default()
|
|
||||||
.direction(Direction::Vertical)
|
|
||||||
.constraints([
|
|
||||||
Constraint::Length(3),
|
|
||||||
Constraint::Percentage(50),
|
|
||||||
Constraint::Percentage(50),
|
|
||||||
Constraint::Length(3),
|
|
||||||
])
|
|
||||||
.split(f.size());
|
|
||||||
|
|
||||||
let title_block = Block::default()
|
|
||||||
.borders(Borders::ALL)
|
|
||||||
.style(Style::default());
|
|
||||||
|
|
||||||
let title = Paragraph::new(Span::styled(
|
|
||||||
"Dns Lookup tool",
|
|
||||||
Style::default().fg(Color::White),
|
|
||||||
))
|
|
||||||
.block(title_block);
|
|
||||||
|
|
||||||
f.render_widget(title, chunks[0]);
|
|
||||||
|
|
||||||
// Whois list
|
|
||||||
let mut whois_list_items = Vec::<ListItem>::new();
|
|
||||||
for record in &app.whois_info {
|
|
||||||
whois_list_items.push(ListItem::new(Line::from(Span::styled(
|
|
||||||
record,
|
|
||||||
Style::default(),
|
|
||||||
))))
|
|
||||||
}
|
|
||||||
let whois_list = List::new(whois_list_items);
|
|
||||||
|
|
||||||
f.render_widget(whois_list, chunks[1]);
|
|
||||||
|
|
||||||
// DNS list
|
|
||||||
let mut dns_list_items = Vec::<ListItem>::new();
|
|
||||||
for record in &app.dns_info {
|
|
||||||
dns_list_items.push(ListItem::new(Line::from(Span::styled(
|
|
||||||
record,
|
|
||||||
Style::default(),
|
|
||||||
))))
|
|
||||||
}
|
|
||||||
let dns_list = List::new(dns_list_items);
|
|
||||||
|
|
||||||
f.render_widget(dns_list, chunks[2]);
|
|
||||||
let footer_chunks = Layout::default()
|
|
||||||
.direction(Direction::Horizontal)
|
|
||||||
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
|
|
||||||
.split(chunks[3]);
|
|
||||||
|
|
||||||
let domain_block = Block::new().borders(Borders::ALL).style(Style::default());
|
|
||||||
let mut domain_string = String::from("Domain: ");
|
|
||||||
domain_string.push_str(&app.domain_input);
|
|
||||||
let domain_text = Paragraph::new(Text::styled(
|
|
||||||
domain_string,
|
|
||||||
Style::default().fg(Color::Blue),
|
|
||||||
))
|
|
||||||
.block(domain_block);
|
|
||||||
f.render_widget(domain_text, footer_chunks[0]);
|
|
||||||
|
|
||||||
let key_hint_block = Block::default()
|
|
||||||
.borders(Borders::ALL)
|
|
||||||
.style(Style::default());
|
|
||||||
|
|
||||||
let key_hint = Paragraph::new(Text::styled(
|
|
||||||
"[ESC] Quit / [Enter] Check domain",
|
|
||||||
Style::default().fg(Color::Red),
|
|
||||||
))
|
|
||||||
.block(key_hint_block);
|
|
||||||
f.render_widget(key_hint, footer_chunks[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CurrentState::Menu => {
|
|
||||||
match app.menu_state {
|
|
||||||
MenuState::Main => {
|
|
||||||
let chunks = Layout::default()
|
|
||||||
.direction(Direction::Vertical)
|
|
||||||
.constraints([
|
|
||||||
Constraint::Length(3),
|
|
||||||
Constraint::Min(1),
|
|
||||||
Constraint::Length(3),
|
|
||||||
])
|
|
||||||
.split(f.size());
|
|
||||||
|
|
||||||
let title_block = Block::new().borders(Borders::ALL).style(Style::default());
|
|
||||||
|
|
||||||
let title = Paragraph::new(Text::styled(
|
|
||||||
"**** Menu ****",
|
|
||||||
Style::default().fg(Color::Cyan),
|
|
||||||
))
|
|
||||||
.block(title_block);
|
|
||||||
f.render_widget(title, chunks[0]);
|
|
||||||
|
|
||||||
let mut options_list = Vec::<ListItem>::new();
|
|
||||||
options_list.push(ListItem::new(Line::from(Span::styled(
|
|
||||||
"ESC) Return to lookup",
|
|
||||||
Style::default(),
|
|
||||||
))));
|
|
||||||
|
|
||||||
// TODO: Add code to save lookup
|
|
||||||
options_list.push(ListItem::new(Line::from(Span::styled(
|
|
||||||
"S) Save lookup",
|
|
||||||
Style::default(),
|
|
||||||
))));
|
|
||||||
|
|
||||||
// TODO: Add code to load and UI to list saved lookups
|
|
||||||
options_list.push(ListItem::new(Line::from(Span::styled(
|
|
||||||
"L) List previous lookups",
|
|
||||||
Style::default(),
|
|
||||||
))));
|
|
||||||
|
|
||||||
// TODO: Add code to read lookup and display
|
|
||||||
options_list.push(ListItem::new(Line::from(Span::styled(
|
|
||||||
"V) View previous lookup",
|
|
||||||
Style::default(),
|
|
||||||
))));
|
|
||||||
|
|
||||||
options_list.push(ListItem::new(Line::from(Span::styled(
|
|
||||||
"Q) Quit",
|
|
||||||
Style::default(),
|
|
||||||
))));
|
|
||||||
|
|
||||||
let options = List::new(options_list);
|
|
||||||
f.render_widget(options, chunks[1]);
|
|
||||||
|
|
||||||
let footer_block = Block::new().borders(Borders::ALL).style(Style::default());
|
|
||||||
|
|
||||||
let footer =
|
|
||||||
Paragraph::new(Text::styled("[q] Quit", Style::default().fg(Color::Red)))
|
|
||||||
.block(footer_block);
|
|
||||||
f.render_widget(footer, chunks[2]);
|
|
||||||
}
|
|
||||||
MenuState::List => {
|
|
||||||
let chunks = Layout::default()
|
|
||||||
.direction(Direction::Vertical)
|
|
||||||
.constraints([
|
|
||||||
Constraint::Length(3),
|
|
||||||
Constraint::Min(1),
|
|
||||||
Constraint::Length(3),
|
|
||||||
])
|
|
||||||
.split(f.size());
|
|
||||||
|
|
||||||
let title_block = Block::new().borders(Borders::ALL).style(Style::default());
|
|
||||||
|
|
||||||
let title = Paragraph::new(Text::styled(
|
|
||||||
"**** List ****",
|
|
||||||
Style::default().fg(Color::Cyan),
|
|
||||||
))
|
|
||||||
.block(title_block);
|
|
||||||
f.render_widget(title, chunks[0]);
|
|
||||||
|
|
||||||
let item_list = DomainData::list_lookups(&app.config);
|
|
||||||
let items = List::new(item_list)
|
|
||||||
.block(Block::default().title("Lookups").borders(Borders::ALL))
|
|
||||||
.style(Style::default())
|
|
||||||
.highlight_style(Style::default().add_modifier(Modifier::BOLD))
|
|
||||||
.highlight_symbol(">>")
|
|
||||||
.highlight_spacing(HighlightSpacing::Always)
|
|
||||||
.repeat_highlight_symbol(true);
|
|
||||||
// f.render_stateful_widget(items, chunks[1], &mut app.state);
|
|
||||||
|
|
||||||
// let t_list = StatefulList::with_items(item_list);
|
|
||||||
// f.render_stateful_widget(t_list, chunks[1], t_list.state);
|
|
||||||
let items = ["Item 1", "Item 2", "Item 3"];
|
|
||||||
let list = List::new(items)
|
|
||||||
.block(Block::default().title("List").borders(Borders::ALL))
|
|
||||||
.highlight_style(Style::new().add_modifier(Modifier::REVERSED))
|
|
||||||
.highlight_symbol(">>")
|
|
||||||
.repeat_highlight_symbol(true);
|
|
||||||
|
|
||||||
f.render_stateful_widget(list, chunks[1], &mut app.state);
|
|
||||||
|
|
||||||
let footer_block = Block::new().borders(Borders::ALL).style(Style::default());
|
|
||||||
|
|
||||||
let footer = Paragraph::new(Text::styled(
|
|
||||||
"[ESC] Return to menu",
|
|
||||||
Style::default().fg(Color::Red),
|
|
||||||
))
|
|
||||||
.block(footer_block);
|
|
||||||
f.render_widget(footer, chunks[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
152
src/whois.rs
Normal file
152
src/whois.rs
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
use core::fmt;
|
||||||
|
use regex::Regex;
|
||||||
|
use whois_rust::{WhoIs, WhoIsLookupOptions};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
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<String> {
|
||||||
|
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)]
|
||||||
|
struct NameServer {
|
||||||
|
host: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NameServer {
|
||||||
|
fn new(host: String) -> NameServer {
|
||||||
|
NameServer { host }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
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: String,
|
||||||
|
domain_status: String,
|
||||||
|
registrant: Vec<Registrant>,
|
||||||
|
nameservers: Vec<NameServer>,
|
||||||
|
dnssec: String,
|
||||||
|
eligibility_type: Option<Eligibility>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for WhoisData {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Registrar: {}\nStatus: {}\nRegistrant: {:?}\nNameservers: {:?}\nDNSSEC: {}",
|
||||||
|
self.registrar, self.domain_status, self.registrant, self.nameservers, self.dnssec
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 dnssec = dnssec_regex.get_matches(&result);
|
||||||
|
|
||||||
|
// println!("{:?}", registrar[0]);
|
||||||
|
WhoisData {
|
||||||
|
registrar: registrar.clone(),
|
||||||
|
domain_status: domain_status.clone(),
|
||||||
|
registrant: vec![Registrant::new(
|
||||||
|
reg_name.clone(),
|
||||||
|
reg_org.clone(),
|
||||||
|
reg_email,
|
||||||
|
RegistrantType::Registrant,
|
||||||
|
)],
|
||||||
|
nameservers: nameservers,
|
||||||
|
dnssec: dnssec[0].clone(),
|
||||||
|
eligibility_type: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn return_regex(caps: Vec<String>, index: usize) -> String {
|
||||||
|
let data: String;
|
||||||
|
match caps.get(index) {
|
||||||
|
Some(tmp) => {
|
||||||
|
data = tmp.to_string();
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
data = String::from("None");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data
|
||||||
|
}
|
||||||
|
}
|
||||||
177
src/whois/au.rs
177
src/whois/au.rs
@ -1,177 +0,0 @@
|
|||||||
use crate::whois::whois_base::{
|
|
||||||
NameServer, RegexQuery, Registrant, RegistrantType, Whois, WhoisData,
|
|
||||||
};
|
|
||||||
use whois_rust::{WhoIs, WhoIsLookupOptions};
|
|
||||||
|
|
||||||
struct Eligibility {
|
|
||||||
e_type: Option<String>,
|
|
||||||
e_name: Option<String>,
|
|
||||||
e_id: Option<String>,
|
|
||||||
r_id: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eligibility {
|
|
||||||
fn new() -> Eligibility {
|
|
||||||
Eligibility {
|
|
||||||
e_id: Some(String::new()),
|
|
||||||
e_name: Some(String::new()),
|
|
||||||
e_type: Some(String::new()),
|
|
||||||
r_id: Some(String::new()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct _Whois {
|
|
||||||
base: WhoisData,
|
|
||||||
eligibility: Eligibility,
|
|
||||||
modified: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Whois for _Whois {
|
|
||||||
fn new() -> Self {
|
|
||||||
_Whois {
|
|
||||||
base: WhoisData::new(),
|
|
||||||
eligibility: Eligibility::new(),
|
|
||||||
modified: String::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn to_vec(&self) -> Vec<String> {
|
|
||||||
let mut ret_vec: Vec<String> = vec![];
|
|
||||||
let mut registrar = String::from("Registrar: ");
|
|
||||||
registrar.push_str(&self.base.registrar.clone().unwrap());
|
|
||||||
ret_vec.push(registrar);
|
|
||||||
|
|
||||||
let mut last_modified = String::from("Last Modified: ");
|
|
||||||
last_modified.push_str(&self.modified.clone());
|
|
||||||
ret_vec.push(last_modified);
|
|
||||||
|
|
||||||
let mut domain_status = String::from("Status: ");
|
|
||||||
domain_status.push_str(&self.base.domain_status.clone().unwrap());
|
|
||||||
ret_vec.push(domain_status);
|
|
||||||
|
|
||||||
let mut dnssec = String::from("DNSSEC: ");
|
|
||||||
dnssec.push_str(&self.base.dnssec.clone().unwrap());
|
|
||||||
ret_vec.push(dnssec);
|
|
||||||
|
|
||||||
let mut registrant_type = String::new();
|
|
||||||
for registrant in &self.base.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.base.nameservers.clone().unwrap() {
|
|
||||||
let mut tmp = String::from("Nameserver: ");
|
|
||||||
tmp.push_str(&nameserver.host);
|
|
||||||
ret_vec.push(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut eligibility_name = String::from("Eligibility Name: ");
|
|
||||||
eligibility_name.push_str(&self.eligibility.e_name.clone().unwrap());
|
|
||||||
ret_vec.push(eligibility_name);
|
|
||||||
|
|
||||||
let mut eligibility_type = String::from("Eligibility Type: ");
|
|
||||||
eligibility_type.push_str(&self.eligibility.e_type.clone().unwrap());
|
|
||||||
ret_vec.push(eligibility_type);
|
|
||||||
|
|
||||||
let mut eligibility_id = String::from("Eligibility ID: ");
|
|
||||||
eligibility_id.push_str(&self.eligibility.e_id.clone().unwrap());
|
|
||||||
ret_vec.push(eligibility_id);
|
|
||||||
|
|
||||||
let mut registrant_id = String::from("Registrant ID: ");
|
|
||||||
registrant_id.push_str(&self.eligibility.r_id.clone().unwrap());
|
|
||||||
ret_vec.push(registrant_id);
|
|
||||||
|
|
||||||
return ret_vec;
|
|
||||||
}
|
|
||||||
fn lookup(&mut self, domain: String) -> Vec<String> {
|
|
||||||
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 last_modified_regex = RegexQuery::new(String::from(r"(?i)(.*last modified:)(.*)"));
|
|
||||||
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 eligebility_name_regex =
|
|
||||||
RegexQuery::new(String::from(r"(?i)(.*eligibility name:)(.*)"));
|
|
||||||
let eligebility_type_regex =
|
|
||||||
RegexQuery::new(String::from(r"(?i)(.*eligibility type:)(.*)"));
|
|
||||||
let eligebility_id_regex = RegexQuery::new(String::from(r"(?i)(.*eligibility id:)(.*)"));
|
|
||||||
let registrant_id_regex = RegexQuery::new(String::from(r"(?i)(.*registrant id:)(.*)"));
|
|
||||||
|
|
||||||
let registrar = WhoisData::return_regex(registrar_regex.get_matches(&result), 0);
|
|
||||||
let last_modified = WhoisData::return_regex(last_modified_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")];
|
|
||||||
}
|
|
||||||
let eligebility_name =
|
|
||||||
WhoisData::return_regex(eligebility_name_regex.get_matches(&result), 0);
|
|
||||||
let eligebility_type =
|
|
||||||
WhoisData::return_regex(eligebility_type_regex.get_matches(&result), 0);
|
|
||||||
let eligebility_id = WhoisData::return_regex(eligebility_id_regex.get_matches(&result), 0);
|
|
||||||
let registrant_id = WhoisData::return_regex(registrant_id_regex.get_matches(&result), 0);
|
|
||||||
|
|
||||||
// println!("{:?}", registrar[0]);
|
|
||||||
self.base.domain_status = Some(domain_status.clone());
|
|
||||||
self.base.registrant = Some(vec![Registrant::new(
|
|
||||||
reg_name.clone(),
|
|
||||||
reg_org.clone(),
|
|
||||||
reg_email,
|
|
||||||
RegistrantType::Registrant,
|
|
||||||
)]);
|
|
||||||
self.base.nameservers = Some(nameservers);
|
|
||||||
self.base.dnssec = Some(dnssec[0].clone());
|
|
||||||
self.base.registrar = Some(registrar.clone());
|
|
||||||
self.eligibility.e_name = Some(eligebility_name.clone());
|
|
||||||
self.eligibility.e_type = Some(eligebility_type.clone());
|
|
||||||
self.eligibility.e_id = Some(eligebility_id.clone());
|
|
||||||
self.eligibility.r_id = Some(registrant_id.clone());
|
|
||||||
self.modified = last_modified;
|
|
||||||
self.to_vec()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,117 +0,0 @@
|
|||||||
use crate::whois::whois_base::{
|
|
||||||
NameServer, RegexQuery, Registrant, RegistrantType, Whois, WhoisData,
|
|
||||||
};
|
|
||||||
use whois_rust::{WhoIs, WhoIsLookupOptions};
|
|
||||||
pub struct _Whois {
|
|
||||||
base: WhoisData,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Whois for _Whois {
|
|
||||||
fn new() -> _Whois {
|
|
||||||
_Whois {
|
|
||||||
base: WhoisData::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_vec(&self) -> Vec<String> {
|
|
||||||
let mut ret_vec: Vec<String> = vec![];
|
|
||||||
let mut registrar = String::from("Registrar: ");
|
|
||||||
registrar.push_str(&self.base.registrar.clone().unwrap());
|
|
||||||
ret_vec.push(registrar);
|
|
||||||
|
|
||||||
let mut domain_status = String::from("Status: ");
|
|
||||||
domain_status.push_str(&self.base.domain_status.clone().unwrap());
|
|
||||||
ret_vec.push(domain_status);
|
|
||||||
|
|
||||||
let mut dnssec = String::from("DNSSEC: ");
|
|
||||||
dnssec.push_str(&self.base.dnssec.clone().unwrap());
|
|
||||||
ret_vec.push(dnssec);
|
|
||||||
|
|
||||||
let mut registrant_type = String::new();
|
|
||||||
for registrant in &self.base.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.base.nameservers.clone().unwrap() {
|
|
||||||
let mut tmp = String::from("Nameserver: ");
|
|
||||||
tmp.push_str(&nameserver.host);
|
|
||||||
ret_vec.push(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret_vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lookup(&mut self, domain: String) -> Vec<String> {
|
|
||||||
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]);
|
|
||||||
self.base.domain_status = Some(domain_status.clone());
|
|
||||||
self.base.registrant = Some(vec![Registrant::new(
|
|
||||||
reg_name.clone(),
|
|
||||||
reg_org.clone(),
|
|
||||||
reg_email,
|
|
||||||
RegistrantType::Registrant,
|
|
||||||
)]);
|
|
||||||
self.base.nameservers = Some(nameservers);
|
|
||||||
self.base.dnssec = Some(dnssec[0].clone());
|
|
||||||
self.base.registrar = Some(registrar.clone());
|
|
||||||
|
|
||||||
self.to_vec()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
pub mod au;
|
|
||||||
pub mod default;
|
|
||||||
pub mod selector;
|
|
||||||
pub mod uk;
|
|
||||||
pub mod whois_base;
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
use addr::parse_domain_name;
|
|
||||||
|
|
||||||
use super::{au, default, uk, whois_base::Whois};
|
|
||||||
|
|
||||||
pub fn select_whois_server(domain: String) -> Result<Box<dyn Whois>, String> {
|
|
||||||
let domain = parse_domain_name(&domain.as_str());
|
|
||||||
match domain {
|
|
||||||
Ok(val) => match val.suffix() {
|
|
||||||
"com.au" => Ok(Box::new(au::_Whois::new())),
|
|
||||||
"org.au" => Ok(Box::new(au::_Whois::new())),
|
|
||||||
"net.au" => Ok(Box::new(au::_Whois::new())),
|
|
||||||
"co.uk" => Ok(Box::new(uk::_Whois::new())),
|
|
||||||
"au" => Ok(Box::new(au::_Whois::new())),
|
|
||||||
_ => Ok(Box::new(default::_Whois::new())),
|
|
||||||
},
|
|
||||||
Err(_) => Err(String::from("Failed to select whois server")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// impl RegexQuery {
|
|
||||||
// pub fn new(expression: String) -> RegexQuery {
|
|
||||||
// let re = Regex::new(&expression).unwrap();
|
|
||||||
// RegexQuery { re }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn get_matches(&self, haystack: &str) -> Vec<String> {
|
|
||||||
// let mut results = vec![];
|
|
||||||
// for (_, [_, rex2]) in self.re.captures_iter(haystack).map(|c| c.extract()) {
|
|
||||||
// results.push(String::from(rex2.trim()));
|
|
||||||
// }
|
|
||||||
// results
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
use crate::whois::whois_base::{
|
|
||||||
NameServer, RegexQuery, Registrant, RegistrantType, Whois, WhoisData,
|
|
||||||
};
|
|
||||||
use regex::Regex;
|
|
||||||
use whois_rust::{WhoIs, WhoIsLookupOptions};
|
|
||||||
|
|
||||||
// (.*registrar:\n)(.*)
|
|
||||||
|
|
||||||
// (.*name servers:\n)((.*\n)+?^\n)
|
|
||||||
|
|
||||||
pub struct _Whois {
|
|
||||||
base: WhoisData,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Whois for _Whois {
|
|
||||||
fn new() -> Self
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
_Whois {
|
|
||||||
base: WhoisData::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn to_vec(&self) -> Vec<String> {
|
|
||||||
let mut ret_vec: Vec<String> = vec![];
|
|
||||||
let mut registrar = String::from("Registrar: ");
|
|
||||||
registrar.push_str(&self.base.registrar.clone().unwrap());
|
|
||||||
ret_vec.push(registrar);
|
|
||||||
|
|
||||||
for nameserver in &self.base.nameservers.clone().unwrap() {
|
|
||||||
let mut tmp = String::from("Nameserver: ");
|
|
||||||
tmp.push_str(&nameserver.host);
|
|
||||||
ret_vec.push(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret_vec;
|
|
||||||
}
|
|
||||||
fn lookup(&mut self, domain: String) -> Vec<String> {
|
|
||||||
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"(?mi)(.*registrar:.*\n)(.*)"));
|
|
||||||
let nameserver_regex =
|
|
||||||
RegexQuery::new(String::from(r"(?miR)(.*name servers:\r\n)((.+\.+.+)+)"));
|
|
||||||
|
|
||||||
let registrar = WhoisData::return_regex(registrar_regex.get_matches(&result), 0);
|
|
||||||
let nameservers = nameserver_regex.captures(&result);
|
|
||||||
// println!("{:?}", nameservers);
|
|
||||||
|
|
||||||
self.base.registrar = Some(registrar.clone());
|
|
||||||
self.base.nameservers = Some(nameservers.clone());
|
|
||||||
|
|
||||||
self.to_vec()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl _Whois {
|
|
||||||
pub fn get_matches(&self, haystack: &str, expression: String) -> Vec<String> {
|
|
||||||
let re = Regex::new(&expression).unwrap();
|
|
||||||
let mut results = vec![];
|
|
||||||
for (_, [_, rex2]) in re.captures_iter(haystack).map(|c| c.extract()) {
|
|
||||||
results.push(String::from(rex2.trim()));
|
|
||||||
println!("{:?}", rex2.trim())
|
|
||||||
}
|
|
||||||
println!("{:?}", results);
|
|
||||||
results
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,123 +0,0 @@
|
|||||||
use crate::logger::Logger;
|
|
||||||
use core::fmt;
|
|
||||||
use regex::Regex;
|
|
||||||
|
|
||||||
pub trait Whois {
|
|
||||||
fn new() -> Self
|
|
||||||
where
|
|
||||||
Self: Sized;
|
|
||||||
fn lookup(&mut self, domain: String) -> Vec<String>;
|
|
||||||
fn to_vec(&self) -> Vec<String>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum RegistrantType {
|
|
||||||
Registrant,
|
|
||||||
Admin,
|
|
||||||
Tech,
|
|
||||||
Billing,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RegexQuery {
|
|
||||||
re: Regex,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RegexQuery {
|
|
||||||
pub fn new(expression: String) -> RegexQuery {
|
|
||||||
let re = Regex::new(&expression).unwrap();
|
|
||||||
RegexQuery { re }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_matches(&self, haystack: &str) -> Vec<String> {
|
|
||||||
let mut results = vec![];
|
|
||||||
for (_, [_, rex2]) in self.re.captures_iter(haystack).map(|c| c.extract()) {
|
|
||||||
results.push(String::from(rex2.trim()));
|
|
||||||
}
|
|
||||||
results
|
|
||||||
}
|
|
||||||
pub fn captures(&self, haystack: &str) -> Vec<NameServer> {
|
|
||||||
// let logger = Logger::new("log.txt");
|
|
||||||
let mut results: Vec<NameServer> = vec![];
|
|
||||||
match self.re.captures(haystack) {
|
|
||||||
Some(rex) => {
|
|
||||||
for x in 1..rex.len() {
|
|
||||||
if x == 1 {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
results.push(NameServer::new(String::from(
|
|
||||||
rex.get(x).unwrap().as_str().trim(),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
results
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct NameServer {
|
|
||||||
pub host: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NameServer {
|
|
||||||
pub fn new(host: String) -> NameServer {
|
|
||||||
NameServer { host }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Registrant {
|
|
||||||
pub name: String,
|
|
||||||
pub org: String,
|
|
||||||
pub email: String,
|
|
||||||
pub rtype: RegistrantType,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Registrant {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Registrant {
|
|
||||||
pub fn new(name: String, org: String, email: String, rtype: RegistrantType) -> Registrant {
|
|
||||||
Registrant {
|
|
||||||
name,
|
|
||||||
org,
|
|
||||||
email,
|
|
||||||
rtype,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub struct WhoisData {
|
|
||||||
pub registrar: Option<String>,
|
|
||||||
pub domain_status: Option<String>,
|
|
||||||
pub registrant: Option<Vec<Registrant>>,
|
|
||||||
pub nameservers: Option<Vec<NameServer>>,
|
|
||||||
pub dnssec: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WhoisData {
|
|
||||||
pub fn new() -> WhoisData {
|
|
||||||
WhoisData {
|
|
||||||
registrar: None,
|
|
||||||
domain_status: None,
|
|
||||||
registrant: None,
|
|
||||||
nameservers: None,
|
|
||||||
dnssec: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn return_regex(caps: Vec<String>, index: usize) -> String {
|
|
||||||
let data: String;
|
|
||||||
match caps.get(index) {
|
|
||||||
Some(tmp) => {
|
|
||||||
data = tmp.to_string();
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
data = String::from("None");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user