Giter Site home page Giter Site logo

erebe / wstunnel Goto Github PK

View Code? Open in Web Editor NEW
4.0K 52.0 349.0 18.3 MB

Tunnel all your traffic over Websocket or HTTP2 - Bypass firewalls/DPI - Static binary available

License: BSD 3-Clause "New" or "Revised" License

Rust 98.44% Dockerfile 0.64% Just 0.57% Shell 0.33% Go 0.01%
reverse-tunnel socks5-proxy tcp-tunnel transparent-proxy tunneling udp-tunnel websocket wireguard wireguard-tunnel http2

wstunnel's Introduction

wstunnel logo


Summary

Description

Most of the time when you are using a public network, you are behind some kind of firewall or proxy. One of their purpose is to constrain you to only use certain kind of protocols and consult only a subset of the web. Nowadays, the most widespread protocol is http and is de facto allowed by third party equipment.

Wstunnel uses the websocket protocol which is compatible with http in order to bypass firewalls and proxies. Wstunnel allows you to tunnel whatever traffic you want and access whatever resources/site you need.

My inspiration came from this project but as I don't want to install npm and nodejs to use this tool, I remade it in Haskell Rust and improved it.

What to expect:

  • Easy to use
  • Good error messages and debug information
  • Static forward and reverse tunneling (TCP, UDP, Unix socket, Stdio)
  • Dynamic tunneling (TCP, UDP Socks5 proxy and Transparent Proxy)
  • Support for http proxy (when behind one)
  • Support of proxy protocol
  • Support for tls/https server with certificates auto-reload (with embedded self-signed certificate, or your own)
  • Support of mTLS with certificates auto-reload - documentation here
  • Support IPv6
  • Support for Websocket and HTTP2 as transport protocol (websocket is more performant)
  • Standalone binaries (so just cp it where you want) here

Sponsors

Part of Wstunnel development has been sponsored by

service planet logo

Note

v7.0.0 is a complete rewrite of wstunnel in Rust and is not compatible with previous version. Previous code in Haskell can be found on branch https://github.com/erebe/wstunnel/tree/haskell

What to expect from previous version:

  • More throughput and less jitter due to Haskell GC. Most of you will not care, as it was performant enough already. But you can now saturate a gigabit ethernet card with a single connection
  • Command line is more homogeneous/has better UX. All tunnel can be specified multiple times
  • Tunnel protocol tries to look like normal traffic, to avoid being flagged
  • Support of reverse tunneling
  • New bug, it is a rewrite (╯'□')╯︵ ┻━┻ ¯\(ツ)
  • Mainly for me to ease the maintenance of the project. I don't do a lot of haskell nowadays and it was harder for me to keep maintening the project over time, as I get lost in touch of the Haskell ecosystem and new release.
  • Armv7 build (aka raspberry pi), as new version of GHC (Haskell compiler) dropped its support

Command line

Usage: wstunnel client [OPTIONS] <ws[s]|http[s]://wstunnel.server.com[:port]>

Arguments:
  <ws[s]|http[s]://wstunnel.server.com[:port]>
          Address of the wstunnel server
          You can either use websocket or http2 as transport protocol. Use websocket if you are unsure.
          Example: For websocket with TLS wss://wstunnel.example.com or without ws://wstunnel.example.com
                   For http2 with TLS https://wstunnel.example.com or without http://wstunnel.example.com
          
          *WARNING* HTTP2 as transport protocol is harder to make it works because:
            - If you are behind a (reverse) proxy/CDN they are going to buffer the whole request before forwarding it to the server
              Obviously, this is not going to work for tunneling traffic
            - if you have wstunnel behind a reverse proxy, most of them (i.e: nginx) are going to turn http2 request into http1
              This is not going to work, because http1 does not support streaming naturally
          The only way to make it works with http2 is to have wstunnel directly exposed to the internet without any reverse proxy in front of it

