Skip to content

Commit

Permalink
Merge pull request #6 from Ant0wan/master
Browse files Browse the repository at this point in the history
Release(v1.3): ready for pre-prod
  • Loading branch information
Ant0wan authored Sep 29, 2020
2 parents 50ec06b + def83a9 commit 30e01df
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 33 deletions.
6 changes: 5 additions & 1 deletion build.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash
arch=('aarch64' 'x86_64')
printf "Check code base:\n"
if (cargo fmt && cargo clippy --all-targets --all-features -- -D clippy::pedantic)
if (cargo fmt && cargo clippy --release --all-targets --all-features -- -D clippy::pedantic)
then
tput bold
tput setaf 46
Expand All @@ -22,8 +22,12 @@ do
tput setaf 93
printf "$a\n"
tput init
#RELEASE
if (cross build --target=${a}-unknown-linux-musl --release &&
cp target/${a}-unknown-linux-musl/release/randetect randetect_${a}-musl)
# DEBUG
#if (cross build --target=${a}-unknown-linux-musl &&
# cp target/${a}-unknown-linux-musl/debug/randetect randetect_${a}-musl)
then
tput bold
tput setaf 46
Expand Down
41 changes: 33 additions & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ macro_rules! nas_shutdown {
};
}

/// Samaba Log Database
const DB: &str = "/var/log/synolog/.SMBXFERDB";

/// Maximum of suspicious actions
const BAN_LIMIT: i32 = 30;
pub const BAN_LIMIT: i32 = 30;

