ipblc/src/ip.rs
Paul Lecuq a654889263 more simple code
* use of some simple macros
* simplified code blocks in ctx read/write access
2023-11-10 23:43:09 +01:00

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
}