use crate::utils::gethostname; use chrono::offset::LocalResult; use chrono::prelude::*; use ipnet::IpNet; use lazy_static::lazy_static; use regex::Regex; use serde::{Deserialize, Serialize}; use std::cmp::Ordering; use std::fmt::{Display, Formatter}; use std::io::{BufRead, BufReader, Read}; use std::net::IpAddr; lazy_static! { static ref R_IPV4: Regex = Regex::new(include_str!("regexps/ipv4.txt")).unwrap(); static ref R_IPV6: Regex = Regex::new(include_str!("regexps/ipv6.txt")).unwrap(); static ref R_DATE: Regex = Regex::new(include_str!("regexps/date.txt")).unwrap(); } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct IpEvent { pub msgtype: String, pub mode: String, pub hostname: String, pub ipdata: IpData, } #[macro_export] macro_rules! ipevent { ($msgtype:expr,$mode:expr,$hostname:expr,$ipdata:expr) => { IpEvent { msgtype: String::from($msgtype), mode: String::from($mode), hostname: $hostname, ipdata: $ipdata, } }; } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct BlockIpData { pub ipdata: IpData, pub tryfail: i64, pub blocktime: i64, pub starttime: DateTime, } #[derive(Clone, Debug, Serialize, Deserialize, Eq)] pub struct IpData { pub t: isize, pub ip: String, pub src: String, pub date: String, pub hostname: String, } #[macro_export] macro_rules! ipdata { ($t:expr,$ip:expr,$src:expr,$date:expr,$hostname:expr) => { IpData { t: $t.clone(), ip: $ip.clone(), src: $src.clone(), date: $date.clone(), hostname: $hostname.clone(), } }; } impl PartialEq for IpData { fn eq(&self, other: &IpData) -> bool { self.ip.as_bytes() == other.ip.as_bytes() && self.src == other.src } fn ne(&self, other: &IpData) -> bool { !self.eq(other) } } impl Ord for IpData { fn cmp(&self, other: &IpData) -> Ordering { self.ip.as_bytes().cmp(&other.ip.as_bytes()) } } impl PartialOrd for IpData { fn partial_cmp(&self, other: &IpData) -> Option { Some(self.cmp(&other)) } } impl Display for IpData { fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { write!( f, "ip: {ip}, src: {src}, date: {date}, hostname: {hostname}", ip = self.ip, src = self.src, date = self.date, hostname = self.hostname, ) } } pub fn filter( reader: Box, iplist: &mut Vec, trustnets: &Vec, regex: &Regex, src: &String, last: &DateTime, ) -> isize { let mut ips = 0; let hostname = gethostname(true); let lines = BufReader::new(reader).lines(); for line in lines.into_iter() { if let Ok(l) = line { if regex.is_match(l.as_str()) { let s_ipaddr: String; let t: isize; match R_IPV4.captures(l.as_str()) { Some(sv4) => { s_ipaddr = sv4.get(0).unwrap().as_str().to_string(); t = 4; } None => { match R_IPV6.captures(l.as_str()) { Some(sv6) => { s_ipaddr = sv6.get(0).unwrap().as_str().to_string(); t = 6; } None => { continue; } }; } }; let ipaddr: IpAddr = match s_ipaddr.parse() { Ok(ip) => ip, Err(err) => { println!("unparseable IP: {err} {s_ipaddr}"); continue; } }; let s_date: DateTime; match R_DATE.captures(l.as_str()) { Some(sdt) => { s_date = parse_date(sdt); if &s_date < last { continue; } } None => { s_date = Local::now(); } }; if !is_trusted(&ipaddr, &trustnets) { iplist.push(ipdata!(t, s_ipaddr, src, s_date.to_rfc3339(), hostname)); ips += 1; }; } } } ips } fn parse_date(input: regex::Captures) -> DateTime { let mut ymd: Vec = vec![]; let mut hms: Vec = vec![]; let ymd_range = 2..5; let hms_range = 5..8; for cap in ymd_range { ymd.push(input.get(cap).unwrap().as_str().parse::().unwrap()); } for cap in hms_range { hms.push(input.get(cap).unwrap().as_str().parse::().unwrap()); } let date: DateTime = match Local.with_ymd_and_hms(ymd[0] as i32, ymd[1], ymd[2], hms[0], hms[1], hms[2]) { LocalResult::Single(s) => s, LocalResult::Ambiguous(a, _b) => a, LocalResult::None => Local::now().trunc_subsecs(0), }; date } fn is_trusted(ip: &IpAddr, trustnets: &Vec) -> bool { for net in trustnets { if net.contains(ip) { return true; } } false }