use {
std::collections::HashMap,
std::fs::File,
std::io::{BufRead, BufReader},
pushover::API,
pushover::requests::message::SendMessage,
chrono::Local,
uuid::Uuid,
};
fn main() -> std::io::Result<()> {
let date = Local::now().format("%Y-%m-%d").to_string();
let log_path = "/var/log/kern.log";
let file = File::open(log_path)?;
let reader = BufReader::new(file);
let mut lines = Vec::new();
let mut ip_count: HashMap<String, u32> = HashMap::new();
let mut proto_count: HashMap<String, u32> = HashMap::new();
let mut port_count: HashMap<String, u32> = HashMap::new();
let mut total_count: u32 = 0;
let mut total_bytes: u64 = 0;
for line in reader.lines() {
let line = line?;
if !line.contains("IPTables-In") {
continue;
}
for part in line.split_whitespace() {
lines.push(line.clone());
if part.starts_with("SRC=") {
let ip = part.trim_start_matches("SRC=").to_string();
*ip_count.entry(ip).or_insert(0) += 1;
}
if part.starts_with("PROTO=") {
let proto = part.trim_start_matches("PROTO=").to_string();
*proto_count.entry(proto).or_insert(0) += 1;
}
if part.starts_with("DPT=") {
let port = part.trim_start_matches("DPT=").to_string();
*port_count.entry(port).or_insert(0) += 1;
}
if part.starts_with("LEN=") {
total_count += 1;
if let Ok(len) = part.trim_start_matches("LEN=").parse::<u64>() {
total_bytes += len;
}
}
}
}
generate_summary(ip_count.clone(), total_bytes);
generate_log(date, ip_count, proto_count, port_count, total_count, total_bytes, lines);
Ok(())
}
fn send_message(message: String) {
let api = API::new();
//very bad practice to hardcode keys, but eh
let user_key = "u7mwq3g4rpg26bd4rzcbq3khta9zsi";
let token = "aeasowifnfwzwgkw4h2ararzu2fp84";
let msg = SendMessage::new(token, user_key, message);
let _ = api.send(&msg);
}
fn generate_summary(ip_count: HashMap<String, u32>, total_bytes: u64) {
// pushover message summary
// Convert the map into a vector so we can sort by count.
let mut counts: Vec<(String, u32)> = ip_count.into_iter().collect();
counts.sort_by(|a, b| b.1.cmp(&a.1));
let top_ips: Vec<_> = counts.into_iter().take(5).collect();
let summary = format!(
"Top IPs:\n{:#?}\n\
Total MegaBytes: {}\n",
top_ips, total_bytes/1024/1024);
send_message(summary);
}
fn generate_log(date: String, ip_count: HashMap<String, u32>, proto_count: HashMap<String, u32>, port_count: HashMap<String, u32>, total_count: u32, total_bytes: u64, lines: Vec<String>) {
// full log of packets, file output
let uuid = Uuid::new_v4();
let filename = format!("/etc/nginx/logr/{}.html", uuid);
let mut file = File::create(&filename).expect("Unable to create file");
use std::io::Write;
writeln!(file, "<html><head><title>Log Report for {}</title></head><body>", date).unwrap();
writeln!(file, "<h1>Log Report for {}</h1>", date).unwrap();
writeln!(file, "<h2>Total Packets: {}</h2>", total_count).unwrap();
writeln!(file, "<h2>Total Bytes: {}</h2>", total_bytes).unwrap();
writeln!(file, "<h2>IP Counts</h2><ul>").unwrap();
let mut ip_counts: Vec<(String, u32)> = ip_count.into_iter().collect();
ip_counts.sort_by(|a, b| b.1.cmp(&a.1));
for (ip, count) in ip_counts {
writeln!(file, "<li>{}: {}</li>", ip, count).unwrap();
}
writeln!(file, "</ul>").unwrap();
writeln!(file, "<h2>Protocol Counts</h2><ul>").unwrap();
let mut proto_counts: Vec<(String, u32)> = proto_count.into_iter().collect();
proto_counts.sort_by(|a, b| b.1.cmp(&a.1));
for (proto, count) in proto_counts {
writeln!(file, "<li>{}: {}</li>", proto, count).unwrap();
}
writeln!(file, "</ul>").unwrap();
writeln!(file, "<h2>Port Counts</h2><ul>").unwrap();
let mut port_counts: Vec<(String, u32)> = port_count.into_iter().collect();
port_counts.sort_by(|a, b| b.1.cmp(&a.1));
for (port, count) in port_counts {
writeln!(file, "<li>{}: {}</li>", port, count).unwrap();
}
writeln!(file, "</ul>").unwrap();
writeln!(file, "<p>Whole log: {}</p>", lines.join("<br>")).unwrap();
writeln!(file, "</body></html>").unwrap();
}