logr / src/main.rs

raw file 4542 bytes
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();
}