Merge pull request 'dev' (#1) from dev into main

Reviewed-on: #1
This commit is contained in:
serxoz 2024-04-18 13:47:09 +02:00
commit 5f3489dbc5
10 changed files with 288 additions and 8 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
/target /target
*.log *.log
*.db

115
Cargo.lock generated
View File

@ -2,6 +2,24 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "ahash"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "allocator-api2"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
[[package]] [[package]]
name = "android-tzdata" name = "android-tzdata"
version = "0.1.1" version = "0.1.1"
@ -41,6 +59,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.16.0" version = "3.16.0"
@ -106,6 +130,18 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "fallible-iterator"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
[[package]]
name = "fallible-streaming-iterator"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@ -128,6 +164,19 @@ name = "hashbrown"
version = "0.14.3" version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
dependencies = [
"ahash",
"allocator-api2",
]
[[package]]
name = "hashlink"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692eaaf7f7607518dd3cef090f1474b61edc5301d8012f09579920df68b725ee"
dependencies = [
"hashbrown",
]
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
@ -198,6 +247,17 @@ version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "libsqlite3-sys"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f"
dependencies = [
"cc",
"pkg-config",
"vcpkg",
]
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.9" version = "0.4.9"
@ -332,6 +392,12 @@ version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
[[package]]
name = "pkg-config"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.17" version = "0.2.17"
@ -392,7 +458,21 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
]
[[package]]
name = "rusqlite"
version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae"
dependencies = [
"bitflags 2.5.0",
"fallible-iterator",
"fallible-streaming-iterator",
"hashlink",
"libsqlite3-sys",
"smallvec",
] ]
[[package]] [[package]]
@ -486,6 +566,7 @@ dependencies = [
"log", "log",
"log4rs", "log4rs",
"rand", "rand",
"rusqlite",
"serde", "serde",
"tokio", "tokio",
"toml", "toml",
@ -654,6 +735,18 @@ version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.11.0+wasi-snapshot-preview1" version = "0.11.0+wasi-snapshot-preview1"
@ -874,3 +967,23 @@ checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "zerocopy"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.59",
]

View File

@ -9,6 +9,7 @@ edition = "2021"
log = "0.4.21" log = "0.4.21"
log4rs = "1.3.0" log4rs = "1.3.0"
rand = "0.8.5" rand = "0.8.5"
rusqlite = { version = "0.31.0", features = ["bundled"] }
serde = { version = "1.0.197", features = ["derive"] } serde = { version = "1.0.197", features = ["derive"] }
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
toml = "0.8.12" toml = "0.8.12"

View File

@ -18,3 +18,8 @@ This way attacker will be entertained for some time... :D
## Configure ## Configure
Read config.toml and adapt it to your preferences. Keep in mind that for docker Read config.toml and adapt it to your preferences. Keep in mind that for docker
use you want to keep log_file="CONSOLE". use you want to keep log_file="CONSOLE".
## Action Script
You can configure action script by adding it to config.toml.
When a new suspicious IP address is detected, the script will be executed. See
action_script.sh for an example.

18
action_script.sh Executable file
View File

@ -0,0 +1,18 @@
#!/bin/sh
# Script to run when a new suspicious IP address is detected.
# Example for Linux:
# iptables -I INPUT -s $1 -j DROP
#
# Example for OpenBSD:
# Having a table in pf.conf:
# table <blacklist> persist file "/etc/blacklist"
# block drop in quick from <blacklist> to any
# then add/delete dinamically:
# pfctl -t badhosts -T add $1
# pfctl -t badhosts -T delete $1
# Example for "debugging":
echo $1 > /tmp/foo

View File

@ -14,3 +14,10 @@ level = "INFO"
[tarpit] [tarpit]
# delay in milliseconds # delay in milliseconds
delay = 1500 delay = 1500
[sqlite]
location = "tarpit.db"
[action]
# path to action script, remember give it execution permission
script = "./action_script.sh"

View File

@ -4,7 +4,9 @@ use serde::{Deserialize, Serialize};
struct ConfigToml { struct ConfigToml {
listen: Option<ConfigTomlListen>, listen: Option<ConfigTomlListen>,
log: Option<ConfigTomlLog>, log: Option<ConfigTomlLog>,
tarpit: Option<ConfigTomlTarpit> tarpit: Option<ConfigTomlTarpit>,
sqlite: Option<ConfigTomlSqlite>,
action: Option<ConfigTomlAction>,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -24,6 +26,16 @@ struct ConfigTomlTarpit {
delay: Option<u64>, delay: Option<u64>,
} }
#[derive(Serialize, Deserialize, Debug)]
struct ConfigTomlSqlite {
location: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
struct ConfigTomlAction {
script: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct Config { pub struct Config {
pub bind_addr: String, pub bind_addr: String,
@ -31,6 +43,8 @@ pub struct Config {
pub log_file: String, pub log_file: String,
pub log_level: String, pub log_level: String,
pub delay: u64, pub delay: u64,
pub database_location: String,
pub action_script: String
} }
impl Config { impl Config {
@ -57,7 +71,9 @@ impl Config {
ConfigToml { ConfigToml {
listen: None, listen: None,
log: None, log: None,
tarpit: None tarpit: None,
sqlite: None,
action: None
} }
}); });
@ -82,12 +98,24 @@ impl Config {
None => 0 None => 0
}; };
let database_location = match config_toml.sqlite {
Some(ConfigTomlSqlite { location }) => location.unwrap_or("./tarpit.db".to_owned()),
None => "./tarpit.db".to_owned()
};
let action_script = match config_toml.action {
Some(ConfigTomlAction { script }) => script.unwrap_or("".to_owned()),
None => "".to_owned()
};
Config { Config {
bind_addr, bind_addr,
bind_port, bind_port,
log_file, log_file,
log_level, log_level,
delay delay,
database_location,
action_script
} }
} }
} }

72
src/database.rs Normal file
View File

@ -0,0 +1,72 @@
use rusqlite::{Connection, Result};
use std::time::SystemTime;
#[allow(dead_code)]
pub struct Suspicious {
ip_addr: String,
banned: u8,
create_time: u64,
}
pub fn init_db(path: &str) -> Result<Connection> {
let conn = Connection::open(path)?;
conn.execute(
"CREATE TABLE IF NOT EXISTS suspicious (
ip_addr VARCHAR(128) PRIMARY KEY,
banned INTEGER NOT NULL,
create_time INTEGER NOT NULL
)", [])?;
Ok(conn)
}
#[allow(dead_code)]
pub fn get_all_suspicious(conn: &Connection) -> Result<Vec<Suspicious>, rusqlite::Error> {
let mut stmt = conn.prepare("SELECT * FROM suspicious")?;
let rows = stmt.query_map([], |row| {
Ok(Suspicious {
ip_addr: row.get(0)?,
banned: row.get(1)?,
create_time: row.get(2)?,
})
})?;
Ok(rows.collect::<Result<Vec<Suspicious>, _>>()?)
}
pub fn get_suspicious_by_ip_addr(conn: &Connection, ip_addr: &str) -> Result<Suspicious, rusqlite::Error> {
let mut stmt = conn.prepare("SELECT * FROM suspicious WHERE ip_addr = ?")?;
let row = stmt.query_row([ip_addr], |row| {
Ok(Suspicious {
ip_addr: row.get(0)?,
banned: row.get(1)?,
create_time: row.get(2)?,
})
})?;
Ok(row)
}
pub fn add_suspicious(conn: &Connection, mut ip_addr: &str) -> Result<(), rusqlite::Error> {
//if ip_addr has ":" in it means it has port, we insert only IP addr
if ip_addr.contains(":") {
ip_addr = ip_addr.split(":").collect::<Vec<&str>>()[0];
}
let epoch = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs()
.to_string();
let mut stmt = conn.prepare("INSERT OR IGNORE INTO suspicious (ip_addr, banned, create_time) VALUES (?, ?, ?)")?;
stmt.execute([ip_addr, "0", epoch.as_str()])?;
Ok(())
}
#[allow(dead_code)]
pub fn delete_suspicious(conn: &Connection, ip_addr: &str) -> Result<(), rusqlite::Error> {
let mut stmt = conn.prepare("DELETE FROM suspicious WHERE ip_addr = ?")?;
stmt.execute([ip_addr])?;
Ok(())
}

View File