Options:
  -L, --local-to-remote <{tcp,udp,socks5,stdio,unix}://[BIND:]PORT:HOST:PORT>
          Listen on local and forwards traffic from remote. Can be specified multiple times
          examples:
          'tcp://1212:google.com:443'      =>       listen locally on tcp on port 1212 and forward to google.com on port 443
          'tcp://2:n.lan:4?proxy_protocol' =>       listen locally on tcp on port 2 and forward to n.lan on port 4
                                                    Send a proxy protocol header v2 when establishing connection to n.lan
          
          'udp://1212:1.1.1.1:53'          =>       listen locally on udp on port 1212 and forward to cloudflare dns 1.1.1.1 on port 53
          'udp://1212:1.1.1.1:53?timeout_sec=10'    timeout_sec on udp force close the tunnel after 10sec. Set it to 0 to disable the timeout [default: 30]
          
          'socks5://[::1]:1212'            =>       listen locally with socks5 on port 1212 and forward dynamically requested tunnel
          'socks5://[::1]:1212?login=admin&password=admin' => listen locally with socks5 on port 1212 and only accept connection with login=admin and password=admin
          
          'tproxy+tcp://[::1]:1212'        =>       listen locally on tcp on port 1212 as a *transparent proxy* and forward dynamically requested tunnel
          'tproxy+udp://[::1]:1212?timeout_sec=10'  listen locally on udp on port 1212 as a *transparent proxy* and forward dynamically requested tunnel
                                                    linux only and requires sudo/CAP_NET_ADMIN
          
          'stdio://google.com:443'         =>       listen for data from stdio, mainly for `ssh -o ProxyCommand="wstunnel client --log-lvl=off -L stdio://%h:%p ws://localhost:8080" my-server`
          
          'unix:///tmp/wstunnel.sock:g.com:443' =>  listen for data from unix socket of path /tmp/wstunnel.sock and forward to g.com:443

  -R, --remote-to-local <{tcp,udp,socks5,unix}://[BIND:]PORT:HOST:PORT>
          Listen on remote and forwards traffic from local. Can be specified multiple times. Only tcp is supported
          examples:
          'tcp://1212:google.com:443'      =>     listen on server for incoming tcp cnx on port 1212 and forward to google.com on port 443 from local machine
          'udp://1212:1.1.1.1:53'          =>     listen on server for incoming udp on port 1212 and forward to cloudflare dns 1.1.1.1 on port 53 from local machine
          'socks5://[::1]:1212'            =>     listen on server for incoming socks5 request on port 1212 and forward dynamically request from local machine
          'unix://wstunnel.sock:g.com:443' =>     listen on server for incoming data from unix socket of path wstunnel.sock and forward to g.com:443 from local machine

      --no-color <NO_COLOR>
          Disable color output in logs
          
          [env: NO_COLOR=]

      --socket-so-mark <INT>
          (linux only) Mark network packet with SO_MARK sockoption with the specified value.
          You need to use {root, sudo, capabilities} to run wstunnel when using this option

  -c, --connection-min-idle <INT>
          Client will maintain a pool of open connection to the server, in order to speed up the connection process.
          This option set the maximum number of connection that will be kept open.
          This is useful if you plan to create/destroy a lot of tunnel (i.e: with socks5 to navigate with a browser)
          It will avoid the latency of doing tcp + tls handshake with the server
          
          [default: 0]

      --nb-worker-threads <INT>
          *WARNING* The flag does nothing, you need to set the env variable *WARNING*
          Control the number of threads that will be used.
          By default, it is equal the number of cpus
          
          [env: TOKIO_WORKER_THREADS=]

      --log-lvl <LOG_LEVEL>
          Control the log verbosity. i.e: TRACE, DEBUG, INFO, WARN, ERROR, OFF
          for more details: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#example-syntax
          
          [env: RUST_LOG=]
          [default: INFO]

      --tls-sni-override <DOMAIN_NAME>
          Domain name that will be used as SNI during TLS handshake
          Warning: If you are behind a CDN (i.e: Cloudflare) you must set this domain also in the http HOST header.
                   or it will be flagged as fishy and your request rejected

      --tls-sni-disable
          Disable sending SNI during TLS handshake
          Warning: Most reverse proxies rely on it

      --tls-verify-certificate
          Enable TLS certificate verification.
          Disabled by default. The client will happily connect to any server with self-signed certificate.

  -p, --http-proxy <USER:PASS@HOST:PORT>
          If set, will use this http proxy to connect to the server
          
          [env: HTTP_PROXY=]

      --http-proxy-login <LOGIN>
          If set, will use this login to connect to the http proxy. Override the one from --http-proxy
          
          [env: WSTUNNEL_HTTP_PROXY_LOGIN=]

      --http-proxy-password <PASSWORD>
          If set, will use this password to connect to the http proxy. Override the one from --http-proxy
          
          [env: WSTUNNEL_HTTP_PROXY_PASSWORD=]

  -P, --http-upgrade-path-prefix <HTTP_UPGRADE_PATH_PREFIX>
          Use a specific prefix that will show up in the http path during the upgrade request.
          Useful if you need to route requests server side but don't have vhosts
          
          [env: WSTUNNEL_HTTP_UPGRADE_PATH_PREFIX=]
          [default: v1]

      --http-upgrade-credentials <USER[:PASS]>
          Pass authorization header with basic auth credentials during the upgrade request.
          If you need more customization, you can use the http_headers option.

      --websocket-ping-frequency-sec <seconds>
          Frequency at which the client will send websocket ping to the server.
          
          [default: 30]

      --websocket-mask-frame
          Enable the masking of websocket frames. Default is false
          Enable this option only if you use unsecure (non TLS) websocket server, and you see some issues. Otherwise, it is just overhead.

  -H, --http-headers <HEADER_NAME: HEADER_VALUE>
          Send custom headers in the upgrade request
          Can be specified multiple time

      --http-headers-file <FILE_PATH>
          Send custom headers in the upgrade request reading them from a file.
          It overrides http_headers specified from command line.
          File is read everytime and file format must contain lines with `HEADER_NAME: HEADER_VALUE`

      --tls-certificate <FILE_PATH>
          [Optional] Certificate (pem) to present to the server when connecting over TLS (HTTPS).
          Used when the server requires clients to authenticate themselves with a certificate (i.e. mTLS).
          The certificate will be automatically reloaded if it changes

      --tls-private-key <FILE_PATH>
          [Optional] The private key for the corresponding certificate used with mTLS.
          The certificate will be automatically reloaded if it changes

      --dns-resolver <DNS_RESOLVER>
          Dns resolver to use to lookup ips of domain name. Can be specified multiple time
          Example:
           dns://1.1.1.1 for using udp
           dns+https://1.1.1.1?sni=cloudflare-dns.com for using dns over HTTPS
           dns+tls://8.8.8.8?sni=dns.google for using dns over TLS
          For Dns over HTTPS/TLS if an HTTP proxy is configured, it will be used also
          To use libc resolver, use
          system://0.0.0.0

          **WARN** On windows you may want to specify explicitly the DNS resolver to avoid excessive DNS queries

SERVER
Usage: wstunnel server [OPTIONS] <ws[s]://0.0.0.0[:port]>

Arguments:
  <ws[s]://0.0.0.0[:port]>
          Address of the wstunnel server to bind to
          Example: With TLS wss://0.0.0.0:8080 or without ws://[::]:8080
          
          The server is capable of detecting by itself if the request is websocket or http2. So you don't need to specify it.

Options:
      --socket-so-mark <INT>
          (linux only) Mark network packet with SO_MARK sockoption with the specified value.
          You need to use {root, sudo, capabilities} to run wstunnel when using this option

      --websocket-ping-frequency-sec <seconds>
          Frequency at which the server will send websocket ping to client.

      --no-color <NO_COLOR>
          Disable color output in logs
          
          [env: NO_COLOR=]

      --websocket-mask-frame
          Enable the masking of websocket frames. Default is false
          Enable this option only if you use unsecure (non TLS) websocket server, and you see some issues. Otherwise, it is just overhead.

      --nb-worker-threads <INT>
          *WARNING* The flag does nothing, you need to set the env variable *WARNING*
          Control the number of threads that will be used.
          By default, it is equal the number of cpus
          
          [env: TOKIO_WORKER_THREADS=]

      --restrict-to <DEST:PORT>
          Server will only accept connection from the specified tunnel information.
          Can be specified multiple time
          Example: --restrict-to "google.com:443" --restrict-to "localhost:22"

      --dns-resolver <DNS_RESOLVER>
          Dns resolver to use to lookup ips of domain name
          This option is not going to work if you use transparent proxy
          Can be specified multiple time
          Example:
           dns://1.1.1.1 for using udp
           dns+https://1.1.1.1?sni=loudflare-dns.com for using dns over HTTPS
           dns+tls://8.8.8.8?sni=dns.google for using dns over TLS
          To use libc resolver, use
          system://0.0.0.0

      --log-lvl <LOG_LEVEL>
          Control the log verbosity. i.e: TRACE, DEBUG, INFO, WARN, ERROR, OFF
          for more details: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#example-syntax
          
          [env: RUST_LOG=]
          [default: INFO]

  -r, --restrict-http-upgrade-path-prefix <RESTRICT_HTTP_UPGRADE_PATH_PREFIX>
          Server will only accept connection from if this specific path prefix is used during websocket upgrade.
          Useful if you specify in the client a custom path prefix, and you want the server to only allow this one.
          The path prefix act as a secret to authenticate clients
          Disabled by default. Accept all path prefix. Can be specified multiple time
          
          [env: WSTUNNEL_RESTRICT_HTTP_UPGRADE_PATH_PREFIX=]

      --restrict-config <RESTRICT_CONFIG>
          Path to the location of the restriction yaml config file.
          Restriction file is automatically reloaded if it changes

      --tls-certificate <FILE_PATH>
          [Optional] Use custom certificate (pem) instead of the default embedded self-signed certificate.
          The certificate will be automatically reloaded if it changes

      --tls-private-key <FILE_PATH>
          [Optional] Use a custom tls key (pem, ec, rsa) that the server will use instead of the default embedded one
          The private key will be automatically reloaded if it changes

      --tls-client-ca-certs <FILE_PATH>
          [Optional] Enables mTLS (client authentication with certificate). Argument must be PEM file
          containing one or more certificates of CA's of which the certificate of clients needs to be signed with.
          The ca will be automatically reloaded if it changes

Release

Static binaries are available in release section

docker image are available at https://github.com/erebe/wstunnel/pkgs/container/wstunnel

docker pull ghcr.io/erebe/wstunnel:latest

Examples

Understand command line syntax

Wstunnel command line mimic ssh tunnel syntax. You can take reference to this article, or this diagram to understand


Simplest one

On your remote host, start the wstunnel's server by typing this command in your terminal

wstunnel server wss://[::]:8080

This will create a websocket server listening on any interface on port 8080. On the client side use this command to forward traffic through the websocket tunnel

wstunnel client -L socks5://127.0.0.1:8888 --connection-min-idle 5 wss://myRemoteHost:8080

This command will create a socks5 server listening on port 8888 of the loopback interface and will forward traffic dynamically. connection-min-idle 10 is going an optimization to create a pool of 10 connection connected to the server, to speed-up the establishement of new tunnels.

With firefox you can setup a proxy using this tunnel, by setting in networking preferences 127.0.0.1:8888 and selecting socks5 proxy. Be sure to check the option Proxy DNS when using SOCKS v5 for the server to resolve DNS name and not your local machine.

or with curl

curl -x socks5h://127.0.0.1:8888 http://google.com/
#Please note h after the 5, it is to avoid curl resolving DNS name locally

As proxy command for SSH

You can specify stdio as source port on the client side if you wish to use wstunnel as part of a proxy command for ssh

ssh -o ProxyCommand="wstunnel client --log-lvl=off -L stdio://%h:%p ws://myRemoteHost:8080" my-server

When behind a corporate proxy

An other useful example is when you want to bypass an http proxy (a corporate proxy for example) The most reliable way to do it is to use wstunnel as described below

Start your wstunnel server with tls activated

wstunnel server wss://[::]:443 --restrict-to 127.0.0.1:22

The server will listen on any interface using port 443 (https) and restrict traffic to be forwarded only to the ssh daemon.

Be aware that the server will use self signed certificate with weak cryptographic algorithm. It was made in order to add the least possible overhead while still being compliant with tls.

Do not rely on wstunnel to protect your privacy, if it is one of your concerns, you should only forwards traffic that is already secure by design (ie: https or vpn traffic)

Now on the client side start the client with

wstunnel client -L tcp://9999:127.0.0.1:22 -p http://mycorporateproxy:8080 wss://myRemoteHost:443

It will start a tcp server on port 9999 that will contact the corporate proxy, negotiate a tls connection with the remote host and forward traffic to the ssh daemon on the remote host.

You may now access your server from your local machine on ssh by using

ssh -p 9999 [email protected]

Wireguard and wstunnel

You have a working wireguard client configuration called wg0.conf. Let's say

[Interface]
Address = 10.200.0.2/32, fd00:cafe::2/128
PrivateKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=

[Peer]
PublicKey = 9iicV7Stdl/U0RH1BNf3VvlVjaa4Eus6QPEfEz6cR0c=
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = my.server.com:51820

Start wstunnel server on my.server.com like this

wstunnel server --restrict-to localhost:51820 wss://[::]:443

on your local machine start the client like this

wstunnel client -L 'udp://51820:localhost:51820?timeout_sec=0' wss://my.server.com:443

change your wireguard client config to something

[Interface]
Address = 10.200.0.2/32, fd00:cafe::2/128
PrivateKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
# Replace by a dns your server has access to
dns = 8.8.8.8
# https://github.com/nitred/nr-wg-mtu-finder to find best mtu for you
MTU = 1400 

[Peer]
PublicKey = 9iicV7Stdl/U0RH1BNf3VvlVjaa4Eus6QPEfEz6cR0c=
AllowedIPs = 0.0.0.0/0, ::/0
# Should target port where wstunnel client is listenning to
Endpoint = localhost:51820
# Should not be necessary if you enable wstunnel client websocket ping
PersistentKeepalive = 20

Add a default route to your server, as your AllowedIps are catch-all, it is to avoid the traffic looping.

sudo ip route add ip.of.my.server.com dev eth0 via 192.168.0.1
# replace eth0 (interface) and 192.168.0.1 (router gateway) by the one given by `ip route get ip.of.my.server.com` 

start your wireguard, and it should be working

sudo wg-quick up wg0
ping 10.200.0.1 # ping another ip of your vpn network

FAQ

  • Disable default udp tunnel timeout that will auto-close it after 30sec. i.e: udp://1212:127.0.0.1:5201?timeout_sec=0
  • If you see some throughput issue, be sure to lower the MTU of your wireguard interface (you can do it via config file) to something like 1300 or you will endup fragmenting udp packet (due to overhead of other layer) which is always causing issues
  • If wstunnel cannot connect to server while wireguard is on, be sure you have added a static route via your main gateway for the ip of wstunnel server. Else if you forward all the traffic without putting a static route, you will endup looping your traffic wireguard interface -> wstunnel client -> wireguard interface
  • If you have trouble making it works on windows, please check this issue #252

Transparent proxy (linux only)

Transparent proxy allows to easily proxy any program. Start wstunnel with

sudo wstunnel client -L 'tproxy+tcp://1080' -L 'tproxy+udp://1080' wss://my.server.com:443

use this project to route traffic seamlessly https://github.com/NOBLES5E/cproxy. It works with any program

cproxy --port 1080 --mode tproxy -- curl https://google.com

You can even start a new shell, were all your commands will be proxyfied

cproxy --port 1080 --mode tproxy -- bash

Reverse tunneling

Start wstunnel with

sudo wstunnel client -R 'tcp://[::]:8000:localhost:8000' wss://my.server.com:443

In another terminal, start a simple webserver on your local machine

python3 -m http.server

From your my.server.com machine/network you can now do

curl http://localhost:8000

How to secure the access of your wstunnel server

Generate a secret, let's say h3GywpDrP6gJEdZ6xbJbZZVFmvFZDCa4KcRd

Now start you server with the following command

wstunnel server --restrict-http-upgrade-path-prefix h3GywpDrP6gJEdZ6xbJbZZVFmvFZDCa4KcRd  wss://[::]:443 

