From bb7eb2da2918dcfdb9b5d672b4165449230c5532 Mon Sep 17 00:00:00 2001 From: Harald Eilertsen Date: Wed, 8 May 2019 18:23:29 +0200 Subject: Create a unix socket server to check URLs. Set up a simple unix domain socket server to handle requests to check if URLs are phishes or not. --- src/lib.rs | 8 +++++++- src/main.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 26be932..8f56601 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,6 @@ use std::net::IpAddr; use std::result::Result; use std::str::FromStr; -#[derive(Deserialize)] pub struct PhishTank { pub phishes: Vec, } @@ -60,6 +59,13 @@ pub fn load_phistank(input: R) -> Result { Ok(PhishTank { phishes }) } + +impl PhishTank { + pub fn is_phish(&self, url: &str) -> bool { + self.phishes.iter().find(|phish| phish.url == url).is_some() + } +} + // Helper function to deserialize a number represented as a string. // // The PhishTank dataset represents numbers this way, so the default diff --git a/src/main.rs b/src/main.rs index 17f443b..d2198e1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,8 +16,14 @@ use phisher; use clap::{clap_app, crate_name, crate_authors, crate_version, crate_description}; -use std::fs::File; -use std::io::BufReader; +use std::boxed::Box; +use std::error::Error; +use std::fs::{ File, remove_file }; +use std::io::{ BufRead, BufReader, Write }; +use std::os::unix::net::{ UnixListener, UnixStream }; +use std::result::Result; +use std::sync::Arc; +use std::thread; use std::time::SystemTime; fn main() { @@ -32,13 +38,60 @@ fn main() { let start_time = SystemTime::now(); let filename = args.value_of("PHISHTANK").unwrap(); if let Ok(file) = File::open(filename) { - let tank = phisher::load_phistank(BufReader::new(file)).unwrap(); + let tank = Arc::new(phisher::load_phistank(BufReader::new(file)).unwrap()); println!("Loaded {} phishes in {} seconds!", tank.phishes.len(), start_time.elapsed().unwrap().as_secs()); + + match run_server(tank) { + Ok(_) => println!("Exiting."), + Err(e) => eprintln!("Received error: {}, terminating.", e.to_string()) + }; } else { eprintln!("Could not open file {}.\nIs the filename correct?", filename); } } + +fn run_server(tank: Arc) -> Result<(), Box> { + let listener = UnixListener::bind("/tmp/phisher")?; + for stream in listener.incoming() { + match stream { + Ok(stream) => { + let t = Arc::clone(&tank); + thread::spawn(move || handle_connection(stream, t)); + } + Err(e) => { + eprintln!("Received error: {}", e.to_string()); + break; + } + } + } + + Ok(remove_file("/tmp/phisher")?) +} + +// Handle a connected client. +// +// Once a client is connected, it can request the status of multiple +// URLs before closing the connection. Each URL must be passed in on +// a separate line, and the results are returned in the same order +// as the URLs were passed in. +// +fn handle_connection(mut stream: UnixStream, tank: Arc) { + // Clone the stream so we get another ref to the underlying socket, + // then wrap it in a BufReader, so we can use read_line on it. + let mut bufreader = BufReader::new(stream.try_clone().unwrap()); + + loop { + let mut buffer = String::new(); + bufreader.read_line(&mut buffer).unwrap(); + if tank.is_phish(buffer.trim_end()) { + stream.write(b"it's a phish!\n").unwrap(); + } + else { + stream.write(b"good url.\n").unwrap(); + } + } +} -- cgit v1.2.3