Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
c8497a6188 | |||
2e0ccc1d0e | |||
f3a78b2863 | |||
225d71d885 | |||
c59cef666a | |||
d026f700a5 | |||
2c902bdddf | |||
efc858f852 | |||
7be828efdf | |||
1650cefa0d | |||
327a23d82d | |||
da86f8da72 | |||
1e7fa84a42 | |||
9d37f3d929 | |||
2cd69aaf15 | |||
7316bb5341 | |||
b363f30298 | |||
d46c440b4e | |||
9b2866c5b4 | |||
4c6f4258b4 | |||
5280c038b7 | |||
5e394bca1e | |||
152bb991d4 | |||
a9f7daf823 |
42
.ci/Jenkinsfile
vendored
Normal file
42
.ci/Jenkinsfile
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
properties(
|
||||||
|
[
|
||||||
|
disableConcurrentBuilds()
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
node('linux && docker') {
|
||||||
|
try {
|
||||||
|
stage('Checkout') {
|
||||||
|
//branch name from Jenkins environment variables
|
||||||
|
echo "My branch is: ${env.BRANCH_NAME}"
|
||||||
|
|
||||||
|
// this doesn't grab tags pointing to this branch
|
||||||
|
//checkout scm
|
||||||
|
// this hack does... https://issues.jenkins.io/browse/JENKINS-45164
|
||||||
|
checkout([
|
||||||
|
$class: 'GitSCM',
|
||||||
|
branches: [[name: 'refs/heads/'+env.BRANCH_NAME]],
|
||||||
|
extensions: [[$class: 'CloneOption', noTags: false, shallow: false, depth: 0, reference: '']],
|
||||||
|
userRemoteConfigs: scm.userRemoteConfigs,
|
||||||
|
])
|
||||||
|
sh '''
|
||||||
|
set -euxo pipefail
|
||||||
|
git checkout "$BRANCH_NAME" --
|
||||||
|
git reset --hard "origin/$BRANCH_NAME"
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Build + Deploy') {
|
||||||
|
sh 'curl --compressed -sL https://code.moparisthebest.com/moparisthebest/self-ci/raw/branch/master/build-ci.sh | bash'
|
||||||
|
}
|
||||||
|
|
||||||
|
currentBuild.result = 'SUCCESS'
|
||||||
|
} catch (Exception err) {
|
||||||
|
currentBuild.result = 'FAILURE'
|
||||||
|
} finally {
|
||||||
|
stage('Email') {
|
||||||
|
step([$class: 'Mailer', notifyEveryUnstableBuild: true, recipients: 'admin.jenkins@moparisthebest.com', sendToIndividuals: true])
|
||||||
|
}
|
||||||
|
deleteDir()
|
||||||
|
}
|
||||||
|
}
|
64
.ci/build.sh
Executable file
64
.ci/build.sh
Executable file
@ -0,0 +1,64 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -exo pipefail
|
||||||
|
|
||||||
|
echo "starting build for TARGET $TARGET"
|
||||||
|
|
||||||
|
export CRATE_NAME=wireguard-proxy
|
||||||
|
export OPENSSL_STATIC=1
|
||||||
|
export CARGO_FEATURES=async
|
||||||
|
|
||||||
|
DISABLE_TESTS=${DISABLE_TESTS:-0}
|
||||||
|
|
||||||
|
SUFFIX=""
|
||||||
|
|
||||||
|
# wine blows up in testing with async build
|
||||||
|
echo "$TARGET" | grep -E '^x86_64-pc-windows-gnu$' >/dev/null && DISABLE_TESTS=1 && SUFFIX=".exe"
|
||||||
|
|
||||||
|
# these only support openssl_vendored, not async
|
||||||
|
if echo "$TARGET" | grep -E '^(s390x|powerpc|mips)' >/dev/null
|
||||||
|
then
|
||||||
|
CARGO_FEATURES=openssl_vendored
|
||||||
|
fi
|
||||||
|
|
||||||
|
# these don't support any TLS at all
|
||||||
|
if echo "$TARGET" | grep -E '(^riscv64gc|solaris$)' >/dev/null
|
||||||
|
then
|
||||||
|
CARGO_FEATURES=verbose
|
||||||
|
fi
|
||||||
|
|
||||||
|
cross rustc --bin wireguard-proxy --target $TARGET --release --no-default-features --features $CARGO_FEATURES
|
||||||
|
cross rustc --bin udp-test --target $TARGET --release --no-default-features --features $CARGO_FEATURES
|
||||||
|
|
||||||
|
# to check how they are built
|
||||||
|
file "target/$TARGET/release/wireguard-proxy$SUFFIX" "target/$TARGET/release/udp-test$SUFFIX"
|
||||||
|
|
||||||
|
if [ $DISABLE_TESTS -ne 1 ]
|
||||||
|
then
|
||||||
|
|
||||||
|
# first make sure udp-test succeeds running against itself
|
||||||
|
cross run --target $TARGET --release --no-default-features --features $CARGO_FEATURES --bin udp-test
|
||||||
|
|
||||||
|
# now run udp-test through proxy/proxyd
|
||||||
|
cross run --target $TARGET --release --no-default-features --features $CARGO_FEATURES --bin udp-test -- -is
|
||||||
|
|
||||||
|
if [ $CARGO_FEATURES != "verbose" ]; then
|
||||||
|
# run TLS tests then too
|
||||||
|
cross run --target $TARGET --release --no-default-features --features $CARGO_FEATURES --bin udp-test -- -is --tls-key ci/cert.key --tls-cert ci/cert.pem
|
||||||
|
|
||||||
|
# now pubkey tests
|
||||||
|
|
||||||
|
# one that should fail (wrong pinnedpubkey lowercase e at end instead of uppercase E)
|
||||||
|
cross run --target $TARGET --release --no-default-features --features $CARGO_FEATURES --bin udp-test -- -is --tls-key ci/cert.key --tls-cert ci/cert.pem --pinnedpubkey sha256//BEyQeSjwwUBLXXNuCILHRWyV1gLmY31CdMHNA4VH4de= && exit 1 || true
|
||||||
|
|
||||||
|
# and one that should pass
|
||||||
|
cross run --target $TARGET --release --no-default-features --features $CARGO_FEATURES --bin udp-test -- -is --tls-key ci/cert.key --tls-cert ci/cert.pem --pinnedpubkey sha256//BEyQeSjwwUBLXXNuCILHRWyV1gLmY31CdMHNA4VH4dE=
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# if this commit has a tag, upload artifact to release
|
||||||
|
strip "target/$TARGET/release/wireguard-proxy$SUFFIX" || true # if strip fails, it's fine
|
||||||
|
mkdir -p release
|
||||||
|
mv "target/$TARGET/release/wireguard-proxy$SUFFIX" "release/wireguard-proxy-$TARGET$SUFFIX"
|
||||||
|
|
||||||
|
echo 'build success!'
|
||||||
|
exit 0
|
133
.travis.yml
133
.travis.yml
@ -1,133 +0,0 @@
|
|||||||
# Based on the "trust" template v0.1.2
|
|
||||||
# https://github.com/japaric/trust/tree/v0.1.2
|
|
||||||
|
|
||||||
dist: trusty
|
|
||||||
language: rust
|
|
||||||
services: docker
|
|
||||||
sudo: required
|
|
||||||
|
|
||||||
# TODO Rust builds on stable by default, this can be
|
|
||||||
# overridden on a case by case basis down below.
|
|
||||||
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
# TODO Update this to match the name of your project.
|
|
||||||
- CRATE_NAME=wireguard-proxy
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
# TODO These are all the build jobs. Adjust as necessary. Comment out what you
|
|
||||||
# don't need
|
|
||||||
include:
|
|
||||||
# Android
|
|
||||||
- env: TARGET=aarch64-linux-android DISABLE_TESTS=1
|
|
||||||
- env: TARGET=arm-linux-androideabi DISABLE_TESTS=1
|
|
||||||
- env: TARGET=armv7-linux-androideabi DISABLE_TESTS=1
|
|
||||||
- env: TARGET=i686-linux-android DISABLE_TESTS=1
|
|
||||||
- env: TARGET=x86_64-linux-android DISABLE_TESTS=1
|
|
||||||
|
|
||||||
# iOS
|
|
||||||
- env: TARGET=aarch64-apple-ios DISABLE_TESTS=1
|
|
||||||
os: osx
|
|
||||||
- env: TARGET=armv7-apple-ios DISABLE_TESTS=1
|
|
||||||
os: osx
|
|
||||||
- env: TARGET=armv7s-apple-ios DISABLE_TESTS=1
|
|
||||||
os: osx
|
|
||||||
- env: TARGET=i386-apple-ios DISABLE_TESTS=1
|
|
||||||
os: osx
|
|
||||||
- env: TARGET=x86_64-apple-ios DISABLE_TESTS=1
|
|
||||||
os: osx
|
|
||||||
|
|
||||||
# Linux
|
|
||||||
- env: TARGET=aarch64-unknown-linux-gnu
|
|
||||||
- env: TARGET=arm-unknown-linux-gnueabi
|
|
||||||
- env: TARGET=armv7-unknown-linux-gnueabihf
|
|
||||||
- env: TARGET=i686-unknown-linux-gnu
|
|
||||||
- env: TARGET=i686-unknown-linux-musl
|
|
||||||
- env: TARGET=mips-unknown-linux-gnu
|
|
||||||
- env: TARGET=mips64-unknown-linux-gnuabi64
|
|
||||||
- env: TARGET=mips64el-unknown-linux-gnuabi64
|
|
||||||
- env: TARGET=mipsel-unknown-linux-gnu
|
|
||||||
- env: TARGET=powerpc-unknown-linux-gnu
|
|
||||||
- env: TARGET=powerpc64-unknown-linux-gnu
|
|
||||||
- env: TARGET=powerpc64le-unknown-linux-gnu
|
|
||||||
- env: TARGET=s390x-unknown-linux-gnu DISABLE_TESTS=1
|
|
||||||
- env: TARGET=x86_64-unknown-linux-gnu
|
|
||||||
- env: TARGET=x86_64-unknown-linux-musl
|
|
||||||
|
|
||||||
# OSX
|
|
||||||
- env: TARGET=i686-apple-darwin
|
|
||||||
os: osx
|
|
||||||
- env: TARGET=x86_64-apple-darwin
|
|
||||||
os: osx
|
|
||||||
|
|
||||||
# *BSD
|
|
||||||
- env: TARGET=i686-unknown-freebsd DISABLE_TESTS=1
|
|
||||||
- env: TARGET=x86_64-unknown-freebsd DISABLE_TESTS=1
|
|
||||||
- env: TARGET=x86_64-unknown-netbsd DISABLE_TESTS=1
|
|
||||||
|
|
||||||
# Windows
|
|
||||||
- env: TARGET=x86_64-pc-windows-gnu
|
|
||||||
|
|
||||||
# Bare metal
|
|
||||||
# These targets don't support std and as such are likely not suitable for
|
|
||||||
# most crates.
|
|
||||||
# - env: TARGET=thumbv6m-none-eabi
|
|
||||||
# - env: TARGET=thumbv7em-none-eabi
|
|
||||||
# - env: TARGET=thumbv7em-none-eabihf
|
|
||||||
# - env: TARGET=thumbv7m-none-eabi
|
|
||||||
|
|
||||||
# Testing other channels
|
|
||||||
- env: TARGET=x86_64-unknown-linux-gnu
|
|
||||||
rust: nightly
|
|
||||||
- env: TARGET=x86_64-apple-darwin
|
|
||||||
os: osx
|
|
||||||
rust: nightly
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- set -e
|
|
||||||
- rustup self update
|
|
||||||
|
|
||||||
install:
|
|
||||||
- sh ci/install.sh
|
|
||||||
- source ~/.cargo/env || true
|
|
||||||
|
|
||||||
script:
|
|
||||||
- bash ci/script.sh
|
|
||||||
|
|
||||||
after_script: set +e
|
|
||||||
|
|
||||||
before_deploy:
|
|
||||||
- sh ci/before_deploy.sh
|
|
||||||
|
|
||||||
deploy:
|
|
||||||
# TODO update `api_key.secure`
|
|
||||||
# - Create a `public_repo` GitHub token. Go to: https://github.com/settings/tokens/new
|
|
||||||
# - Encrypt it: `travis encrypt 0123456789012345678901234567890123456789
|
|
||||||
# - Paste the output down here
|
|
||||||
api_key:
|
|
||||||
secure: $GITHUB_OAUTH
|
|
||||||
file_glob: true
|
|
||||||
file: $CRATE_NAME-$TRAVIS_TAG-$TARGET.*
|
|
||||||
on:
|
|
||||||
# TODO Here you can pick which targets will generate binary releases
|
|
||||||
# In this example, there are some targets that are tested using the stable
|
|
||||||
# and nightly channels. This condition makes sure there is only one release
|
|
||||||
# for such targets and that's generated using the stable channel
|
|
||||||
condition: $TRAVIS_RUST_VERSION = stable
|
|
||||||
tags: true
|
|
||||||
provider: releases
|
|
||||||
skip_cleanup: true
|
|
||||||
|
|
||||||
cache: cargo
|
|
||||||
before_cache:
|
|
||||||
# Travis can't cache files that are not readable by "others"
|
|
||||||
- chmod -R a+r $HOME/.cargo
|
|
||||||
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
# release tags
|
|
||||||
- /^v\d+\.\d+\.\d+.*$/
|
|
||||||
- master
|
|
||||||
- travis
|
|
||||||
- ci
|
|
||||||
|
|
525
Cargo.lock
generated
525
Cargo.lock
generated
@ -1,6 +1,531 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bumpalo"
|
||||||
|
version = "3.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "0.5.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.58"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types-shared"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fuchsia-zircon"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fuchsia-zircon-sys"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-core"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iovec"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "js-sys"
|
||||||
|
version = "0.3.42"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"wasm-bindgen 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kernel32-sys"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.73"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mio"
|
||||||
|
version = "0.6.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"net2 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mio-uds"
|
||||||
|
version = "0.6.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miow"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"net2 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "net2"
|
||||||
|
version = "0.2.34"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_cpus"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl"
|
||||||
|
version = "0.10.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"openssl-sys 0.9.53 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-src"
|
||||||
|
version = "111.6.1+1.1.1d"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"cc 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-sys"
|
||||||
|
version = "0.9.53"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"cc 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"openssl-src 111.6.1+1.1.1d (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-lite"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ring"
|
||||||
|
version = "0.16.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"cc 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"once_cell 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"web-sys 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls"
|
||||||
|
version = "0.18.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ring 0.16.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"sct 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"webpki 0.21.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sct"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"ring 0.16.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "slab"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio"
|
||||||
|
version = "0.2.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"bytes 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"mio-uds 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"pin-project-lite 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tokio-macros 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-macros"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-rustls"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rustls 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tokio 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"webpki 0.21.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-xid"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "untrusted"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vcpkg"
|
||||||
|
version = "0.2.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen"
|
||||||
|
version = "0.2.65"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"wasm-bindgen-macro 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-backend"
|
||||||
|
version = "0.2.65"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"wasm-bindgen-shared 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro"
|
||||||
|
version = "0.2.65"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"wasm-bindgen-macro-support 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro-support"
|
||||||
|
version = "0.2.65"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"wasm-bindgen-backend 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"wasm-bindgen-shared 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-shared"
|
||||||
|
version = "0.2.65"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "web-sys"
|
||||||
|
version = "0.3.42"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"js-sys 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"wasm-bindgen 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "webpki"
|
||||||
|
version = "0.21.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"ring 0.16.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.2.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-build"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wireguard-proxy"
|
name = "wireguard-proxy"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"openssl 0.10.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ring 0.16.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tokio 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tokio-rustls 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ws2_32-sys"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
|
||||||
|
"checksum base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
|
||||||
|
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
|
"checksum bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820"
|
||||||
|
"checksum bytes 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
|
||||||
|
"checksum cc 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)" = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518"
|
||||||
|
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
|
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||||
|
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||||
|
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||||
|
"checksum futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399"
|
||||||
|
"checksum hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9"
|
||||||
|
"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
|
||||||
|
"checksum js-sys 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)" = "52732a3d3ad72c58ad2dc70624f9c17b46ecd0943b9a4f1ee37c4c18c5d983e2"
|
||||||
|
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||||
|
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
"checksum libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)" = "bd7d4bd64732af4bf3a67f367c27df8520ad7e230c5817b8ff485864d80242b9"
|
||||||
|
"checksum log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
|
||||||
|
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||||
|
"checksum mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)" = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430"
|
||||||
|
"checksum mio-uds 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0"
|
||||||
|
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||||
|
"checksum net2 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7"
|
||||||
|
"checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
|
||||||
|
"checksum once_cell 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d"
|
||||||
|
"checksum openssl 0.10.26 (registry+https://github.com/rust-lang/crates.io-index)" = "3a3cc5799d98e1088141b8e01ff760112bbd9f19d850c124500566ca6901a585"
|
||||||
|
"checksum openssl-src 111.6.1+1.1.1d (registry+https://github.com/rust-lang/crates.io-index)" = "c91b04cb43c1a8a90e934e0cd612e2a5715d976d2d6cff4490278a0cddf35005"
|
||||||
|
"checksum openssl-sys 0.9.53 (registry+https://github.com/rust-lang/crates.io-index)" = "465d16ae7fc0e313318f7de5cecf57b2fbe7511fd213978b457e1c96ff46736f"
|
||||||
|
"checksum pin-project-lite 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "282adbf10f2698a7a77f8e983a74b2d18176c19a7fd32a45446139ae7b02b715"
|
||||||
|
"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
|
||||||
|
"checksum proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12"
|
||||||
|
"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
|
||||||
|
"checksum ring 0.16.15 (registry+https://github.com/rust-lang/crates.io-index)" = "952cd6b98c85bbc30efa1ba5783b8abf12fec8b3287ffa52605b9432313e34e4"
|
||||||
|
"checksum rustls 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac94b333ee2aac3284c5b8a1b7fb4dd11cba88c244e3fe33cdbd047af0eb693"
|
||||||
|
"checksum sct 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3042af939fca8c3453b7af0f1c66e533a15a86169e39de2657310ade8f98d3c"
|
||||||
|
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||||
|
"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||||
|
"checksum syn 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "fb7f4c519df8c117855e19dd8cc851e89eb746fe7a73f0157e0d95fdec5369b0"
|
||||||
|
"checksum tokio 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5d34ca54d84bf2b5b4d7d31e901a8464f7b60ac145a284fba25ceb801f2ddccd"
|
||||||
|
"checksum tokio-macros 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389"
|
||||||
|
"checksum tokio-rustls 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "228139ddd4fea3fa345a29233009635235833e52807af7ea6448ead03890d6a9"
|
||||||
|
"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||||
|
"checksum untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||||
|
"checksum vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168"
|
||||||
|
"checksum wasm-bindgen 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "f3edbcc9536ab7eababcc6d2374a0b7bfe13a2b6d562c5e07f370456b1a8f33d"
|
||||||
|
"checksum wasm-bindgen-backend 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "89ed2fb8c84bfad20ea66b26a3743f3e7ba8735a69fe7d95118c33ec8fc1244d"
|
||||||
|
"checksum wasm-bindgen-macro 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "eb071268b031a64d92fc6cf691715ca5a40950694d8f683c5bb43db7c730929e"
|
||||||
|
"checksum wasm-bindgen-macro-support 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "cf592c807080719d1ff2f245a687cbadb3ed28b2077ed7084b47aba8b691f2c6"
|
||||||
|
"checksum wasm-bindgen-shared 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "72b6c0220ded549d63860c78c38f3bcc558d1ca3f4efa74942c536ddbbb55e87"
|
||||||
|
"checksum web-sys 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)" = "8be2398f326b7ba09815d0b403095f34dd708579220d099caae89be0b32137b2"
|
||||||
|
"checksum webpki 0.21.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ab146130f5f790d45f82aeeb09e55a256573373ec64409fc19a6fb82fb1032ae"
|
||||||
|
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||||
|
"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||||
|
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||||
|
17
Cargo.toml
17
Cargo.toml
@ -18,3 +18,20 @@ include = [
|
|||||||
"LICENSE-*",
|
"LICENSE-*",
|
||||||
"*.md",
|
"*.md",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["async"]
|
||||||
|
tls = ["openssl"]
|
||||||
|
openssl_vendored = ["openssl/vendored"]
|
||||||
|
verbose = []
|
||||||
|
async = ["tokio", "tokio-rustls", "ring", "base64"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# only for non-async build with TLS support
|
||||||
|
openssl = { version = "0.10.26", optional = true }
|
||||||
|
# the rest of these are only required for async build
|
||||||
|
tokio = { version = "0.2", features = [ "macros", "net", "udp", "io-std", "io-util", "rt-threaded" ], optional = true }
|
||||||
|
tokio-rustls = { version = "0.14", features = ["dangerous_configuration"], optional = true }
|
||||||
|
# probably should try to keep ring the exact same version as rustls, same features too
|
||||||
|
ring = { version = "0.16.11", optional = true }
|
||||||
|
base64 = { version = "0.12.3", optional = true }
|
||||||
|
121
README.md
121
README.md
@ -1,16 +1,91 @@
|
|||||||
# wireguard-proxy
|
# wireguard-proxy
|
||||||
|
|
||||||
|
[![Build Status](https://ci.moparisthe.best/job/moparisthebest/job/wireguard-proxy/job/master/badge/icon%3Fstyle=plastic)](https://ci.moparisthe.best/job/moparisthebest/job/wireguard-proxy/job/master/)
|
||||||
|
[![Build status](https://ci.appveyor.com/api/projects/status/vl8c9xdhvgn997d2/branch/master?svg=true)](https://ci.appveyor.com/project/moparisthebest/wireguard-proxy)
|
||||||
|
[![crates.io](https://img.shields.io/crates/v/wireguard-proxy.svg)](https://crates.io/crates/wireguard-proxy)
|
||||||
|
|
||||||
Proxy wireguard UDP packets over TCP/TLS
|
Proxy wireguard UDP packets over TCP/TLS
|
||||||
|
|
||||||
`wireguard-proxyd` is a server-side daemon to accept TCP connections from multiple clients and pipe data to and from the specified UDP port
|
`wireguard-proxy` has 2 modes:
|
||||||
`wireguard-proxy` is a client-side daemon that accepts UDP packets on a local port from a single client, connects to a single remote TCP port, and pipes data between them
|
- server-side daemon to accept TCP/TLS connections from multiple clients and pipe data to and from the specified UDP port
|
||||||
|
- client-side daemon that accepts UDP packets on a local port from a single client, connects to a single remote TCP/TLS port, and pipes data between them
|
||||||
|
|
||||||
|
```
|
||||||
|
$ wireguard-proxy -h
|
||||||
|
usage: wireguard-proxy [options...]
|
||||||
|
Client Mode (requires --tcp-target):
|
||||||
|
-tt, --tcp-target <ip:port> TCP target to send packets to, where
|
||||||
|
wireguard-proxy server is running
|
||||||
|
-uh, --udp-host <ip:port> UDP host to listen on, point wireguard
|
||||||
|
client here, default: 127.0.0.1:51820
|
||||||
|
--tls use TLS when connecting to tcp-target
|
||||||
|
WARNING: authenticates/verifies nothing
|
||||||
|
without --pinnedpubkey below!!
|
||||||
|
--pinnedpubkey <sha256_hashes> Public key to verify peer against,
|
||||||
|
format is any number of base64 encoded
|
||||||
|
sha256 hashes preceded by "sha256//"
|
||||||
|
and separated by ";". Identical to curl's
|
||||||
|
--pinnedpubkey and CURLOPT_PINNEDPUBLICKEY
|
||||||
|
--tls-hostname send this in SNI instead of host
|
||||||
|
from --tcp-target, useful for avoiding
|
||||||
|
DNS lookup on connect
|
||||||
|
|
||||||
|
Server Mode (requires --tcp-host):
|
||||||
|
-th, --tcp-host <ip:port> TCP host to listen on
|
||||||
|
-ut, --udp-target <ip:port> UDP target to send packets to, where
|
||||||
|
wireguard server is running,
|
||||||
|
default: 127.0.0.1:51820
|
||||||
|
-ur, --udp-bind-host-range <ip:low-high> UDP host and port range to bind to,
|
||||||
|
one port per TCP connection, to
|
||||||
|
listen on for UDP packets to send
|
||||||
|
back over the TCP connection,
|
||||||
|
default: 127.0.0.1:30000-40000
|
||||||
|
-tk, --tls-key <ip:port> TLS key to listen with,
|
||||||
|
requires --tls-cert also
|
||||||
|
-tc, --tls-cert <ip:port> TLS cert to listen with,
|
||||||
|
requires --tls-key also
|
||||||
|
Note: with both --tls-key and --tls-cert,
|
||||||
|
- means stdin,
|
||||||
|
also the same file can work for both if you combine them into
|
||||||
|
one pem file
|
||||||
|
|
||||||
|
Common Options:
|
||||||
|
-h, --help print this usage text
|
||||||
|
-V, --version Show version number and TLS support then quit
|
||||||
|
-st, --socket-timeout <seconds> Socket timeout (time to wait for data)
|
||||||
|
before terminating, default: 0
|
||||||
|
|
||||||
|
Environment variable support:
|
||||||
|
For every long command line option (starting with --), if you replace the
|
||||||
|
leading -- with WGP_, and replace all remaining - with _, and uppercase
|
||||||
|
the whole thing, if you don't specify that command line option we will
|
||||||
|
read that environment variable for the argument. boolean arguments are
|
||||||
|
true if anything but unset, empty, 0, or false.
|
||||||
|
Examples:
|
||||||
|
--tcp-target ARG is WGP_TCP_TARGET=ARG
|
||||||
|
--socket-timeout 5 is WGP_SOCKET_TIMEOUT=5
|
||||||
|
--tls is WGP_TLS=1 or WGP_TLS=true
|
||||||
|
WGP_TLS=0 or WGP_TLS=false would be like not sending --tls
|
||||||
|
```
|
||||||
|
|
||||||
|
Binaries:
|
||||||
|
|
||||||
|
- [releases](https://github.com/moparisthebest/wireguard-proxy/releases) has static builds for most platforms performed by [self-ci](https://github.com/moparisthebest/self-ci) and appveyor courtesy of [trust](https://github.com/japaric/trust)
|
||||||
|
- Arch Linux AUR [wireguard-proxy](https://aur.archlinux.org/packages/wireguard-proxy/) and [wireguard-proxy-git](https://aur.archlinux.org/packages/wireguard-proxy-git/)
|
||||||
|
|
||||||
|
Building:
|
||||||
|
|
||||||
|
- `cargo build --release` - async build with TLS support supplied by rustls
|
||||||
|
- `cargo build --release --no-default-features ` - minimal build without TLS support, no dependencies
|
||||||
|
- `cargo build --release --no-default-features --feature tls` - links to system openssl
|
||||||
|
- `cargo build --release --no-default-features --feature openssl_vendored` - compiles vendored openssl and link to it
|
||||||
|
|
||||||
Testing:
|
Testing:
|
||||||
|
|
||||||
`udp-test` is a utility to send a UDP packet and then receive a UDP packet and ensure they are the same, this verifies packets sent through proxy/proxyd are unmolested
|
- `udp-test` is a utility to send a UDP packet and then receive a UDP packet and ensure they are the same, this verifies packets sent through proxy server/client are unmolested
|
||||||
`test.sh` runs udp-test against itself and then through proxyd/proxy
|
- `udp-test -s` runs udp-test against itself through proxy server/client by spawning actual binaries
|
||||||
`udp-test -s` runs udp-test against itself through proxyd/proxy by spawning actual binaries
|
- `udp-test -is` runs udp-test against itself through proxy server/client in same executable by using library, so does not test command line parsing etc
|
||||||
`udp-test -is` runs udp-test against itself through proxyd/proxy in same executable by using library, so does not test command line parsing etc
|
- `test.sh` runs udp-test against itself, the udp-test self tests above, and through proxy server/client in the shell script
|
||||||
|
|
||||||
Testing with GNU netcat:
|
Testing with GNU netcat:
|
||||||
|
|
||||||
@ -20,6 +95,40 @@ Testing with GNU netcat:
|
|||||||
- `nc 127.0.0.1 5555` connect directly to local tcp wireguard-proxy port to send/recieve data
|
- `nc 127.0.0.1 5555` connect directly to local tcp wireguard-proxy port to send/recieve data
|
||||||
- so to test through wireguard-proxy run first and last command while it's running, type in both places
|
- so to test through wireguard-proxy run first and last command while it's running, type in both places
|
||||||
|
|
||||||
|
# OpenSSL cert generation
|
||||||
|
|
||||||
|
Quick commands to generate your own certificate to use with wireguard-proxy, note if you are actually only sending
|
||||||
|
wireguard packets over this, the TLS layer doesn't really need to provide any security or authentication, only obfuscation
|
||||||
|
|
||||||
|
Currently the only authentication performed is optional and via --pinnedpubkey only if supplied
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# single command self signed RSA cert
|
||||||
|
openssl req -new -x509 -sha256 -days 3650 -nodes -subj "/C=US/CN=example.org" -newkey rsa:2048 -out cert.pem -keyout key.pem
|
||||||
|
|
||||||
|
# customize key type
|
||||||
|
# more info: https://github.com/openssl/openssl/blob/master/doc/man1/openssl-genpkey.pod
|
||||||
|
# ordered roughly starting from oldest/worst/most supported (rsa) to newest/best/least supported (ed448) order
|
||||||
|
# run one of these only to generate the preferred key type
|
||||||
|
openssl genpkey -algorithm RSA -out key.pem -pkeyopt rsa_keygen_bits:1024
|
||||||
|
openssl genpkey -algorithm RSA -out key.pem -pkeyopt rsa_keygen_bits:2048
|
||||||
|
openssl genpkey -algorithm RSA -out key.pem -pkeyopt rsa_keygen_bits:4096
|
||||||
|
openssl genpkey -algorithm EC -out key.pem -pkeyopt ec_paramgen_curve:P-256 -pkeyopt ec_param_enc:named_curve
|
||||||
|
openssl genpkey -algorithm EC -out key.pem -pkeyopt ec_paramgen_curve:P-384 -pkeyopt ec_param_enc:named_curve
|
||||||
|
openssl genpkey -algorithm EC -out key.pem -pkeyopt ec_paramgen_curve:P-521 -pkeyopt ec_param_enc:named_curve
|
||||||
|
openssl genpkey -algorithm ED25519 -out key.pem
|
||||||
|
openssl genpkey -algorithm ED448 -out key.pem
|
||||||
|
|
||||||
|
# then run this to generate and self-sign a cert with the above key
|
||||||
|
openssl req -new -x509 -sha256 -days 3650 -nodes -subj "/C=US/CN=example.org" -out cert.pem -key key.pem
|
||||||
|
|
||||||
|
# optionally (but recommended) extract pinnedpubkey hash from the above generated cert like so:
|
||||||
|
# openssl x509 -in cert.pem -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
|
||||||
|
|
||||||
|
# optionally run this to see human readable info about the cert
|
||||||
|
openssl x509 -in cert.pem -noout -text
|
||||||
|
```
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
This project is licensed under either of
|
This project is licensed under either of
|
||||||
|
21
appveyor.yml
21
appveyor.yml
@ -9,6 +9,9 @@ environment:
|
|||||||
|
|
||||||
# TODO Update this to match the name of your project.
|
# TODO Update this to match the name of your project.
|
||||||
CRATE_NAME: wireguard-proxy
|
CRATE_NAME: wireguard-proxy
|
||||||
|
# gnu fails to compile with any openssl combo for some reason
|
||||||
|
OPENSSL_STATIC: 1
|
||||||
|
CARGO_FEATURES: async
|
||||||
|
|
||||||
# TODO These are all the build jobs. Adjust as necessary. Comment out what you
|
# TODO These are all the build jobs. Adjust as necessary. Comment out what you
|
||||||
# don't need
|
# don't need
|
||||||
@ -44,20 +47,23 @@ install:
|
|||||||
test_script:
|
test_script:
|
||||||
# we don't run the "test phase" when doing deploys
|
# we don't run the "test phase" when doing deploys
|
||||||
- if [%APPVEYOR_REPO_TAG%]==[false] (
|
- if [%APPVEYOR_REPO_TAG%]==[false] (
|
||||||
cargo build --target %TARGET% &&
|
cargo build --target %TARGET% --release --features %CARGO_FEATURES% &&
|
||||||
cargo build --target %TARGET% --release &&
|
cargo run --target %TARGET% --release --features %CARGO_FEATURES% --bin udp-test &&
|
||||||
cargo run --target %TARGET% --release --bin udp-test &&
|
cargo run --target %TARGET% --release --features %CARGO_FEATURES% --bin udp-test -- -is
|
||||||
cargo run --target %TARGET% --release --bin udp-test -- -is
|
)
|
||||||
|
# todo: should run --pinnedpubkey test here where we expect failure, but unsure how to do that with windows, help?
|
||||||
|
- if [%CARGO_FEATURES%]==[async] (
|
||||||
|
cargo run --target %TARGET% --release --features %CARGO_FEATURES% --bin udp-test -- -is --tls-key ci/cert.key --tls-cert ci/cert.pem &&
|
||||||
|
cargo run --target %TARGET% --release --features %CARGO_FEATURES% --bin udp-test -- -is --tls-key ci/cert.key --tls-cert ci/cert.pem --pinnedpubkey sha256//BEyQeSjwwUBLXXNuCILHRWyV1gLmY31CdMHNA4VH4dE=
|
||||||
)
|
)
|
||||||
|
|
||||||
before_deploy:
|
before_deploy:
|
||||||
# TODO Update this to build the artifacts that matter to you
|
# TODO Update this to build the artifacts that matter to you
|
||||||
- cargo rustc --target %TARGET% --release --bin wireguard-proxy -- -C lto
|
- cargo rustc --target %TARGET% --release --features %CARGO_FEATURES% --bin wireguard-proxy -- -C lto
|
||||||
- cargo rustc --target %TARGET% --release --bin wireguard-proxyd -- -C lto
|
|
||||||
- ps: ci\before_deploy.ps1
|
- ps: ci\before_deploy.ps1
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
artifact: /.*\.zip/
|
artifact: /wireguard-proxy-.*\.exe/
|
||||||
# TODO update `auth_token.secure`
|
# TODO update `auth_token.secure`
|
||||||
# - Create a `public_repo` GitHub token. Go to: https://github.com/settings/tokens/new
|
# - Create a `public_repo` GitHub token. Go to: https://github.com/settings/tokens/new
|
||||||
# - Encrypt it. Go to https://ci.appveyor.com/tools/encrypt
|
# - Encrypt it. Go to https://ci.appveyor.com/tools/encrypt
|
||||||
@ -85,6 +91,7 @@ branches:
|
|||||||
- master
|
- master
|
||||||
- appveyor
|
- appveyor
|
||||||
- ci
|
- ci
|
||||||
|
- openssl
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
- provider: Email
|
- provider: Email
|
||||||
|
85
benchmark.sh
Executable file
85
benchmark.sh
Executable file
@ -0,0 +1,85 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#set -x
|
||||||
|
|
||||||
|
# cert created with:
|
||||||
|
# cd ci && echo -e '\n\n\n\n\n\n\n' | openssl req -new -x509 -days 3650 -nodes -out cert.pem -keyout cert.key
|
||||||
|
|
||||||
|
export PATH="$(pwd)/target/release:$PATH"
|
||||||
|
|
||||||
|
run_tests() {
|
||||||
|
client_arg="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
# now run proxyd pointing to nc
|
||||||
|
wireguard-proxy -th 127.0.0.1:5555 -ut 127.0.0.1:51822 "$@" &
|
||||||
|
proxyd_pid=$!
|
||||||
|
# wait for ports to be set up, this is fragile...
|
||||||
|
sleep 5
|
||||||
|
# proxy pointing to proxyd
|
||||||
|
wireguard-proxy -tt 127.0.0.1:5555 "$client_arg" &
|
||||||
|
proxy_pid=$!
|
||||||
|
# wait for ports to be set up, this is fragile...
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
# nc running through wireguard-proxy's above
|
||||||
|
nc -lup 51822 >/dev/null &
|
||||||
|
nc_listen_pid=$!
|
||||||
|
|
||||||
|
wireguard-proxy -V
|
||||||
|
|
||||||
|
dd if=/dev/zero bs=128M count=10 | nc -u 127.0.0.1 51820 &
|
||||||
|
nc_connect_pid=$!
|
||||||
|
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
kill $nc_listen_pid $nc_connect_pid $proxyd_pid $proxy_pid
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# first no-network baseline
|
||||||
|
dd if=/dev/zero bs=128M count=10 | cat >/dev/null
|
||||||
|
|
||||||
|
# now openbsd netcat for network baseline
|
||||||
|
nc -lup 51822 >/dev/null &
|
||||||
|
nc_listen_pid=$!
|
||||||
|
|
||||||
|
dd if=/dev/zero bs=128M count=10 | nc -u 127.0.0.1 51822 &
|
||||||
|
nc_connect_pid=$!
|
||||||
|
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
kill $nc_listen_pid $nc_connect_pid
|
||||||
|
|
||||||
|
# first run without TLS
|
||||||
|
#cargo clean
|
||||||
|
cargo build --release --no-default-features 2>/dev/null || exit 1
|
||||||
|
run_tests || exit 1
|
||||||
|
|
||||||
|
# third run with async+rustls
|
||||||
|
#cargo clean
|
||||||
|
cargo build --release --no-default-features --features async 2>/dev/null || exit 1
|
||||||
|
# first plaintext tests
|
||||||
|
run_tests || exit 1
|
||||||
|
# then TLS tests
|
||||||
|
run_tests --tls --tls-key ci/cert.key --tls-cert ci/cert.pem || exit 1
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
# first run with non-vendored tls
|
||||||
|
#cargo clean
|
||||||
|
cargo build --release --no-default-features --features tls 2>/dev/null || exit 1
|
||||||
|
# first plaintext tests
|
||||||
|
run_tests || exit 1
|
||||||
|
# then TLS tests
|
||||||
|
run_tests --tls --tls-key ci/cert.key --tls-cert ci/cert.pem || exit 1
|
||||||
|
|
||||||
|
# second run with vendored tls
|
||||||
|
#cargo clean
|
||||||
|
cargo build --release --no-default-features --features openssl_vendored 2>/dev/null || exit 1
|
||||||
|
# first plaintext tests
|
||||||
|
run_tests || exit 1
|
||||||
|
# then TLS tests
|
||||||
|
run_tests --tls --tls-key ci/cert.key --tls-cert ci/cert.pem || exit 1
|
||||||
|
|
||||||
|
exit 0
|
@ -1,24 +0,0 @@
|
|||||||
# This script takes care of packaging the build artifacts that will go in the
|
|
||||||
# release zipfile
|
|
||||||
|
|
||||||
$SRC_DIR = $PWD.Path
|
|
||||||
$STAGE = [System.Guid]::NewGuid().ToString()
|
|
||||||
|
|
||||||
Set-Location $ENV:Temp
|
|
||||||
New-Item -Type Directory -Name $STAGE
|
|
||||||
Set-Location $STAGE
|
|
||||||
|
|
||||||
$ZIP = "$SRC_DIR\$($Env:CRATE_NAME)-$($Env:APPVEYOR_REPO_TAG_NAME)-$($Env:TARGET).zip"
|
|
||||||
|
|
||||||
# TODO Update this to package the right artifacts
|
|
||||||
Copy-Item "$SRC_DIR\target\$($Env:TARGET)\release\wireguard-proxyd.exe" '.\'
|
|
||||||
Copy-Item "$SRC_DIR\target\$($Env:TARGET)\release\wireguard-proxy.exe" '.\'
|
|
||||||
|
|
||||||
7z a "$ZIP" *
|
|
||||||
|
|
||||||
Push-AppveyorArtifact "$ZIP"
|
|
||||||
|
|
||||||
Remove-Item *.* -Force
|
|
||||||
Set-Location ..
|
|
||||||
Remove-Item $STAGE
|
|
||||||
Set-Location $SRC_DIR
|
|
@ -1,43 +0,0 @@
|
|||||||
# This script takes care of building your crate and packaging it for release
|
|
||||||
|
|
||||||
set -ex
|
|
||||||
|
|
||||||
main() {
|
|
||||||
local src=$(pwd) \
|
|
||||||
stage=
|
|
||||||
|
|
||||||
case $TRAVIS_OS_NAME in
|
|
||||||
linux)
|
|
||||||
stage=$(mktemp -d)
|
|
||||||
;;
|
|
||||||
osx)
|
|
||||||
stage=$(mktemp -d -t tmp)
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
test -f Cargo.lock || cargo generate-lockfile
|
|
||||||
|
|
||||||
# TODO Update this to build the artifacts that matter to you
|
|
||||||
cross rustc --bin wireguard-proxy --target $TARGET --release -- -C lto
|
|
||||||
cross rustc --bin wireguard-proxyd --target $TARGET --release -- -C lto
|
|
||||||
|
|
||||||
# TODO Update this to package the right artifacts, this needs to handle .exe too...
|
|
||||||
case $TARGET in
|
|
||||||
x86_64-pc-windows-gnu)
|
|
||||||
strip target/$TARGET/release/wireguard-proxy.exe target/$TARGET/release/wireguard-proxyd.exe || echo 'strip failed, ignoring...'
|
|
||||||
cp target/$TARGET/release/wireguard-proxy.exe target/$TARGET/release/wireguard-proxyd.exe $stage/
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
strip target/$TARGET/release/wireguard-proxy target/$TARGET/release/wireguard-proxyd || echo 'strip failed, ignoring...'
|
|
||||||
cp target/$TARGET/release/wireguard-proxy target/$TARGET/release/wireguard-proxyd $stage/
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
cd $stage
|
|
||||||
tar czf $src/$CRATE_NAME-$TRAVIS_TAG-$TARGET.tar.gz *
|
|
||||||
cd $src
|
|
||||||
|
|
||||||
rm -rf $stage
|
|
||||||
}
|
|
||||||
|
|
||||||
main
|
|
28
ci/cert.key
Normal file
28
ci/cert.key
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCrvZ+p0/2i/p1s
|
||||||
|
xzg3ydOS4z5S3QD0WAD1gdBTUBPjqmeGNbtXl5XLGPTYJeBqNNGRv6louB+jL8U+
|
||||||
|
TSBsyyARVZfJ9EDU3iG1fOQzz6sK8yhVL15bL4wJHobDGkL1zc0//ozDbr9iH5Xi
|
||||||
|
5Xh1q9lEyLMviASNjZbWcdGWxxKQRceluzcTyowesBr7K9nQaQF7cSmetCYaA1L9
|
||||||
|
JXokHY3P8pPEOhfo8SI7Lkt7XzKrnI0RBEIQBDF5F/XsKHO2Iso8bVq1huNr37MH
|
||||||
|
QDEDo+D8803oFS+89j9SFDv2QgITZgl0gtY5w911qbNtyz0hWYloXzmlPH2QF/+Z
|
||||||
|
XThI2Kd/AgMBAAECggEARmvN4Xxsv346HRWfhri6ibumnaHDt22yjvj47ICkdzEz
|
||||||
|
nAPCWwtsP8hu9Yaqe8JGwMXfeHIvfuGitoY3qoSsFI+NWyFNyDuBhQK+LESWNTo5
|
||||||
|
qpxuy2M2v7KFvdCx7krCQ+Bj5esujNS4yD4h49Zgk+TcHLxgaY7KcAphz7q3cPKP
|
||||||
|
hJPkwSvFmLMdqomyLJfBTWPx6Ue3ioAfKxM62hbaYlBth1ch5YqOhL84YCMnPmbq
|
||||||
|
hL/iTTlPcXeZoCodEHoOac/t8Nvv4fRetrBqk9uMZXZ1Bm9VfKbVDysfiKp9W+np
|
||||||
|
uvtYUht/TdlrzjE01h3QHNnkYgJA+yuK/qjL0nvoYQKBgQDjN4HdZqA7ZBPvQUtq
|
||||||
|
LVfpm2jy/8Sf3ewUUx7Pwselft7FOpKzkouVhdyWY8BweN97zwaYPJo7OtfMzT3Y
|
||||||
|
NPO5Vz7nxMcvwZXir0VV514lLIYjqkZkDY94thGayFaF8DmyqfIfTuyVPrigRfOR
|
||||||
|
8+dbYJrSVn9hnP4i9cxoIu39TwKBgQDBfxAFp2gJ1G3U2YAjNt4qrbsdPZvsX6CI
|
||||||
|
A8T5EuiPanAqaVWbQnkPFQq077qBSlCI/zUunw01I0pyuR74paY7PaiKT3hLkovh
|
||||||
|
v2VlOFEMaA7K/TTjv6tZS5P8DXuM/r34h5XRVsaKXKPNBGoAcbvanJ/96N42j+E1
|
||||||
|
G4+R8FMG0QKBgFMmKfkKqFJzojPpEh8N7uEHRVW/sYXLYaxiaqEfJ45xqjZE5BCg
|
||||||
|
7UHPldTXNkIyiZ42ObSWYN6R/wzsgthPMG2/9r48LaRVVHN7LoVsQPCbpY8BrfbJ
|
||||||
|
W5qSDkk1TSyAp6yxMnCwojVPmaLVVngv6Jdw99dHXiAronjKuH3XYn5TAoGAUUpd
|
||||||
|
Y9Kx3bdWMR7zO1gYvBtiyeURNZvzKFFVFkMAWwgfeWHpaiHiFBkF93/jfd/Ht9Zn
|
||||||
|
9F8zwEhERbBKN7H4BVlhDkJWyoEVrVCoe37OZgTtehAogSoMBaa/1Buh9VksXFYx
|
||||||
|
9dGb9ZL36fDZy7f8cNpuSNDlUkzeE16x0WECsJECgYBdekYJFJWppHjQ0ID5Jt1T
|
||||||
|
GHQIovXFsHfACIKC1lyytqgtEdSaWQD0SfFsg/s6BYcW7bfs/tejTnbJySvcp3rC
|
||||||
|
+FCznrEfk6wVFuj/nrgB/MpmxbsG2N5EmchRX5YJHVDRtWpQxPkNgRvdNBPkPY54
|
||||||
|
5zSUEJh+lLSg+ZjuM52eOg==
|
||||||
|
-----END PRIVATE KEY-----
|
21
ci/cert.pem
Normal file
21
ci/cert.pem
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDazCCAlOgAwIBAgIUfeb7Ocg4fLv5BEiXLhLS5/fQGm0wDQYJKoZIhvcNAQEL
|
||||||
|
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||||
|
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xOTEyMTcwMjE2MDhaFw0yOTEy
|
||||||
|
MTQwMjE2MDhaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
|
||||||
|
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
|
||||||
|
AQUAA4IBDwAwggEKAoIBAQCrvZ+p0/2i/p1sxzg3ydOS4z5S3QD0WAD1gdBTUBPj
|
||||||
|
qmeGNbtXl5XLGPTYJeBqNNGRv6louB+jL8U+TSBsyyARVZfJ9EDU3iG1fOQzz6sK
|
||||||
|
8yhVL15bL4wJHobDGkL1zc0//ozDbr9iH5Xi5Xh1q9lEyLMviASNjZbWcdGWxxKQ
|
||||||
|
RceluzcTyowesBr7K9nQaQF7cSmetCYaA1L9JXokHY3P8pPEOhfo8SI7Lkt7XzKr
|
||||||
|
nI0RBEIQBDF5F/XsKHO2Iso8bVq1huNr37MHQDEDo+D8803oFS+89j9SFDv2QgIT
|
||||||
|
Zgl0gtY5w911qbNtyz0hWYloXzmlPH2QF/+ZXThI2Kd/AgMBAAGjUzBRMB0GA1Ud
|
||||||
|
DgQWBBSxoWXwmMEmKrsRsii2l1/IBhlvMzAfBgNVHSMEGDAWgBSxoWXwmMEmKrsR
|
||||||
|
sii2l1/IBhlvMzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB3
|
||||||
|
NIlwmAL3FBrqHmg5M+zh+xKkNl/O8SK4bJwhPoTYR+DHsDlEQWvwSVaGV5HGyqy2
|
||||||
|
cv39kHJ6OisSuOitESV4gdOUZvm/WCSV5xHpokJpGlztRSKi4iwFNONn0LUi4lnF
|
||||||
|
gkYgjS4OfOCjVJ0YgAkYaBYALM3PTY3VpG32vaz62A7mIzO5Jn/kMtEIgFT+32Be
|
||||||
|
BE/8E+pcOhgkvoE1xwv0STbrnM8dGN8/zyXvb1wt4b2ijkBlT5Wsqs0yvPa31SD0
|
||||||
|
FDqc+4/H3bJXjwfBGDbf18sTY1UQEPyQdNC7vhiy/w2AgjVNjVpNBI9nvj+9rkZ5
|
||||||
|
8m8sP3ldEkdIqSRCl95o
|
||||||
|
-----END CERTIFICATE-----
|
@ -1,47 +0,0 @@
|
|||||||
set -ex
|
|
||||||
|
|
||||||
main() {
|
|
||||||
local target=
|
|
||||||
if [ $TRAVIS_OS_NAME = linux ]; then
|
|
||||||
target=x86_64-unknown-linux-musl
|
|
||||||
sort=sort
|
|
||||||
else
|
|
||||||
target=x86_64-apple-darwin
|
|
||||||
sort=gsort # for `sort --sort-version`, from brew's coreutils.
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Builds for iOS are done on OSX, but require the specific target to be
|
|
||||||
# installed.
|
|
||||||
case $TARGET in
|
|
||||||
aarch64-apple-ios)
|
|
||||||
rustup target install aarch64-apple-ios
|
|
||||||
;;
|
|
||||||
armv7-apple-ios)
|
|
||||||
rustup target install armv7-apple-ios
|
|
||||||
;;
|
|
||||||
armv7s-apple-ios)
|
|
||||||
rustup target install armv7s-apple-ios
|
|
||||||
;;
|
|
||||||
i386-apple-ios)
|
|
||||||
rustup target install i386-apple-ios
|
|
||||||
;;
|
|
||||||
x86_64-apple-ios)
|
|
||||||
rustup target install x86_64-apple-ios
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# This fetches latest stable release
|
|
||||||
local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \
|
|
||||||
| cut -d/ -f3 \
|
|
||||||
| grep -E '^v[0.1.0-9.]+$' \
|
|
||||||
| $sort --version-sort \
|
|
||||||
| tail -n1)
|
|
||||||
curl -LSfs https://japaric.github.io/trust/install.sh | \
|
|
||||||
sh -s -- \
|
|
||||||
--force \
|
|
||||||
--git japaric/cross \
|
|
||||||
--tag $tag \
|
|
||||||
--target $target
|
|
||||||
}
|
|
||||||
|
|
||||||
main
|
|
24
ci/script.sh
24
ci/script.sh
@ -1,24 +0,0 @@
|
|||||||
# This script takes care of testing your crate
|
|
||||||
|
|
||||||
set -ex
|
|
||||||
|
|
||||||
# TODO This is the "test phase", tweak it as you see fit
|
|
||||||
main() {
|
|
||||||
cross build --target $TARGET
|
|
||||||
cross build --target $TARGET --release
|
|
||||||
|
|
||||||
if [ ! -z $DISABLE_TESTS ]; then
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
# first make sure udp-test succeeds running against itself
|
|
||||||
cross run --target $TARGET --release --bin udp-test
|
|
||||||
|
|
||||||
# now run udp-test through proxy/proxyd
|
|
||||||
cross run --target $TARGET --release --bin udp-test -- -is
|
|
||||||
}
|
|
||||||
|
|
||||||
# we don't run the "test phase" when doing deploys
|
|
||||||
if [ -z $TRAVIS_TAG ]; then
|
|
||||||
main
|
|
||||||
fi
|
|
304
src/asyncmod.rs
Normal file
304
src/asyncmod.rs
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
|
||||||
|
use tokio::net::UdpSocket;
|
||||||
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
|
use tokio::runtime::Runtime;
|
||||||
|
use tokio_rustls::webpki::DNSNameRef;
|
||||||
|
|
||||||
|
use crate::error;
|
||||||
|
use crate::error::Result;
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
pub struct TcpUdpPipe<T: AsyncReadExt + AsyncWriteExt + std::marker::Unpin + std::marker::Send + 'static> {
|
||||||
|
buf: [u8; 2050], // 2048 + 2 for len
|
||||||
|
tcp_stream: T,
|
||||||
|
udp_socket: UdpSocket,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AsyncReadExt + AsyncWriteExt + std::marker::Unpin + std::marker::Send + 'static> TcpUdpPipe<T> {
|
||||||
|
|
||||||
|
pub fn new(tcp_stream: T, udp_socket: UdpSocket) -> TcpUdpPipe<T> {
|
||||||
|
TcpUdpPipe {
|
||||||
|
tcp_stream,
|
||||||
|
udp_socket,
|
||||||
|
buf: [0u8; 2050],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn shuffle_after_first_udp(mut self) -> Result<usize> {
|
||||||
|
let (len, src_addr) = self.udp_socket.recv_from(&mut self.buf[2..]).await?;
|
||||||
|
|
||||||
|
println!("first packet from {}, connecting to that", src_addr);
|
||||||
|
self.udp_socket.connect(src_addr).await?;
|
||||||
|
|
||||||
|
send_udp(&mut self.buf, &mut self.tcp_stream, len).await?;
|
||||||
|
|
||||||
|
self.shuffle().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn shuffle(self) -> Result<usize> {
|
||||||
|
// todo: investigate https://docs.rs/tokio/0.2.22/tokio/net/struct.TcpStream.html#method.into_split
|
||||||
|
let (mut tcp_rd, mut tcp_wr) = tokio::io::split(self.tcp_stream);
|
||||||
|
let (mut udp_rd, mut udp_wr) = self.udp_socket.split();
|
||||||
|
let mut recv_buf = self.buf.clone(); // or zeroed or?
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
loop {
|
||||||
|
let len = udp_rd.recv(&mut recv_buf[2..]).await?;
|
||||||
|
send_udp(&mut recv_buf, &mut tcp_wr, len).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sometimes, the rust type inferencer needs
|
||||||
|
// a little help
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
{
|
||||||
|
unsafe { std::hint::unreachable_unchecked(); }
|
||||||
|
Ok::<_, error::Error>(())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut send_buf = self.buf.clone(); // or zeroed or?
|
||||||
|
|
||||||
|
loop {
|
||||||
|
tcp_rd.read_exact(&mut send_buf[..2]).await?;
|
||||||
|
let len = ((send_buf[0] as usize) << 8) + send_buf[1] as usize;
|
||||||
|
#[cfg(feature = "verbose")]
|
||||||
|
println!("tcp expecting len: {}", len);
|
||||||
|
tcp_rd.read_exact(&mut send_buf[..len]).await?;
|
||||||
|
#[cfg(feature = "verbose")]
|
||||||
|
println!("tcp got len: {}", len);
|
||||||
|
udp_wr.send(&send_buf[..len]).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
{
|
||||||
|
unsafe { std::hint::unreachable_unchecked(); }
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_udp<T: AsyncWriteExt + std::marker::Unpin + 'static>(buf: &mut [u8; 2050], tcp_stream: &mut T, len: usize) -> Result<()> {
|
||||||
|
#[cfg(feature = "verbose")]
|
||||||
|
println!("udp got len: {}", len);
|
||||||
|
|
||||||
|
buf[0] = ((len >> 8) & 0xFF) as u8;
|
||||||
|
buf[1] = (len & 0xFF) as u8;
|
||||||
|
|
||||||
|
// todo: tcp_stream.write_all(&buf[..len + 2]).await
|
||||||
|
Ok(tcp_stream.write_all(&buf[..len + 2]).await?)
|
||||||
|
// todo: do this? self.tcp_stream.flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProxyClient {
|
||||||
|
|
||||||
|
pub async fn start_async(&self) -> Result<usize> {
|
||||||
|
let tcp_stream = self.tcp_connect()?;
|
||||||
|
|
||||||
|
let udp_socket = self.udp_connect()?;
|
||||||
|
|
||||||
|
TcpUdpPipe::new(tokio::net::TcpStream::from_std(tcp_stream).expect("how could this tokio tcp fail?"), UdpSocket::from_std(udp_socket).expect("how could this tokio udp fail?"))
|
||||||
|
.shuffle_after_first_udp().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start(&self) -> Result<usize> {
|
||||||
|
let mut rt = Runtime::new()?;
|
||||||
|
|
||||||
|
rt.block_on(async {
|
||||||
|
self.start_async().await
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn start_tls_async(&self, hostname: Option<&str>, pinnedpubkey: Option<&str>) -> Result<usize> {
|
||||||
|
let tcp_stream = self.tcp_connect()?;
|
||||||
|
let tcp_stream = tokio::net::TcpStream::from_std(tcp_stream).expect("how could this tokio tcp fail?");
|
||||||
|
|
||||||
|
use tokio_rustls::{ TlsConnector, rustls::ClientConfig };
|
||||||
|
|
||||||
|
let mut config = ClientConfig::new();
|
||||||
|
config.dangerous().set_certificate_verifier(match pinnedpubkey {
|
||||||
|
Some(pinnedpubkey) => Arc::new(PinnedpubkeyCertVerifier { pinnedpubkey: pinnedpubkey.to_owned() }),
|
||||||
|
None => Arc::new(DummyCertVerifier{}),
|
||||||
|
});
|
||||||
|
|
||||||
|
let hostname = match hostname {
|
||||||
|
Some(hostname) => match DNSNameRef::try_from_ascii_str(hostname) {
|
||||||
|
Ok(hostname) => hostname,
|
||||||
|
Err(_) => {
|
||||||
|
config.enable_sni = false;
|
||||||
|
DNSNameRef::try_from_ascii_str(&"dummy.hostname").unwrap() // why does rustls ABSOLUTELY REQUIRE this ????
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
config.enable_sni = false;
|
||||||
|
DNSNameRef::try_from_ascii_str(&"dummy.hostname").unwrap() // why does rustls ABSOLUTELY REQUIRE this ????
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//println!("hostname: {:?}", hostname);
|
||||||
|
|
||||||
|
let connector = TlsConnector::from(Arc::new(config));
|
||||||
|
|
||||||
|
let tcp_stream= connector.connect(hostname, tcp_stream).await?;
|
||||||
|
|
||||||
|
let udp_socket = self.udp_connect()?;
|
||||||
|
|
||||||
|
// we want to wait for first udp packet from client first, to set the target to respond to
|
||||||
|
TcpUdpPipe::new(tcp_stream, UdpSocket::from_std(udp_socket).expect("how could this tokio udp fail?"))
|
||||||
|
.shuffle_after_first_udp().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_tls(&self, hostname: Option<&str>, pinnedpubkey: Option<&str>) -> Result<usize> {
|
||||||
|
let mut rt = Runtime::new()?;
|
||||||
|
|
||||||
|
rt.block_on(async {
|
||||||
|
self.start_tls_async(hostname, pinnedpubkey).await
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use tokio_rustls::rustls;
|
||||||
|
use tokio_rustls::webpki;
|
||||||
|
|
||||||
|
struct DummyCertVerifier;
|
||||||
|
|
||||||
|
impl rustls::ServerCertVerifier for DummyCertVerifier {
|
||||||
|
fn verify_server_cert(&self,
|
||||||
|
_roots: &rustls::RootCertStore,
|
||||||
|
_certs: &[rustls::Certificate],
|
||||||
|
_hostname: webpki::DNSNameRef<'_>,
|
||||||
|
_ocsp: &[u8]) -> core::result::Result<rustls::ServerCertVerified, rustls::TLSError> {
|
||||||
|
// verify nothing, subject to MITM
|
||||||
|
Ok(rustls::ServerCertVerified::assertion())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PinnedpubkeyCertVerifier {
|
||||||
|
pinnedpubkey: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl rustls::ServerCertVerifier for PinnedpubkeyCertVerifier {
|
||||||
|
fn verify_server_cert(&self,
|
||||||
|
_roots: &rustls::RootCertStore,
|
||||||
|
certs: &[rustls::Certificate],
|
||||||
|
_hostname: webpki::DNSNameRef<'_>,
|
||||||
|
_ocsp: &[u8]) -> core::result::Result<rustls::ServerCertVerified, rustls::TLSError> {
|
||||||
|
if certs.is_empty() {
|
||||||
|
return Err(rustls::TLSError::NoCertificatesPresented);
|
||||||
|
}
|
||||||
|
let cert = webpki::trust_anchor_util::cert_der_as_trust_anchor(&certs[0].0)
|
||||||
|
.map_err(rustls::TLSError::WebPKIError)?;
|
||||||
|
|
||||||
|
//println!("spki.len(): {}", cert.spki.len());
|
||||||
|
//println!("spki: {:?}", cert.spki);
|
||||||
|
// todo: what is wrong with webpki? it returns *almost* the right answer but missing these leading bytes:
|
||||||
|
// guess I'll open an issue... (I assume this is some type of algorithm identifying header or something)
|
||||||
|
let mut pubkey: Vec<u8> = vec![48, 130, 1, 34];
|
||||||
|
pubkey.extend(cert.spki);
|
||||||
|
|
||||||
|
let pubkey = ring::digest::digest(&ring::digest::SHA256, &pubkey);
|
||||||
|
let pubkey = base64::encode(pubkey);
|
||||||
|
let pubkey = ["sha256//", &pubkey].join("");
|
||||||
|
|
||||||
|
for key in self.pinnedpubkey.split(";") {
|
||||||
|
if key == pubkey {
|
||||||
|
return Ok(rustls::ServerCertVerified::assertion());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(rustls::TLSError::General(format!("pubkey '{}' not found in allowed list '{}'", pubkey, self.pinnedpubkey)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProxyServer {
|
||||||
|
|
||||||
|
pub async fn start_async(&self) -> Result<()> {
|
||||||
|
let mut listener = tokio::net::TcpListener::bind(&self.tcp_host).await?;
|
||||||
|
println!("Listening for connections on {}", &self.tcp_host);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let (stream, _) = listener.accept().await?;
|
||||||
|
let client_handler = self.client_handler.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
client_handler
|
||||||
|
.handle_client_async(stream).await
|
||||||
|
.expect("error handling connection");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
{
|
||||||
|
unsafe { std::hint::unreachable_unchecked(); }
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start(&self) -> Result<()> {
|
||||||
|
let mut rt = Runtime::new()?;
|
||||||
|
|
||||||
|
rt.block_on(async {
|
||||||
|
self.start_async().await
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn start_tls_async(&self, tls_key: &str, tls_cert: &str) -> Result<()> {
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::BufReader;
|
||||||
|
use std::io;
|
||||||
|
use tokio_rustls::rustls::internal::pemfile::{ certs, pkcs8_private_keys };
|
||||||
|
|
||||||
|
let mut tls_key = pkcs8_private_keys(&mut BufReader::new(File::open(tls_key)?))
|
||||||
|
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid key"))?;
|
||||||
|
if tls_key.is_empty() {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid key"))?;
|
||||||
|
}
|
||||||
|
let tls_key = tls_key.remove(0);
|
||||||
|
|
||||||
|
let tls_cert = certs(&mut BufReader::new(File::open(tls_cert)?))
|
||||||
|
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid cert"))?;
|
||||||
|
|
||||||
|
let mut config = rustls::ServerConfig::new(rustls::NoClientAuth::new());
|
||||||
|
config.set_single_cert(tls_cert, tls_key)
|
||||||
|
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?;
|
||||||
|
let acceptor = tokio_rustls::TlsAcceptor::from(Arc::new(config));
|
||||||
|
|
||||||
|
let mut listener = tokio::net::TcpListener::bind(&self.tcp_host).await?;
|
||||||
|
println!("Listening for TLS connections on {}", &self.tcp_host);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let (stream, _) = listener.accept().await?;
|
||||||
|
let client_handler = self.client_handler.clone();
|
||||||
|
let acceptor = acceptor.clone();
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let stream = acceptor.accept(stream).await.expect("failed to wrap with TLS?");
|
||||||
|
|
||||||
|
client_handler
|
||||||
|
.handle_client_async(stream).await
|
||||||
|
.expect("error handling connection");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
{
|
||||||
|
unsafe { std::hint::unreachable_unchecked(); }
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_tls(&self, tls_key: &str, tls_cert: &str) -> Result<()> {
|
||||||
|
let mut rt = Runtime::new()?;
|
||||||
|
|
||||||
|
rt.block_on(async {
|
||||||
|
self.start_tls_async(tls_key, tls_cert).await
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProxyServerClientHandler {
|
||||||
|
|
||||||
|
pub async fn handle_client_async<T: AsyncReadExt + AsyncWriteExt + std::marker::Unpin + std::marker::Send + 'static>(&self, tcp_stream: T) -> Result<usize> {
|
||||||
|
TcpUdpPipe::new(tcp_stream,
|
||||||
|
UdpSocket::from_std(self.udp_bind()?).expect("how could this tokio udp fail?")
|
||||||
|
).shuffle().await
|
||||||
|
}
|
||||||
|
}
|
@ -50,6 +50,22 @@ impl Server {
|
|||||||
assert_eq!(sent, PONG.len());
|
assert_eq!(sent, PONG.len());
|
||||||
|
|
||||||
let mut buf = [0u8; 2048];
|
let mut buf = [0u8; 2048];
|
||||||
|
match udp_socket.recv_from(&mut buf) {
|
||||||
|
Ok((len, src_addr)) => {
|
||||||
|
println!("udp got len: {} from src_addr: {}", len, src_addr);
|
||||||
|
assert_eq!(len, PONG.len());
|
||||||
|
assert_eq!(&buf[..len], &PONG[..]);
|
||||||
|
|
||||||
|
// now reply back to src_addr to make sure other direction works
|
||||||
|
let sent = udp_socket.send_to(&PONG, &src_addr)?;
|
||||||
|
assert_eq!(sent, PONG.len());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
panic!("recv function failed first round: {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we are here, we successfully sent the reply, did we get it back?
|
||||||
match udp_socket.recv(&mut buf) {
|
match udp_socket.recv(&mut buf) {
|
||||||
Ok(len) => {
|
Ok(len) => {
|
||||||
println!("udp got len: {}", len);
|
println!("udp got len: {}", len);
|
||||||
@ -57,11 +73,11 @@ impl Server {
|
|||||||
assert_eq!(&buf[..len], &PONG[..]);
|
assert_eq!(&buf[..len], &PONG[..]);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
panic!("recv function failed: {:?}", e);
|
panic!("recv function failed second round: {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("success! received back exactly what we sent!");
|
println!("success! received back exactly what we sent both ways!");
|
||||||
|
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
@ -70,41 +86,128 @@ impl Server {
|
|||||||
fn main() {
|
fn main() {
|
||||||
let raw_args = env::args().collect();
|
let raw_args = env::args().collect();
|
||||||
let args = Args::new(&raw_args);
|
let args = Args::new(&raw_args);
|
||||||
let mut first_arg = args.get_str(1, "127.0.0.1:51821");
|
|
||||||
if first_arg.contains("-h") {
|
if args.flag("-V") || args.flag("--version") {
|
||||||
println!(
|
print!("udp-test {} ", env!("CARGO_PKG_VERSION"));
|
||||||
"usage: {} [-h] [-s run a self test through proxy/proxyd] [-is run a self test through proxy/proxyd without spawning other processes] [udp_host, 127.0.0.1:51821] [udp_target, 127.0.0.1:51821] [socket_timeout, 10]",
|
#[cfg(not(any(feature = "tls", feature = "openssl_vendored")))]
|
||||||
args.get_str(0, "udp-test")
|
println!("TLS support: None");
|
||||||
);
|
#[cfg(feature = "openssl_vendored")]
|
||||||
|
println!("TLS support: Static/Vendored OpenSSL");
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
|
println!("TLS support: System OpenSSL");
|
||||||
return;
|
return;
|
||||||
} else if first_arg.contains("-s") {
|
}
|
||||||
|
|
||||||
|
let default_udp_host_target = "127.0.0.1:51820";
|
||||||
|
let default_socket_timeout = 10;
|
||||||
|
|
||||||
|
let tls_key = args.get_option(&["-tk", "--tls-key"]);
|
||||||
|
let tls_cert = args.get_option(&["-tc", "--tls-cert"]);
|
||||||
|
let pinnedpubkey = args.get_option(&["--pinnedpubkey"]);
|
||||||
|
|
||||||
|
let tls = if tls_key.is_some() && tls_cert.is_some() {
|
||||||
|
true
|
||||||
|
} else if tls_key.is_none() && tls_cert.is_none() {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
println!("Error: if one of --tls-key or --tls-cert is specified both must be!");
|
||||||
|
exit(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut first_arg = args.get_str(&["-uh", "--udp-host"], default_udp_host_target);
|
||||||
|
if args.flag("-h") || args.flag("--help") {
|
||||||
|
println!(r#"usage: udp-test [options...]
|
||||||
|
-h, --help print this usage text
|
||||||
|
-V, --version Show version number and TLS support then quit
|
||||||
|
-s, --self-test run a self test through proxy
|
||||||
|
-is, --internal-self-test run a self test through proxy without
|
||||||
|
spawning other processes
|
||||||
|
-uh, --udp-host <ip:port> UDP host to listen on, default: {}
|
||||||
|
-ut, --udp-target <ip:port> UDP target to send packets to, default: {}
|
||||||
|
-st, --socket-timeout <seconds> Socket timeout (time to wait for data)
|
||||||
|
before terminating, default: {}
|
||||||
|
|
||||||
|
TLS option for self tests only, otherwise self tests are plaintext only:
|
||||||
|
-tk, --tls-key <ip:port> TLS key to listen with,
|
||||||
|
requires --tls-cert also
|
||||||
|
-tc, --tls-cert <ip:port> TLS cert to listen with,
|
||||||
|
requires --tls-key also
|
||||||
|
--pinnedpubkey <sha256_hashes> Public key to verify peer against,
|
||||||
|
format is any number of base64 encoded
|
||||||
|
sha256 hashes preceded by "sha256//"
|
||||||
|
and separated by ";". Identical to curl's
|
||||||
|
--pinnedpubkey and CURLOPT_PINNEDPUBLICKEY
|
||||||
|
Note: with both --tls-key and --tls-cert,
|
||||||
|
only for -is (not -s) - means stdin,
|
||||||
|
also the same file can work for both if you combine them into
|
||||||
|
one pem file
|
||||||
|
|
||||||
|
Environment variable support:
|
||||||
|
For every long command line option (starting with --), if you replace the
|
||||||
|
leading -- with WGP_, and replace all remaining - with _, and uppercase
|
||||||
|
the whole thing, if you don't specify that command line option we will
|
||||||
|
read that environment variable for the argument. boolean arguments are
|
||||||
|
true if anything but unset, empty, 0, or false.
|
||||||
|
Examples:
|
||||||
|
--tcp-target ARG is WGP_TCP_TARGET=ARG
|
||||||
|
--socket-timeout 5 is WGP_SOCKET_TIMEOUT=5
|
||||||
|
--tls is WGP_TLS=1 or WGP_TLS=true
|
||||||
|
WGP_TLS=0 or WGP_TLS=false would be like not sending --tls
|
||||||
|
"#, default_udp_host_target, default_udp_host_target, default_socket_timeout);
|
||||||
|
return;
|
||||||
|
} else if args.flag("-s") || args.flag("--self-test") {
|
||||||
// here is the hard work, we need to spawn proxyd and proxy from the same dir as udp-test...
|
// here is the hard work, we need to spawn proxyd and proxy from the same dir as udp-test...
|
||||||
let host = "127.0.0.1:51822";
|
let host = "127.0.0.1:51822";
|
||||||
let tcp_host = "127.0.0.1:5555";
|
let tcp_host = "127.0.0.1:5555";
|
||||||
let sleep = Duration::from_secs(5);
|
let sleep = Duration::from_secs(5);
|
||||||
|
|
||||||
let udp_test = args.get_str(0, "udp-test");
|
let udp_test = std::env::current_exe().expect("cannot get path to current executable");
|
||||||
let proxyd = udp_test.clone().replace("udp-test", "wireguard-proxyd");
|
let proxy = udp_test.clone().with_file_name("wireguard-proxy")
|
||||||
let proxy = udp_test.clone().replace("udp-test", "wireguard-proxy");
|
.with_extension(udp_test.extension().unwrap_or_else(|| "".as_ref()));
|
||||||
|
|
||||||
println!("executing: {} '{}' '{}'", proxyd, tcp_host, host);
|
let udp_test = udp_test.to_str().expect("non-utf8 executable path?");
|
||||||
let mut proxyd = Command::new(proxyd)
|
let proxy = proxy.to_str().expect("non-utf8 executable path?");
|
||||||
.arg(tcp_host)
|
|
||||||
.arg(host)
|
let mut proxyd_args = vec!["-th", tcp_host, "-ut", host];
|
||||||
|
|
||||||
|
let tls_key = tls_key.as_ref().map(String::as_str);
|
||||||
|
let tls_cert = tls_cert.as_ref().map(String::as_str);
|
||||||
|
if tls {
|
||||||
|
let tls_key = tls_key.unwrap();
|
||||||
|
let tls_cert = tls_cert.unwrap();
|
||||||
|
proxyd_args.extend(["-tk", &tls_key, "-tc", &tls_cert].iter().cloned());
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("executing: {} {}", proxy, proxyd_args.join(" "));
|
||||||
|
let mut proxyd = Command::new(proxy.clone())
|
||||||
|
.args(&proxyd_args)
|
||||||
.spawn()
|
.spawn()
|
||||||
.expect("wireguard-proxyd failed to launch");
|
.expect("wireguard-proxy server failed to launch");
|
||||||
println!("waiting: {:?} for wireguard-proxyd to come up.....", sleep);
|
println!("waiting: {:?} for wireguard-proxy server to come up.....", sleep);
|
||||||
thread::sleep(sleep);
|
thread::sleep(sleep);
|
||||||
|
|
||||||
println!("executing: {}", proxy);
|
let mut proxy_args = vec!["-tt", tcp_host];
|
||||||
|
|
||||||
|
let pinnedpubkey = pinnedpubkey.as_ref().map(String::as_str);
|
||||||
|
if tls {
|
||||||
|
proxy_args.push("--tls");
|
||||||
|
if pinnedpubkey.is_some() {
|
||||||
|
proxy_args.push("--pinnedpubkey");
|
||||||
|
proxy_args.push(&pinnedpubkey.unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("executing: {} {}", proxy, proxy_args.join(" "));
|
||||||
let mut proxy = Command::new(proxy)
|
let mut proxy = Command::new(proxy)
|
||||||
|
.args(proxy_args)
|
||||||
.spawn()
|
.spawn()
|
||||||
.expect("wireguard-proxy failed to launch");
|
.expect("wireguard-proxy TLS client failed to launch");
|
||||||
println!("waiting: {:?} for wireguard-proxy to come up.....", sleep);
|
println!("waiting: {:?} for wireguard-proxy client to come up.....", sleep);
|
||||||
thread::sleep(sleep);
|
thread::sleep(sleep);
|
||||||
|
|
||||||
println!("executing: {} '{}'", udp_test, host);
|
println!("executing: {} -uh '{}'", udp_test, host);
|
||||||
let mut udp_test = Command::new(udp_test)
|
let mut udp_test = Command::new(udp_test)
|
||||||
|
.arg("-uh")
|
||||||
.arg(host)
|
.arg(host)
|
||||||
.spawn()
|
.spawn()
|
||||||
.expect("udp-test failed to launch");
|
.expect("udp-test failed to launch");
|
||||||
@ -123,7 +226,7 @@ fn main() {
|
|||||||
.code()
|
.code()
|
||||||
.expect("could not get udp-test exit code"),
|
.expect("could not get udp-test exit code"),
|
||||||
);
|
);
|
||||||
} else if first_arg.contains("-is") {
|
} else if args.flag("-is") || args.flag("--internal-self-test") {
|
||||||
let host = "127.0.0.1:51822";
|
let host = "127.0.0.1:51822";
|
||||||
let tcp_host = "127.0.0.1:5555";
|
let tcp_host = "127.0.0.1:5555";
|
||||||
let sleep = Duration::from_secs(5);
|
let sleep = Duration::from_secs(5);
|
||||||
@ -142,38 +245,58 @@ fn main() {
|
|||||||
proxy_server.client_handler.udp_target, proxy_server.client_handler.socket_timeout,
|
proxy_server.client_handler.udp_target, proxy_server.client_handler.socket_timeout,
|
||||||
);
|
);
|
||||||
|
|
||||||
println!("executing: wireguard-proxyd '{}' '{}'", tcp_host, host);
|
if tls {
|
||||||
|
let tls_key = tls_key.unwrap().to_owned();
|
||||||
|
let tls_cert = tls_cert.unwrap().to_owned();
|
||||||
|
println!("executing: wireguard-proxy -th '{}' -ut '{}' -tk '{}' -tc '{}'", tcp_host, host, tls_key, tls_cert);
|
||||||
|
thread::spawn(move || proxy_server.start_tls(&tls_key, &tls_cert).expect("error running TLS proxy_server"));
|
||||||
|
} else {
|
||||||
|
println!("executing: wireguard-proxy -th '{}' -ut '{}'", tcp_host, host);
|
||||||
thread::spawn(move || proxy_server.start().expect("error running proxy_server"));
|
thread::spawn(move || proxy_server.start().expect("error running proxy_server"));
|
||||||
println!("waiting: {:?} for wireguard-proxyd to come up.....", sleep);
|
}
|
||||||
|
println!("waiting: {:?} for wireguard-proxy server to come up.....", sleep);
|
||||||
thread::sleep(sleep);
|
thread::sleep(sleep);
|
||||||
|
|
||||||
let proxy_client = ProxyClient::new(
|
let proxy_client = ProxyClient::new(
|
||||||
"127.0.0.1:51821".to_owned(),
|
|
||||||
"127.0.0.1:51820".to_owned(),
|
"127.0.0.1:51820".to_owned(),
|
||||||
tcp_host.to_owned().to_owned(),
|
tcp_host.to_owned(),
|
||||||
15,
|
15,
|
||||||
);
|
);
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"udp_host: {}, udp_target: {}, tcp_target: {}, socket_timeout: {:?}",
|
"udp_host: {}, tcp_target: {}, socket_timeout: {:?}",
|
||||||
proxy_client.udp_host,
|
proxy_client.udp_host,
|
||||||
proxy_client.udp_target,
|
|
||||||
proxy_client.tcp_target,
|
proxy_client.tcp_target,
|
||||||
proxy_client.socket_timeout,
|
proxy_client.socket_timeout,
|
||||||
);
|
);
|
||||||
|
|
||||||
println!("executing: wireguard-proxy");
|
if tls {
|
||||||
|
let hostname = tcp_host.split(":").next();
|
||||||
|
let pinnedpubkey = pinnedpubkey.as_ref().map(String::as_str);
|
||||||
|
match pinnedpubkey {
|
||||||
|
Some(pinnedpubkey) =>
|
||||||
|
println!("executing: wireguard-proxy -tt {} --tls --pinnedpubkey {}", tcp_host, pinnedpubkey),
|
||||||
|
None =>
|
||||||
|
println!("executing: wireguard-proxy -tt {} --tls", tcp_host),
|
||||||
|
}
|
||||||
|
// this is a little funky, is this the only way to do it?
|
||||||
|
let pinnedpubkey = pinnedpubkey.map(&str::to_owned);
|
||||||
|
// can use pinnedpubkey.as_deref() below when it's stabilized
|
||||||
|
thread::spawn(move || proxy_client.start_tls(hostname, pinnedpubkey.as_ref().map(String::as_str)).expect("error running proxy_client"));
|
||||||
|
} else {
|
||||||
|
println!("executing: wireguard-proxy -tt {}", tcp_host);
|
||||||
thread::spawn(move || proxy_client.start().expect("error running proxy_client"));
|
thread::spawn(move || proxy_client.start().expect("error running proxy_client"));
|
||||||
println!("waiting: {:?} for wireguard-proxy to come up.....", sleep);
|
}
|
||||||
|
println!("waiting: {:?} for wireguard-proxy client to come up.....", sleep);
|
||||||
thread::sleep(sleep);
|
thread::sleep(sleep);
|
||||||
|
|
||||||
first_arg = host;
|
first_arg = host.to_owned();
|
||||||
}
|
}
|
||||||
|
|
||||||
let server = Server::new(
|
let server = Server::new(
|
||||||
first_arg.to_owned(),
|
first_arg.to_owned(),
|
||||||
args.get_str(2, "127.0.0.1:51821").to_owned(),
|
args.get_str(&["-ut", "--udp-target"], default_udp_host_target).to_owned(),
|
||||||
args.get(3, 10),
|
args.get(&["-st", "--socket-timeout"], default_socket_timeout),
|
||||||
);
|
);
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
|
@ -1,31 +1,177 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
use wireguard_proxy::{Args, ProxyClient};
|
use wireguard_proxy::{Args, ProxyClient, ProxyServer};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let raw_args = env::args().collect();
|
let raw_args = env::args().collect();
|
||||||
let args = Args::new(&raw_args);
|
let args = Args::new(&raw_args);
|
||||||
if args.get_str(1, "").contains("-h") {
|
|
||||||
println!(
|
if args.flag("-V") || args.flag("--version") {
|
||||||
"usage: {} [-h] [udp_host, 127.0.0.1:51821] [udp_target, 127.0.0.1:51820] [tcp_target, 127.0.0.1:5555] [socket_timeout, 0]",
|
print!("wireguard-proxy {} ", env!("CARGO_PKG_VERSION"));
|
||||||
args.get_str(0, "wireguard-proxy")
|
#[cfg(not(any(feature = "tls", feature = "openssl_vendored", feature = "async")))]
|
||||||
);
|
println!("TLS support: None");
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
println!("TLS support: tokio-rustls");
|
||||||
|
#[cfg(all(feature = "openssl_vendored", not(feature = "async")))]
|
||||||
|
println!("TLS support: Static/Vendored OpenSSL");
|
||||||
|
#[cfg(all(feature = "tls", not(feature = "openssl_vendored"), not(feature = "async")))]
|
||||||
|
println!("TLS support: System OpenSSL");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let default_udp_host_target = "127.0.0.1:51820";
|
||||||
|
let default_socket_timeout = 0;
|
||||||
|
|
||||||
|
let tcp_target = args.get_option(&["-tt", "--tcp-target"]);
|
||||||
|
let tcp_host = args.get_option(&["-th", "--tcp-host"]);
|
||||||
|
|
||||||
|
if args.flag("-h") || args.flag("--help") ||
|
||||||
|
// one of them must be set
|
||||||
|
(tcp_target.is_none() && tcp_host.is_none()) ||
|
||||||
|
// but both cannot be set
|
||||||
|
(tcp_target.is_some() && tcp_host.is_some())
|
||||||
|
{
|
||||||
|
println!(r#"usage: wireguard-proxy [options...]
|
||||||
|
Client Mode (requires --tcp-target):
|
||||||
|
-tt, --tcp-target <ip:port> TCP target to send packets to, where
|
||||||
|
wireguard-proxy server is running
|
||||||
|
-uh, --udp-host <ip:port> UDP host to listen on, point wireguard
|
||||||
|
client here, default: {}
|
||||||
|
--tls use TLS when connecting to tcp-target
|
||||||
|
WARNING: authenticates/verifies nothing
|
||||||
|
without --pinnedpubkey below!!
|
||||||
|
--pinnedpubkey <sha256_hashes> Public key to verify peer against,
|
||||||
|
format is any number of base64 encoded
|
||||||
|
sha256 hashes preceded by "sha256//"
|
||||||
|
and separated by ";". Identical to curl's
|
||||||
|
--pinnedpubkey and CURLOPT_PINNEDPUBLICKEY
|
||||||
|
--tls-hostname send this in SNI instead of host
|
||||||
|
from --tcp-target, useful for avoiding
|
||||||
|
DNS lookup on connect
|
||||||
|
|
||||||
|
Server Mode (requires --tcp-host):
|
||||||
|
-th, --tcp-host <ip:port> TCP host to listen on
|
||||||
|
-ut, --udp-target <ip:port> UDP target to send packets to, where
|
||||||
|
wireguard server is running,
|
||||||
|
default: {}
|
||||||
|
-ur, --udp-bind-host-range <ip:low-high> UDP host and port range to bind to,
|
||||||
|
one port per TCP connection, to
|
||||||
|
listen on for UDP packets to send
|
||||||
|
back over the TCP connection,
|
||||||
|
default: 127.0.0.1:30000-40000
|
||||||
|
-tk, --tls-key <ip:port> TLS key to listen with,
|
||||||
|
requires --tls-cert also
|
||||||
|
-tc, --tls-cert <ip:port> TLS cert to listen with,
|
||||||
|
requires --tls-key also
|
||||||
|
Note: with both --tls-key and --tls-cert,
|
||||||
|
- means stdin,
|
||||||
|
also the same file can work for both if you combine them into
|
||||||
|
one pem file
|
||||||
|
|
||||||
|
Common Options:
|
||||||
|
-h, --help print this usage text
|
||||||
|
-V, --version Show version number and TLS support then quit
|
||||||
|
-st, --socket-timeout <seconds> Socket timeout (time to wait for data)
|
||||||
|
before terminating, default: {}
|
||||||
|
|
||||||
|
Environment variable support:
|
||||||
|
For every long command line option (starting with --), if you replace the
|
||||||
|
leading -- with WGP_, and replace all remaining - with _, and uppercase
|
||||||
|
the whole thing, if you don't specify that command line option we will
|
||||||
|
read that environment variable for the argument. boolean arguments are
|
||||||
|
true if anything but unset, empty, 0, or false.
|
||||||
|
Examples:
|
||||||
|
--tcp-target ARG is WGP_TCP_TARGET=ARG
|
||||||
|
--socket-timeout 5 is WGP_SOCKET_TIMEOUT=5
|
||||||
|
--tls is WGP_TLS=1 or WGP_TLS=true
|
||||||
|
WGP_TLS=0 or WGP_TLS=false would be like not sending --tls
|
||||||
|
"#, default_udp_host_target, default_udp_host_target, default_socket_timeout);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let socket_timeout = args.get(&["-st", "--socket-timeout"], default_socket_timeout);
|
||||||
|
|
||||||
|
if tcp_target.is_some() {
|
||||||
|
client(&tcp_target.unwrap(), socket_timeout, args);
|
||||||
|
} else {
|
||||||
|
server(&tcp_host.unwrap(), socket_timeout, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn client(tcp_target: &str, socket_timeout: u64, args: Args) {
|
||||||
let proxy_client = ProxyClient::new(
|
let proxy_client = ProxyClient::new(
|
||||||
args.get_str(1, "127.0.0.1:51821").to_owned(),
|
args.get_str(&["-uh", "--udp-host"], "127.0.0.1:51820").to_owned(),
|
||||||
args.get_str(2, "127.0.0.1:51820").to_owned(),
|
tcp_target.to_owned(),
|
||||||
args.get_str(3, "127.0.0.1:5555").to_owned(),
|
socket_timeout,
|
||||||
args.get(4, 0),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let tls = args.flag("--tls");
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"udp_host: {}, udp_target: {}, tcp_target: {}, socket_timeout: {:?}",
|
"udp_host: {}, tcp_target: {}, socket_timeout: {:?}, tls: {}",
|
||||||
proxy_client.udp_host,
|
proxy_client.udp_host,
|
||||||
proxy_client.udp_target,
|
|
||||||
proxy_client.tcp_target,
|
proxy_client.tcp_target,
|
||||||
proxy_client.socket_timeout,
|
proxy_client.socket_timeout,
|
||||||
|
tls,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if tls {
|
||||||
|
let hostname = args.get_option(&["--tls-hostname"]).or_else(|| tcp_target.split(":").next().map(&str::to_owned));
|
||||||
|
let pinnedpubkey = args.get_option(&["--pinnedpubkey"]);
|
||||||
|
proxy_client.start_tls(hostname.as_ref().map(String::as_str), pinnedpubkey.as_ref().map(String::as_str)).expect("error running tls proxy_client");
|
||||||
|
} else {
|
||||||
proxy_client.start().expect("error running proxy_client");
|
proxy_client.start().expect("error running proxy_client");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn server(tcp_host: &str, socket_timeout: u64, args: Args) {
|
||||||
|
let udp_bind_host_range_str = args.get_str(&["-ur", "--udp-bind-host-range"], "127.0.0.1:30000-40000");
|
||||||
|
let mut udp_bind_host_range = udp_bind_host_range_str.split(":");
|
||||||
|
let udp_host = udp_bind_host_range
|
||||||
|
.next()
|
||||||
|
.expect("udp_bind_host_range host invalid");
|
||||||
|
let mut udp_ports = udp_bind_host_range
|
||||||
|
.next()
|
||||||
|
.expect("udp_bind_host_range port range invalid")
|
||||||
|
.split("-");
|
||||||
|
let udp_low_port = udp_ports
|
||||||
|
.next()
|
||||||
|
.expect("udp_bind_host_range low port invalid")
|
||||||
|
.trim()
|
||||||
|
.parse::<u16>()
|
||||||
|
.expect("udp_bind_host_range low port invalid");
|
||||||
|
let udp_high_port = udp_ports
|
||||||
|
.next()
|
||||||
|
.expect("udp_bind_host_range low port invalid")
|
||||||
|
.trim()
|
||||||
|
.parse::<u16>()
|
||||||
|
.expect("udp_bind_host_range low port invalid");
|
||||||
|
|
||||||
|
let proxy_server = ProxyServer::new(
|
||||||
|
tcp_host.to_owned(),
|
||||||
|
args.get_str(&["-ut", "--udp-target"], "127.0.0.1:51820").to_owned(),
|
||||||
|
udp_host.to_string(),
|
||||||
|
udp_low_port,
|
||||||
|
udp_high_port,
|
||||||
|
socket_timeout,
|
||||||
|
);
|
||||||
|
|
||||||
|
let tls_key = args.get_option(&["-tk", "--tls-key"]);
|
||||||
|
let tls_cert = args.get_option(&["-tc", "--tls-cert"]);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"udp_target: {}, udp_bind_host_range: {}, socket_timeout: {:?}, tls_key: {:?}, tls_cert: {:?}",
|
||||||
|
proxy_server.client_handler.udp_target,
|
||||||
|
udp_bind_host_range_str,
|
||||||
|
proxy_server.client_handler.socket_timeout,
|
||||||
|
tls_key,
|
||||||
|
tls_cert,
|
||||||
|
);
|
||||||
|
|
||||||
|
if tls_key.is_some() && tls_cert.is_some() {
|
||||||
|
proxy_server.start_tls(&tls_key.unwrap(), &tls_cert.unwrap()).expect("error running TLS proxy_server");
|
||||||
|
} else if tls_key.is_none() && tls_cert.is_none() {
|
||||||
|
proxy_server.start().expect("error running proxy_server");
|
||||||
|
} else {
|
||||||
|
println!("Error: if one of --tls-key or --tls-cert is specified both must be!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
use std::env;
|
|
||||||
use wireguard_proxy::{Args, ProxyServer};
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let raw_args = env::args().collect();
|
|
||||||
let args = Args::new(&raw_args);
|
|
||||||
if args.get_str(1, "").contains("-h") {
|
|
||||||
println!(
|
|
||||||
"usage: {} [-h] [tcp_host, 127.0.0.1:5555] [udp_target, 127.0.0.1:51820] [udp_bind_host_range, 127.0.0.1:30000-40000] [socket_timeout, 0]",
|
|
||||||
args.get_str(0, "wireguard-proxyd")
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let udp_bind_host_range_str = args.get_str(3, "127.0.0.1:30000-40000");
|
|
||||||
let mut udp_bind_host_range = udp_bind_host_range_str.split(":");
|
|
||||||
let udp_host = udp_bind_host_range
|
|
||||||
.next()
|
|
||||||
.expect("udp_bind_host_range host invalid");
|
|
||||||
let mut udp_ports = udp_bind_host_range
|
|
||||||
.next()
|
|
||||||
.expect("udp_bind_host_range port range invalid")
|
|
||||||
.split("-");
|
|
||||||
let udp_low_port = udp_ports
|
|
||||||
.next()
|
|
||||||
.expect("udp_bind_host_range low port invalid")
|
|
||||||
.trim()
|
|
||||||
.parse::<u16>()
|
|
||||||
.expect("udp_bind_host_range low port invalid");
|
|
||||||
let udp_high_port = udp_ports
|
|
||||||
.next()
|
|
||||||
.expect("udp_bind_host_range low port invalid")
|
|
||||||
.trim()
|
|
||||||
.parse::<u16>()
|
|
||||||
.expect("udp_bind_host_range low port invalid");
|
|
||||||
|
|
||||||
let proxy_server = ProxyServer::new(
|
|
||||||
args.get_str(1, "127.0.0.1:5555").to_owned(),
|
|
||||||
args.get_str(2, "127.0.0.1:51820").to_owned(),
|
|
||||||
udp_host.to_string(),
|
|
||||||
udp_low_port,
|
|
||||||
udp_high_port,
|
|
||||||
args.get(4, 0),
|
|
||||||
);
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"udp_target: {}, udp_bind_host_range: {}, socket_timeout: {:?}",
|
|
||||||
proxy_server.client_handler.udp_target,
|
|
||||||
udp_bind_host_range_str,
|
|
||||||
proxy_server.client_handler.socket_timeout,
|
|
||||||
);
|
|
||||||
|
|
||||||
proxy_server.start().expect("error running proxy_server");
|
|
||||||
}
|
|
44
src/error.rs
Normal file
44
src/error.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
use core::result;
|
||||||
|
|
||||||
|
#[cfg(not(any(feature = "async")))]
|
||||||
|
pub type IoResult<T> = result::Result<T, std::io::Error>;
|
||||||
|
|
||||||
|
pub type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Error(String);
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
pub fn new(msg: &str) -> Error {
|
||||||
|
Error(msg.to_owned())
|
||||||
|
}
|
||||||
|
pub fn new_owned(msg: String) -> Error {
|
||||||
|
Error(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
f.write_str(&self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for Error {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<std::io::Error> for Error {
|
||||||
|
fn from(value: std::io::Error) -> Self {
|
||||||
|
Error::new(&format!("{}", value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
impl From<std::option::NoneError> for Error {
|
||||||
|
fn from(value: std::option::NoneError) -> Self {
|
||||||
|
Error::new(value.description())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
227
src/lib.rs
227
src/lib.rs
@ -1,10 +1,37 @@
|
|||||||
use std::io::{Read, Write};
|
use std::net::{TcpStream, UdpSocket};
|
||||||
use std::net::{TcpListener, TcpStream, UdpSocket};
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::thread;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
mod error;
|
||||||
|
use error::Result;
|
||||||
|
|
||||||
|
fn arg_to_env(arg: &str) -> Option<String> {
|
||||||
|
if !arg.starts_with("--") {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let env = "WGP_".to_owned();
|
||||||
|
let mut env = env + &arg.trim_matches('-').replace("-", "_");
|
||||||
|
env.make_ascii_uppercase();
|
||||||
|
Some(env)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn env_for_arg(arg: &str) -> Option<String> {
|
||||||
|
arg_to_env(arg).and_then(|key| std::env::var(key).ok())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
#[test]
|
||||||
|
fn test_arg_to_env() {
|
||||||
|
assert_eq!(arg_to_env("--tcp-host"), Some("WGP_TCP_HOST".to_owned()));
|
||||||
|
assert_eq!(arg_to_env("--tls"), Some("WGP_TLS".to_owned()));
|
||||||
|
assert_eq!(arg_to_env("-h"), None);
|
||||||
|
assert_eq!(arg_to_env("-th"), None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Args<'a> {
|
pub struct Args<'a> {
|
||||||
args: &'a Vec<String>,
|
args: &'a Vec<String>,
|
||||||
}
|
}
|
||||||
@ -13,14 +40,45 @@ impl<'a> Args<'a> {
|
|||||||
pub fn new(args: &'a Vec<String>) -> Args {
|
pub fn new(args: &'a Vec<String>) -> Args {
|
||||||
Args { args }
|
Args { args }
|
||||||
}
|
}
|
||||||
pub fn get_str(&self, index: usize, def: &'a str) -> &'a str {
|
pub fn flag(&self, flag: &'a str) -> bool {
|
||||||
match self.args.get(index) {
|
if self.args.contains(&flag.to_owned()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// because env we want slightly special handling of empty/0/false
|
||||||
|
match env_for_arg(flag) {
|
||||||
|
Some(env) => &env != "" && &env != "0" && &env != "false",
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn get_option(&self, flags: &[&'a str]) -> Option<String> {
|
||||||
|
for flag in flags.iter() {
|
||||||
|
let mut found = false;
|
||||||
|
for arg in self.args.iter() {
|
||||||
|
if found {
|
||||||
|
return Some(arg.to_owned());
|
||||||
|
}
|
||||||
|
if arg == flag {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// no matching arguments are found, so check env variables as a fallback
|
||||||
|
for flag in flags.iter() {
|
||||||
|
let env = env_for_arg(flag);
|
||||||
|
if env.is_some() {
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
pub fn get_str(&self, flags: &[&'a str], def: &'a str) -> String {
|
||||||
|
match self.get_option(flags) {
|
||||||
Some(ret) => ret,
|
Some(ret) => ret,
|
||||||
None => def,
|
None => def.to_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn get<T: FromStr>(&self, index: usize, def: T) -> T {
|
pub fn get<T: FromStr>(&self, flags: &[&'a str], def: T) -> T {
|
||||||
match self.args.get(index) {
|
match self.get_option(flags) {
|
||||||
Some(ret) => match ret.parse::<T>() {
|
Some(ret) => match ret.parse::<T>() {
|
||||||
Ok(ret) => ret,
|
Ok(ret) => ret,
|
||||||
Err(_) => def, // or panic
|
Err(_) => def, // or panic
|
||||||
@ -30,66 +88,45 @@ impl<'a> Args<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TcpUdpPipe {
|
|
||||||
buf: [u8; 2050], // 2048 + 2 for len
|
|
||||||
tcp_stream: TcpStream,
|
|
||||||
udp_socket: UdpSocket,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TcpUdpPipe {
|
|
||||||
pub fn new(tcp_stream: TcpStream, udp_socket: UdpSocket) -> TcpUdpPipe {
|
|
||||||
TcpUdpPipe {
|
|
||||||
tcp_stream,
|
|
||||||
udp_socket,
|
|
||||||
buf: [0u8; 2050],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_clone(&self) -> std::io::Result<TcpUdpPipe> {
|
|
||||||
Ok(TcpUdpPipe::new(
|
|
||||||
self.tcp_stream.try_clone()?,
|
|
||||||
self.udp_socket.try_clone()?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn udp_to_tcp(&mut self) -> std::io::Result<usize> {
|
|
||||||
let len = self.udp_socket.recv(&mut self.buf[2..])?;
|
|
||||||
println!("udp got len: {}", len);
|
|
||||||
|
|
||||||
self.buf[0] = ((len >> 8) & 0xFF) as u8;
|
|
||||||
self.buf[1] = (len & 0xFF) as u8;
|
|
||||||
|
|
||||||
//let test_len = ((self.buf[0] as usize) << 8) + self.buf[1] as usize;
|
|
||||||
//println!("tcp sending test_len: {}", test_len);
|
|
||||||
|
|
||||||
self.tcp_stream.write(&self.buf[..len + 2])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tcp_to_udp(&mut self) -> std::io::Result<usize> {
|
|
||||||
self.tcp_stream.read_exact(&mut self.buf[..2])?;
|
|
||||||
let len = ((self.buf[0] as usize) << 8) + self.buf[1] as usize;
|
|
||||||
println!("tcp expecting len: {}", len);
|
|
||||||
self.tcp_stream.read_exact(&mut self.buf[..len])?;
|
|
||||||
println!("tcp got len: {}", len);
|
|
||||||
self.udp_socket.send(&self.buf[..len])
|
|
||||||
|
|
||||||
//let sent = udp_socket.send_to(&buf[..len], &self.udp_target)?;
|
|
||||||
//assert_eq!(sent, len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ProxyClient {
|
pub struct ProxyClient {
|
||||||
pub udp_host: String,
|
pub udp_host: String,
|
||||||
pub udp_target: String,
|
|
||||||
pub tcp_target: String,
|
pub tcp_target: String,
|
||||||
pub socket_timeout: Option<Duration>,
|
pub socket_timeout: Option<Duration>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ProxyServer {
|
||||||
|
pub tcp_host: String,
|
||||||
|
pub client_handler: Arc<ProxyServerClientHandler>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ProxyServerClientHandler {
|
||||||
|
pub udp_target: String,
|
||||||
|
pub udp_host: String,
|
||||||
|
pub udp_low_port: u16,
|
||||||
|
pub udp_high_port: u16,
|
||||||
|
pub socket_timeout: Option<Duration>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "async"))]
|
||||||
|
#[path = ""]
|
||||||
|
mod net {
|
||||||
|
mod asyncmod;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(feature = "async")))]
|
||||||
|
#[path = ""]
|
||||||
|
mod net {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
mod syncmod;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl ProxyClient {
|
impl ProxyClient {
|
||||||
pub fn new(udp_host: String, udp_target: String, tcp_target: String, secs: u64) -> ProxyClient {
|
pub fn new(udp_host: String, tcp_target: String, secs: u64) -> ProxyClient {
|
||||||
ProxyClient {
|
ProxyClient {
|
||||||
udp_host,
|
udp_host,
|
||||||
udp_target,
|
|
||||||
tcp_target,
|
tcp_target,
|
||||||
socket_timeout: match secs {
|
socket_timeout: match secs {
|
||||||
0 => None,
|
0 => None,
|
||||||
@ -98,32 +135,17 @@ impl ProxyClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(&self) -> std::io::Result<usize> {
|
fn tcp_connect(&self) -> Result<TcpStream> {
|
||||||
let tcp_stream = TcpStream::connect(&self.tcp_target)?;
|
let tcp_stream = TcpStream::connect(&self.tcp_target)?;
|
||||||
|
|
||||||
tcp_stream.set_read_timeout(self.socket_timeout)?;
|
tcp_stream.set_read_timeout(self.socket_timeout)?;
|
||||||
|
Ok(tcp_stream)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn udp_connect(&self) -> Result<UdpSocket> {
|
||||||
let udp_socket = UdpSocket::bind(&self.udp_host)?;
|
let udp_socket = UdpSocket::bind(&self.udp_host)?;
|
||||||
udp_socket.set_read_timeout(self.socket_timeout)?;
|
udp_socket.set_read_timeout(self.socket_timeout)?;
|
||||||
//udp_socket.connect(&self.udp_target)?; // this isn't strictly needed... just filters who we can receive from
|
Ok(udp_socket)
|
||||||
|
|
||||||
let mut udp_pipe = TcpUdpPipe::new(tcp_stream, udp_socket);
|
|
||||||
let mut udp_pipe_clone = udp_pipe.try_clone()?;
|
|
||||||
thread::spawn(move || loop {
|
|
||||||
udp_pipe_clone
|
|
||||||
.udp_to_tcp()
|
|
||||||
.expect("cannot write to tcp_clone");
|
|
||||||
});
|
|
||||||
|
|
||||||
loop {
|
|
||||||
udp_pipe.tcp_to_udp()?;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ProxyServer {
|
|
||||||
pub tcp_host: String,
|
|
||||||
pub client_handler: Arc<ProxyServerClientHandler>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProxyServer {
|
impl ProxyServer {
|
||||||
@ -150,42 +172,10 @@ impl ProxyServer {
|
|||||||
client_handler,
|
client_handler,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(&self) -> std::io::Result<()> {
|
|
||||||
let listener = TcpListener::bind(&self.tcp_host)?;
|
|
||||||
println!("Listening for connections on {}", &self.tcp_host);
|
|
||||||
|
|
||||||
for stream in listener.incoming() {
|
|
||||||
match stream {
|
|
||||||
Ok(stream) => {
|
|
||||||
let client_handler = self.client_handler.clone();
|
|
||||||
thread::spawn(move || {
|
|
||||||
client_handler
|
|
||||||
.handle_client(stream)
|
|
||||||
.expect("error handling connection")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
println!("Unable to connect: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ProxyServerClientHandler {
|
|
||||||
pub udp_target: String,
|
|
||||||
pub udp_host: String,
|
|
||||||
pub udp_low_port: u16,
|
|
||||||
pub udp_high_port: u16,
|
|
||||||
pub socket_timeout: Option<Duration>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProxyServerClientHandler {
|
impl ProxyServerClientHandler {
|
||||||
pub fn handle_client(&self, tcp_stream: TcpStream) -> std::io::Result<usize> {
|
fn udp_bind(&self) -> Result<UdpSocket> {
|
||||||
tcp_stream.set_read_timeout(self.socket_timeout)?;
|
|
||||||
|
|
||||||
let mut port = self.udp_low_port;
|
let mut port = self.udp_low_port;
|
||||||
let udp_socket = loop {
|
let udp_socket = loop {
|
||||||
match UdpSocket::bind((&self.udp_host[..], port)) {
|
match UdpSocket::bind((&self.udp_host[..], port)) {
|
||||||
@ -200,17 +190,6 @@ impl ProxyServerClientHandler {
|
|||||||
};
|
};
|
||||||
udp_socket.set_read_timeout(self.socket_timeout)?;
|
udp_socket.set_read_timeout(self.socket_timeout)?;
|
||||||
udp_socket.connect(&self.udp_target)?;
|
udp_socket.connect(&self.udp_target)?;
|
||||||
|
Ok(udp_socket)
|
||||||
let mut udp_pipe = TcpUdpPipe::new(tcp_stream, udp_socket);
|
|
||||||
let mut udp_pipe_clone = udp_pipe.try_clone()?;
|
|
||||||
thread::spawn(move || loop {
|
|
||||||
udp_pipe_clone
|
|
||||||
.udp_to_tcp()
|
|
||||||
.expect("cannot write to tcp_clone");
|
|
||||||
});
|
|
||||||
|
|
||||||
loop {
|
|
||||||
udp_pipe.tcp_to_udp()?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
49
src/notls.rs
Normal file
49
src/notls.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use std::net::TcpStream;
|
||||||
|
use super::super::TryClone;
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
use crate::error::*;
|
||||||
|
|
||||||
|
fn err() -> Error {
|
||||||
|
Error::new("Error: compiled without TLS support")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TlsStream;
|
||||||
|
|
||||||
|
impl TlsStream {
|
||||||
|
pub fn client(_hostname: Option<&str>, _pinnedpubkey: Option<&str>, _tcp_stream: TcpStream) -> Result<TlsStream> {
|
||||||
|
Err(err())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryClone<TlsStream> for TlsStream {
|
||||||
|
fn try_clone(&self) -> Result<TlsStream> {
|
||||||
|
Err(err())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Read for TlsStream {
|
||||||
|
fn read(&mut self, _buf: &mut [u8]) -> IoResult<usize> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for TlsStream {
|
||||||
|
fn write(&mut self, _buf: &[u8]) -> IoResult<usize> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> IoResult<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TlsListener;
|
||||||
|
|
||||||
|
impl TlsListener {
|
||||||
|
pub fn new(_tls_key: &str, _tls_cert: &str) -> Result<TlsListener> {
|
||||||
|
Err(err())
|
||||||
|
}
|
||||||
|
pub fn wrap(&self, _tcp_stream: TcpStream) -> Result<TlsStream> {
|
||||||
|
Err(err())
|
||||||
|
}
|
||||||
|
}
|
154
src/openssl.rs
Normal file
154
src/openssl.rs
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
|
||||||
|
use openssl::ssl::{SslConnector, SslMethod, SslStream, SslVerifyMode, SslAcceptor, SslFiletype, HandshakeError};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::cell::UnsafeCell;
|
||||||
|
use std::net::TcpStream;
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
use super::super::TryClone;
|
||||||
|
|
||||||
|
use crate::error::*;
|
||||||
|
|
||||||
|
impl TryClone<TlsStream> for TlsStream {
|
||||||
|
fn try_clone(&self) -> Result<TlsStream> {
|
||||||
|
Ok(self.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TlsStream {
|
||||||
|
sess: Arc<UnsafeCell<SslStream<TcpStream>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TlsStream {
|
||||||
|
fn new(stream: SslStream<TcpStream>) -> TlsStream {
|
||||||
|
TlsStream {
|
||||||
|
sess: Arc::new(UnsafeCell::new(stream))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn client(hostname: Option<&str>, pinnedpubkey: Option<&str>, tcp_stream: TcpStream) -> Result<TlsStream> {
|
||||||
|
let mut connector = SslConnector::builder(SslMethod::tls())?.build().configure()?;
|
||||||
|
connector.set_use_server_name_indication(hostname.is_some());
|
||||||
|
connector.set_verify_hostname(false);
|
||||||
|
connector.set_verify(SslVerifyMode::NONE);
|
||||||
|
if pinnedpubkey.is_some() {
|
||||||
|
let pinnedpubkey = pinnedpubkey.unwrap().to_owned();
|
||||||
|
connector.set_verify_callback(SslVerifyMode::PEER, move|_preverify_ok, x509_store_ctx| {
|
||||||
|
//println!("preverify_ok: {}", preverify_ok);
|
||||||
|
let cert = x509_store_ctx.current_cert().expect("could not get TLS cert");
|
||||||
|
let pubkey = cert.public_key().expect("could not get public key from TLS cert");
|
||||||
|
let pubkey = pubkey.public_key_to_der().expect("could not get TLS public key bytes");
|
||||||
|
//println!("spki.len(): {}", pubkey.len());
|
||||||
|
//println!("spki: {:?}", pubkey);
|
||||||
|
|
||||||
|
let mut sha256 = openssl::sha::Sha256::new();
|
||||||
|
sha256.update(&pubkey);
|
||||||
|
let pubkey = sha256.finish();
|
||||||
|
|
||||||
|
let pubkey = ["sha256//", &openssl::base64::encode_block(&pubkey)].join("");
|
||||||
|
println!("pubkey from cert: {}", pubkey);
|
||||||
|
|
||||||
|
for key in pinnedpubkey.split(";") {
|
||||||
|
if key == pubkey {
|
||||||
|
println!("SUCCESS: pubkey match found!",);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("ERROR: pubkey match not found!");
|
||||||
|
false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let tcp_stream = connector.connect(hostname.unwrap_or(""), tcp_stream)?;
|
||||||
|
Ok(TlsStream::new(tcp_stream))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for TlsStream {}
|
||||||
|
unsafe impl Send for TlsStream {}
|
||||||
|
|
||||||
|
impl Clone for TlsStream {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
TlsStream {
|
||||||
|
sess: self.sess.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TlsStream {
|
||||||
|
pub fn borrow_mut(&self) -> &mut SslStream<TcpStream> {
|
||||||
|
unsafe {
|
||||||
|
&mut *self.sess.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Read for TlsStream {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
|
||||||
|
self.borrow_mut().read(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for TlsStream {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
|
||||||
|
self.borrow_mut().write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> IoResult<()> {
|
||||||
|
self.borrow_mut().flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TlsListener {
|
||||||
|
acceptor: SslAcceptor,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TlsListener {
|
||||||
|
pub fn new(tls_key: &str, tls_cert: &str) -> Result<TlsListener> {
|
||||||
|
let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls())?;
|
||||||
|
|
||||||
|
if tls_key == "-" || tls_cert == "-" {
|
||||||
|
let mut key_and_or_cert = Vec::new();
|
||||||
|
println!("fully reading stdin...");
|
||||||
|
std::io::stdin().read_to_end(&mut key_and_or_cert)?;
|
||||||
|
println!("finished reading stdin");
|
||||||
|
|
||||||
|
if tls_key == "-" {
|
||||||
|
let tls_key = openssl::pkey::PKey::private_key_from_pem(&key_and_or_cert)?;
|
||||||
|
acceptor.set_private_key(&tls_key)?;
|
||||||
|
} else {
|
||||||
|
acceptor.set_private_key_file(tls_key, SslFiletype::PEM)?;
|
||||||
|
}
|
||||||
|
if tls_cert == "-" {
|
||||||
|
// todo: read whole chain here or???
|
||||||
|
let tls_cert = openssl::x509::X509::from_pem(&key_and_or_cert)?;
|
||||||
|
acceptor.set_certificate(&tls_cert)?;
|
||||||
|
} else {
|
||||||
|
acceptor.set_certificate_chain_file(tls_cert)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// set from files
|
||||||
|
acceptor.set_private_key_file(tls_key, SslFiletype::PEM)?;
|
||||||
|
acceptor.set_certificate_chain_file(tls_cert)?;
|
||||||
|
}
|
||||||
|
acceptor.check_private_key()?;
|
||||||
|
let acceptor = acceptor.build();
|
||||||
|
Ok(TlsListener {
|
||||||
|
acceptor
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn wrap(&self, tcp_stream: TcpStream) -> Result<TlsStream> {
|
||||||
|
Ok(TlsStream::new(self.acceptor.accept(tcp_stream)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<openssl::error::ErrorStack> for Error {
|
||||||
|
fn from(value: openssl::error::ErrorStack) -> Self {
|
||||||
|
Error::new_owned(format!("{}", value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<HandshakeError<std::net::TcpStream>> for Error {
|
||||||
|
fn from(value: HandshakeError<std::net::TcpStream>) -> Self {
|
||||||
|
Error::new(&format!("{}", value))
|
||||||
|
}
|
||||||
|
}
|
208
src/syncmod.rs
Normal file
208
src/syncmod.rs
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
use std::thread;
|
||||||
|
use crate::error::Result;
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
use std::net::TcpListener;
|
||||||
|
use std::io::{Write, Read};
|
||||||
|
|
||||||
|
#[cfg(any(feature = "tls", feature = "openssl_vendored"))]
|
||||||
|
#[path = ""]
|
||||||
|
mod tls {
|
||||||
|
pub mod openssl;
|
||||||
|
pub use super::tls::openssl::{TlsStream, TlsListener};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(feature = "tls", feature = "openssl_vendored")))]
|
||||||
|
#[path = ""]
|
||||||
|
mod tls {
|
||||||
|
pub mod notls;
|
||||||
|
pub use super::tls::notls::{TlsStream, TlsListener};
|
||||||
|
}
|
||||||
|
|
||||||
|
use tls::{TlsStream, TlsListener};
|
||||||
|
|
||||||
|
pub struct TcpUdpPipe<T: Write + Read + TryClone<T> + Send + 'static> {
|
||||||
|
buf: [u8; 2050], // 2048 + 2 for len
|
||||||
|
tcp_stream: T,
|
||||||
|
udp_socket: UdpSocket,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Write + Read + TryClone<T> + Send + 'static> TcpUdpPipe<T> {
|
||||||
|
pub fn new(tcp_stream: T, udp_socket: UdpSocket) -> TcpUdpPipe<T> {
|
||||||
|
TcpUdpPipe {
|
||||||
|
tcp_stream,
|
||||||
|
udp_socket,
|
||||||
|
buf: [0u8; 2050],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_clone(&self) -> Result<TcpUdpPipe<T>> {
|
||||||
|
Ok(TcpUdpPipe::new(
|
||||||
|
self.tcp_stream.try_clone()?,
|
||||||
|
self.udp_socket.try_clone()?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shuffle_after_first_udp(&mut self) -> Result<usize> {
|
||||||
|
let (len, src_addr) = self.udp_socket.recv_from(&mut self.buf[2..])?;
|
||||||
|
|
||||||
|
println!("first packet from {}, connecting to that", src_addr);
|
||||||
|
self.udp_socket.connect(src_addr)?;
|
||||||
|
|
||||||
|
self.send_udp(len)?;
|
||||||
|
|
||||||
|
self.shuffle()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn udp_to_tcp(&mut self) -> Result<()> {
|
||||||
|
let len = self.udp_socket.recv(&mut self.buf[2..])?;
|
||||||
|
self.send_udp(len)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_udp(&mut self, len: usize) -> Result<()> {
|
||||||
|
#[cfg(feature = "verbose")]
|
||||||
|
println!("udp got len: {}", len);
|
||||||
|
|
||||||
|
self.buf[0] = ((len >> 8) & 0xFF) as u8;
|
||||||
|
self.buf[1] = (len & 0xFF) as u8;
|
||||||
|
|
||||||
|
Ok(self.tcp_stream.write_all(&self.buf[..len + 2])?)
|
||||||
|
// todo: do this? self.tcp_stream.flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tcp_to_udp(&mut self) -> Result<usize> {
|
||||||
|
self.tcp_stream.read_exact(&mut self.buf[..2])?;
|
||||||
|
let len = ((self.buf[0] as usize) << 8) + self.buf[1] as usize;
|
||||||
|
#[cfg(feature = "verbose")]
|
||||||
|
println!("tcp expecting len: {}", len);
|
||||||
|
self.tcp_stream.read_exact(&mut self.buf[..len])?;
|
||||||
|
#[cfg(feature = "verbose")]
|
||||||
|
println!("tcp got len: {}", len);
|
||||||
|
Ok(self.udp_socket.send(&self.buf[..len])?)
|
||||||
|
|
||||||
|
//let sent = udp_socket.send_to(&buf[..len], &self.udp_target)?;
|
||||||
|
//assert_eq!(sent, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shuffle(&mut self) -> Result<usize> {
|
||||||
|
let mut udp_pipe_clone = self.try_clone()?;
|
||||||
|
thread::spawn(move || loop {
|
||||||
|
udp_pipe_clone
|
||||||
|
.udp_to_tcp()
|
||||||
|
.expect("cannot write to tcp_clone");
|
||||||
|
});
|
||||||
|
|
||||||
|
loop {
|
||||||
|
self.tcp_to_udp()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait TryClone<T> {
|
||||||
|
fn try_clone(&self) -> Result<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryClone<UdpSocket> for UdpSocket {
|
||||||
|
fn try_clone(&self) -> Result<UdpSocket> {
|
||||||
|
Ok(self.try_clone()?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryClone<TcpStream> for TcpStream {
|
||||||
|
fn try_clone(&self) -> Result<TcpStream> {
|
||||||
|
Ok(self.try_clone()?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProxyClient {
|
||||||
|
|
||||||
|
pub fn start(&self) -> Result<usize> {
|
||||||
|
let tcp_stream = self.tcp_connect()?;
|
||||||
|
|
||||||
|
let udp_socket = self.udp_connect()?;
|
||||||
|
|
||||||
|
// we want to wait for first udp packet from client first, to set the target to respond to
|
||||||
|
TcpUdpPipe::new(tcp_stream, udp_socket).shuffle_after_first_udp()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_tls(&self, hostname: Option<&str>, pinnedpubkey: Option<&str>) -> Result<usize> {
|
||||||
|
let tcp_stream = self.tcp_connect()?;
|
||||||
|
|
||||||
|
let tcp_stream = TlsStream::client(hostname, pinnedpubkey, tcp_stream)?;
|
||||||
|
|
||||||
|
let udp_socket = self.udp_connect()?;
|
||||||
|
|
||||||
|
// we want to wait for first udp packet from client first, to set the target to respond to
|
||||||
|
TcpUdpPipe::new(tcp_stream, udp_socket).shuffle_after_first_udp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProxyServer {
|
||||||
|
|
||||||
|
pub fn start(&self) -> Result<()> {
|
||||||
|
let listener = TcpListener::bind(&self.tcp_host)?;
|
||||||
|
println!("Listening for connections on {}", &self.tcp_host);
|
||||||
|
|
||||||
|
for stream in listener.incoming() {
|
||||||
|
match stream {
|
||||||
|
Ok(stream) => {
|
||||||
|
let client_handler = self.client_handler.clone();
|
||||||
|
client_handler.set_tcp_options(&stream).expect("cannot set tcp options");
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
client_handler
|
||||||
|
.handle_client(stream)
|
||||||
|
.expect("error handling connection")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("Unable to connect: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_tls(&self, tls_key: &str, tls_cert: &str) -> Result<()> {
|
||||||
|
let tls_listener = Arc::new(TlsListener::new(tls_key, tls_cert)?);
|
||||||
|
|
||||||
|
let listener = TcpListener::bind(&self.tcp_host)?;
|
||||||
|
println!("Listening for TLS connections on {}", &self.tcp_host);
|
||||||
|
|
||||||
|
for stream in listener.incoming() {
|
||||||
|
match stream {
|
||||||
|
Ok(stream) => {
|
||||||
|
let client_handler = self.client_handler.clone();
|
||||||
|
client_handler.set_tcp_options(&stream).expect("cannot set tcp options");
|
||||||
|
|
||||||
|
let tls_listener = tls_listener.clone();
|
||||||
|
thread::spawn(move || {
|
||||||
|
let stream = tls_listener.wrap(stream).expect("cannot wrap with tls");
|
||||||
|
client_handler
|
||||||
|
.handle_client_tls(stream)
|
||||||
|
.expect("error handling connection")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("Unable to connect: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProxyServerClientHandler {
|
||||||
|
|
||||||
|
pub fn set_tcp_options(&self, tcp_stream: &TcpStream) -> Result<()> {
|
||||||
|
Ok(tcp_stream.set_read_timeout(self.socket_timeout)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_client(&self, tcp_stream: TcpStream) -> Result<usize> {
|
||||||
|
TcpUdpPipe::new(tcp_stream, self.udp_bind()?).shuffle()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_client_tls(&self, tcp_stream: TlsStream) -> Result<usize> {
|
||||||
|
TcpUdpPipe::new(tcp_stream, self.udp_bind()?).shuffle()
|
||||||
|
}
|
||||||
|
}
|
11
systemd/client.conf
Normal file
11
systemd/client.conf
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# refer to wireguard-proxy --help for info on what these are
|
||||||
|
|
||||||
|
WGP_TCP_TARGET=192.168.1.1:5555
|
||||||
|
#WGP_TCP_TARGET=example.org:5555
|
||||||
|
WGP_UDP_HOST=127.0.0.1:51820
|
||||||
|
|
||||||
|
#WGP_TLS=true
|
||||||
|
#WGP_PINNEDPUBKEY=sha256//YhKJKSzoTt2b5FP18fvpHo7fJYqQCjAa3HWY3tvRMwE=;sha256//t62CeU2tQiqkexU74Gxa2eg7fRbEgoChTociMee9wno=
|
||||||
|
#WGP_TLS_HOSTNAME=example.org
|
||||||
|
|
||||||
|
#WGP_SOCKET_TIMEOUT=0
|
25
systemd/server.conf
Normal file
25
systemd/server.conf
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# refer to wireguard-proxy --help for info on what these are
|
||||||
|
|
||||||
|
# this binds ipv4 and ipv6 if dual stacked
|
||||||
|
WGP_TCP_HOST=[::]:5555
|
||||||
|
# this binds all ipv4 addresses
|
||||||
|
#WGP_TCP_HOST=0.0.0.0:5555
|
||||||
|
|
||||||
|
WGP_UDP_TARGET=127.0.0.1:51820
|
||||||
|
|
||||||
|
# on the server you'll want to set this to slightly more than PersistentKeepalive= in your client's wireguard config
|
||||||
|
# this allows the udp sockets to be closed in a reasonable amount of time after the TCP connections are terminated
|
||||||
|
# if PersistentKeepalive=25 as is recommended just set this to 60
|
||||||
|
WGP_SOCKET_TIMEOUT=60
|
||||||
|
|
||||||
|
WGP_UDP_BIND_HOST_RANGE=127.0.0.1:30000-40000
|
||||||
|
|
||||||
|
# if you don't want proper cert generate with:
|
||||||
|
# openssl req -new -x509 -sha256 -days 3650 -nodes -subj "/C=US/CN=example.org" -newkey rsa:2048 -out cert.pem -keyout key.pem
|
||||||
|
# if systemd template has SupplementaryGroups=systemd-network set permissions on key properly:
|
||||||
|
# chown root.systemd-network key.pem && chmod 640 key.pem
|
||||||
|
# optionally (but recommended) extract pinnedpubkey hash from the above generated cert like so:
|
||||||
|
# openssl x509 -in cert.pem -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
|
||||||
|
#WGP_TLS_KEY=/etc/wireguard-proxy/key.pem
|
||||||
|
#WGP_TLS_CERT=/etc/wireguard-proxy/cert.pem
|
||||||
|
|
59
systemd/wireguard-proxy@.service
Normal file
59
systemd/wireguard-proxy@.service
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=wireguard-proxy for %I
|
||||||
|
After=network-online.target nss-lookup.target
|
||||||
|
Wants=network-online.target nss-lookup.target
|
||||||
|
StartLimitIntervalSec=0
|
||||||
|
Documentation=https://code.moparisthebest.com/moparisthebest/wireguard-proxy
|
||||||
|
Documentation=https://github.com/moparisthebest/wireguard-proxy
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
EnvironmentFile=/etc/wireguard-proxy/%i.conf
|
||||||
|
ExecStart=/usr/bin/wireguard-proxy
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1s
|
||||||
|
# anything under here isn't strictly needed, but probably good
|
||||||
|
# to lock this down with the minimal permissions necessary
|
||||||
|
# which are not many at all
|
||||||
|
User=wireguard-proxy
|
||||||
|
DynamicUser=yes
|
||||||
|
ConfigurationDirectory=wireguard-proxy
|
||||||
|
ConfigurationDirectoryMode=0750
|
||||||
|
ProtectSystem=strict
|
||||||
|
ProtectHome=true
|
||||||
|
PrivateTmp=true
|
||||||
|
PrivateDevices=true
|
||||||
|
ProtectHostname=true
|
||||||
|
ProtectKernelTunables=true
|
||||||
|
ProtectKernelModules=true
|
||||||
|
ProtectKernelLogs=true
|
||||||
|
ProtectControlGroups=true
|
||||||
|
RestrictAddressFamilies=AF_INET AF_INET6
|
||||||
|
RestrictNamespaces=net
|
||||||
|
LockPersonality=true
|
||||||
|
MemoryDenyWriteExecute=true
|
||||||
|
RestrictRealtime=true
|
||||||
|
RestrictSUIDSGID=true
|
||||||
|
RemoveIPC=true
|
||||||
|
SystemCallArchitectures=native
|
||||||
|
# these are just needed to bind to low ports
|
||||||
|
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||||
|
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||||
|
|
||||||
|
# this is any existing group the key/cert can be owned by
|
||||||
|
# so that our random user can read them
|
||||||
|
# not needed at all without TLS, can comment out
|
||||||
|
# see https://github.com/systemd/systemd/issues/9535
|
||||||
|
SupplementaryGroups=systemd-network
|
||||||
|
|
||||||
|
# this would be ideal because you wouldn't need file permissions
|
||||||
|
# on the key so wireguard-proxy could read it, only systemd
|
||||||
|
# but only the first of these works which doesn't make this
|
||||||
|
# feasible for a template...
|
||||||
|
#StandardInput=file:/full/hardcoded/path/to/key_and_cert.pem
|
||||||
|
#StandardInput=${WGP_STDIN}
|
||||||
|
#StandardInput=file:${WGP_STDIN}
|
||||||
|
#StandardInput=file:/etc/wireguard-proxy/%i.pem
|
||||||
|
#StandardOutput=journal
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
71
test.sh
71
test.sh
@ -1,22 +1,81 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
set -x
|
||||||
|
|
||||||
|
# cert created with:
|
||||||
|
# cd ci && echo -e '\n\n\n\n\n\n\n' | openssl req -new -x509 -days 3650 -nodes -out cert.pem -keyout cert.key
|
||||||
|
|
||||||
|
export PATH="$(pwd)/target/release:$PATH"
|
||||||
|
|
||||||
|
run_tests() {
|
||||||
|
client_arg="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
# first make sure udp-test succeeds running against itself
|
# first make sure udp-test succeeds running against itself
|
||||||
cargo run --release --bin udp-test || exit 1
|
udp-test || exit 1
|
||||||
|
|
||||||
|
# now run udp-test without spawning other processes
|
||||||
|
udp-test -is "$@" || exit 1
|
||||||
|
|
||||||
# now run proxyd pointing to udp-test
|
# now run proxyd pointing to udp-test
|
||||||
cargo run --release --bin wireguard-proxyd -- 127.0.0.1:5555 127.0.0.1:51822 &
|
wireguard-proxy -th 127.0.0.1:5555 -ut 127.0.0.1:51822 "$@" &
|
||||||
proxyd_pid=$!
|
proxyd_pid=$!
|
||||||
# wait for ports to be set up, this is fragile...
|
# wait for ports to be set up, this is fragile...
|
||||||
sleep 1
|
sleep 5
|
||||||
# proxy pointing to proxyd
|
# proxy pointing to proxyd
|
||||||
cargo run --release --bin wireguard-proxy &
|
wireguard-proxy -tt 127.0.0.1:5555 "$client_arg" &
|
||||||
proxy_pid=$!
|
proxy_pid=$!
|
||||||
# wait for ports to be set up, this is fragile...
|
# wait for ports to be set up, this is fragile...
|
||||||
sleep 1
|
sleep 1
|
||||||
# and udp-test pointing to proxy, which then hops to proxyd, and finally back to udp-test
|
# and udp-test pointing to proxy, which then hops to proxyd, and finally back to udp-test
|
||||||
cargo run --release --bin udp-test -- 127.0.0.1:51822
|
udp-test -uh 127.0.0.1:51822
|
||||||
udp_exit=$?
|
udp_exit=$?
|
||||||
|
|
||||||
kill $proxyd_pid $proxy_pid
|
kill $proxyd_pid $proxy_pid
|
||||||
|
|
||||||
exit $udp_exit
|
[ $udp_exit -ne 0 ] && exit $udp_exit
|
||||||
|
|
||||||
|
# now run udp-test essentially just like the script above, but all in rust
|
||||||
|
udp-test -s "$@" || exit 1
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# first run without TLS
|
||||||
|
cargo clean
|
||||||
|
cargo build --release --no-default-features || exit 1
|
||||||
|
run_tests || exit 1
|
||||||
|
|
||||||
|
# first run with non-vendored tls
|
||||||
|
cargo clean
|
||||||
|
cargo build --release --no-default-features --features tls || exit 1
|
||||||
|
# first plaintext tests
|
||||||
|
run_tests || exit 1
|
||||||
|
# then TLS tests
|
||||||
|
run_tests --tls --tls-key ci/cert.key --tls-cert ci/cert.pem || exit 1
|
||||||
|
|
||||||
|
# second run with vendored tls
|
||||||
|
cargo clean
|
||||||
|
cargo build --release --no-default-features --features openssl_vendored || exit 1
|
||||||
|
# first plaintext tests
|
||||||
|
run_tests || exit 1
|
||||||
|
# then TLS tests
|
||||||
|
run_tests --tls --tls-key ci/cert.key --tls-cert ci/cert.pem || exit 1
|
||||||
|
|
||||||
|
# third run with async+rustls
|
||||||
|
cargo clean
|
||||||
|
cargo build --release --no-default-features --features async || exit 1
|
||||||
|
# first plaintext tests
|
||||||
|
run_tests || exit 1
|
||||||
|
# then TLS tests
|
||||||
|
run_tests --tls --tls-key ci/cert.key --tls-cert ci/cert.pem || exit 1
|
||||||
|
|
||||||
|
# now pubkey tests
|
||||||
|
|
||||||
|
# these should fail
|
||||||
|
udp-test -s --tls-key ci/cert.key --tls-cert ci/cert.pem --pinnedpubkey sha256//BEyQeSjwwUBLXXNuCILHRWyV1gLmY31CdMHNA4VH4de= && exit 1
|
||||||
|
udp-test -is --tls-key ci/cert.key --tls-cert ci/cert.pem --pinnedpubkey sha256//BEyQeSjwwUBLXXNuCILHRWyV1gLmY31CdMHNA4VH4de= && exit 1
|
||||||
|
|
||||||
|
# these should pass
|
||||||
|
udp-test -s --tls-key ci/cert.key --tls-cert ci/cert.pem --pinnedpubkey sha256//BEyQeSjwwUBLXXNuCILHRWyV1gLmY31CdMHNA4VH4dE= || exit 1
|
||||||
|
udp-test -is --tls-key ci/cert.key --tls-cert ci/cert.pem --pinnedpubkey sha256//BEyQeSjwwUBLXXNuCILHRWyV1gLmY31CdMHNA4VH4dE= || exit 1
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
Loading…
Reference in New Issue
Block a user