And start your client with

wstunnel client --http-upgrade-path-prefix h3GywpDrP6gJEdZ6xbJbZZVFmvFZDCa4KcRd ... wss://myRemoteHost

Now your wstunnel server, will only accept connection if the client specify the correct path prefix during the upgrade request.

If you need more customization, you can use a config file to specify specific rules with --restrict-config. You can find examples of restriction rules there


Use HTTP2 instead of websocket for the transport protocol

Use this only if websocket is blocked by your firewall/proxy. Otherwise, it is less performant than websocket.

Start your wstunnel server as usual with

wstunnel server wss://[::]:8080

On the client the only difference is to specify https:// instead of wss://

wstunnel client -L socks5://127.0.0.1:8888 https://myRemoteHost:8080

WARNING HTTP2 as transport protocol is harder to make it works because:

  • If you are behind a (reverse) proxy/CDN they may buffer the whole request before forwarding it to the server. Cloudflare is doing that, and obviously, this is not going to work for tunneling traffic
  • if you have wstunnel behind a reverse proxy, most of them (i.e: nginx) are going to turn http2 request into http1 This is not going to work, because http1 does not support streaming naturally

The only way to make it works with HTTP2 is to have wstunnel server directly exposed to the internet without any reverse proxy in front of it

In addition, you may also want to play with the request headers (i.e: content-length and content-type) to make it looks like normal traffic to bypass your firewall/proxy. Some firewall may not like to see request with content-length not set, or with content-type set to application/octet-stream