pub struct Cdtl {
user: String,
Expand Down Expand Up @@ -83,6 +84,7 @@ fn daemonize() {
}

fn main() {
#[cfg(not(debug_assertions))]
daemonize();

let var: Cdtl = env_variables();
Expand All @@ -98,41 +100,64 @@ fn main() {
let mut id = query::updated_id(&conn);
let mut idsup = id;

#[cfg(debug_assertions)]
println!("loop: {}", TIME);

loop {
let mut list: HashMap<String, parse::UserInfo> = HashMap::new();
#[cfg(debug_assertions)]
{
println!("id: {:?}", id);
println!("idsup: {:?}\n", idsup);
}

let mut list: HashMap<String, parse::UserInfo> = HashMap::new();
let mut query = query::select(&conn, Type::Move, id);
query.extend(query::select(&conn, Type::Delete, id));
query.extend(query::select(&conn, Type::SuspiciousCwd, idsup));

id = query::updated_id(&conn);

parse::log(query, &mut list);

let mut shutdown = 0;

#[cfg(debug_assertions)]
println!("list {:?}\n-------", list);

for user in &list {
let (name, info) = user;
for beh in info.get_behaviors() {
match beh {
Behavior::Delete(c) if *c >= BAN_LIMIT => {
#[cfg(debug_assertions)]
{
println!("Alert NAS {} user: {} banned because of deleting +{} files from ip:{:?}"
, sys_info::hostname().unwrap(), name, c, info.get_ips());
}

nas::ban(info);
email::send(&var, &name, info, "delete");
sms::send(&var, &format!(
"Alert NAS {} user: {} banned because of deleting {} files from ip:{:?}"
"Alert NAS {} user: {} banned because of deleting +{} files from ip:{:?}"
, sys_info::hostname().unwrap(), name, c, info.get_ips()));
id = query::updated_id(&conn);
}
Behavior::Suspicious(c) if *c >= BAN_LIMIT => {
#[cfg(debug_assertions)]
{
println!("Alert NAS {} user: {} banned because of suspicious activity +{} times from ip:{:?}"
, sys_info::hostname().unwrap(), name, c, info.get_ips());
println!("idsup: {:?}", idsup);
}

nas::ban(info);
shutdown += 1;
email::send(&var, &name, info, "Suspicious");
sms::send(&var, &format!(
"Alert NAS {} user: {} banned because of suspicious activity {} times from ip:{:?}"
"Alert NAS {} user: {} banned because of suspicious activity +{} times from ip:{:?}"
, sys_info::hostname().unwrap(), name, c, info.get_ips()));
idsup = query::updated_id(&conn);
id = query::updated_id(&conn);
}
Behavior::Move(_s) => {
email::send(&var, &name, info, "Move");
id = query::updated_id(&conn);
}
_ => (),
}
Expand Down
17 changes: 11 additions & 6 deletions src/nas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,8 @@ pub fn cmd_exec(cmd: &str) -> (String, String, String) {
.output()
.unwrap_or_else(|e| panic!("failed to execute process: {}", e));

#[cfg(debug_assertions)]
println!("status: {}", output.status);
#[cfg(debug_assertions)]
println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
#[cfg(debug_assertions)]
println!("stderr: {}", String::from_utf8_lossy(&output.stderr));

(
Expand Down Expand Up @@ -70,6 +67,9 @@ fn close_request() -> String {
/// - Restart Samba to kick off user,
/// then slow redo for webclient to capture it.
pub fn ban(info: &UserInfo) {
println!("BAN: {:?}", info);

#[cfg(not(debug_assertions))]
{
for ip in info.get_ips().iter() {
let cmd = ban_profile(&ip);
Expand All @@ -87,10 +87,13 @@ pub fn ban(info: &UserInfo) {
let cmd = close_request();
cmd_exec(&cmd);

cmd_exec("/sbin/restart smbd");
//cmd_exec("/sbin/restart smbd");
//cmd_exec("/sbin/restart sshd");
cmd_exec("synoservicectl --restart sshd");
cmd_exec("synoservicectl --restart smbd");
}
}

#[cfg(not(debug_assertions))]
{
for ip in info.get_ips().iter() {
let cmd = ban_profile(&ip);
Expand All @@ -108,11 +111,13 @@ pub fn ban(info: &UserInfo) {
let cmd = close_request();
cmd_exec(&cmd);
thread::sleep(Duration::from_millis(1_000));
cmd_exec("/sbin/restart smbd");
cmd_exec("synoservicectl --restart smbd");
//cmd_exec("/sbin/restart smbd");
}
}
}

pub fn poweroff() {
#[cfg(not(debug_assertions))]
cmd_exec("shutdown -h now");
}
38 changes: 34 additions & 4 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,29 @@ impl UserInfo {
}
}

fn update(&mut self, newip: String, t: Type, dir: String) {
match t {
Type::Delete => {
for each in &mut self.kind {
if let Behavior::Delete(c) = each {
*c += 1
};
}
}
Type::SuspiciousCwd => {
for each in &mut self.kind {
if let Behavior::Suspicious(c) = each {
*c += 1
};
}
}
Type::Move => self.kind.push(Behavior::Move(dir)),
}
if !self.ip.contains(&newip) {
self.ip.push(newip);
}
}

pub fn get_behaviors(&self) -> &Vec<Behavior> {
&self.kind
}
Expand All @@ -50,9 +73,16 @@ impl UserInfo {
pub fn log(entry: Vec<Log>, users: &mut HashMap<String, UserInfo>) {
for el in entry {
let uname = el.get_username();
let update = users
.entry(uname)
.or_insert_with(|| UserInfo::new(el.get_ip(), el.get_kind(), el.get_dir()));
*update = UserInfo::new(el.get_ip(), el.get_kind(), el.get_dir());
if users.contains_key(&uname) {
users
.get_mut(&uname)
.unwrap()
.update(el.get_ip(), el.get_kind(), el.get_dir());
} else {
users.insert(
uname,
UserInfo::new(el.get_ip(), el.get_kind(), el.get_dir()),
);
}
}
}
61 changes: 47 additions & 14 deletions src/query.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
use rusqlite::{params, Connection, Result};

#[cfg(debug_assertions)]
use std::time::Instant;

/// Query performed to Samba Log Database
/// - `id` is the last log number from which scan is performed, id is updated after a banned to
/// the newest id number.
/// - `period` is the period scanned
fn fmt_qdelete(id: i32, period: i32) -> String {
format!(
"SELECT username, ip
FROM logs
WHERE id > {} AND isdir = 0
AND cmd = 'delete'
AND time > ( SELECT MAX(time)
FROM logs ) - {}
WHERE id > {} AND isdir = 0 AND cmd = 'delete' AND time > ( SELECT MAX(time) FROM logs WHERE id > {} ) - {}
;",
id, period
id, id, period
)
}

fn fmt_qsuspiciouscwd(id: i32, period: i32) -> String {
/// Query performed to Samba Log Database
/// - `id` is the last log number from which scan is performed, id is updated after a banned to
/// the newest id number,
/// - `delay` hypothetical time encryption of file would take,
/// - `period` is the overall period scanned to find pattern.
fn fmt_qsuspiciouscwd(id: i32, delay: i32, period: i32) -> String {
format!(
"SELECT D.username, D.ip
FROM
Expand All @@ -26,12 +35,12 @@ fn fmt_qsuspiciouscwd(id: i32, period: i32) -> String {
(
SELECT *
FROM logs
WHERE id > {} AND time > strftime('%s', 'now') - 5 * 60 AND isdir = 0
WHERE id > {} AND time > strftime('%s', 'now') - {} AND isdir = 0
) A,
(
SELECT *
FROM logs
WHERE id > {} AND time > strftime('%s', 'now') - 5 * 60 AND isdir = 0
WHERE id > {} AND time > strftime('%s', 'now') - {} AND isdir = 0
) B
WHERE A.filename = B.filename
AND A.cmd = 'create' AND B.cmd = 'write'
Expand All @@ -41,13 +50,13 @@ fn fmt_qsuspiciouscwd(id: i32, period: i32) -> String {
SELECT *
FROM logs
WHERE isdir = 0 AND cmd = 'delete'
AND id > {} AND time > strftime('%s', 'now') - 5 * 60 AND isdir = 0
AND id > {} AND time > strftime('%s', 'now') - {} AND isdir = 0
) D
WHERE CWp.writetime <= D.time
AND (D.time - CWp.writetime) <= {}
AND D.filesize <= CWp.wrotefilesize
;",
id, id, id, period
id, delay, id, delay, id, delay, period
)
}

Expand Down Expand Up @@ -132,14 +141,23 @@ impl Log {
pub fn select(conn: &Connection, qtype: Type, id: i32) -> Vec<Log> {
let mut stmt = {
match qtype {
Type::Delete => conn.prepare(&fmt_qdelete(id, 10)).unwrap(),
Type::SuspiciousCwd => conn.prepare(&fmt_qsuspiciouscwd(id, 5)).unwrap(),
// Check maximum delete number within interval of 5seconds from last id (last ban or
// start id)
// Recommanded interval value: 3
Type::Delete => conn.prepare(&fmt_qdelete(id, 3)).unwrap(),

// Check maximum possible encryption schemes which encryption took 20seconds.
// Recommanded interval value: 5sec
// Increase this number will capture large files, but increase query time.
// Overall period scanned in Database 2 * 60 seconds.
Type::SuspiciousCwd => conn.prepare(&fmt_qsuspiciouscwd(id, 5, 2 * 60)).unwrap(),

Type::Move => conn.prepare(&fmt_qmove(id)).unwrap(),
}
};

#[cfg(debug_assertions)]
println!("query stmt:{:?}", stmt);
let now = Instant::now();

let logs = stmt
.query_map(params![], |row| {
Expand All @@ -152,15 +170,30 @@ pub fn select(conn: &Connection, qtype: Type, id: i32) -> Vec<Log> {
})
.unwrap();

#[cfg(debug_assertions)]
println!("Logs map time {}", now.elapsed().as_millis());

let mut iter: i32 = 0; // To be compared with BAN_LIMIT, no need to allocate more memory than the limit itself.
let mut relation: Vec<Log> = Vec::new();
for each in logs {
#[cfg(debug_assertions)]
println!("each in logs: {:?}", each);
println!("eachlog: {:?}", each);

if iter >= super::BAN_LIMIT {
break;
}
match each {
Ok(t) => relation.push(t),
Err(_e) => (),
}
iter += 1;
}

#[cfg(debug_assertions)]
{
println!("relation push time {}", now.elapsed().as_millis());
println!("relation: {:?}", relation);
}

relation
}

0 comments on commit 30e01df

Please sign in to comment.