200 lines
5.4 KiB
Rust
200 lines
5.4 KiB
Rust
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<Local>,
|
|
}
|
|
|
|
#[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<Ordering> {
|
|
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<dyn Read>,
|
|
iplist: &mut Vec<IpData>,
|
|
trustnets: &Vec<IpNet>,
|
|
regex: &Regex,
|
|
src: &String,
|
|
last: &DateTime<Local>,
|
|
) -> 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<Local>;
|
|
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<Local> {
|
|
let mut ymd: Vec<u32> = vec![];
|
|
let mut hms: Vec<u32> = 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::<u32>().unwrap());
|
|
}
|
|
for cap in hms_range {
|
|
hms.push(input.get(cap).unwrap().as_str().parse::<u32>().unwrap());
|
|
}
|
|
|
|
let date: DateTime<Local> =
|
|
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<IpNet>) -> bool {
|
|
for net in trustnets {
|
|
if net.contains(ip) {
|
|
return true;
|
|
}
|
|
}
|
|
false
|
|
}
|