Skip to content
Snippets Groups Projects
Commit 9e257e82 authored by Sebastien Boutelier's avatar Sebastien Boutelier
Browse files

Import initial des fichiers. WIP.

parent 0ed81d68
No related branches found
No related tags found
No related merge requests found
[package]
name = "parselog"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
gethostname = "0.4.3"
regex = "1.9.5"
rusqlite = { version = "0.29.0", features = ["bundled"] }
syslog = "6.1.0"
[[bin]]
name = "parselog"
path = "parselog.rs"
//extern crate log;
use std::net::TcpListener;
use std::io::{self, BufRead, Write};
use std::fs;
use std::env;
use std::fs::File;
use rusqlite::{Connection, Result,params};
use regex::Regex;
use syslog::{Facility, Formatter3164};
use gethostname::gethostname;
thread_local!(static LOGHOST: String = getloghost().unwrap(););
#[derive(Debug)]
struct Log {
ip: String,
con: u32,
op: u32,
bind: Option<String>,
command: String,
base: Option<String>,
filter: Option<String>,
attr: Option<String>,
result: Option<String>,
}
fn getport()->Result<String> {
let regexp_arg = Regex::new(r"--listen=(?<port>[0-9]+)").unwrap();
for argument in env::args() {
let Some(caps) = regexp_arg.captures(&argument) else {
continue;
};
return Ok(caps["port"].to_string());
}
Ok("0".to_string())
}
fn getloghost()->Result<String> {
//let regexp_arg = Regex::new(r"--loghost=(?<ipport>(25[0–5]|2[0–4][0–9]|[01]?[0–9][0–9]?).(25[0–5]|2[0–4][0–9]|[01]?[0–9][0–9]?).(25[0–5]|2[0–4][0–9]|[01]?[0–9][0–9]?).(25[0–5]|2[0–4][0–9]|[01]?[0–9][0–9]?):[0-9]{1,5})").unwrap();
let regexp_arg = Regex::new(r"--loghost=(?<ipport>[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}:[0-9]{1,5})").unwrap();
for argument in env::args() {
let Some(caps) = regexp_arg.captures(&argument) else {
continue;
};
return Ok(caps["ipport"].to_string());
}
Ok("0".to_string())
}
fn getip(con: &str) -> Result<String> {
let c = Connection::open("/dev/shm/parselog.db")?;
let mut stmt = c.prepare("SELECT ip FROM conip WHERE con = :con")?;
let rows = stmt.query_map(&[(":con", &con)], |row| {
Ok(row.get(0)?)
})?;
for row in rows {
let ip: String = row?;
return Ok(ip);
}
Ok("0".to_string())
}
fn getbind(con: &str) -> Result<String> {
let c = Connection::open("/dev/shm/parselog.db")?;
let mut stmt = c.prepare("SELECT bind FROM conip WHERE con = :con")?;
let rows = stmt.query_map(&[(":con", &con)], |row| {
Ok(row.get(0)?)
})?;
for row in rows {
let bind: String = row?;
if bind == "dn=\"\"" {
return Ok("Anonymous".to_string());
}
return Ok(bind);
}
Ok("Anonymous".to_string())
}
fn getlog(con: &str,op: &str) -> Result<Log> {
let empty = Log {ip: "0".to_string(),con: 0,op: 0,bind: None,command: "0".to_string(),base: None,filter: None,attr: None,result: None};
let c = Connection::open("/dev/shm/parselog.db")?;
let mut stmt = c.prepare("SELECT * FROM log WHERE con = :con AND op = :op")?;
let log_iter = stmt.query_map(&[(":con", &con),(":op", &op)], |row| {
Ok(Log {
ip: row.get(0)?,
con: row.get(1)?,
op: row.get(2)?,
bind: row.get(3)?,
command: row.get(4)?,
base: row.get(5)?,
filter: row.get(6)?,
attr: row.get(7)?,
result: row.get(8)?,
})
})?;
for log in log_iter {
return Ok(log?)
}
Ok(empty)
}
fn com_accept(line: String){
let regexp_command = Regex::new(r"^\S+ \S+ conn=(?<con>[0-9]+) \S+ ACCEPT from IP=(?<ip>[0-9.:]+):[0-9]+").unwrap();
let Some(caps) = regexp_command.captures(&line) else {
return;
};
let c = Connection::open("/dev/shm/parselog.db").unwrap();
let query = "INSERT INTO conip VALUES(?1,?2,'Anonymous')";
c.execute(query,(&caps["con"],&caps["ip"]),).unwrap();
}
fn com_bind(line: String){
let regexp_command = Regex::new(r"^\S+ \S+ conn=(?<con>[0-9]+) op=(?<op>[0-9]+) (?<command>[A-Z]+) (?<dn>\S+)").unwrap();
let Some(caps) = regexp_command.captures(&line) else {
return;
};
let ip = getip(&caps["con"]).unwrap();
if ip != "0" {
let c = Connection::open("/dev/shm/parselog.db").unwrap();
let query = "INSERT INTO log ('ip','con','op','command','bind') VALUES(?1,?2,?3,?4,?5)";
c.execute(query,(ip,&caps["con"],&caps["op"],&caps["command"],&caps["dn"]),).unwrap();
}
}
fn com_result(line: String){
let regexp_command = Regex::new(r"^\S+ (?<date>\S+) conn=(?<con>[0-9]+) op=(?<op>[0-9]+) RESULT \S+ (?<res>\S+)").unwrap();
let Some(caps) = regexp_command.captures(&line) else {
return;
};
let c = Connection::open("/dev/shm/parselog.db").unwrap();
let mut stmt = c.prepare("UPDATE log SET result = ?1 WHERE con = ?2 AND op = ?3").unwrap();
stmt.execute(params![&caps["res"],&caps["con"],&caps["op"]]).unwrap();
let log = getlog(&caps["con"],&caps["op"]).unwrap();
let linelog : String;
if log.ip != "0" {
let err : String;
let bind = log.bind.as_deref().unwrap_or("Anonymous");
match &caps["res"]{
"err=0" => err = "OK".to_string(),
_ => err = "refused".to_string(),
}
match log.command.as_str() {
"BIND" => { let b: String;
if bind == "dn=\"\"" {
b = "Anonymous".to_string();
} else {
b=bind.to_string();
}
if &caps["res"] == "err=0" {
let mut stmt = c.prepare("UPDATE conip SET bind = ?1 WHERE con = ?2").unwrap();
stmt.execute(params![b,&caps["con"]]).unwrap();
}
linelog = format!("{} BIND {} {}",log.ip,b,err);
},
_ => { let b = getbind(&caps["con"]).unwrap();
linelog = format!("{} BIND {} {} {} {}",log.ip,b,log.command,bind,err);
}
}
sendlog(linelog);
}
//dumpcon();
//let _ = dumplog();
}
fn com_srch_filter(line: String){
let regexp_command = Regex::new(r"^\S+ \S+ conn=(?<con>[0-9]+) op=(?<op>[0-9]+) SRCH base=(?<base>\S+) \S+ \S+ filter=(?<filter>\S+)").unwrap();
let Some(caps) = regexp_command.captures(&line) else {
return;
};
let ip = getip(&caps["con"]).unwrap();
let bind = getbind(&caps["con"]).unwrap();
if ip != "0" {
let c = Connection::open("/dev/shm/parselog.db").unwrap();
let query = "INSERT INTO log ('ip','con','op','command','bind','base','filter') VALUES(?1,?2,?3,?4,?5,?6,?7)";
c.execute(query,(ip,&caps["con"],&caps["op"],"SRCH",bind,&caps["base"],&caps["filter"]),).unwrap();
}
}
fn com_srch_attr(line: String){
let regexp_command = Regex::new(r"^\S+ \S+ conn=(?<con>[0-9]+) op=(?<op>[0-9]+) SRCH attr=(?<attr>\S+)").unwrap();
let Some(caps) = regexp_command.captures(&line) else {
return;
};
let c = Connection::open("/dev/shm/parselog.db").unwrap();
let mut stmt = c.prepare("UPDATE log SET attr = ?1 WHERE con = ?2 AND op = ?3").unwrap();
stmt.execute(params![&caps["attr"],&caps["con"],&caps["op"]]).unwrap();
}
fn com_srch(line: String){
let regexp_command = Regex::new(r"^\S+ \S+ \S+ \S+ SRCH (?<cmd>[a-z]+)=.*").unwrap();
let Some(caps) = regexp_command.captures(&line) else {
return;
};
match &caps["cmd"]{
"base"=>com_srch_filter(line.to_string()),
"attr"=>com_srch_attr(line.to_string()),
_=>com_default(line.to_string()),
}
}
fn com_search(line: String){
let regexp_command = Regex::new(r"^\S+ \S+ conn=(?<con>[0-9]+) op=(?<op>[0-9]+) SEARCH RESULT \S+ err=(?<err>[0-9]+) nentries=(?<nentries>[0-9]+)").unwrap();
let Some(caps) = regexp_command.captures(&line) else {
return;
};
let log = getlog(&caps["con"],&caps["op"]).unwrap();
if log.ip != "0" {
let bind = getbind(&caps["con"]).unwrap();
let attr = log.attr.as_deref().unwrap_or("\"\"");
let linelog : String;
let err : String;
match &caps["err"]{
"0" => err = format!("{}{}{}", "OK -> ".to_string(),&caps["nentries"]," answer".to_string()),
_ => err = "error".to_string(),
}
linelog = format!("{} BIND {} SRCH attr {} in {} with filter {} {}",log.ip,bind,attr,log.base.expect(""),log.filter.expect(""),err);
sendlog(linelog);
}
}
fn com_closed(line: String){
let regexp_command = Regex::new(r"^\S+ \S+ conn=(?<con>[0-9]+) \S+ closed").unwrap();
let Some(caps) = regexp_command.captures(&line) else {
return;
};
let c = Connection::open("/dev/shm/parselog.db").unwrap();
let mut stmt = c.prepare("DELETE FROM conip WHERE con = ?1").unwrap();
stmt.execute(params![&caps["con"]]).unwrap();
let mut stmt = c.prepare("DELETE FROM log WHERE con = ?1").unwrap();
stmt.execute(params![&caps["con"]]).unwrap();
}
fn com_default(line: String){
let _ = line;
//println!("DEF {}", &line);
}
fn sendlog(line: String){
let formatter = Formatter3164 {
facility: Facility::LOG_USER,
hostname: Some(gethostname().into_string().unwrap()),
process: "ldap".into(),
pid: 6666,
};
let s = LOGHOST.with(|text| text.clone());
match syslog::udp(formatter,"0.0.0.0:0",&s) {
Err(e) => println!("impossible to connect to syslog: {:?}", e),
Ok(mut writer) => {
writer.info(line).expect("could not write error message");
}
}
//println!("OUT: {}",line);
}
fn dumpcon() {
let c = Connection::open("/dev/shm/parselog.db").unwrap();
let mut stmt = c.prepare("SELECT * FROM conip").unwrap();
let rows = stmt.query_map([], |row| {
Ok((row.get(0)?, row.get(1)?, row.get(2)?))
}).unwrap();
for row in rows {
let (con,ip,bind): (u32, String, String) = row.unwrap();
println!("Dump con - con: {} - IP: {} - bind: {}",con,ip,bind);
}
}
fn dumplog() -> Result<()> {
let c = Connection::open("/dev/shm/parselog.db")?;
let mut stmt = c.prepare("SELECT * FROM log")?;
let log_iter = stmt.query_map([], |row| {
Ok(Log {
ip: row.get(0)?,
con: row.get(1)?,
op: row.get(2)?,
bind: row.get(3)?,
command: row.get(4)?,
base: row.get(5)?,
filter: row.get(6)?,
attr: row.get(7)?,
result: row.get(8)?,
})
})?;
for log in log_iter {
println!("Dump Log {:?}", log);
}
Ok(())
}
fn launch<R: BufRead>(reader: R) {
let regexp_command = Regex::new(r"^\S+ \S+ (?<con>\S+) (?<op>\S+) (?<command>\S+)").unwrap();
for l in reader.lines() {
let line = l.unwrap();
let Some(caps) = regexp_command.captures(&line) else {
return;
};
match &caps["command"]{
"ACCEPT"=>com_accept(line.to_string()),
"BIND"=>com_bind(line.to_string()),
"DEL"=>com_bind(line.to_string()),
"RESULT"=>com_result(line.to_string()),
"SRCH"=>com_srch(line.to_string()),
"SEARCH"=>com_search(line.to_string()),
"closed"=>com_closed(line.to_string()),
_=>com_default(line.to_string()),
}
}
}
fn initdb(){
let _res = fs::remove_file("/dev/shm/parselog.db");
let mut file = File::create("/dev/shm/parselog.db").expect("Error encountered while creating file!");
file.write_all(b"Writing").expect("Error while writing to file");
fs::remove_file("/dev/shm/parselog.db").unwrap();
let c = Connection::open("/dev/shm/parselog.db").unwrap();
let query = "CREATE TABLE conip (con INT, ip TEXT, bind TEXT)";
c.execute(query,(),).unwrap();
let query = "CREATE TABLE log (ip TEXT, con INT, op INT, bind TEXT, command TEXT, base TEXT, filter TEXT, attr TEXT, result TEXT)";
c.execute(query,(),).unwrap();
}
fn main() {
initdb();
let port = getport().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);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment