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.
|
||||
# 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]]
|
||||
name = "wireguard-proxy"
|
||||
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-*",
|
||||
"*.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
|
||||
|
||||
[![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
|
||||
|
||||
`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` 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
|
||||
`wireguard-proxy` has 2 modes:
|
||||
- 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:
|
||||
|
||||
`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
|
||||
`test.sh` runs udp-test against itself and then through proxyd/proxy
|
||||
`udp-test -s` runs udp-test against itself through proxyd/proxy by spawning actual binaries
|
||||
`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
|
||||
- `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
|
||||
- `udp-test -s` runs udp-test against itself through proxy server/client 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
|
||||
- `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:
|
||||
|
||||
@ -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
|
||||
- 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
|
||||
|
||||
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.
|
||||
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
|
||||
# don't need
|
||||
@ -44,20 +47,23 @@ install:
|
||||
test_script:
|
||||
# we don't run the "test phase" when doing deploys
|
||||
- if [%APPVEYOR_REPO_TAG%]==[false] (
|
||||
cargo build --target %TARGET% &&
|
||||
cargo build --target %TARGET% --release &&
|
||||
cargo run --target %TARGET% --release --bin udp-test &&
|
||||
cargo run --target %TARGET% --release --bin udp-test -- -is
|
||||
cargo build --target %TARGET% --release --features %CARGO_FEATURES% &&
|
||||
cargo run --target %TARGET% --release --features %CARGO_FEATURES% --bin udp-test &&
|
||||
cargo run --target %TARGET% --release --features %CARGO_FEATURES% --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:
|
||||
# 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 --bin wireguard-proxyd -- -C lto
|
||||
- cargo rustc --target %TARGET% --release --features %CARGO_FEATURES% --bin wireguard-proxy -- -C lto
|
||||
- ps: ci\before_deploy.ps1
|
||||
|
||||
deploy:
|
||||
artifact: /.*\.zip/
|
||||
artifact: /wireguard-proxy-.*\.exe/
|
||||
# TODO update `auth_token.secure`
|
||||
# - Create a `public_repo` GitHub token. Go to: https://github.com/settings/tokens/new
|
||||
# - Encrypt it. Go to https://ci.appveyor.com/tools/encrypt
|
||||
@ -85,6 +91,7 @@ branches:
|
||||
- master
|
||||
- appveyor
|
||||
- ci
|
||||
- openssl
|
||||
|
||||
notifications:
|
||||
- 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());
|
||||
|
||||
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) {
|
||||
Ok(len) => {
|
||||
println!("udp got len: {}", len);
|
||||
@ -57,11 +73,11 @@ impl Server {
|
||||
assert_eq!(&buf[..len], &PONG[..]);
|
||||
}
|
||||
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)
|
||||
}
|
||||
@ -70,41 +86,128 @@ impl Server {
|
||||
fn main() {
|
||||
let raw_args = env::args().collect();
|
||||
let args = Args::new(&raw_args);
|
||||
let mut first_arg = args.get_str(1, "127.0.0.1:51821");
|
||||
if first_arg.contains("-h") {
|
||||
println!(
|
||||
"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]",
|
||||
args.get_str(0, "udp-test")
|
||||
);
|
||||
|
||||
if args.flag("-V") || args.flag("--version") {
|
||||
print!("udp-test {} ", env!("CARGO_PKG_VERSION"));
|
||||
#[cfg(not(any(feature = "tls", feature = "openssl_vendored")))]
|
||||
println!("TLS support: None");
|
||||
#[cfg(feature = "openssl_vendored")]
|
||||
println!("TLS support: Static/Vendored OpenSSL");
|
||||
#[cfg(feature = "tls")]
|
||||
println!("TLS support: System OpenSSL");
|
||||
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...
|
||||
let host = "127.0.0.1:51822";
|
||||
let tcp_host = "127.0.0.1:5555";
|
||||
let sleep = Duration::from_secs(5);
|
||||
|
||||
let udp_test = args.get_str(0, "udp-test");
|
||||
let proxyd = udp_test.clone().replace("udp-test", "wireguard-proxyd");
|
||||
let proxy = udp_test.clone().replace("udp-test", "wireguard-proxy");
|
||||
let udp_test = std::env::current_exe().expect("cannot get path to current executable");
|
||||
let proxy = udp_test.clone().with_file_name("wireguard-proxy")
|
||||
.with_extension(udp_test.extension().unwrap_or_else(|| "".as_ref()));
|
||||
|
||||
println!("executing: {} '{}' '{}'", proxyd, tcp_host, host);
|
||||
let mut proxyd = Command::new(proxyd)
|
||||
.arg(tcp_host)
|
||||
.arg(host)
|
||||
.spawn()
|
||||
.expect("wireguard-proxyd failed to launch");
|
||||
println!("waiting: {:?} for wireguard-proxyd to come up.....", sleep);
|
||||
let udp_test = udp_test.to_str().expect("non-utf8 executable path?");
|
||||
let proxy = proxy.to_str().expect("non-utf8 executable path?");
|
||||
|
||||
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()
|
||||
.expect("wireguard-proxy server failed to launch");
|
||||
println!("waiting: {:?} for wireguard-proxy server to come up.....", 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)
|
||||
.spawn()
|
||||
.expect("wireguard-proxy failed to launch");
|
||||
println!("waiting: {:?} for wireguard-proxy to come up.....", sleep);
|
||||
.args(proxy_args)
|
||||
.spawn()
|
||||
.expect("wireguard-proxy TLS client failed to launch");
|
||||
println!("waiting: {:?} for wireguard-proxy client to come up.....", sleep);
|
||||
thread::sleep(sleep);
|
||||
|
||||
println!("executing: {} '{}'", udp_test, host);
|
||||
println!("executing: {} -uh '{}'", udp_test, host);
|
||||
let mut udp_test = Command::new(udp_test)
|
||||
.arg("-uh")
|
||||
.arg(host)
|
||||
.spawn()
|
||||
.expect("udp-test failed to launch");
|
||||
@ -123,7 +226,7 @@ fn main() {
|
||||
.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 tcp_host = "127.0.0.1:5555";
|
||||
let sleep = Duration::from_secs(5);
|
||||
@ -142,38 +245,58 @@ fn main() {
|
||||
proxy_server.client_handler.udp_target, proxy_server.client_handler.socket_timeout,
|
||||
);
|
||||
|
||||
println!("executing: wireguard-proxyd '{}' '{}'", tcp_host, host);
|
||||
thread::spawn(move || proxy_server.start().expect("error running proxy_server"));
|
||||
println!("waiting: {:?} for wireguard-proxyd to come up.....", sleep);
|
||||
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"));
|
||||
}
|
||||
println!("waiting: {:?} for wireguard-proxy server to come up.....", sleep);
|
||||
thread::sleep(sleep);
|
||||
|
||||
let proxy_client = ProxyClient::new(
|
||||
"127.0.0.1:51821".to_owned(),
|
||||
"127.0.0.1:51820".to_owned(),
|
||||
tcp_host.to_owned().to_owned(),
|
||||
tcp_host.to_owned(),
|
||||
15,
|
||||
);
|
||||
|
||||
println!(
|
||||
"udp_host: {}, udp_target: {}, tcp_target: {}, socket_timeout: {:?}",
|
||||
"udp_host: {}, tcp_target: {}, socket_timeout: {:?}",
|
||||
proxy_client.udp_host,
|
||||
proxy_client.udp_target,
|
||||
proxy_client.tcp_target,
|
||||
proxy_client.socket_timeout,
|
||||
);
|
||||
|
||||
println!("executing: wireguard-proxy");
|
||||
thread::spawn(move || proxy_client.start().expect("error running proxy_client"));
|
||||
println!("waiting: {:?} for wireguard-proxy to come up.....", sleep);
|
||||
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"));
|
||||
}
|
||||
println!("waiting: {:?} for wireguard-proxy client to come up.....", sleep);
|
||||
thread::sleep(sleep);
|
||||
|
||||
first_arg = host;
|
||||
first_arg = host.to_owned();
|
||||
}
|
||||
|
||||
let server = Server::new(
|
||||
first_arg.to_owned(),
|
||||
args.get_str(2, "127.0.0.1:51821").to_owned(),
|
||||
args.get(3, 10),
|
||||
args.get_str(&["-ut", "--udp-target"], default_udp_host_target).to_owned(),
|
||||
args.get(&["-st", "--socket-timeout"], default_socket_timeout),
|
||||
);
|
||||
|
||||
println!(
|
||||
|
@ -1,31 +1,177 @@
|
||||
use std::env;
|
||||
use wireguard_proxy::{Args, ProxyClient};
|
||||
use wireguard_proxy::{Args, ProxyClient, 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] [udp_host, 127.0.0.1:51821] [udp_target, 127.0.0.1:51820] [tcp_target, 127.0.0.1:5555] [socket_timeout, 0]",
|
||||
args.get_str(0, "wireguard-proxy")
|
||||
);
|
||||
|
||||
if args.flag("-V") || args.flag("--version") {
|
||||
print!("wireguard-proxy {} ", env!("CARGO_PKG_VERSION"));
|
||||
#[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;
|
||||
}
|
||||
|
||||
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(
|
||||
args.get_str(1, "127.0.0.1:51821").to_owned(),
|
||||
args.get_str(2, "127.0.0.1:51820").to_owned(),
|
||||
args.get_str(3, "127.0.0.1:5555").to_owned(),
|
||||
args.get(4, 0),
|
||||
args.get_str(&["-uh", "--udp-host"], "127.0.0.1:51820").to_owned(),
|
||||
tcp_target.to_owned(),
|
||||
socket_timeout,
|
||||
);
|
||||
|
||||
let tls = args.flag("--tls");
|
||||
|
||||
println!(
|
||||
"udp_host: {}, udp_target: {}, tcp_target: {}, socket_timeout: {:?}",
|
||||
"udp_host: {}, tcp_target: {}, socket_timeout: {:?}, tls: {}",
|
||||
proxy_client.udp_host,
|
||||
proxy_client.udp_target,
|
||||
proxy_client.tcp_target,
|
||||
proxy_client.socket_timeout,
|
||||
tls,
|
||||
);
|
||||
|
||||
proxy_client.start().expect("error running proxy_client");
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
*/
|
229
src/lib.rs
229
src/lib.rs
@ -1,10 +1,37 @@
|
||||
use std::io::{Read, Write};
|
||||
use std::net::{TcpListener, TcpStream, UdpSocket};
|
||||
use std::net::{TcpStream, UdpSocket};
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
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> {
|
||||
args: &'a Vec<String>,
|
||||
}
|
||||
@ -13,14 +40,45 @@ impl<'a> Args<'a> {
|
||||
pub fn new(args: &'a Vec<String>) -> Args {
|
||||
Args { args }
|
||||
}
|
||||
pub fn get_str(&self, index: usize, def: &'a str) -> &'a str {
|
||||
match self.args.get(index) {
|
||||
Some(ret) => ret,
|
||||
None => def,
|
||||
pub fn flag(&self, flag: &'a str) -> bool {
|
||||
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<T: FromStr>(&self, index: usize, def: T) -> T {
|
||||
match self.args.get(index) {
|
||||
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,
|
||||
None => def.to_owned(),
|
||||
}
|
||||
}
|
||||
pub fn get<T: FromStr>(&self, flags: &[&'a str], def: T) -> T {
|
||||
match self.get_option(flags) {
|
||||
Some(ret) => match ret.parse::<T>() {
|
||||
Ok(ret) => ret,
|
||||
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 udp_host: String,
|
||||
pub udp_target: String,
|
||||
pub tcp_target: String,
|
||||
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 {
|
||||
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 {
|
||||
udp_host,
|
||||
udp_target,
|
||||
tcp_target,
|
||||
socket_timeout: match secs {
|
||||
0 => None,
|
||||
@ -98,34 +135,19 @@ impl ProxyClient {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(&self) -> std::io::Result<usize> {
|
||||
fn tcp_connect(&self) -> Result<TcpStream> {
|
||||
let tcp_stream = TcpStream::connect(&self.tcp_target)?;
|
||||
|
||||
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)?;
|
||||
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
|
||||
|
||||
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()?;
|
||||
}
|
||||
Ok(udp_socket)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ProxyServer {
|
||||
pub tcp_host: String,
|
||||
pub client_handler: Arc<ProxyServerClientHandler>,
|
||||
}
|
||||
|
||||
impl ProxyServer {
|
||||
pub fn new(
|
||||
tcp_host: String,
|
||||
@ -150,42 +172,10 @@ impl ProxyServer {
|
||||
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 {
|
||||
pub fn handle_client(&self, tcp_stream: TcpStream) -> std::io::Result<usize> {
|
||||
tcp_stream.set_read_timeout(self.socket_timeout)?;
|
||||
|
||||
fn udp_bind(&self) -> Result<UdpSocket> {
|
||||
let mut port = self.udp_low_port;
|
||||
let udp_socket = loop {
|
||||
match UdpSocket::bind((&self.udp_host[..], port)) {
|
||||
@ -200,17 +190,6 @@ impl ProxyServerClientHandler {
|
||||
};
|
||||
udp_socket.set_read_timeout(self.socket_timeout)?;
|
||||
udp_socket.connect(&self.udp_target)?;
|
||||
|
||||
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()?;
|
||||
}
|
||||
Ok(udp_socket)
|
||||
}
|
||||
}
|
||||
|
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
|
||||
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
|
||||
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
|
||||
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=$!
|
||||
# wait for ports to be set up, this is fragile...
|
||||
sleep 1
|
||||
sleep 5
|
||||
# proxy pointing to proxyd
|
||||
cargo run --release --bin wireguard-proxy &
|
||||
wireguard-proxy -tt 127.0.0.1:5555 "$client_arg" &
|
||||
proxy_pid=$!
|
||||
# wait for ports to be set up, this is fragile...
|
||||
sleep 1
|
||||
# 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=$?
|
||||
|
||||
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