mirror of
https://codeberg.org/YGGverse/psocks.git
synced 2026-03-31 16:35:28 +00:00
rename list to rules, change api to free list control namespace
This commit is contained in:
parent
949a8a3b2c
commit
c821fa7492
5 changed files with 43 additions and 41 deletions
|
|
@ -25,7 +25,7 @@ RUST_LOG=trace cargo run -- --allow=http://localhost/allow.txt \
|
||||||
* use http://127.0.0.1:8010 for API:
|
* use http://127.0.0.1:8010 for API:
|
||||||
* `/api/allow/{domain.com}` - add rule to the current session (and `--cache` if defined)
|
* `/api/allow/{domain.com}` - add rule to the current session (and `--cache` if defined)
|
||||||
* `/api/block/{domain.com}` - delete rule from the current session (and `--cache` if defined)
|
* `/api/block/{domain.com}` - delete rule from the current session (and `--cache` if defined)
|
||||||
* `/api/list` - return active rules (from server memory)
|
* `/api/rules` - return active rules (from server memory)
|
||||||
* `/api/cache/clean` - clean the `--cache` file (returns deleted rules or `null` if not enabled)
|
* `/api/cache/clean` - clean the `--cache` file (returns deleted rules or `null` if not enabled)
|
||||||
|
|
||||||
### Allow list example
|
### Allow list example
|
||||||
|
|
|
||||||
54
src/main.rs
54
src/main.rs
|
|
@ -1,5 +1,5 @@
|
||||||
mod list;
|
|
||||||
mod opt;
|
mod opt;
|
||||||
|
mod rules;
|
||||||
mod stats;
|
mod stats;
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
|
@ -7,10 +7,10 @@ use fast_socks5::{
|
||||||
ReplyError, Result, Socks5Command, SocksError,
|
ReplyError, Result, Socks5Command, SocksError,
|
||||||
server::{DnsResolveHelper as _, Socks5ServerProtocol, run_tcp_proxy, run_udp_proxy},
|
server::{DnsResolveHelper as _, Socks5ServerProtocol, run_tcp_proxy, run_udp_proxy},
|
||||||
};
|
};
|
||||||
use list::List;
|
|
||||||
use log::*;
|
use log::*;
|
||||||
use opt::{AuthMode, Opt};
|
use opt::{AuthMode, Opt};
|
||||||
use rocket::{State, http::Status, serde::json::Json};
|
use rocket::{State, http::Status, serde::json::Json};
|
||||||
|
use rules::Rules;
|
||||||
use stats::{Snap, Total};
|
use stats::{Snap, Total};
|
||||||
use std::{future::Future, sync::Arc, time::Instant};
|
use std::{future::Future, sync::Arc, time::Instant};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
@ -29,11 +29,11 @@ async fn api_totals(totals: &State<Arc<Total>>, startup_time: &State<Instant>) -
|
||||||
#[rocket::get("/api/allow/<rule>")]
|
#[rocket::get("/api/allow/<rule>")]
|
||||||
async fn api_allow(
|
async fn api_allow(
|
||||||
rule: &str,
|
rule: &str,
|
||||||
list: &State<Arc<List>>,
|
rules: &State<Arc<Rules>>,
|
||||||
totals: &State<Arc<Total>>,
|
totals: &State<Arc<Total>>,
|
||||||
) -> Result<Json<bool>, Status> {
|
) -> Result<Json<bool>, Status> {
|
||||||
let result = list.allow(rule).await;
|
let result = rules.allow(rule).await;
|
||||||
totals.set_entries(list.rules().await);
|
totals.set_entries(rules.rules().await);
|
||||||
info!("Delete `{rule}` from the in-memory rules (operation status: {result:?})");
|
info!("Delete `{rule}` from the in-memory rules (operation status: {result:?})");
|
||||||
Ok(Json(result.map_err(|e| {
|
Ok(Json(result.map_err(|e| {
|
||||||
error!("Allow request handle error for `{rule}`: `{e}`");
|
error!("Allow request handle error for `{rule}`: `{e}`");
|
||||||
|
|
@ -44,11 +44,11 @@ async fn api_allow(
|
||||||
#[rocket::get("/api/block/<rule>")]
|
#[rocket::get("/api/block/<rule>")]
|
||||||
async fn api_block(
|
async fn api_block(
|
||||||
rule: &str,
|
rule: &str,
|
||||||
list: &State<Arc<List>>,
|
rules: &State<Arc<Rules>>,
|
||||||
totals: &State<Arc<Total>>,
|
totals: &State<Arc<Total>>,
|
||||||
) -> Result<Json<bool>, Status> {
|
) -> Result<Json<bool>, Status> {
|
||||||
let result = list.block(rule).await;
|
let result = rules.block(rule).await;
|
||||||
totals.set_entries(list.rules().await);
|
totals.set_entries(rules.rules().await);
|
||||||
info!("Add `{rule}` to the in-memory rules (operation status: {result:?})");
|
info!("Add `{rule}` to the in-memory rules (operation status: {result:?})");
|
||||||
Ok(Json(result.map_err(|e| {
|
Ok(Json(result.map_err(|e| {
|
||||||
error!("Block request handle error for `{rule}`: `{e}`");
|
error!("Block request handle error for `{rule}`: `{e}`");
|
||||||
|
|
@ -56,16 +56,16 @@ async fn api_block(
|
||||||
})?))
|
})?))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rocket::get("/api/list")]
|
#[rocket::get("/api/rules")]
|
||||||
async fn api_list(list: &State<Arc<List>>) -> Result<Json<Vec<String>>, Status> {
|
async fn api_rules(rules: &State<Arc<Rules>>) -> Result<Json<Vec<String>>, Status> {
|
||||||
let result = list.list().await;
|
let result = rules.list().await;
|
||||||
info!("Get list rules (total: {})", result.len());
|
info!("Get rules (total: {})", result.len());
|
||||||
Ok(Json(result))
|
Ok(Json(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rocket::get("/api/cache/clean")]
|
#[rocket::get("/api/cache/clean")]
|
||||||
async fn api_cache_clean(list: &State<Arc<List>>) -> Result<Json<Option<Vec<String>>>, Status> {
|
async fn api_cache_clean(rules: &State<Arc<Rules>>) -> Result<Json<Option<Vec<String>>>, Status> {
|
||||||
let result = list.cache_clean().await;
|
let result = rules.cache_clean().await;
|
||||||
info!("Clean cache file: {result:?}");
|
info!("Clean cache file: {result:?}");
|
||||||
Ok(Json(result.map_err(|e| {
|
Ok(Json(result.map_err(|e| {
|
||||||
error!("Could not handle cache clean request: `{e}`");
|
error!("Could not handle cache clean request: `{e}`");
|
||||||
|
|
@ -79,19 +79,19 @@ async fn rocket() -> _ {
|
||||||
|
|
||||||
let opt: &'static Opt = Box::leak(Box::new(Opt::from_args()));
|
let opt: &'static Opt = Box::leak(Box::new(Opt::from_args()));
|
||||||
|
|
||||||
let list = Arc::new(
|
let rules = Arc::new(
|
||||||
List::from_opt(&opt.allow_list, opt.cache.clone())
|
Rules::from_opt(&opt.allow_list, opt.cache.clone())
|
||||||
.await
|
.await
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let totals = Arc::new(Total::with_rules(list.rules().await));
|
let totals = Arc::new(Total::with_rules(rules.rules().await));
|
||||||
|
|
||||||
tokio::spawn({
|
tokio::spawn({
|
||||||
let socks_list = list.clone();
|
let socks_rules = rules.clone();
|
||||||
let socks_totals = totals.clone();
|
let socks_totals = totals.clone();
|
||||||
async move {
|
async move {
|
||||||
if let Err(err) = spawn_socks_server(opt, socks_list, socks_totals).await {
|
if let Err(err) = spawn_socks_server(opt, socks_rules, socks_totals).await {
|
||||||
error!("SOCKS server failed: `{err}`");
|
error!("SOCKS server failed: `{err}`");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -103,7 +103,7 @@ async fn rocket() -> _ {
|
||||||
address: opt.api_addr.ip(),
|
address: opt.api_addr.ip(),
|
||||||
..rocket::Config::release_default()
|
..rocket::Config::release_default()
|
||||||
})
|
})
|
||||||
.manage(list)
|
.manage(rules)
|
||||||
.manage(totals)
|
.manage(totals)
|
||||||
.manage(Instant::now())
|
.manage(Instant::now())
|
||||||
.mount(
|
.mount(
|
||||||
|
|
@ -113,13 +113,17 @@ async fn rocket() -> _ {
|
||||||
api_totals,
|
api_totals,
|
||||||
api_allow,
|
api_allow,
|
||||||
api_block,
|
api_block,
|
||||||
api_list,
|
api_rules,
|
||||||
api_cache_clean
|
api_cache_clean
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn spawn_socks_server(opt: &'static Opt, list: Arc<List>, totals: Arc<Total>) -> Result<()> {
|
async fn spawn_socks_server(
|
||||||
|
opt: &'static Opt,
|
||||||
|
rules: Arc<Rules>,
|
||||||
|
totals: Arc<Total>,
|
||||||
|
) -> Result<()> {
|
||||||
if opt.allow_udp && opt.public_addr.is_none() {
|
if opt.allow_udp && opt.public_addr.is_none() {
|
||||||
return Err(SocksError::ArgumentInputError(
|
return Err(SocksError::ArgumentInputError(
|
||||||
"Can't allow UDP if public-addr is not set",
|
"Can't allow UDP if public-addr is not set",
|
||||||
|
|
@ -138,7 +142,7 @@ async fn spawn_socks_server(opt: &'static Opt, list: Arc<List>, totals: Arc<Tota
|
||||||
loop {
|
loop {
|
||||||
match listener.accept().await {
|
match listener.accept().await {
|
||||||
Ok((socket, _client_addr)) => {
|
Ok((socket, _client_addr)) => {
|
||||||
spawn_and_log_error(serve_socks5(opt, socket, list.clone(), totals.clone()));
|
spawn_and_log_error(serve_socks5(opt, socket, rules.clone(), totals.clone()));
|
||||||
}
|
}
|
||||||
Err(err) => error!("accept error = {:?}", err),
|
Err(err) => error!("accept error = {:?}", err),
|
||||||
}
|
}
|
||||||
|
|
@ -148,7 +152,7 @@ async fn spawn_socks_server(opt: &'static Opt, list: Arc<List>, totals: Arc<Tota
|
||||||
async fn serve_socks5(
|
async fn serve_socks5(
|
||||||
opt: &Opt,
|
opt: &Opt,
|
||||||
socket: tokio::net::TcpStream,
|
socket: tokio::net::TcpStream,
|
||||||
list: Arc<List>,
|
rules: Arc<Rules>,
|
||||||
totals: Arc<Total>,
|
totals: Arc<Total>,
|
||||||
) -> Result<(), SocksError> {
|
) -> Result<(), SocksError> {
|
||||||
totals.increase_request();
|
totals.increase_request();
|
||||||
|
|
@ -170,7 +174,7 @@ async fn serve_socks5(
|
||||||
|
|
||||||
let (host, _) = request.2.clone().into_string_and_port();
|
let (host, _) = request.2.clone().into_string_and_port();
|
||||||
|
|
||||||
if !list.any(&host).await {
|
if !rules.any(&host).await {
|
||||||
totals.increase_blocked();
|
totals.increase_blocked();
|
||||||
info!("Blocked connection attempt to: {host}");
|
info!("Blocked connection attempt to: {host}");
|
||||||
request
|
request
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,14 @@ use log::*;
|
||||||
use std::{collections::HashSet, path::PathBuf};
|
use std::{collections::HashSet, path::PathBuf};
|
||||||
use tokio::{fs, sync::RwLock};
|
use tokio::{fs, sync::RwLock};
|
||||||
|
|
||||||
pub struct List {
|
pub struct Rules {
|
||||||
/// In-memory registry, based on `--allow-list` + `--cache`
|
/// In-memory registry, based on `--allow-list` + `--cache`
|
||||||
index: RwLock<HashSet<Item>>,
|
index: RwLock<HashSet<Item>>,
|
||||||
/// FS cache for JSON/API changes, based on `--cache` value
|
/// FS cache for JSON/API changes, based on `--cache` value
|
||||||
cache: Cache,
|
cache: Cache,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl List {
|
impl Rules {
|
||||||
/// Build new List object
|
/// Build new List object
|
||||||
pub async fn from_opt(list: &Vec<String>, cache: Option<PathBuf>) -> Result<Self> {
|
pub async fn from_opt(list: &Vec<String>, cache: Option<PathBuf>) -> Result<Self> {
|
||||||
fn handle(this: &mut HashSet<Item>, line: &str) -> Option<bool> {
|
fn handle(this: &mut HashSet<Item>, line: &str) -> Option<bool> {
|
||||||
|
|
@ -27,27 +27,27 @@ impl List {
|
||||||
|
|
||||||
let mut index = HashSet::new();
|
let mut index = HashSet::new();
|
||||||
|
|
||||||
let mut list_rules_total = 0;
|
let mut rules_total = 0;
|
||||||
|
|
||||||
for i in list {
|
for l in list {
|
||||||
for line in if i.contains("://") {
|
for line in if l.contains("://") {
|
||||||
let response = reqwest::get(i).await?;
|
let response = reqwest::get(l).await?;
|
||||||
let status = response.status();
|
let status = response.status();
|
||||||
if status.is_success() {
|
if status.is_success() {
|
||||||
response.text().await?
|
response.text().await?
|
||||||
} else {
|
} else {
|
||||||
warn!("Could not receive remote list `{i}`: `{status}`");
|
warn!("Could not receive remote list `{l}`: `{status}`");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fs::read_to_string(i).await?
|
fs::read_to_string(l).await?
|
||||||
}
|
}
|
||||||
.lines()
|
.lines()
|
||||||
{
|
{
|
||||||
if handle(&mut index, line).is_some_and(|status| !status) {
|
if handle(&mut index, line).is_some_and(|status| !status) {
|
||||||
warn!("List `{i}` contains duplicated entry: `{line}`")
|
warn!("Ruleset `{l}` contains duplicated entry: `{line}`")
|
||||||
}
|
}
|
||||||
list_rules_total += 1
|
rules_total += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,9 +65,7 @@ impl List {
|
||||||
});
|
});
|
||||||
|
|
||||||
let len = index.len();
|
let len = index.len();
|
||||||
info!(
|
info!("Total rules parsed: {len} (riles: {rules_total} / cache: {cache_rules_total:?})",);
|
||||||
"Total rules parsed: {len} (lists: {list_rules_total} / cache: {cache_rules_total:?})",
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
index: RwLock::new(index),
|
index: RwLock::new(index),
|
||||||
|
|
@ -9,10 +9,10 @@ pub enum Item {
|
||||||
impl Item {
|
impl Item {
|
||||||
pub fn from_line(rule: &str) -> Self {
|
pub fn from_line(rule: &str) -> Self {
|
||||||
if let Some(item) = rule.strip_prefix(".") {
|
if let Some(item) = rule.strip_prefix(".") {
|
||||||
debug!("Add `{rule}` to the whitelist");
|
debug!("Init `{rule}` rule");
|
||||||
Self::Ending(item.to_string())
|
Self::Ending(item.to_string())
|
||||||
} else {
|
} else {
|
||||||
debug!("Add `{rule}` exact match to the whitelist");
|
debug!("Init `{rule}` exact match rule");
|
||||||
Self::Exact(rule.to_string())
|
Self::Exact(rule.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue