diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..5c71278 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,78 @@ +name: Build Rust Application + +on: + push: + branches: [ master ] + pull_request: + workflow_dispatch: + +env: + CARGO_TERM_COLOR: always + +jobs: + linux-amd64: + name: Linux amd64 (.deb) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + + - name: Install cargo-deb + run: cargo install cargo-deb + + - name: Build Debian package + run: cargo deb -- --bin cheburchecker + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: linux-amd64-deb + path: target/debian/*.deb + + linux-arm64: + name: Linux arm64 (.deb via cross) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + + - name: Install cargo-deb + run: cargo install cargo-deb + + - name: Build binary + uses: houseabsolute/actions-rust-cross@v1 + with: + command: build + target: "aarch64-unknown-linux-gnu" + args: "--release" + + - name: Create Debian archive + run: cargo deb --target aarch64-unknown-linux-gnu --no-build --bin cheburchecker + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: linux-arm64-deb + path: target/aarch64-unknown-linux-gnu/debian/*.deb + + windows: + name: Windows amd64 + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + + - name: Build release binary + run: cargo build --release + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: windows-amd64-exe + path: target/release/*.exe diff --git a/Cargo.lock b/Cargo.lock index 4b4099c..35fb59b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2559,7 +2559,7 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "reporter" -version = "0.1.0" +version = "0.1.1" dependencies = [ "anyhow", "clap", @@ -4225,7 +4225,7 @@ dependencies = [ [[package]] name = "website" -version = "0.2.0" +version = "0.2.1" dependencies = [ "dotenvy", "env_logger", diff --git a/Cargo.toml b/Cargo.toml index fb49698..403a09d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,6 @@ resolver = "3" [workspace.dependencies] tokio = { version = "1.48.0", features = ["full"] } -reqwest = { version = "0.12.24", features = ["stream", "rustls-tls-webpki-roots"] } +reqwest = { version = "0.12.24", default-features = false, features = ["stream", "rustls-tls-webpki-roots"] } log = "0.4.28" serde = { version = "1", features = ["derive"] } diff --git a/Cross.toml b/Cross.toml new file mode 100644 index 0000000..14e105e --- /dev/null +++ b/Cross.toml @@ -0,0 +1,5 @@ +[target.aarch64-unknown-linux-gnu] +pre-build = [ + "dpkg --add-architecture $CROSS_DEB_ARCH", + "apt-get update && apt-get --assume-yes install pkg-config libssl-dev" +] diff --git a/Rocket.toml b/Rocket.toml index 9aa669c..e5f46b8 100644 --- a/Rocket.toml +++ b/Rocket.toml @@ -2,4 +2,4 @@ template_dir = "website/templates/" [global.limits] -msgpack = 5242880 +msgpack = 33554432 diff --git a/reporter/Cargo.toml b/reporter/Cargo.toml index 89ffa5e..8ae87e2 100644 --- a/reporter/Cargo.toml +++ b/reporter/Cargo.toml @@ -1,11 +1,21 @@ [package] name = "reporter" -version = "0.1.0" +version = "0.1.1" edition = "2024" +license-file = "../LICENSE" +description = "DPI probe: checks blockage of domains by SNI" + +[[bin]] +name = "cheburchecker" +path = "src/main.rs" + +[package.metadata.deb] +name = "cheburchecker" +maintainer = "Lowder " [dependencies] tokio = { workspace = true } -reqwest = { workspace = true } +reqwest = { workspace = true, default-features = false } log = { workspace = true } reports = { path = "../reports" } anyhow = "1.0" @@ -21,5 +31,5 @@ serde = { version = "1.0.228", features = ["derive"] } libc = "0.2.177" [build-dependencies] -reqwest = { workspace = true } +reqwest = { workspace = true, default-features = false, features = ["blocking"] } getrandom = "0.3.4" diff --git a/reporter/README.md b/reporter/README.md index 1682a33..ccf6255 100644 --- a/reporter/README.md +++ b/reporter/README.md @@ -3,21 +3,39 @@ Инструмент для автоматического сканирования и анализа блокировок. Позволяет сканировать большое количество доменов за короткий срок за счет параллелизации запросов. +## Сборка + +Чекер можно использовать на Debian-based дистрибутивах, собрав его через cargo-deb: + +```shell +cargo deb +``` + +На прочих дистрибутивах и ОС можно запустить через: + +```shell +cargo run +``` + ## Использование +> [!IMPORTANT] +> Если вы используете большое количество одновременных запросов, убедитесь, что ограничение +> `open files` в вашей системе достаточное. Посмотреть и изменить значение можно через `ulimit -n`. + В программе заранее установлены настройки по-умолчанию для сканирования топ-100,000 доменов из [Tranco list от 26 ноября 2025](https://tranco-list.eu/list/2NPQ9). Для этого достаточно запустить его: 1. Сохранить результаты в CSV ```shell -reporter output.csv +cheburchecker output.csv ``` 2. Отправить результаты в **Cheburcheck Agency** ```shell -reporter -k +cheburchecker -k ``` > Для того чтобы получить API-ключ, diff --git a/reporter/src/main.rs b/reporter/src/main.rs index 3378b09..361a99f 100644 --- a/reporter/src/main.rs +++ b/reporter/src/main.rs @@ -13,7 +13,6 @@ use reqwest::redirect::Policy; use reqwest::Client; use serde::Serialize; use std::collections::HashMap; -use std::fmt::Display; use std::net::IpAddr; use std::path::PathBuf; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -85,7 +84,7 @@ struct Args { /// Custom agency endpoint address #[arg(short, long = "endpoint", default_value_t = option_env!("AGENCY_ENDPOINT") - .unwrap_or("https://cheburcheck.ru/agency/upload") + .unwrap_or("https://cheburcheck.ru/agency/report") .to_string())] agency_endpoint: String, @@ -220,8 +219,6 @@ async fn upload_results(args: &Args, api_client: &Client, results: HashMap Result { - if !status.is_success() { - warn!("Domain {target} returned non-OK code: {status}"); - } - if bytes.len() < 65535 { - warn!("Domain {target} completed with {} bytes: \n{}", bytes.len(), String::from_utf8_lossy(bytes.as_ref())); + let warn = if !status.is_success() { + Some(format!("Domain {target} returned non-OK code: {status}")) + } else if bytes.len() < 65535 { + Some(format!("Domain {target} completed with {} bytes: \n{}", bytes.len(), String::from_utf8_lossy(bytes.as_ref()))) + } else { + None + }; + + if let Some(warn) = warn { + warn!("{warn}"); + if attempts < args.retry_count { + continue; + } else { + return Ok(Verdict::Blocked { early: false }); + } } + Ok(Verdict::Accepted) } Err((e, early)) => { diff --git a/website/Cargo.toml b/website/Cargo.toml index 046f428..ae1a28c 100644 --- a/website/Cargo.toml +++ b/website/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "website" -version = "0.2.0" +version = "0.2.1" edition = "2024" [dependencies] diff --git a/website/src/main.rs b/website/src/main.rs index 82dbfb4..8d6449a 100644 --- a/website/src/main.rs +++ b/website/src/main.rs @@ -24,6 +24,7 @@ use serde::Serialize; use std::path::PathBuf; use std::sync::Arc; use std::time::Duration; +use rocket::serde::json::Json; use sqlx::types::Uuid; #[derive(rocket_db_pools::Database)] @@ -198,6 +199,17 @@ fn default(status: Status, _req: &Request) -> Template { ) } +#[derive(Debug, Serialize)] +struct JsonError { + code: u16, + info: String, +} + +#[catch(default)] +fn api_error(status: Status, _: &Request) -> Json { + Json(JsonError { code: status.code, info: status.reason_lossy().to_string() }) +} + #[rocket::get("/lucide.js")] fn lucide() -> CacheResponse> { CacheResponse::Public { @@ -288,6 +300,7 @@ async fn rocket() -> _ { .mount("/vendor", routes![lucide, chartjs, chartjs_datalabels]) .mount("/agency", routes![agency::upload_report]) .mount("/whitelist", routes![whitelist::histogram, whitelist::export_csv]) + .register("/agency", catchers![api_error]) .register("/", catchers![default]) .mount("/", FileServer::from(PathBuf::from("static"))) .attach(Template::fairing())