commit
5f3489dbc5
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
/target
|
||||
*.log
|
||||
*.db
|
||||
|
115
Cargo.lock
generated
115
Cargo.lock
generated
@ -2,6 +2,24 @@
|
||||
# It is not intended for manual editing.
|
||||
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]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
@ -41,6 +59,12 @@ version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
@ -106,6 +130,18 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
@ -128,6 +164,19 @@ name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "hermit-abi"
|
||||
@ -198,6 +247,17 @@ version = "0.2.153"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "lock_api"
|
||||
version = "0.4.9"
|
||||
@ -332,6 +392,12 @@ version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
@ -392,7 +458,21 @@ version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
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]]
|
||||
@ -486,6 +566,7 @@ dependencies = [
|
||||
"log",
|
||||
"log4rs",
|
||||
"rand",
|
||||
"rusqlite",
|
||||
"serde",
|
||||
"tokio",
|
||||
"toml",
|
||||
@ -654,6 +735,18 @@ version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
@ -874,3 +967,23 @@ checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352"
|
||||
dependencies = [
|
||||
"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",
|
||||
]
|
||||
|
@ -9,6 +9,7 @@ edition = "2021"
|
||||
log = "0.4.21"
|
||||
log4rs = "1.3.0"
|
||||
rand = "0.8.5"
|
||||
rusqlite = { version = "0.31.0", features = ["bundled"] }
|
||||
serde = { version = "1.0.197", features = ["derive"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
toml = "0.8.12"
|
||||
|
@ -18,3 +18,8 @@ This way attacker will be entertained for some time... :D
|
||||
## Configure
|
||||
Read config.toml and adapt it to your preferences. Keep in mind that for docker
|
||||
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
18
action_script.sh
Executable 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
|
||||
|
||||
|
@ -14,3 +14,10 @@ level = "INFO"
|
||||
[tarpit]
|
||||
# delay in milliseconds
|
||||
delay = 1500
|
||||
|
||||
[sqlite]
|
||||
location = "tarpit.db"
|
||||
|
||||
[action]
|
||||
# path to action script, remember give it execution permission
|
||||
script = "./action_script.sh"
|
||||
|
@ -4,7 +4,9 @@ use serde::{Deserialize, Serialize};
|
||||
struct ConfigToml {
|
||||
listen: Option<ConfigTomlListen>,
|
||||
log: Option<ConfigTomlLog>,
|
||||
tarpit: Option<ConfigTomlTarpit>
|
||||
tarpit: Option<ConfigTomlTarpit>,
|
||||
sqlite: Option<ConfigTomlSqlite>,
|
||||
action: Option<ConfigTomlAction>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
@ -24,6 +26,16 @@ struct ConfigTomlTarpit {
|
||||
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)]
|
||||
pub struct Config {
|
||||
pub bind_addr: String,
|
||||
@ -31,6 +43,8 @@ pub struct Config {
|
||||
pub log_file: String,
|
||||
pub log_level: String,
|
||||
pub delay: u64,
|
||||
pub database_location: String,
|
||||
pub action_script: String
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@ -57,7 +71,9 @@ impl Config {
|
||||
ConfigToml {
|
||||
listen: None,
|
||||
log: None,
|
||||
tarpit: None
|
||||
tarpit: None,
|
||||
sqlite: None,
|
||||
action: None
|
||||
}
|
||||
});
|
||||
|
||||
@ -82,12 +98,24 @@ impl Config {
|
||||
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 {
|
||||
bind_addr,
|
||||
bind_port,
|
||||
log_file,
|
||||
log_level,
|
||||
delay
|
||||
delay,
|
||||
database_location,
|
||||
action_script
|
||||
}
|
||||
}
|
||||
}
|
||||
|
72
src/database.rs
Normal file
72
src/database.rs
Normal 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(())
|
||||
}
|
42
src/main.rs
42
src/main.rs
@ -5,12 +5,14 @@
|
||||
*/
|
||||
mod sip;
|
||||
mod config;
|
||||
mod database;
|
||||
|
||||
use crate::sip::generic::*;
|
||||
use crate::sip::not_found::*;
|
||||
use crate::sip::options::*;
|
||||
use crate::sip::register::*;
|
||||
use crate::sip::unauthorized::*;
|
||||
use crate::database::*;
|
||||
use rand::Rng;
|
||||
use std::error::Error;
|
||||
use std::net::SocketAddr;
|
||||
@ -22,12 +24,15 @@ use log4rs::append::file::FileAppender;
|
||||
use log4rs::append::console::ConsoleAppender;
|
||||
use log4rs::config::{Appender, Config, Root};
|
||||
use log4rs::encode::pattern::PatternEncoder;
|
||||
use rusqlite::Connection;
|
||||
use std::process::Command;
|
||||
|
||||
struct Server {
|
||||
socket: UdpSocket,
|
||||
buf: Vec<u8>,
|
||||
to_send: Option<(usize, SocketAddr)>,
|
||||
config: config::Config
|
||||
config: config::Config,
|
||||
db_con: Connection
|
||||
}
|
||||
|
||||
impl Server {
|
||||
@ -36,7 +41,8 @@ impl Server {
|
||||
socket,
|
||||
mut buf,
|
||||
mut to_send,
|
||||
config
|
||||
config,
|
||||
db_con
|
||||
} = self;
|
||||
|
||||
loop {
|
||||
@ -44,8 +50,33 @@ impl Server {
|
||||
// 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.
|
||||
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
|
||||
let msg = String::from_utf8(buf[..size].to_vec()).unwrap();
|
||||
match msg {
|
||||
@ -206,6 +237,8 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
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 socket = UdpSocket::bind(&addr).await?;
|
||||
log::info!("Listening on: {}", socket.local_addr()?);
|
||||
@ -215,6 +248,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||
buf: vec![0; 1024],
|
||||
to_send: None,
|
||||
config,
|
||||
db_con
|
||||
};
|
||||
|
||||
// This starts the server task.
|
||||
|
@ -19,6 +19,7 @@ pub struct Forbidden {
|
||||
pub content_length: Option<i32>, // 0
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl Forbidden {
|
||||
pub fn serialize(&self) -> Vec<u8> {
|
||||
let mut preout = format!(
|
||||
|
Loading…
Reference in New Issue
Block a user