Skip to content
Snippets Groups Projects
Select Git revision
  • 5f9021d6959744a6ee21e9494886227cfa2f3aed
  • master default protected
2 results

prototypes.html

Blame
  • parselog.rs 7.61 KiB
    use std::net::TcpListener;
    use std::process;
    use std::io::{self, BufRead};
    use std::env;
    use regex::Regex;
    use syslog::{Facility, Formatter3164};
    use std::sync::OnceLock;
    use gethostname::gethostname;
    
    mod hashmap;
    
    static HOSTNAME:        OnceLock<Option<String>> = OnceLock::new();
    static REGEXP_CLOSE:    OnceLock<Regex>  = OnceLock::new();
    static REGEXP_CMD:      OnceLock<Regex>  = OnceLock::new();
    static REGEXP_CONNECT:  OnceLock<Regex>  = OnceLock::new();
    static REGEXP_LAUNCH:   OnceLock<Regex>  = OnceLock::new();
    static REGEXP_OTHERLOG: OnceLock<Regex>  = OnceLock::new();
    static REGEXP_RESULT:   OnceLock<Regex>  = OnceLock::new();
    
    fn help() {
        println!("Usage: parselog-ldap --listen=NUMBER");
        println!("       NUMBER: Le port sur lequel on reçoit les logs.");
    }
    
    fn getport()->Result<String,String> {
        let regexp_arg = Regex::new(r"--listen=(?<port>[0-9]{1,5})").unwrap();
        for argument in env::args() {
            let Some(caps) = regexp_arg.captures(&argument) else {
                continue;
            };
            return Ok(caps["port"].to_string());
        }
        println!("Port invalide");
        help();
        process::exit(1);
    }
    
    fn com_accept(line: String){
        let Some(caps) = REGEXP_CONNECT.get().expect("unitialized Regexp").captures(&line) else {
          return;
        };
        let val = caps["ip"].to_string();
        let key = caps["con"].to_string();
        hashmap::set_val("ip",key.clone(),val);
    }
    
    fn com_result(line: String){
        let Some(caps) = REGEXP_RESULT.get().expect("unitialized Regexp").captures(&line) else {
          return;
        };
        let nentries = caps.name("nentries").map_or("0", |m| m.as_str());
        let ip = hashmap::get_val("ip",caps["con"].to_string());
        if ip == "0" { return; }
        let con = &caps["con"];
        let bind = hashmap::get_val("bind",caps["con"].to_string());
        let key = format!("{}-{}",&caps["con"],&caps["op"]);
        let cmd = hashmap::get_val("cmd",key.clone());
        let val1 = hashmap::get_val("val1",key.clone());
        let val2 = hashmap::get_val("val2",key.clone());
        let attr = hashmap::get_val("attr",key.clone());
    
        let linelog : String;
        let err : String;
        let user : String;
        match &caps["err"]{
            "err=0" => err = "OK".to_string(),
            "err="  => err = "OK".to_string(),
            _       => err = "refused".to_string(),
        }
         match bind.as_str(){
            "\"\""      => user = "Anonymous".to_string(),
            _           => user = bind,
        }  
        match cmd.as_str() {
             "BIND" => { 
                  if &caps["err"] == "err=0" {
                      hashmap::set_val("bind",caps["con"].to_string(),val1.clone());
                  }
                  if val1 == "\"\"" { hashmap::removeop(key.clone()); return; }
                  linelog = format!("ID={} SRC={} BIND={} {} -> {}",con,ip,val1,cmd,err);
             },
             "UNBIND" => {
                  hashmap::set_val("bind",caps["con"].to_string(),"Anonymous".to_string());
                  return;
             },
             "SRCH"  => {
                  linelog = format!("ID={} SRC={} BIND={} {} attr {} in {} with filter {} -> {} ({} answer)",con,ip,user,cmd,attr,val1,val2,err,nentries);
             },
             "MOD"   => {
                  linelog = format!("ID={} SRC={} BIND={} {} dn={} attr={} -> {}",con,ip,user,cmd,val1,attr,err);
             },
             "CMP"   => {
                  linelog = format!("ID={} SRC={} BIND={} {} dn={} attr={} -> {}",con,ip,user,cmd,val1,val2,err);
             },
             _      => { // ADD DEL 
                  linelog = format!("ID={} SRC={} BIND={} {} dn={} -> {}",con,ip,user,cmd,val1,err);
             }
           }
        hashmap::removeop(key.clone());
        sendlog(linelog,false); 
    }
    
    fn create_log(line: String){
        let Some(caps) = REGEXP_CMD.get().expect("unitialized Regexp").captures(&line) else {
          return;
        };
        let val2 = caps.name("val2").map_or("-", |m| m.as_str());
        let key = format!("{}-{}",&caps["con"],&caps["op"]);
        hashmap::set_val("cmd",key.clone(),caps["cmd"].to_string());
        match &caps["v"]{
         "base"=>{
            hashmap::set_val("val1",key.clone(),caps["val1"].to_string());
            hashmap::set_val("val2",key.clone(),val2.to_string());
         },
         "dn"=>{
            hashmap::set_val("val1",key.clone(),caps["val1"].to_string());
            hashmap::set_val("val2",key.clone(),val2.to_string());
         },
         "attr"=>{
            hashmap::set_val("attr",key,caps["val1"].to_string());
         },
         "id"=>{
            hashmap::set_val("val1",key,caps["val1"].to_string());
         },
         _=>com_default(line.to_string()),
        }
    }
    
    
    fn com_closed(line: String){
        let Some(caps) = REGEXP_CLOSE.get().expect("unitialized Regexp").captures(&line) else {
          return;
        };
        hashmap::removecon(caps["con"].to_string());
    }
    
    fn com_default(line: String){
      let _ = line;
      //println!("DEF {}", &line);
    
    }
    
    fn sendlog(line: String,otherlog: bool){
    
        let formatter = Formatter3164 {
            facility: Facility::LOG_LOCAL5,
            hostname: None,
            process: "slapd".into(),
            pid: 6666,
        };
    
        match syslog::unix(formatter) {
            Err(e) => println!("impossible to connect to syslog: {:?}", e),
            Ok(mut writer) => {
                if otherlog {
                    let Some(caps) = REGEXP_OTHERLOG.get().expect("unitialized Regexp").captures(&line) else { return; };
                    let log = &caps["log"].to_string();
                    writer.debug(log).expect("could not write message");
                } else {
                    writer.info(line).expect("could not write message");
                }
            }
        }
    }
    
    fn launch<R: BufRead>(reader: R) {
        for l in reader.lines() {
          let line = l.unwrap();
          //println!("LINE: {}",line);
          let Some(caps) = REGEXP_LAUNCH.get().expect("unitialized Regexp").captures(&line) else {
            sendlog(line.to_string(),true);
            return;
          };
        match &caps["command"]{
         "ABANDON"  =>com_closed(line.to_string()),
         "do_abandon:"  =>{},
         "ACCEPT"  =>com_accept(line.to_string()),
         "closed"  =>com_closed(line.to_string()),
         "RESULT"  =>com_result(line.to_string()),
         "SEARCH"  =>com_result(line.to_string()),
         "ADD"     =>create_log(line.to_string()),
         "BIND"    =>create_log(line.to_string()),
         "CMP"     =>create_log(line.to_string()),
         "DEL"     =>create_log(line.to_string()),
         "MOD"     =>create_log(line.to_string()),
         "PASSMOD" =>create_log(line.to_string()),
         "SRCH"    =>create_log(line.to_string()),
         "TLS"     =>{},
         "UNBIND"  =>create_log(line.to_string()),
         _         =>sendlog(line.to_string(),true),
        }
        }
    }
    
    fn main() {
        let port = getport().unwrap();
        let hostname = Some(gethostname().into_string().unwrap());
        let _ = HOSTNAME.set(hostname);
        let _ = REGEXP_LAUNCH.set(Regex::new(r"^\S+ \S+ \S+ \S+ \S+ (?<con>\S+) (?<op>\S+) (?<command>\S+)").unwrap());
        let _ = REGEXP_OTHERLOG.set(Regex::new(r"^\S+ \S+ \S+ \S+ \S+ (?<log>.+)").unwrap());
        let _ = REGEXP_RESULT.set(Regex::new(r"^\S+ \S+ \S+ \S+ \S+ conn=(?<con>[0-9]+) op=(?<op>[0-9]+)( SEARCH)? RESULT \S+ (?<err>\S+)( nentries=(?<nentries>[0-9]+))?").unwrap());
        let _ = REGEXP_CMD.set(Regex::new(r"^\S+ \S+ \S+ \S+ \S+ conn=(?<con>[0-9]+) op=(?<op>[0-9]+) (?<cmd>(ADD|DEL|BIND|CMP|MOD|PASSMOD|SRCH)) (?<v>[a-z]+)=(?<val1>\S+)( \S+ \S+)?( (attr|filter)=(?<val2>\S+))?").unwrap());
        let _ = REGEXP_CONNECT.set(Regex::new(r"^\S+ \S+ \S+ \S+ \S+ conn=(?<con>[0-9]+) \S+ ACCEPT from IP=(?<ip>[0-9.:]+):[0-9]+").unwrap());
        let _ = REGEXP_CLOSE.set(Regex::new(r"^\S+ \S+ \S+ \S+ \S+ conn=(?<con>[0-9]+) \S+ (closed|ABANDON)").unwrap());
        let s = format!("127.0.0.1:{}",port);
        let listener = TcpListener::bind(s).unwrap();
        for stream in listener.incoming() {
            let reader = io::BufReader::new(stream.unwrap());
            launch(reader);
        }
    }