Maximize your stealthiness/Make your traffic discrete

  • Use wstunnel with TLS activated (wss://) and use your own certificate
    • Embedded certificate is self-signed and are the same for everyone, so can be easily fingerprinted/flagged
    • Use valid certificate (i.e: with Let's Encrypt), self-signed certificate are suspicious
  • Use a custom http path prefix (see --http-upgrade-path-prefix option)
    • To avoid having the same url than every other wstunnel user
  • Change your tls-sni-override to a domain is known to be allowed (i.e: google.com, baidu.com, etc...)
    • this will not work if your wstunnel server is behind a reverse proxy (i.e: Nginx, Cloudflare, HAProxy, ...)

Benchmark

image

How to Build

Install the Rust https://www.rust-lang.org/tools/install or if you are a believer

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

and run those commands at the root of the project

cargo build
target/debug/wstunnel ...

wstunnel's People

Contributors

0xflotus avatar cattyhouse avatar contrun avatar corrm avatar dima-kal avatar dmitmel avatar erebe avatar gebner avatar grimsteel avatar jasongiedymin avatar kazamasion avatar r-vdp avatar shubhamkashyap1601 avatar siepkes avatar vercas avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wstunnel's Issues

wstunnel armv7l crashes on startup (but not on gdb) after it has been running for months

I discovered only today that since a week wstunnel on my server causes a segmentation fault and crashes when launched. It has worked properly for 3 months, but since the 28 of September it is giving me this problem. The server is a Raspberry Pi 2 running Arch Arm (armv7l), the client is a 64 bit Manjaro laptop (wstunnel here works fine).
Running gdb --args wstunnel --server --restrictTo=127.0.0.1:yyyyy ws://127.0.0.1:xxxxx, or even time wstunnel make wstunnel run correctly, while simply running wstunnel with or without arguments returns:

[1]    29440 segmentation fault (core dumped)  wstunnel

If it may help, these are the steps I've used to install it back in July:

wget https://github.com/erebe/wstunnel/releases/download/2.0/wstunnel-armv7l
chmod +x wstunnel-armv7l
sudo mv wstunnel-armv7l /usr/bin/wstunnel

This is the service that I use to run it at startup:
wstunnel.service

[Unit]
Description=Tunnel WG UDP over websocket
After=network.target

[Service]
Type=simple
User=nobody
ExecStart=/usr/bin/wstunnel --server --restrictTo=127.0.0.1:yyyyy ws://127.0.0.1:xxxxx
Restart=no

[Install]
WantedBy=multi-user.target

This is the journalctl log:
journalctl -u wstunnel.service

[...]
-- Reboot --
Sep 23 04:00:09 hostname systemd[1]: Started Tunnel WG UDP over websocket.
Sep 23 04:00:15 hostname wstunnel[326]: WAIT for connection on 127.0.0.1:xxxxx
Sep 23 15:30:15 hostname systemd[1]: Stopping Tunnel WG UDP over websocket...
Sep 23 15:30:15 hostname systemd[1]: wstunnel.service: Succeeded.
Sep 23 15:30:15 hostname systemd[1]: Stopped Tunnel WG UDP over websocket.
-- Reboot --
Sep 23 15:30:50 hostname systemd[1]: Started Tunnel WG UDP over websocket.
Sep 23 15:30:53 hostname wstunnel[272]: WAIT for connection on 127.0.0.1:xxxxx
Sep 25 12:24:20 hostname wstunnel[272]: SENDING datagrammes to 127.0.0.1:yyyyy
Sep 25 13:43:30 hostname wstunnel[272]: CLOSE udp connection to 127.0.0.1:yyyyy
-- Reboot --
Sep 27 09:29:46 hostname systemd[1]: Started Tunnel WG UDP over websocket.
Sep 27 09:29:49 hostname wstunnel[314]: WAIT for connection on 127.0.0.1:xxxxx
Sep 27 14:47:37 hostname wstunnel[314]: SENDING datagrammes to 127.0.0.1:yyyyy
Sep 27 17:25:41 hostname wstunnel[314]: CLOSE udp connection to 127.0.0.1:yyyyy
-- Reboot --
Sep 28 13:33:25 hostname systemd[1]: Started Tunnel WG UDP over websocket.
Sep 28 13:33:31 hostname systemd[1]: wstunnel.service: Main process exited, code=dumped, status=11/SEGV
Sep 28 13:33:31 hostname systemd[1]: wstunnel.service: Failed with result 'core-dump'.
-- Reboot --
Sep 28 20:42:15 hostname systemd[1]: Started Tunnel WG UDP over websocket.
Sep 28 20:42:23 hostname systemd[1]: wstunnel.service: Main process exited, code=dumped, status=11/SEGV
Sep 28 20:42:23 hostname systemd[1]: wstunnel.service: Failed with result 'core-dump'.
-- Reboot --
[...]

Of course I have checked if the file has been altered and no, it has the same hashes of the one I downloaded in July.

stdio support is broken

At least as of version 3 stdio support is broken:

Example

Server

wstunnel -v --server ws://0.0.0.0
netcat -l -p 1234

Client

wstunnel  -vL stdio:127.0.0.1:1234 ws://192.168.0.14

No Public IP

First of all I have to say this is a very useful piece of software :) My question is: Is it possible to connect to a client that has NO public IP address with some sort of NAT traversal or a similar technique?

Add path support

Hello,

if the 'Client' is wstunnel it 's can not connect to wstunnel server in this case:

Client <---> Caddy  <----proxy ws with fixed path ---> wstunnel server <---> tcp server

So,can you add path support?

thanks.

SSL handshake error with server behind nginx

Description

I have problem with the wstunnel v3 (linux) causing my nginx saying

client timed out (110: Connection timed out) while SSL handshaking

On previous versions, everything is ok. Even on your recent build, the binary worked for me.

How to reproduce

Here is my simple topology:

client <=> nginx <=> server

Client side

wstunnel -L 127.0.0.1:4505:my_remote:4505 wss://mynginx

Server side

wstunnel --server ws://0.0.0.0:4515 -r 127.0.0.1:4505
# Service is listening to port 4505 on server side

nginx

server {
    listen  443 ssl;
    tcp_nopush on;
    tcp_nodelay on;
   ... some ssl config ...

    location ~ ^/wstunnel/tcp/my_remote/4505 {
        rewrite ^ /tcp/127.0.0.1/4505 break;
        proxy_pass              http://myserver:4515;
        proxy_next_upstream     off;
        proxy_http_version      1.1;
        proxy_set_header        Upgrade $http_upgrade;
        proxy_set_header        Connection "upgrade";
        proxy_send_timeout      5m;
        proxy_read_timeout      5m;
    }

I try to check the changes from the working build 39b37f0 with the latest release here. It seems that you add some features for SO_MARK.
I have no idea about Haskell so could you please check it for me?

For now, I am using the binary from this build: https://github.com/erebe/wstunnel/runs/377533985

Build for iphoneos aarch64?

It’d be really nice for jailbroken iOS users to connect from wireguard over websocket to bypass restricted networks without taking much of a performance hit.

I can provide you SSH access to a jailbroken iPhone if you’d like to run test builds on.

There’s also this project but I don’t think it uses websocket.

UDP not stable

Hello sir
UDP session isn't stable connection always reset on DPI network and opens new connection any solution please TCP looks solid

"Phone Home" Style connections?

Does this project support "phone home" connections like:
https://github.com/rightscale/wstunnel

Basically, a "probe" device connects to a "server" out on the internet and establishes a persistent websocket, then other "clients" can connect to the server and ride the connection back in to access an internal tcp port.

Our use case for this is management systems that we have at customer client sites as an MSP that we'd like to SSH and RDP to other devices but without having to set up IPSec connectiviy. We do this with SSH tunneling today but websockets would be more "transparent" to firewalls.

Thanks.

win32 binary

Hello,
Is it possible for you to build a standalone archive for windows 32 bit ?
Thanks in advance.

Binary for MIPS architecture

Hi there erebe, I was wondering if you have all of the tools at your disposal to create a MIPS-compliant binary. The GL-iNet AR300M is an awesome little travel router, and I was wanting to get wstunnel set up on it for an upcoming trip.

If not, I'm planning on cloning and seeing if I can get one to build successfully, but I'm not familiar with Haskell and I haven't worked with it before for any projects.

Here's an output of /proc/cpuinfo for reference:

root@ar300m:~# cat /proc/cpuinfo
system type             : Qualcomm Atheros QCA9533 ver 2 rev 0
machine                 : GL.iNet GL-AR300M
processor               : 0
cpu model               : MIPS 24Kc V7.4
BogoMIPS                : 432.53
wait instruction        : yes
microsecond timers      : yes
tlb_entries             : 16
extra interrupt vector  : yes
hardware watchpoint     : yes, count: 4, address/irw mask: [0x0ffc, 0x0ffc, 0x0ffb, 0x0ffb]
isa                     : mips1 mips2 mips32r1 mips32r2
ASEs implemented        : mips16
shadow register sets    : 1
kscratch registers      : 0
package                 : 0
core                    : 0
VCED exceptions         : not available
VCEI exceptions         : not available

Thanks for checking out my request and I hope to hear back!

Bountysource

SO_MARK support

Hi, can u add option to mark wstunnel packets as realized in v2ray?

Limit number of connections

Hello,

I would like to ask about the number of connections that wstunnel can keep at a same time (for the server side).
I have done some tests and the result shows that it could hold around 500 connections.
Is there a limit in the number of connections that 1 process of wstunnel can hold? Is it set anywhere in the code?

Thanks

HandshakeFailed error when using wss:// (works with ws://)

On the same machine, running the following commands works fine and allows me to access port 8000 through port 8001:

sudo wstunnel -v --server ws://localhost -r localhost:8000 & # sudo to use port 80
wstunnel -v -L localhost:8001:localhost:8000 ws://localhost &
# test
curl localhost:8001

But the following, just swapping ws:// for wss://, does not:

sudo wstunnel -v --server wss://localhost -r localhost:8000 &
wstunnel -v -L localhost:8001:localhost:8000 wss://localhost &
curl localhost:8001

The curl command says: curl: (56) Recv failure: Connection reset by peer.
The server says:

Starting server with opts WsServerInfo {useTls = True, host = "localhost", port = 443}
WAIT for TLS connection on localhost:443
wstunnel: HandshakeFailed (Error_Protocol ("credential not found",True,HandshakeFailure))

The client says:

WAIT for tcp connection on localhost:8001
DEBUG :: Oppening tcp connection to localhost:443
DEBUG :: Doing tls Handshake
DEBUG :: Closing tcp connection to localhost:443
ERROR :: Cannot do tls handshake with the server
DEBUG :: ====
HandshakeFailed (Error_Protocol ("expecting server hello, got alert : [(AlertLevel_Fatal,HandshakeFailure)]",True,HandshakeFailure))
====

Am I doing something incorrectly? I am using NixOS on aarch64 and just installed it with nix-env -iA nixos.wstunnel if that matters.

Thanks beforehand

UDP Support

Can I enable TCP/UDP listening at the same time?

MacOS binary?

Hello,

Is there a MacOS binary/build instructions available?

Corporate proxy checks pages

They check if a real page is there on 443 port, before allowing the connection. I can see in output "Failed reading: invalid header type" on the server side, and "ERROR :: Connection not allowed by the proxy" on the client side.
Is it possible to give them a sample page instead of generating an error?

Cheers, Alex

store location nginx

Please tell me if it is possible to work with another location.
Example client connect:
Its work:
/usr/bin/docker run --rm -it -p 9091:9091/tcp --name wstunnel local/wstunnel:1.2 -v -L 0.0.0.0:9091:192.168.0.3:9091 wss://domain.com:443
WAIT for tcp connection on 0.0.0.0:9091
DEBUG :: Oppening tcp connection to domain.com:443
DEBUG :: Doing tls Handshake
DEBUG :: Oppening Websocket stream

Use store locations do not work:
/usr/bin/docker run --rm -it -p 9091:9091/tcp --name wstunnel local/wstunnel:1.2 -v -L 0.0.0.0:9091:192.168.0.3:9091 wss://domain.com:443/storelocation
WAIT for tcp connection on 0.0.0.0:9091
DEBUG :: Oppening tcp connection to Error writing log message: Invalid port number 443/storelocation
CallStack (from HasCallStack):
error, called at app/Main.hs:82:31 in main:Main (original message: DEBUG :: Oppening tcp connection to DEBUG :: Oppening tcp connection to Error writing log message: Invalid port number 443/storelocation

/usr/bin/docker run --rm -it -p 9091:9091/tcp --name wstunnel local/wstunnel:1.2 -v -L 0.0.0.0:9091:192.168.0.3:9091 wss://domain.com/storelocation:443
WAIT for tcp connection on 0.0.0.0:9091
DEBUG :: Oppening tcp connection to domain.com/storelocation:443

Example Nginx config:
...
location /storelocation {
proxy_pass http://192.168.0.3:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}

Thank you.

Compilation error

Hello,

First thanks for this very interesting software. I'm trying to package it for the great pure package manager nix, but I have a compilation error: after running cabal2nix . > wstunnel.nix, that generated the following file:

{ mkDerivation, async, base, base64-bytestring, binary, bytestring
, classy-prelude, cmdargs, connection, hslogger, mtl, network
, network-conduit-tls, stdenv, streaming-commons, text
, unordered-containers, websockets
}:
mkDerivation {
  pname = "wstunnel";
  version = "0.1.0.0";
  src = ./.;
  isLibrary = true;
  isExecutable = true;
  libraryHaskellDepends = [
    async base base64-bytestring binary bytestring classy-prelude
    connection hslogger mtl network network-conduit-tls
    streaming-commons text unordered-containers websockets
  ];
  executableHaskellDepends = [
    base bytestring classy-prelude cmdargs hslogger text
  ];
  testHaskellDepends = [ base text ];
  homepage = "https://github.com/githubuser/wstunnel#readme";
  description = "Initial project template from stack";
  license = stdenv.lib.licenses.bsd3;
}

I put in default.nix the code:

{ nixpkgs ? import <nixpkgs> {}, compiler ? "ghc863" }:
nixpkgs.pkgs.haskell.packages.${compiler}.callPackage ./wstunnel.nix { }

and to compile I ran nix-build default.nix. This downloads all the dependencies, however when it comes to compilation, the 3rd file "src/Types.hs" fails to compile:

Preprocessing library for wstunnel-0.1.0.0..
Building library for wstunnel-0.1.0.0..
[1 of 7] Compiling Credentials      ( src/Credentials.hs, dist/build/Credentials.o )
[2 of 7] Compiling Logger           ( src/Logger.hs, dist/build/Logger.o )
[3 of 7] Compiling Socks5           ( src/Socks5.hs, dist/build/Socks5.o )
[4 of 7] Compiling Types            ( src/Types.hs, dist/build/Types.o )

src/Types.hs:22:1: error:
    • Can't make a derived instance of ‘Generic PortNumber’:
        The data constructors of ‘PortNumber’ are not all in scope
          so you cannot derive an instance for it
    • In the stand-alone deriving instance for ‘Generic PortNumber’
   |
22 | deriving instance Generic PortNumber
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
builder for '/nix/store/dp76w5kgmypi9n4fj9smlgd7zf5px3z3-wstunnel-0.1.0.0.drv' failed with exit code 1
error: build of '/nix/store/dp76w5kgmypi9n4fj9smlgd7zf5px3z3-wstunnel-0.1.0.0.drv' failed

Any idea why? (note: with stack init && stack build it works)

Idle connection can be close by some firewall

Hello,

I'm facing the following issue, my case is on AWS using NLB (Network Load Balancer) but I think other can face it on other kind of environment.

The topology is the following:

ClientHost <---> wsTunnelClient <-- AWS NLB --> wsTunnelServer <---> RemoteHost

The connection is initiate by ClientHost through RemoteHost, but data are sent from RemoteHost to ClientHost. When everything is starting up everything is ok, RemotHost can send data to clientHost through the tunnel. After 6 minutes of idle connection (no data send in the tunnel by RemoteHost) the AWS NLB is closing the connection silently so for wsTunnelClient and wsTunnelServer every seems ok but in fact the TCP connection is closed on NLB. So when RemoteHost is trying to send data again after the 6 minutes it's got a TCP RST and on ClientHost nothing happen because for it connection seems up (because it's not trying to using it, it's just waiting for data that will never come).

I'm wondering if there is any possibility for wsTunnelClient to use TCP KEEP ALIVE or Websokcet Ping to keep the tunnel up without activity ?

Regards,
Macfly

socks5 server error

use git latest version and curl for socks5 proxy test

Starting socks5 proxy ServerSettings {listenOn = 9999, bindOn = "0.0.0.0"}
wstunnel: Data.Binary.Get.runGet at position 4: Data.Binary.Get(Alternative).empty
CallStack (from HasCallStack):
error, called at libraries/binary/src/Data/Binary/Get.hs:342:5 in binary-0.8.3.0:Data.Binary.Get
wstunnel: Data.Binary.Get.runGet at position 4: Data.Binary.Get(Alternative).empty

UDP tunnel is mono-directional?

Greetings,

while trying to forward an UDP port through the tunnel, I discovered that the wstunnel client seems to keep the port busy because it's apparently listening for datagrams to forward through the tunnel.
This, however, seems to make it impossible to receive anything from the said port from the remote end, as any application trying to listen for datagrams gets a "port is busy" error.
Is this expected behavior?

TLS 1.3 support

ERROR :: Cannot do tls handshake with the server
DEBUG :: ====
HandshakeFailed (Error_Protocol ("expecting server hello, got alert : [(AlertLevel_Fatal,ProtocolVersion)]",True,HandshakeFailure))

Ha sorry, I can't upgrade to the latest LTS due to this issue #8
I need to make some changes in order for wstunnel to work with the latest tls package.

Sadly I don't have much free time right now, so it may take time before I upgrade it.

Originally posted by @erebe in #17 (comment)

authentication support

to secure the server tunnel we should be able to set credentials

wstunnel --server --credentials mycredentials.htpasswd wss://0.0.0.0:443

then the client wstunnel wss://myuser:mypass@server:443

Version 3 stable release date

Hello,

I am glad that wstunnel have new features and I really love to use the -L parameters to group severals wstunnel process. But right now, it's still a pre-release version.
May I know that when will we have the stable version?

Thank you

Feature request: prefix path

Hi, I have recently discovered this project and it's proving to be very useful to me. I'm planning on using this to tunnel wireguard udp traffic from behind firewall that blocks udp but allows https without proxy.

I'm using nginx as a reverse proxy with config like:

location /udp/ {
        proxy_pass http://127.0.0.1:33344/udp/;
        proxy_http_version  1.1;
        proxy_set_header    Upgrade $http_upgrade;
        proxy_set_header    Connection "upgrade";
        proxy_set_header    Host $http_host;
        proxy_set_header    X-Real-IP $remote_addr;
    }

and run wstunnel like so: wstunnel --server ws://127.0.0.1:33344 --restrictTo=127.0.0.1:$wgport

And this works great, but I would like to have an option to have extra prefix before /{udp|tcp|socks5}/{host}/{port}. For my use-case it's only needed on a client side as nginx can just strip it away before passing to wstunnel server.

I'd like to be able to supply uri like this to the client: wss://some.host.com/.wstunnel/ meaning

  1. Connect to some.host.com:443
  2. Prepend /.wstunnel/ path when creating websocket

Nginx config will then look like

location /.wstunnel/ {
   proxy_pass http://127.0.0.1:33344/;
...
}

I can barely read Haskell, but I think this should be quite doable, toPath, parseServerInfo will need to change as well their data structures WsServerInfo,TunnelSettings.

IPv6 support

It seems that wstunnel does not support IPv6 yet

./wstunnel_linux_x64 -D [2001:da8:e::1:6]:24080 ws://127.0.0.1:8080

with errror

wstunnel_linux_x64: Invalid tunneling information `[2001:da8:e::1:6]:24080:127.0.0.1:1212`, please use format [BIND:]PORT:HOST:PORT
CallStack (from HasCallStack):
  error, called at app/Main.hs:97:35 in main:Main

I try using host (set in dns, or in etc\hosts)

./wstunnel_linux_x64 -D ws.uk.to:24080 ws://127.0.0.1:8080

then not be resolved

Starting socks5 proxy ServerSettings {listenOn = 24080, bindOn = "ws.uk.to"}
wstunnel_linux_x64: Network.Socket.getAddrInfo: does not exist (Name does not resolve)

MacOS: Connectivity Issue

I'm trying to use this in my Mac OS (Mojave) by installing the "wstunnel-macos" binaries but for some reason, I can't get it to work. Post installation, I execute the following command to get the process started:

wstunnel -D 8888 wss://{url}
I see the following getting printed:
Starting socks5 proxy ServerSettings {listenOn = 8888, bindOn = "127.0.0.1"}

However, after that, when I try to connect to any specific service, I see the following errors on the command line (because of which the connectivity fails):

wstunnel: Data.Binary.Get.runGet at position 0: not enough bytes
CallStack (from HasCallStack):
  error, called at libraries/binary/src/Data/Binary/Get.hs:342:5 in binary-0.8.3.0:Data.Binary.Get
CLOSE tunnel :: 127.0.0.1:8888 <==WSS==> {url} <==TCP==> {some_ip}

I'm not sure what I'm doing wrong though. Would appreciate any help or pointers with this one. Thanks!

Udp not working

Using version 2.0
On the Linux server side: wstunnel --server ws://0.0.0.0:10001
On the Windows client side: wstunnel.exe -u ws://name.domain -D 1080
Now tcp traffic works fine, but udp doesn't work.
On the server side, there is a lot of logs:
CONNECTING to 0.0.0.0:0 wstunnel: Network.Socket.connect: <socket: 12>: does not exist (Connection refused)

Support Basic Auth

I'm using your wstunnel behind NginX as Proxy. The upgradePathPrefix makes it capable to run next to a deployed website.

But I additinally want to secure this websocket by a basic authentication.
Therefore I thought it would be great to support something like wstunnel -L 1234:remote.tld:4321 --upgradePathPrefix=/some/subpath wss://<user>:<pass>@domain.tld

Supporting <user>:<pass>@ in the connection string would be great!

Current behaviour: The parser detects <pass>@... as port - well, and fails^^

Can I have something like `--not-so-paranoid`?

When I'm connecting to a bad endpoint, wstunnel keeps trying to connect and spams terminal.

$ wstunnel ws://192.168.1.1 -L stdio:localhost:22
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
ERROR :: Cannot establish websocket connection with the server
...

I would like wstunnelto just give up.

"publicness"

Even though there is already an option to restrict proxying to single target, the default error message is quite unique which led me to check shodan for it.

So maybe it would make sense to update that text to Bad request or something like the default 400 response bodies?

Also, tried to see how to add a "HTTP header check" but my haskell is quite Nothing.

Would that be a simple "security" feature, passing --key RandomKeyString on both server and client, client sends it over in an HTTP header during WS handshake and server makes sure it matches or just 400 on it

hostname vs IP address in client

For me, using the hostname for the client command, as given in the examples in README.MD, does not work (neither with nor without specifying the :443)

[jan@one-arch ~]$ wstunnel -v --udp --udpTimeoutSec -1 -L 127.0.0.1:37123:127.0.0.1:37123 wss://sub.domain.tld:443
WAIT for datagrames on 127.0.0.1:37123
DEBUG :: Oppening tcp connection to sub.domain.tld:443
DEBUG :: TIMEOUT connection

Instead, specifying the IP address wss://1.2.3.4 will work.

ssh configuration

I've been using mhzed/wstunnel in my setup, and been using it's -t stdio feature to use .ssh/config, the idea of a single executable binary is wonderful, and i prefer to use this project over the other, can someone help with the ProxyCommand ?
thanks

wstunnel on android.

Hello sir.

Question #1:
How can i use wstunnel on my android cellphone as a client to use it as a VPN to tunnel all the connection ?
i just install wstunnel on my UBUNTU vps as a server.

Question #2:
I am behind a firewall and the firewall only let pass packet no more to 2000 bytes .

is it possible to add a option on the server to send the packet via "segment packet" , so the server should send the packet no more than 2000 bytes for example, Like " data chunk over multiple packet"? .

i will wait your answer. i really need your opinions.

Dump request

Any update will be added SNI?? I know it's already support tls but it's might be better add SNI for bypassing if blocked by firewall

Server segfault

v2.0 server quickly crashes with SIGSEGV on Raspbian Buster while running as SOCKS5 proxy.
Looks like it works only for small, single requests.

very slow (udp)

Hello.
https://kirill888.github.io/notes/wireguard-via-websocket/
Putting together a test bench on a localhost (virtual machine).
Measurements (on wg interface):

  1. Wireguard tunnel (no nginx, no wstunnel) via VM.

iperf3 -c 10.8.11.1
Connecting to host 10.8.11.1, port 5301
[ 5] local 10.8.11.5 port 40502 connected to 10.8.11.1 port 5301
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 16.3 MBytes 137 Mbits/sec 0 657 KBytes
[ 5] 1.00-2.00 sec 20.1 MBytes 168 Mbits/sec 0 1.24 MBytes
[ 5] 2.00-3.01 sec 20.0 MBytes 167 Mbits/sec 0 1.51 MBytes
[ 5] 3.01-4.00 sec 21.2 MBytes 179 Mbits/sec 0 1.51 MBytes
[ 5] 4.00-5.01 sec 20.0 MBytes 168 Mbits/sec 78 1.16 MBytes
[ 5] 5.01-6.01 sec 18.8 MBytes 157 Mbits/sec 0 1.26 MBytes
[ 5] 6.01-7.01 sec 20.0 MBytes 168 Mbits/sec 0 1.35 MBytes
[ 5] 7.01-8.00 sec 18.8 MBytes 158 Mbits/sec 0 1.41 MBytes
[ 5] 8.00-9.00 sec 21.2 MBytes 179 Mbits/sec 0 1.46 MBytes
[ 5] 9.00-10.01 sec 22.5 MBytes 188 Mbits/sec 0 1.49 MBytes


[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.01 sec 199 MBytes 167 Mbits/sec 78 sender
[ 5] 0.00-10.06 sec 196 MBytes 164 Mbits/sec receiver

iperf Done.

  1. Wireguard tunnel (with nginx, with wstunnel) via VM.

iperf3 -c 10.8.11.1
Connecting to host 10.8.11.1, port 5301
[ 5] local 10.8.11.5 port 40508 connected to 10.8.11.1 port 5301
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 1.89 MBytes 15.9 Mbits/sec 5 75.7 KBytes
[ 5] 1.00-2.00 sec 1.62 MBytes 13.6 Mbits/sec 0 95.6 KBytes
[ 5] 2.00-3.00 sec 1.71 MBytes 14.3 Mbits/sec 1 77.0 KBytes
[ 5] 3.00-4.00 sec 1.71 MBytes 14.3 Mbits/sec 0 91.6 KBytes
[ 5] 4.00-5.00 sec 1.84 MBytes 15.5 Mbits/sec 1 77.0 KBytes
[ 5] 5.00-6.00 sec 1.83 MBytes 15.3 Mbits/sec 0 91.6 KBytes
[ 5] 6.00-7.00 sec 1.77 MBytes 14.9 Mbits/sec 3 71.7 KBytes
[ 5] 7.00-8.01 sec 1.95 MBytes 16.2 Mbits/sec 0 90.3 KBytes
[ 5] 8.01-9.00 sec 1.72 MBytes 14.5 Mbits/sec 1 69.1 KBytes
[ 5] 9.00-10.00 sec 1.77 MBytes 14.8 Mbits/sec 0 83.7 KBytes


[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 17.8 MBytes 14.9 Mbits/sec 11 sender
[ 5] 0.00-10.03 sec 17.6 MBytes 14.7 Mbits/sec receiver

iperf Done.

As you can see, the speed dropped 10 times. Or is it okay?

ARMv7 support

Hi, is it possible for you to publish a binary for ARMv7 (Raspberry PI)

I've tried to compile myself, but there seems to be some problems downloading indexes and GHC version for ARM.

[DOC] Build requirements and instructions

Greetings,

from what I've got, to build the project from sources one needs ghc-8+ (as some extensions are not implemented in previous versiosn) and cabal-install-1.24+ (required by ghc-8+).
Is this correct?

Binary for aarch64?

I know it is a bit of an ask, but as a haskel noob I have found the process for getting a build environment up and running for arm64 to be a bit more complicated than I was prepared for. Since you have an armv7 environment I am hoping that an aarch64 build is a simple tweak for you rather than the long and semi-borked process that they rest of us face...

socks5 proxy error

server

./wstunnel_linux_x64 --server wss://0.0.0.0:443 -v

client

 wstunnel -D 0.0.0.0:5566 wss://ws.feds.club:443 -v

client error and print log

Starting socks5 proxy ServerSettings {listenOn = 5566, bindOn = "0.0.0.0"}
DEBUG :: Socks5 authentification request ResponseAuth {version = 5, method = Login}
DEBUG :: Socks5 forward request Error writing log message: Data.Binary.Get.runGet at position 4: Data.Binary.Get(Alternative).empty
CallStack (from HasCallStack):
  error, called at libraries/binary/src/Data/Binary/Get.hs:342:5 in binary-0.8.3.0:Data.Binary.Get (original message: DEBUG :: Socks5 forward request wstunnel: Data.Binary.Get.runGet at position 4: Data.Binary.Get(Alternative).empty
CallStack (from HasCallStack):
  error, called at libraries/binary/src/Data/Binary/Get.hs:342:5 in binary-0.8.3.0:Data.Binary.Get

(v3.0)High CPU utilization.

Server:
wstunnel-linux --server ws://0.0.0.0:8080 -r 127.0.0.1:2333
(127.0.0.1:2333 => caddy web server,convert ws to wss)

Client:
wstunnel-linux -L 8081:127.0.0.1:2333 wss://remote

Run command:
curl 127.0.0.1:8081
then
the wstunnel-linux process of the server use almost 100% of the CPU.
image_6.png

This problem will not repetition in v2.0.

arm32

Can we have a release for arm 32 bits? for Raspberry armv7l, because I've been using this through a linux VPS but wanted to use my RPi.

wstunnel is awesome btw (OpenVPN UDP over wstunnel working great), cheers!

[Feature request] allow url path after port in websocket endpoint

(Actually i found another implementation of wstunnel that supports what i want so this is not an "request" rather a feature "proposition")

My situation:

I have nginx(web server) that listen (ssl) on port 4433 and redirect path /websocket-ssh to port 4000

server {
  listen 4433 ssl http2;
  server_name myhostname.com;
   location / {
      # other stuff
   }
    location /websocket-ssh {
        include proxy_params;
        proxy_http_version 1.1;
        proxy_buffering off;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_pass http://localhost:4000;
    }
}

I have wstunnel server that listen on port 4000
./wstunnel --server ws://localhost:4000 --restrictTo localhost:22

I would like to be able to do something like that;
ssh -o ProxyCommand="./wstunnel -L stdio:%h:%p wss://myhostname.com:4433/websocket-ssh" myuser@localhost -p 22

This is what i get

wstunnel: Invalid port number `4433/websocket-ssh`
CallStack (from HasCallStack):
  error, called at app/Main.hs:87:31 in main:Main
ssh_exchange_identification: Connection closed by remote host

This would be a nice addition to add support for the path.

Show source ip in logging

It is possible to add client's source ip in log? Now even with verbose logging enabled (-v) its shows only
wstunnel[16586]: CONNECTING to 127.0.0.1:22
wstunnel[16586]: CLOSE connection to 127.0.0.1:22

I'm running wstunnel server behind cloud serviice (which send x-forwarded-for with real ip) but with direct connection all the same. And ssh or other service "in the end" only see 127.0.0.1 so no ip logging at all.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.