@ -5,12 +5,14 @@
*/ */
mod sip; mod sip;
mod config; mod config;
mod database;
use crate::sip::generic::*; use crate::sip::generic::*;
use crate::sip::not_found::*; use crate::sip::not_found::*;
use crate::sip::options::*; use crate::sip::options::*;
use crate::sip::register::*; use crate::sip::register::*;
use crate::sip::unauthorized::*; use crate::sip::unauthorized::*;
use crate::database::*;
use rand::Rng; use rand::Rng;
use std::error::Error; use std::error::Error;
use std::net::SocketAddr; use std::net::SocketAddr;
@ -22,12 +24,15 @@ use log4rs::append::file::FileAppender;
use log4rs::append::console::ConsoleAppender; use log4rs::append::console::ConsoleAppender;
use log4rs::config::{Appender, Config, Root}; use log4rs::config::{Appender, Config, Root};
use log4rs::encode::pattern::PatternEncoder; use log4rs::encode::pattern::PatternEncoder;
use rusqlite::Connection;
use std::process::Command;
struct Server { struct Server {
socket: UdpSocket, socket: UdpSocket,
buf: Vec<u8>, buf: Vec<u8>,
to_send: Option<(usize, SocketAddr)>, to_send: Option<(usize, SocketAddr)>,
config: config::Config config: config::Config,
db_con: Connection
} }
impl Server { impl Server {
@ -36,7 +41,8 @@ impl Server {
socket, socket,
mut buf, mut buf,
mut to_send, mut to_send,
config config,
db_con
} = self; } = self;
loop { loop {
@ -44,8 +50,33 @@ impl Server {
// If so then we try to send it back to the original source, waiting // If so then we try to send it back to the original source, waiting
// until it's writable and we're able to do so. // until it's writable and we're able to do so.
if let Some((size, peer)) = to_send { if let Some((size, peer)) = to_send {
log::info!("Suspicious peer: {}", peer); // save peer
// let str_peer_ip = peer.ip().to_string();
match get_suspicious_by_ip_addr(&db_con, str_peer_ip.as_str()) {
Ok(_) => {
// was added to database, do nothing
// log::info!("Peer already added to database");
},
Err(_e) => {
// was not in database
// log::info!("Error getting suspicious peer from database: {}", _e);
log::info!("Suspicious peer: {}", peer.ip());
match add_suspicious(&db_con, str_peer_ip.as_str()) {
Ok(_) => {
// launch action script
let output = Command::new(config.action_script.to_owned())
.arg(str_peer_ip.as_str())
.output();
match output {
Ok(_) => log::info!("Action script executed"),
Err(e) => log::info!("Error executing action script {}", e)
}
},
Err(_) => return Err(io::Error::new(io::ErrorKind::Other, "Error adding suspicious peer to database")),
}
}
}
// test type of message received // test type of message received
let msg = String::from_utf8(buf[..size].to_vec()).unwrap(); let msg = String::from_utf8(buf[..size].to_vec()).unwrap();
match msg { match msg {
@ -206,6 +237,8 @@ async fn main() -> Result<(), Box<dyn Error>> {
log4rs::init_config(logconfig).unwrap(); log4rs::init_config(logconfig).unwrap();
let db_con = init_db(config.database_location.as_str())?;
let addr = format!("{}:{}", config.bind_addr, config.bind_port); let addr = format!("{}:{}", config.bind_addr, config.bind_port);
let socket = UdpSocket::bind(&addr).await?; let socket = UdpSocket::bind(&addr).await?;
log::info!("Listening on: {}", socket.local_addr()?); log::info!("Listening on: {}", socket.local_addr()?);
@ -215,6 +248,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
buf: vec![0; 1024], buf: vec![0; 1024],
to_send: None, to_send: None,
config, config,
db_con
}; };
// This starts the server task. // This starts the server task.

View File

@ -19,6 +19,7 @@ pub struct Forbidden {
pub content_length: Option<i32>, // 0 pub content_length: Option<i32>, // 0
} }
#[allow(dead_code)]
impl Forbidden { impl Forbidden {
pub fn serialize(&self) -> Vec<u8> { pub fn serialize(&self) -> Vec<u8> {
let mut preout = format!( let mut preout = format!(