feat: build deb (#3)

This commit is contained in:
LowderPlay 2025-12-12 05:26:52 +05:00 committed by GitHub
parent 0fd8bc3eaf
commit a085dad811
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 151 additions and 19 deletions

78
.github/workflows/build.yml vendored Normal file
View file

@ -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

4
Cargo.lock generated
View file

@ -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",

View file

@ -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"] }

5
Cross.toml Normal file
View file

@ -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"
]

View file

@ -2,4 +2,4 @@
template_dir = "website/templates/"
[global.limits]
msgpack = 5242880
msgpack = 33554432

View file

@ -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 <me@lowderplay.dev>"
[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"

View file

@ -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 <API-ключ>
cheburchecker -k <API-ключ>
```
> Для того чтобы получить API-ключ,

View file

@ -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<Strin
let uploaded = uploaded.send().await?;
// let uploaded = uploaded.error_for_status()?;
if uploaded.status().is_success() {
info!("Uploaded ({})!", uploaded.status().to_string());
} else {
@ -283,12 +280,23 @@ async fn check_target(args: &Args, target: &str) -> Result<Verdict, reqwest::Err
};
return match resp {
Ok((status, bytes)) => {
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)) => {

View file

@ -1,6 +1,6 @@
[package]
name = "website"
version = "0.2.0"
version = "0.2.1"
edition = "2024"
[dependencies]

View file

@ -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<JsonError> {
Json(JsonError { code: status.code, info: status.reason_lossy().to_string() })
}
#[rocket::get("/lucide.js")]
fn lucide() -> CacheResponse<RawJavaScript<&'static [u8]>> {
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())