mirror of
https://github.com/TrustTunnel/TrustTunnel.git
synced 2026-07-09 17:18:36 +00:00
Pull request 121: Clippy and github actions
Squashed commit of the following:
commit 6eae1e962a27b2c3bcb6362f53bb1d7d92a66983
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Fri Dec 26 11:46:12 2025 +0400
Run lint on both macos and linux
commit 94254caec3ea166db80c6b3f4004b4126605a1b7
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Thu Dec 25 22:44:10 2025 +0400
Fix note again by adding lint hint
commit 5a67ae358a5676a22e85798683674607d2788a51
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Thu Dec 25 22:42:02 2025 +0400
Fix note
commit 937b178302244fe237d06b6f38ba0f29db6e0d7e
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Thu Dec 25 22:39:45 2025 +0400
Fix README
commit 769c5d9ebdc03e8500f9fc00d7f2b6f316924557
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Thu Dec 25 22:39:15 2025 +0400
Cargo update
commit 1e932e4037c2b9ffc4b12f398f1ef14c32b5481e
Merge: dcf6a53 2041edc
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Thu Dec 25 22:37:24 2025 +0400
Merge remote-tracking branch 'origin/master' into feature/TRUST-235
commit dcf6a53410e59411a3e05f798ed4be7f7c9994ce
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Thu Dec 25 22:24:56 2025 +0400
Get rid of rustls-pemfile and update sentry
commit cb2e26e47d4612d65ae990ec887875bb1ac94456
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Thu Dec 25 19:08:23 2025 +0400
Fix tests
commit a3cde3fdf16edfe2e2a574b8d729c2b9d59daf84
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Thu Dec 25 18:33:46 2025 +0400
Fix vulnerabilities
commit 35cb9c699a0ddf2eb344c7c475be3c36a26dbf83
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Thu Dec 25 17:13:18 2025 +0400
Don't install cargo-audit manually
commit 71a5411ac4fe31fc08c3bacb83d327bf6b7ab8c3
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Thu Dec 25 17:07:30 2025 +0400
Install stable rust for cargo-audit
commit b7f38a90054cda39d72760b0ebc3ce295fba95d2
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Thu Dec 25 16:54:13 2025 +0400
Fix yaml
commit fbbe78f68b2987280874f23d4ed05ef75ed42f46
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Thu Dec 25 16:53:15 2025 +0400
Try to lock cargo-audit version
commit 08f31734b49c70d9dc03c7977ac6182198d1cbde
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Thu Dec 25 16:46:06 2025 +0400
Update audit workflow
commit c202f186cd1610439a13928fc1fabac88e83097b
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Thu Dec 25 16:30:55 2025 +0400
Install rust tools and better rust cache
commit eccf2fa91efcc4c6e5684960e368892bc68e67cd
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Thu Dec 25 16:30:25 2025 +0400
Name for job
commit dccc19f13180e767b8390c8ea32fde4285c0cab8
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Thu Dec 25 16:30:17 2025 +0400
Update checkout step version
commit edbb4404bf6fc1927f0184433df9982767a9c762
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Thu Dec 25 16:30:02 2025 +0400
Run lint only on linux
commit b59ed893fa55edf030f9ffee2e442c8b947fa28f
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Thu Dec 25 16:09:43 2025 +0400
Lint in the same workflow as testing to avoid rebuilds
commit 8d8ecd51859c825d0437361f8c51bde6b46994bc
Author: Andrey Yakushin <a.yakushin@adguard.com>
Date: Thu Dec 25 15:27:23 2025 +0400
More clippy fixes
... and 6 more commits
This commit is contained in:
parent
2041edc1bf
commit
783908b315
41 changed files with 1643 additions and 1151 deletions
30
.github/workflows/clippy.yml
vendored
30
.github/workflows/clippy.yml
vendored
|
|
@ -1,30 +0,0 @@
|
|||
name: Clippy check
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "*"
|
||||
paths-ignore:
|
||||
- '**/README.md'
|
||||
- 'bamboo-specs/**'
|
||||
- 'scripts/**'
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
clippy-check:
|
||||
runs-on: ubuntu-latest
|
||||
if: "!startsWith(github.event.head_commit.message, 'skipci:')"
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install clippy
|
||||
run: rustup component add clippy
|
||||
|
||||
- name: Run clippy
|
||||
uses: actions-rs/clippy-check@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --all-features
|
||||
67
.github/workflows/deploy.yml
vendored
67
.github/workflows/deploy.yml
vendored
|
|
@ -1,67 +0,0 @@
|
|||
name: Deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
pack-sources:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Prepare changelog
|
||||
id: changelog
|
||||
run: |
|
||||
LAST_TAG="${GITHUB_REF#refs/*/}"
|
||||
PREV_TAG=$(git describe --tags --abbrev=0 ${LAST_TAG}^)
|
||||
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
|
||||
echo "CHANGELOG<<$EOF" >> "$GITHUB_ENV"
|
||||
./scripts/ci/extract_changelog.py "$PREV_TAG" "$LAST_TAG" >> "$GITHUB_ENV"
|
||||
echo "$EOF" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
body: ${{ env.CHANGELOG }}
|
||||
|
||||
# TODO: check with public repository
|
||||
# notify:
|
||||
# needs: pack-sources
|
||||
#
|
||||
# # Secrets are not passed to workflows that are triggered by a pull request
|
||||
# # from a fork.
|
||||
# #
|
||||
# # Use always() to signal to the runner that this job must run even if the
|
||||
# # previous ones failed.
|
||||
# if:
|
||||
# ${{
|
||||
# always() &&
|
||||
# github.repository_owner == 'AdguardTeam' &&
|
||||
# (
|
||||
# github.event_name == 'push' ||
|
||||
# github.event.pull_request.head.repo.full_name == github.repository
|
||||
# )
|
||||
# }}
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - name: Conclusion
|
||||
# uses: technote-space/workflow-conclusion-action@v1
|
||||
# - name: Send Slack notification
|
||||
# uses: 8398a7/action-slack@v3
|
||||
# with:
|
||||
# status: ${{ env.WORKFLOW_CONCLUSION }}
|
||||
# fields: repo, message, commit, author, workflow
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
22
.github/workflows/md-lint.yml
vendored
Normal file
22
.github/workflows/md-lint.yml
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
name: Lint Markdown
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "*"
|
||||
paths:
|
||||
- '**.md'
|
||||
- '.markdown-lint.json'
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
markdown-lint:
|
||||
runs-on: ubuntu-latest
|
||||
if: "!startsWith(github.event.head_commit.message, 'skipci:')"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Markdown Lint
|
||||
uses: DavidAnson/markdownlint-cli2-action@v22
|
||||
with:
|
||||
globs: '**/*.md'
|
||||
27
.github/workflows/run-tests.yml
vendored
27
.github/workflows/run-tests.yml
vendored
|
|
@ -1,7 +1,7 @@
|
|||
name: Run tests
|
||||
name: Run tests and lint
|
||||
|
||||
env:
|
||||
RUST_CHANNEL: 1.67
|
||||
RUST_CHANNEL: 1.85
|
||||
|
||||
on:
|
||||
push:
|
||||
|
|
@ -17,6 +17,7 @@ on:
|
|||
|
||||
jobs:
|
||||
tests:
|
||||
name: Test & Lint
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
|
|
@ -24,19 +25,21 @@ jobs:
|
|||
if: "!startsWith(github.event.head_commit.message, 'skipci:')"
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Cargo cache
|
||||
uses: actions/cache@v3
|
||||
id: cargo-cache
|
||||
- name: Install Rust ${{ env.RUST_CHANNEL }}
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
key: ${{ matrix.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
toolchain: ${{ env.RUST_CHANNEL }}
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Rust Cache
|
||||
uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cargo test --workspace
|
||||
|
||||
- name: Lint Rust
|
||||
run: |
|
||||
make lint-rust
|
||||
|
|
|
|||
12
.github/workflows/security-audit.yml
vendored
12
.github/workflows/security-audit.yml
vendored
|
|
@ -16,10 +16,18 @@ jobs:
|
|||
permissions:
|
||||
checks: write # for rustsec/audit-check to create check
|
||||
contents: read # for actions/checkout to fetch code
|
||||
env:
|
||||
# This OVERRIDES the rust-toolchain.toml file for this job only
|
||||
# because cargo-audit requires newer Rust version
|
||||
RUSTUP_TOOLCHAIN: stable
|
||||
runs-on: ubuntu-latest
|
||||
if: "!startsWith(github.event.head_commit.message, 'skipci:')"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: rustsec/audit-check@v1.4.1
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- uses: actions-rust-lang/audit@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
|
|||
2331
Cargo.lock
generated
2331
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
2
Makefile
2
Makefile
|
|
@ -75,6 +75,7 @@ lint-md:
|
|||
.PHONY: lint-rust
|
||||
lint-rust:
|
||||
cargo fmt --all -- --check
|
||||
cargo clippy -- -D warnings
|
||||
|
||||
## Fix linter issues that are auto-fixable.
|
||||
.PHONY: lint-fix
|
||||
|
|
@ -83,6 +84,7 @@ lint-fix: lint-fix-rust lint-fix-md
|
|||
## Auto-fix Rust code formatting issues with rustfmt.
|
||||
.PHONY: lint-fix-rust
|
||||
lint-fix-rust:
|
||||
cargo clippy --fix --allow-dirty
|
||||
cargo fmt --all
|
||||
|
||||
## Auto-fix markdown files.
|
||||
|
|
|
|||
|
|
@ -287,6 +287,7 @@ cat /opt/trusttunnel_client/trusttunnel_client.toml
|
|||
>
|
||||
> See the [TrustTunnel CLI Client README](https://github.com/TrustTunnel/TrustTunnelClient/blob/master/trusttunnel/README.md#configuration-reference) for all available options.
|
||||
|
||||
<!-- markdownlint-disable MD028 -->
|
||||
> [!NOTE]
|
||||
> After editing the config, restart the client for the changes to take effect.
|
||||
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@ name = "trusttunnel_endpoint"
|
|||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
clap = "4.3.8"
|
||||
clap = "4.5"
|
||||
console-subscriber = { version = "0.1.9", optional = true }
|
||||
log = "0.4.19"
|
||||
nix = { version = "0.28.0", features = ["resource"] }
|
||||
sentry = { version = "0.31.5", default-features = false, features = ["backtrace", "panic", "reqwest", "rustls", "contexts"] }
|
||||
tokio = { version = "1.28.2", features = ["rt-multi-thread", "signal"] }
|
||||
sentry = { version = "0.46.0", default-features = false, features = ["backtrace", "panic", "reqwest", "rustls", "contexts"] }
|
||||
tokio = { version = "1.42", features = ["rt-multi-thread", "signal"] }
|
||||
toml = { version = "0.7.4", default-features = false, features = ["parse"] }
|
||||
trusttunnel = { version = "0.1", path = "../lib" }
|
||||
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ fn main() {
|
|||
.collect();
|
||||
|
||||
let client_config = client_config::build(
|
||||
&username,
|
||||
username,
|
||||
addresses,
|
||||
settings.get_clients(),
|
||||
&tls_hosts_settings,
|
||||
|
|
@ -258,6 +258,7 @@ fn main() {
|
|||
}
|
||||
};
|
||||
|
||||
#[allow(clippy::await_holding_lock)]
|
||||
let interrupt_task = async move {
|
||||
tokio::signal::ctrl_c().await.unwrap();
|
||||
shutdown.lock().unwrap().submit();
|
||||
|
|
|
|||
|
|
@ -30,14 +30,14 @@ libc = "0.2.147"
|
|||
log = "0.4.19"
|
||||
macros = { version = "0.1.0", path = "../macros", optional = true }
|
||||
once_cell = "1.18.0"
|
||||
prometheus = { version = "0.13.3", features = ["process"] }
|
||||
prometheus = { version = "0.14", features = ["process"] }
|
||||
quiche = { version = "0.24.5", features = ["qlog", "boringssl-boring-crate"] }
|
||||
ring = "0.16.20"
|
||||
ring = "0.17.12"
|
||||
rustls = { version = "0.21.2", features = ["logging"] }
|
||||
rustls-pemfile = "1.0.2"
|
||||
rustls-pki-types = "1.13.2"
|
||||
serde = "1.0.164"
|
||||
smallvec = "1.10.0"
|
||||
tokio = { version = "1.28.2", features = ["net", "rt", "sync", "time", "macros", "rt-multi-thread"] }
|
||||
tokio = { version = "1.42", features = ["net", "rt", "sync", "time", "macros", "rt-multi-thread"] }
|
||||
tokio-rustls = "0.24.1"
|
||||
toml_edit = "0.19.10"
|
||||
boring = "4"
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ pub trait Authenticator: Send + Sync {
|
|||
fn authenticate(&self, source: &Source<'_>, log_id: &log_utils::IdChain<u64>) -> Status;
|
||||
}
|
||||
|
||||
impl<'a> Source<'a> {
|
||||
impl Source<'_> {
|
||||
pub fn into_owned(self) -> Source<'static> {
|
||||
match self {
|
||||
Source::Sni(x) => Source::Sni(Cow::Owned(x.into_owned())),
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ pub struct RegistryBasedAuthenticator {
|
|||
}
|
||||
|
||||
impl RegistryBasedAuthenticator {
|
||||
pub fn new(clients: &Vec<Client>) -> Self {
|
||||
pub fn new(clients: &[Client]) -> Self {
|
||||
Self {
|
||||
clients: clients
|
||||
.iter()
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use toml_edit::{value, Document};
|
|||
pub fn build(
|
||||
client: &String,
|
||||
addresses: Vec<SocketAddr>,
|
||||
username: &Vec<registry_based::Client>,
|
||||
username: &[registry_based::Client],
|
||||
hostsettings: &TlsHostsSettings,
|
||||
) -> ClientConfig {
|
||||
let user = username
|
||||
|
|
@ -23,7 +23,7 @@ pub fn build(
|
|||
|
||||
ClientConfig {
|
||||
hostname: host.hostname.clone(),
|
||||
addresses: addresses,
|
||||
addresses,
|
||||
has_ipv6: true, // Hardcoded to true, client could change this himself
|
||||
username: user.username.clone(),
|
||||
password: user.password.clone(),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
use crate::forwarder::Forwarder;
|
||||
use crate::forwarder::{Forwarder, IcmpMultiplexer, UdpMultiplexer};
|
||||
use crate::tcp_forwarder::TcpForwarder;
|
||||
use crate::{
|
||||
authentication, core, datagram_pipe, downstream, forwarder, log_utils, tunnel, udp_forwarder,
|
||||
};
|
||||
use crate::{authentication, core, forwarder, log_utils, tunnel, udp_forwarder};
|
||||
use async_trait::async_trait;
|
||||
use std::io;
|
||||
use std::net::IpAddr;
|
||||
|
|
@ -46,23 +44,14 @@ impl Forwarder for DirectForwarder {
|
|||
&self,
|
||||
id: log_utils::IdChain<u64>,
|
||||
_: forwarder::UdpMultiplexerMeta,
|
||||
) -> io::Result<(
|
||||
Arc<dyn forwarder::UdpDatagramPipeShared>,
|
||||
Box<dyn datagram_pipe::Source<Output = forwarder::UdpDatagramReadStatus>>,
|
||||
Box<dyn datagram_pipe::Sink<Input = downstream::UdpDatagram>>,
|
||||
)> {
|
||||
) -> io::Result<UdpMultiplexer> {
|
||||
udp_forwarder::make_multiplexer(id)
|
||||
}
|
||||
|
||||
fn make_icmp_datagram_multiplexer(
|
||||
&self,
|
||||
id: log_utils::IdChain<u64>,
|
||||
) -> io::Result<
|
||||
Option<(
|
||||
Box<dyn datagram_pipe::Source<Output = forwarder::IcmpDatagram>>,
|
||||
Box<dyn datagram_pipe::Sink<Input = downstream::IcmpDatagram>>,
|
||||
)>,
|
||||
> {
|
||||
) -> io::Result<Option<IcmpMultiplexer>> {
|
||||
self.context
|
||||
.icmp_forwarder
|
||||
.as_ref()
|
||||
|
|
|
|||
|
|
@ -99,6 +99,17 @@ pub(crate) enum UdpDatagramReadStatus {
|
|||
UdpClose(UdpDatagramMeta, io::Error),
|
||||
}
|
||||
|
||||
pub(crate) type UdpMultiplexer = (
|
||||
Arc<dyn UdpDatagramPipeShared>,
|
||||
Box<dyn datagram_pipe::Source<Output = UdpDatagramReadStatus>>,
|
||||
Box<dyn datagram_pipe::Sink<Input = downstream::UdpDatagram>>,
|
||||
);
|
||||
|
||||
pub(crate) type IcmpMultiplexer = (
|
||||
Box<dyn datagram_pipe::Source<Output = IcmpDatagram>>,
|
||||
Box<dyn datagram_pipe::Sink<Input = downstream::IcmpDatagram>>,
|
||||
);
|
||||
|
||||
/// An abstract interface for a traffic forwarder implementation
|
||||
pub(crate) trait Forwarder: Send {
|
||||
/// Create a TCP connector object
|
||||
|
|
@ -112,22 +123,13 @@ pub(crate) trait Forwarder: Send {
|
|||
&self,
|
||||
id: log_utils::IdChain<u64>,
|
||||
meta: UdpMultiplexerMeta,
|
||||
) -> io::Result<(
|
||||
Arc<dyn UdpDatagramPipeShared>,
|
||||
Box<dyn datagram_pipe::Source<Output = UdpDatagramReadStatus>>,
|
||||
Box<dyn datagram_pipe::Sink<Input = downstream::UdpDatagram>>,
|
||||
)>;
|
||||
) -> io::Result<UdpMultiplexer>;
|
||||
|
||||
/// Create an ICMP datagram multiplexer
|
||||
fn make_icmp_datagram_multiplexer(
|
||||
&self,
|
||||
id: log_utils::IdChain<u64>,
|
||||
) -> io::Result<
|
||||
Option<(
|
||||
Box<dyn datagram_pipe::Source<Output = IcmpDatagram>>,
|
||||
Box<dyn datagram_pipe::Sink<Input = downstream::IcmpDatagram>>,
|
||||
)>,
|
||||
>;
|
||||
) -> io::Result<Option<IcmpMultiplexer>>;
|
||||
}
|
||||
|
||||
impl UdpDatagramMeta {
|
||||
|
|
|
|||
|
|
@ -196,9 +196,7 @@ impl pipe::Source for RequestStream {
|
|||
match self.rx.data().await {
|
||||
None => Ok(pipe::Data::Eof),
|
||||
Some(Ok(chunk)) => Ok(pipe::Data::Chunk(chunk)),
|
||||
Some(Err(e)) if e.reason().map_or(true, |r| r == Reason::NO_ERROR) => {
|
||||
Ok(pipe::Data::Eof)
|
||||
}
|
||||
Some(Err(e)) if e.reason().is_none_or(|r| r == Reason::NO_ERROR) => Ok(pipe::Data::Eof),
|
||||
Some(Err(e)) => Err(h2_to_io_error(e)),
|
||||
}
|
||||
}
|
||||
|
|
@ -252,7 +250,7 @@ pub struct WaitWritable<'a> {
|
|||
stream: &'a mut SendStream<Bytes>,
|
||||
}
|
||||
|
||||
impl<'a> std::future::Future for WaitWritable<'a> {
|
||||
impl std::future::Future for WaitWritable<'_> {
|
||||
type Output = io::Result<()>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
|
|
@ -313,7 +311,7 @@ impl http_codec::DroppingSink for RespondStream {
|
|||
|
||||
fn h2_to_io_error(e: h2::Error) -> io::Error {
|
||||
let reason = e.reason();
|
||||
if reason.as_ref().map_or(true, |r| *r == Reason::NO_ERROR) {
|
||||
if reason.as_ref().is_none_or(|r| *r == Reason::NO_ERROR) {
|
||||
return io::Error::from(ErrorKind::UnexpectedEof);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,6 @@ impl HttpDemux {
|
|||
.reverse_proxy
|
||||
.as_ref()
|
||||
.map(|x| x.path_mask.as_str())
|
||||
.map_or(false, |x| request.uri.path().starts_with(x))
|
||||
.is_some_and(|x| request.uri.path().starts_with(x))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -512,6 +512,7 @@ impl ForwardedStreamSink {
|
|||
}
|
||||
|
||||
impl SinkWaitingResponse {
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn parse_response(
|
||||
&mut self,
|
||||
data: Bytes,
|
||||
|
|
@ -615,7 +616,7 @@ impl SinkWaitingResponse {
|
|||
if self.request_method == http::Method::HEAD
|
||||
|| response
|
||||
.code
|
||||
.map_or(false, |x| (100..200).contains(&x) || x == 204 || x == 304)
|
||||
.is_some_and(|x| (100..200).contains(&x) || x == 204 || x == 304)
|
||||
{
|
||||
body_length = Some(BodyLength::Determined(0));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ extern "C" {
|
|||
fn set_icmpv6_filter(fd: libc::c_int) -> libc::c_int;
|
||||
}
|
||||
|
||||
use crate::forwarder::IcmpMultiplexer;
|
||||
use crate::settings::Settings;
|
||||
use crate::{datagram_pipe, downstream, forwarder, icmp_utils, log_utils, net_utils, utils};
|
||||
use async_trait::async_trait;
|
||||
|
|
@ -79,13 +80,7 @@ impl IcmpForwarder {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn make_multiplexer(
|
||||
&self,
|
||||
id: log_utils::IdChain<u64>,
|
||||
) -> io::Result<(
|
||||
Box<dyn datagram_pipe::Source<Output = forwarder::IcmpDatagram>>,
|
||||
Box<dyn datagram_pipe::Sink<Input = downstream::IcmpDatagram>>,
|
||||
)> {
|
||||
pub fn make_multiplexer(&self, id: log_utils::IdChain<u64>) -> io::Result<IcmpMultiplexer> {
|
||||
let (tx, rx) = mpsc::channel(
|
||||
self.shared
|
||||
.core_settings
|
||||
|
|
@ -421,9 +416,8 @@ impl RawPacketStream {
|
|||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
let socket = AsyncFd::new(fd).map_err(|e| {
|
||||
let socket = AsyncFd::new(fd).inspect_err(|_| {
|
||||
libc::close(fd);
|
||||
e
|
||||
})?;
|
||||
|
||||
Ok(Self { inner: socket })
|
||||
|
|
|
|||
|
|
@ -360,13 +360,14 @@ pub(crate) fn rfc1071_checksum(bytes: &[u8]) -> u16 {
|
|||
/// - the unspecified address (see [`Ipv4Addr::is_unspecified()`]), and the whole
|
||||
/// `0.0.0.0/8` block
|
||||
/// - addresses reserved for future protocols, except
|
||||
/// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable
|
||||
/// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable
|
||||
/// - addresses reserved for future use (see [IETF RFC 1112])
|
||||
/// - addresses reserved for networking devices benchmarking (see [IETF RFC 2544])
|
||||
///
|
||||
/// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
|
||||
///
|
||||
/// @todo: replace with [`Ipv4Addr::is_global`] when it becomes stable
|
||||
#[allow(clippy::nonminimal_bool)]
|
||||
pub(crate) const fn is_global_ipv4(ip: &Ipv4Addr) -> bool {
|
||||
let octets = ip.octets();
|
||||
// check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two
|
||||
|
|
@ -414,15 +415,15 @@ pub(crate) const fn is_global_ipv4(ip: &Ipv4Addr) -> bool {
|
|||
pub(crate) const fn is_unicast_global_ipv6(ip: &Ipv6Addr) -> bool {
|
||||
let segments = ip.segments();
|
||||
|
||||
!ip.is_multicast()
|
||||
&& !ip.is_loopback()
|
||||
!(ip.is_multicast()
|
||||
|| ip.is_loopback()
|
||||
// unicast address with link-local scope [RFC 4291]
|
||||
&& (segments[0] & 0xffc0) != 0xfe80
|
||||
|| (segments[0] & 0xffc0) == 0xfe80
|
||||
// unique local address (`fc00::/7`) [IETF RFC 4193]
|
||||
&& (segments[0] & 0xfe00) != 0xfc00
|
||||
&& !ip.is_unspecified()
|
||||
|| (segments[0] & 0xfe00) == 0xfc00
|
||||
|| ip.is_unspecified()
|
||||
// address reserved for documentation (`2001:db8::/32`) [IETF RFC 3849]
|
||||
&& !((segments[0] == 0x2001) && (segments[1] == 0xdb8))
|
||||
|| (segments[0] == 0x2001) && (segments[1] == 0xdb8))
|
||||
}
|
||||
|
||||
/// Returns [`true`] if the address appears to be globally routable.
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ impl QuicMultiplexer {
|
|||
Some(m) => Some(Event::UdpSend(m)),
|
||||
None => return Err(io::Error::new(ErrorKind::Other, "Message receiving channel closed unexpectedly")),
|
||||
},
|
||||
_ = &mut wait_timeout, if self.closest_deadline.map_or(false, |x| x > Instant::now()) => None,
|
||||
_ = &mut wait_timeout, if self.closest_deadline.is_some_and(|x| x > Instant::now()) => None,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -567,6 +567,7 @@ impl QuicMultiplexer {
|
|||
})
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn on_new_connection(
|
||||
&mut self,
|
||||
peer: &SocketAddr,
|
||||
|
|
@ -691,7 +692,7 @@ impl QuicMultiplexer {
|
|||
) {
|
||||
let deadline = Instant::now() + duration;
|
||||
self.deadlines.insert(conn_id, deadline);
|
||||
if self.closest_deadline.map_or(true, |x| x > deadline) {
|
||||
if self.closest_deadline.is_none_or(|x| x > deadline) {
|
||||
self.closest_deadline = Some(deadline);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ pub struct Rule {
|
|||
}
|
||||
|
||||
/// Rules configuration
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct RulesConfig {
|
||||
/// List of filter rules
|
||||
#[serde(default)]
|
||||
|
|
@ -150,12 +150,6 @@ impl RulesEngine {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for RulesConfig {
|
||||
fn default() -> Self {
|
||||
Self { rule: vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
|||
|
|
@ -1289,7 +1289,7 @@ where
|
|||
{
|
||||
struct Visitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for Visitor {
|
||||
impl serde::de::Visitor<'_> for Visitor {
|
||||
type Value = u64;
|
||||
|
||||
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
|
||||
|
|
@ -1324,7 +1324,7 @@ where
|
|||
{
|
||||
struct Visitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for Visitor {
|
||||
impl serde::de::Visitor<'_> for Visitor {
|
||||
type Value = String;
|
||||
|
||||
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
|
||||
|
|
@ -1382,7 +1382,7 @@ where
|
|||
.map(|(idx, x)| {
|
||||
let username = demangle_toml_string(x["username"].to_string());
|
||||
let password = demangle_toml_string(x["password"].to_string());
|
||||
|
||||
|
||||
if username.is_empty() {
|
||||
return Err(serde::de::Error::custom(format!(
|
||||
"Client #{}: username cannot be empty",
|
||||
|
|
@ -1395,7 +1395,7 @@ where
|
|||
idx + 1
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
Ok(Client { username, password })
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ impl Display for NotificationError {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::await_holding_lock)]
|
||||
mod tests {
|
||||
use crate::shutdown::Shutdown;
|
||||
use std::time::Duration;
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ pub(crate) enum ExtendedAuthenticationValue<'this> {
|
|||
SniAuth,
|
||||
}
|
||||
|
||||
impl<'this> ExtendedAuthenticationValue<'this> {
|
||||
impl ExtendedAuthenticationValue<'_> {
|
||||
const fn type_code(&self) -> u8 {
|
||||
match self {
|
||||
Self::Domain(_) => 0x01,
|
||||
|
|
@ -178,7 +178,7 @@ pub(crate) enum Authentication<'this> {
|
|||
Extended(Vec<ExtendedAuthenticationValue<'this>>),
|
||||
}
|
||||
|
||||
impl<'this> Authentication<'this> {
|
||||
impl Authentication<'_> {
|
||||
const fn to_method(&self) -> AuthenticationMethod {
|
||||
match self {
|
||||
Self::UsernamePassword(..) => AuthenticationMethod::UsernamePassword,
|
||||
|
|
@ -211,7 +211,7 @@ pub(crate) enum Address<'this> {
|
|||
DomainName(Cow<'this, str>),
|
||||
}
|
||||
|
||||
impl<'this> Address<'this> {
|
||||
impl Address<'_> {
|
||||
const fn address_type(&self) -> u8 {
|
||||
match self {
|
||||
Self::IpAddress(IpAddr::V4(_)) => ADDRESS_TYPE_IP_V4,
|
||||
|
|
@ -229,7 +229,7 @@ pub(crate) enum Request<'this> {
|
|||
UdpAssociate,
|
||||
}
|
||||
|
||||
impl<'this> Request<'this> {
|
||||
impl Request<'_> {
|
||||
const fn command_code(&self) -> u8 {
|
||||
match self {
|
||||
Self::Connect(..) => 0x01,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::forwarder::Forwarder;
|
||||
use crate::forwarder::{Forwarder, IcmpMultiplexer, UdpMultiplexer};
|
||||
use crate::settings::{ForwardProtocolSettings, Settings, Socks5ForwarderSettings};
|
||||
use crate::tcp_forwarder::TcpForwarder;
|
||||
use crate::{
|
||||
|
|
@ -157,11 +157,7 @@ impl Forwarder for Socks5Forwarder {
|
|||
&self,
|
||||
id: log_utils::IdChain<u64>,
|
||||
meta: forwarder::UdpMultiplexerMeta,
|
||||
) -> io::Result<(
|
||||
Arc<dyn forwarder::UdpDatagramPipeShared>,
|
||||
Box<dyn datagram_pipe::Source<Output = forwarder::UdpDatagramReadStatus>>,
|
||||
Box<dyn datagram_pipe::Sink<Input = downstream::UdpDatagram>>,
|
||||
)> {
|
||||
) -> io::Result<UdpMultiplexer> {
|
||||
let (tx, rx) = mpsc::channel(1);
|
||||
let shared = Arc::new(DatagramTransceiverShared {
|
||||
core_settings: self.context.settings.clone(),
|
||||
|
|
@ -202,12 +198,7 @@ impl Forwarder for Socks5Forwarder {
|
|||
fn make_icmp_datagram_multiplexer(
|
||||
&self,
|
||||
id: log_utils::IdChain<u64>,
|
||||
) -> io::Result<
|
||||
Option<(
|
||||
Box<dyn datagram_pipe::Source<Output = forwarder::IcmpDatagram>>,
|
||||
Box<dyn datagram_pipe::Sink<Input = downstream::IcmpDatagram>>,
|
||||
)>,
|
||||
> {
|
||||
) -> io::Result<Option<IcmpMultiplexer>> {
|
||||
self.context
|
||||
.icmp_forwarder
|
||||
.as_ref()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use crate::forwarder::UdpMultiplexer;
|
||||
use crate::{datagram_pipe, downstream, forwarder, log_id, log_utils, net_utils};
|
||||
use async_trait::async_trait;
|
||||
use bytes::Bytes;
|
||||
|
|
@ -45,13 +46,7 @@ enum PollStatus {
|
|||
SocketError(SocketError),
|
||||
}
|
||||
|
||||
pub(crate) fn make_multiplexer(
|
||||
id: log_utils::IdChain<u64>,
|
||||
) -> io::Result<(
|
||||
Arc<dyn forwarder::UdpDatagramPipeShared>,
|
||||
Box<dyn datagram_pipe::Source<Output = forwarder::UdpDatagramReadStatus>>,
|
||||
Box<dyn datagram_pipe::Sink<Input = downstream::UdpDatagram>>,
|
||||
)> {
|
||||
pub(crate) fn make_multiplexer(id: log_utils::IdChain<u64>) -> io::Result<UdpMultiplexer> {
|
||||
let shared = Arc::new(MultiplexerShared {
|
||||
connections: Mutex::new(Default::default()),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -208,6 +208,7 @@ impl UdpConnection {
|
|||
}
|
||||
|
||||
impl<F: Fn(pipe::SimplexDirection, usize) + Send + Sync> DuplexPipe<F> {
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn new(
|
||||
(source1, sink1): (
|
||||
Box<dyn datagram_pipe::Source<Output = downstream::UdpDatagram>>,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use rustls::{Certificate, PrivateKey};
|
||||
use rustls_pemfile::{certs, pkcs8_private_keys};
|
||||
use rustls_pki_types::pem::PemObject;
|
||||
use rustls_pki_types::{CertificateDer, PrivateKeyDer};
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::{BufReader, ErrorKind};
|
||||
use std::io::{BufReader, ErrorKind, Read};
|
||||
|
||||
pub fn hex_dump(buf: &[u8]) -> String {
|
||||
buf.iter()
|
||||
|
|
@ -71,20 +72,39 @@ impl<L, R> Either<L, R> {
|
|||
}
|
||||
|
||||
pub fn load_certs(filename: &str) -> io::Result<Vec<Certificate>> {
|
||||
certs(&mut BufReader::new(File::open(filename)?))
|
||||
let mut reader = BufReader::new(File::open(filename)?);
|
||||
let mut pem_data = String::new();
|
||||
reader.read_to_string(&mut pem_data).map_err(|e| {
|
||||
io::Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
format!("Failed to read file: {}", e),
|
||||
)
|
||||
})?;
|
||||
|
||||
CertificateDer::pem_slice_iter(pem_data.as_bytes())
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|e| io::Error::new(ErrorKind::InvalidInput, format!("Invalid cert: {}", e)))
|
||||
.map(|mut certs| certs.drain(..).map(Certificate).collect())
|
||||
.map(|certs| {
|
||||
certs
|
||||
.into_iter()
|
||||
.map(|c| Certificate(c.into_owned().to_vec()))
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn load_private_key(filename: &str) -> io::Result<PrivateKey> {
|
||||
pkcs8_private_keys(&mut BufReader::new(File::open(filename)?))
|
||||
let mut reader = BufReader::new(File::open(filename)?);
|
||||
let mut pem_data = String::new();
|
||||
reader.read_to_string(&mut pem_data).map_err(|e| {
|
||||
io::Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
format!("Failed to read file: {}", e),
|
||||
)
|
||||
})?;
|
||||
|
||||
PrivateKeyDer::from_pem_slice(pem_data.as_bytes())
|
||||
.map_err(|e| io::Error::new(ErrorKind::InvalidInput, format!("Invalid key: {}", e)))
|
||||
.and_then(|keys| {
|
||||
keys.first()
|
||||
.cloned()
|
||||
.ok_or_else(|| io::Error::new(ErrorKind::Other, "No keys found"))
|
||||
})
|
||||
.map(PrivateKey)
|
||||
.map(|key| PrivateKey(key.secret_der().to_vec()))
|
||||
}
|
||||
|
||||
pub trait IterJoin {
|
||||
|
|
|
|||
|
|
@ -204,6 +204,7 @@ async fn do_connect_request(
|
|||
|
||||
fn make_socks_server_harness() -> (SocketAddr, impl Future<Output = Vec<u8>>) {
|
||||
let server = std::net::TcpListener::bind((Ipv4Addr::LOCALHOST, 0)).unwrap();
|
||||
let _ = server.set_nonblocking(true);
|
||||
let server_addr = server.local_addr().unwrap();
|
||||
|
||||
let task = async move {
|
||||
|
|
|
|||
|
|
@ -339,7 +339,7 @@ impl Http3Session {
|
|||
.map(|x| x.to_str().unwrap().parse::<usize>().unwrap())
|
||||
});
|
||||
let mut content = BytesMut::with_capacity(content_length.unwrap_or_default());
|
||||
while content_length.map_or(true, |x| content.len() < x) {
|
||||
while content_length.is_none_or(|x| content.len() < x) {
|
||||
let mut buffer = [0; 64 * 1024];
|
||||
match self.recv(&mut buffer).await {
|
||||
0 => break,
|
||||
|
|
@ -416,7 +416,7 @@ impl Http3Session {
|
|||
pub async fn recv_response(&mut self) -> http::response::Parts {
|
||||
self.recv_response_with_method(&http::Method::GET).await
|
||||
}
|
||||
|
||||
|
||||
async fn recv_response_with_method(&mut self, method: &http::Method) -> http::response::Parts {
|
||||
Self::read_out_socket(&self.socket, &mut self.quic_conn);
|
||||
Self::flush_quic_data(&self.socket, &mut self.quic_conn);
|
||||
|
|
@ -434,16 +434,19 @@ impl Http3Session {
|
|||
|
||||
let response = response.body(()).unwrap().into_parts().0;
|
||||
info!("Received response: {:?}", response);
|
||||
|
||||
|
||||
// Track if this is a CONNECT tunnel - don't send FIN for tunnels
|
||||
if method == &http::Method::CONNECT {
|
||||
if method == http::Method::CONNECT {
|
||||
self.is_tunnel = true;
|
||||
}
|
||||
|
||||
if !self.is_tunnel {
|
||||
loop {
|
||||
let stream_id = self.stream_id();
|
||||
match self.h3_conn.send_body(&mut self.quic_conn, stream_id, &[], true) {
|
||||
match self
|
||||
.h3_conn
|
||||
.send_body(&mut self.quic_conn, stream_id, &[], true)
|
||||
{
|
||||
Ok(_) => break,
|
||||
Err(h3::Error::Done) => {
|
||||
Self::flush_quic_data(&self.socket, &mut self.quic_conn);
|
||||
|
|
@ -455,7 +458,11 @@ impl Http3Session {
|
|||
Self::read_out_socket(&self.socket, &mut self.quic_conn);
|
||||
}
|
||||
// If stream/connection already closed, that's fine
|
||||
Err(h3::Error::TransportError(_) | h3::Error::StreamBlocked | h3::Error::IdError) => {
|
||||
Err(
|
||||
h3::Error::TransportError(_)
|
||||
| h3::Error::StreamBlocked
|
||||
| h3::Error::IdError,
|
||||
) => {
|
||||
break;
|
||||
}
|
||||
Err(e) => panic!("Failed to finish stream: {}", e),
|
||||
|
|
@ -463,7 +470,7 @@ impl Http3Session {
|
|||
}
|
||||
Self::flush_quic_data(&self.socket, &mut self.quic_conn);
|
||||
}
|
||||
|
||||
|
||||
return response;
|
||||
}
|
||||
h3::Event::Finished => {
|
||||
|
|
@ -530,7 +537,10 @@ impl Http3Session {
|
|||
if !self.is_tunnel {
|
||||
loop {
|
||||
let stream_id = self.stream_id();
|
||||
match self.h3_conn.send_body(&mut self.quic_conn, stream_id, &[], true) {
|
||||
match self
|
||||
.h3_conn
|
||||
.send_body(&mut self.quic_conn, stream_id, &[], true)
|
||||
{
|
||||
Ok(_) => break,
|
||||
Err(h3::Error::Done) => {
|
||||
Self::flush_quic_data(&self.socket, &mut self.quic_conn);
|
||||
|
|
@ -542,7 +552,11 @@ impl Http3Session {
|
|||
Self::read_out_socket(&self.socket, &mut self.quic_conn);
|
||||
}
|
||||
// If stream/connection already closed
|
||||
Err(h3::Error::TransportError(_) | h3::Error::StreamBlocked | h3::Error::IdError) => {
|
||||
Err(
|
||||
h3::Error::TransportError(_)
|
||||
| h3::Error::StreamBlocked
|
||||
| h3::Error::IdError,
|
||||
) => {
|
||||
break;
|
||||
}
|
||||
Err(e) => panic!("Failed to finish stream: {}", e),
|
||||
|
|
|
|||
|
|
@ -165,6 +165,7 @@ async fn run_endpoint(endpoint_address: &SocketAddr, proxy_address: &SocketAddr)
|
|||
|
||||
fn run_proxy() -> (SocketAddr, impl Future<Output = ()>) {
|
||||
let server = std::net::TcpListener::bind((Ipv4Addr::LOCALHOST, 0)).unwrap();
|
||||
let _ = server.set_nonblocking(true);
|
||||
let server_addr = server.local_addr().unwrap();
|
||||
(server_addr, async move {
|
||||
let (socket, peer) = TcpListener::from_std(server)
|
||||
|
|
|
|||
|
|
@ -443,6 +443,7 @@ async fn make_h2_tunnel(
|
|||
|
||||
fn run_tcp_server(is_download: bool) -> SocketAddr {
|
||||
let server = std::net::TcpListener::bind((Ipv4Addr::LOCALHOST, 0)).unwrap();
|
||||
let _ = server.set_nonblocking(true);
|
||||
let server_addr = server.local_addr().unwrap();
|
||||
|
||||
thread::spawn(move || {
|
||||
|
|
@ -484,6 +485,7 @@ fn run_tcp_server(is_download: bool) -> SocketAddr {
|
|||
|
||||
fn run_udp_server(is_download: bool) -> SocketAddr {
|
||||
let server = std::net::UdpSocket::bind((Ipv4Addr::LOCALHOST, 0)).unwrap();
|
||||
let _ = server.set_nonblocking(true);
|
||||
let server_addr = server.local_addr().unwrap();
|
||||
|
||||
thread::spawn(move || {
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@ path = "setup_wizard/main.rs"
|
|||
|
||||
[dependencies]
|
||||
chrono = { version = "0.4.26", default-features = false, features = ["clock"] }
|
||||
clap = "4.3.8"
|
||||
clap = "4.5"
|
||||
dialoguer = "0.10.4"
|
||||
hex = "0.4"
|
||||
ipnet = "2.9"
|
||||
lazy_static = "1.4.0"
|
||||
log = "0.4.19"
|
||||
once_cell = "1.18.0"
|
||||
rcgen = "0.10.0"
|
||||
rcgen = "0.13"
|
||||
serde = "1.0.164"
|
||||
toml = "0.7.4"
|
||||
toml_edit = "0.19.10"
|
||||
|
|
|
|||
|
|
@ -232,28 +232,30 @@ impl AcmeClient {
|
|||
// 4. Generate key pair and CSR
|
||||
println!("Generating certificate signing request...");
|
||||
|
||||
let mut params = CertificateParams::new(vec![domain.to_string()]);
|
||||
let key_pair = rcgen::KeyPair::generate_for(&rcgen::PKCS_ECDSA_P256_SHA256)
|
||||
.map_err(|e| AcmeError::CsrGeneration(e.to_string()))?;
|
||||
|
||||
let mut params = CertificateParams::new(vec![domain.to_string()])
|
||||
.map_err(|e| AcmeError::CsrGeneration(e.to_string()))?;
|
||||
params.distinguished_name = DistinguishedName::new();
|
||||
params.distinguished_name.push(DnType::CommonName, domain);
|
||||
params.alg = &rcgen::PKCS_ECDSA_P256_SHA256;
|
||||
|
||||
let cert = rcgen::Certificate::from_params(params)
|
||||
let csr = params
|
||||
.serialize_request(&key_pair)
|
||||
.map_err(|e| AcmeError::CsrGeneration(e.to_string()))?;
|
||||
|
||||
let csr_der = cert
|
||||
.serialize_request_der()
|
||||
.map_err(|e| AcmeError::CsrGeneration(e.to_string()))?;
|
||||
let csr_der = csr.der().as_ref();
|
||||
|
||||
// 5. Finalize order
|
||||
if order.state().status == OrderStatus::Ready {
|
||||
order
|
||||
.finalize(&csr_der)
|
||||
.finalize(csr_der)
|
||||
.await
|
||||
.map_err(|e| AcmeError::Finalization(e.to_string()))?;
|
||||
println!("✓ Order finalized");
|
||||
}
|
||||
|
||||
let key_pem = cert.serialize_private_key_pem();
|
||||
let key_pem = key_pair.serialize_pem();
|
||||
|
||||
// 6. Wait for certificate
|
||||
println!("Waiting for certificate...");
|
||||
|
|
|
|||
|
|
@ -26,9 +26,7 @@ async fn handle_request(
|
|||
) -> Result<Response<Full<Bytes>>, Infallible> {
|
||||
let path = req.uri().path();
|
||||
|
||||
if path.starts_with(ACME_CHALLENGE_PATH_PREFIX) {
|
||||
let request_token = &path[ACME_CHALLENGE_PATH_PREFIX.len()..];
|
||||
|
||||
if let Some(request_token) = path.strip_prefix(ACME_CHALLENGE_PATH_PREFIX) {
|
||||
if request_token == challenge_data.token {
|
||||
println!(
|
||||
" ✓ Serving ACME challenge response for token: {}",
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ fn generate_rules_toml_content(rules_config: &trusttunnel::rules::RulesConfig) -
|
|||
// Serialize the actual rules (usually empty)
|
||||
if !rules_config.rule.is_empty() {
|
||||
content.push_str(&toml::ser::to_string(rules_config).unwrap());
|
||||
content.push_str("\n");
|
||||
content.push('\n');
|
||||
}
|
||||
|
||||
content
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ Required in non-interactive mode."#,
|
|||
.map(|x| x.splitn(2, ':'))
|
||||
.and_then(|mut x| x.next().zip(x.next()))
|
||||
.map(|(a, b)| (a.to_string(), b.to_string()))
|
||||
.and_then(|(username, password)| {
|
||||
.map(|(username, password)| {
|
||||
if username.is_empty() {
|
||||
eprintln!("Error: Username cannot be empty");
|
||||
std::process::exit(1);
|
||||
|
|
@ -183,7 +183,7 @@ Required in non-interactive mode."#,
|
|||
eprintln!("Error: Password cannot be empty");
|
||||
std::process::exit(1);
|
||||
}
|
||||
Some((username, password))
|
||||
(username, password)
|
||||
}),
|
||||
hostname: args.get_one::<String>(HOSTNAME_PARAM_NAME).cloned(),
|
||||
library_settings_file: args
|
||||
|
|
@ -287,10 +287,7 @@ fn print_setup_complete_summary(
|
|||
" • {} - Main endpoint settings",
|
||||
lib_settings_path
|
||||
);
|
||||
println!(
|
||||
" • {} - TLS host configuration",
|
||||
hosts_settings_path
|
||||
);
|
||||
println!(" • {} - TLS host configuration", hosts_settings_path);
|
||||
println!(
|
||||
" • {} - User credentials",
|
||||
library_settings::DEFAULT_CREDENTIALS_PATH
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ fn add_ip_rule(rules: &mut Vec<Rule>) {
|
|||
);
|
||||
|
||||
// Validate CIDR format
|
||||
if let Err(_) = cidr.parse::<ipnet::IpNet>() {
|
||||
if cidr.parse::<ipnet::IpNet>().is_err() {
|
||||
warn!("Invalid CIDR format. Skipping rule.");
|
||||
return;
|
||||
}
|
||||
|
|
@ -137,7 +137,7 @@ fn add_combined_rule(rules: &mut Vec<Rule>) {
|
|||
);
|
||||
|
||||
// Validate CIDR format
|
||||
if let Err(_) = cidr.parse::<ipnet::IpNet>() {
|
||||
if cidr.parse::<ipnet::IpNet>().is_err() {
|
||||
warn!("Invalid CIDR format. Skipping rule.");
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -229,8 +229,10 @@ fn generate_cert() -> Option<Cert> {
|
|||
});
|
||||
(name.clone(), vec![name.clone(), format!("*.{}", name)])
|
||||
};
|
||||
let mut params = rcgen::CertificateParams::new(alt_names.clone());
|
||||
params.alg = &rcgen::PKCS_ECDSA_P256_SHA256;
|
||||
let key_pair = rcgen::KeyPair::generate_for(&rcgen::PKCS_ECDSA_P256_SHA256)
|
||||
.expect("Failed to generate key pair");
|
||||
|
||||
let mut params = rcgen::CertificateParams::new(alt_names.clone()).unwrap();
|
||||
let now = chrono::Local::now();
|
||||
let end_date = now
|
||||
.checked_add_days(chrono::Days::new(DEFAULT_CERTIFICATE_DURATION_DAYS))
|
||||
|
|
@ -245,7 +247,9 @@ fn generate_cert() -> Option<Cert> {
|
|||
.distinguished_name
|
||||
.push(DnType::CommonName, &common_name);
|
||||
|
||||
let cert = rcgen::Certificate::from_params(params).unwrap();
|
||||
let cert = params
|
||||
.self_signed(&key_pair)
|
||||
.expect("Failed to generate self-signed cert");
|
||||
let cert_path = format!("{DEFAULT_CERTIFICATE_FOLDER}/cert.pem");
|
||||
if !checked_overwrite(&cert_path, "Overwrite the existing certificate file?") {
|
||||
return None;
|
||||
|
|
@ -258,22 +262,20 @@ fn generate_cert() -> Option<Cert> {
|
|||
|
||||
fs::create_dir_all(Path::new(&cert_path).parent().unwrap())
|
||||
.expect("Couldn't create certificate directory path");
|
||||
fs::write(&cert_path, cert.serialize_pem().unwrap())
|
||||
.expect("Couldn't write the certificate into a file");
|
||||
fs::write(&cert_path, cert.pem()).expect("Couldn't write the certificate into a file");
|
||||
println!("The generated certificate is stored in file: {}", cert_path);
|
||||
|
||||
fs::create_dir_all(Path::new(&key_path).parent().unwrap())
|
||||
.expect("Couldn't create private key directory path");
|
||||
if key_path != cert_path {
|
||||
fs::write(key_path.clone(), cert.serialize_private_key_pem())
|
||||
fs::write(key_path.clone(), key_pair.serialize_pem())
|
||||
.expect("Couldn't write the private key into a file");
|
||||
} else {
|
||||
fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.append(true)
|
||||
.open(key_path.clone())
|
||||
.expect("Couldn't open a file for writing the private key")
|
||||
.write_all(cert.serialize_private_key_pem().as_bytes())
|
||||
.write_all(key_pair.serialize_pem().as_bytes())
|
||||
.expect("Couldn't write the private key into a file");
|
||||
}
|
||||
println!("The generated private key is stored in file: {}", key_path);
|
||||
|
|
@ -498,7 +500,7 @@ fn ask_for_alternative_snis() -> Vec<String> {
|
|||
if crate::get_mode() == Mode::NonInteractive {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
|
||||
if !ask_for_agreement("Do you want to configure alternative SNIs?") {
|
||||
return vec![];
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue