Preamble
In connection with the
emerging trends, I decided to obfuscate my modest OpenVPN tunnel, just to get my hand — you never need it ...
It is given: cheap VPS with white IP, working under Ubuntu Trusty Server Edition and serving OpenVPN server.
Required: if possible, hide the OpenVPN tunnel, preferably without the invention of bicycles.
obfsproxy
Since the Tor-node has already been raised on the VPS, the idea of
obfsproxy came by itself. As it turned out, the utility really knows how to pretend to be SOCKS-proxy, which means obfuscate not only Tor connections, but also virtually arbitrary traffic. Rummaging around on the web, I found several manuals, but many were either outdated or out of sight the necessary details.
From the man obfsproxy you can learn the following
obfsproxy [logging_options] [--data-dir path] transport [--dest destination] [--password BASE32PASS] mode listen_addr
The VPN server itself can either be hidden behind obfsproxy completely (by making you listen to 127.0.0.1), or you can leave it on the external network interface in case of obfsproxy failure. I chose the second option as more reliable.
Thus, to run obfsproxy on the server side, it suffices to perform something like:
obfsproxy --log-file /var/log/obfsproxy-openvpn.log --log-min-severity info scramblesuit --password BASE32LONGPASS --dest 1.2.3.4:1800 server 1.2.3.4:81
where 1.2.3.4 is the external IP of the host, 1800 is the port that OpenVPN listens to, 81 is the port that obfsproxy will listen to.
A serious drawback is the inability of obfsproxy to run in daemon mode, but this can be circumvented.
Running on the client is almost identical to the server:
obfsproxy scramblesuit --password BASE32LONGPASS --dest 1.2.3.4:81 {client|socks} 127.0.0.1:81
where 1.2.3.4:81 is the address that the obfsproxy server listens to, 127.0.0.1:81 is the address that the client listens to.
')
OpenVPN setup
Important : OpenVPN must use the TCP protocol.
If we use client mode, we simply replace the address of the remote server in the openvpn configuration file with the address of the local obfsproxy:
#remote 1.2.3.4 1800 # remote 127.0.0.1 81 # obfsproxy
Socks modeTo work in socks mode, we configure OpenVPN a little bit differently:
#remote 1.2.3.4 1800 # remote 1.2.3.4 81 # obfsproxy- (! ) socks-proxy-retry socks-proxy 127.0.0.1 81 # socks proxy
Considering the need to replace the address of the OpenVPN server with the address of the obfsproxy server, I do not see any particular benefit from the proxy mode — applications in which the connection addresses are tightly protected are still not zaproksirue.
If openvpn traffic is blocked only occasionally (for example, only on the working network), you can use the following technique. In the OpenVPN configuration file, write the following:
<connection> remote 1.2.3.4 1800 # </connection> <connection> remote 127.0.0.1 81 # , obfsproxy </connection>
OpenVPN will try to use each <connection> section in turn, until it makes a successful connection.
Regarding the launch of obfsproxy, unfortunately, OpenVPN itself does not support pre-connect scripts (running the command before attempting to connect). You can try to install one of the unofficial
patches , run obfsproxy manually, or use one of the following methods.
openvpn-gui for windows
If you use the openvpn-gui wrapper to connect manually (or automatically with the
--connect key), then the easiest thing to do is to create the
XXXXXX_pre.bat file in the
config folder, where
XXXXXX is the name of the configuration file (without the .ovpn extension). This file will be automatically executed before openvpn-gui tries to connect. The contents of the file will look something like this:
start "window title" /MIN "%USERPROFILE%\Tor Browser\Tor\PluggableTransports\obfsproxy.exe" --log-min-severity info --data-dir "%TEMP%\obfs-openvpn" scramblesuit --password-file obfsproxy.key --dest 1.2.3.4:81 client 127.0.0.1:81
- window title - window title , required.
- % USERPROFILE% \ Desktop \ Tor Browser \ Tor \ PluggableTransports \ obfsproxy.exe is the path to the obfsproxy executable file. By default, the Tor Browser is installed on the desktop, although this is not necessary.
- % TEMP% \ obfs-openvpn - the path to place the obfsproxy state files.
- obfsproxy.key - the path to the file with the key, if you use it.
- 1.2.3.4:81 - the address that the obfsproxy server listens to.
- 127.0.0.1:81 - the address that the client will listen to.
Using the start command (without the / wait key, it works as an analogue of the & operator in the shell) is necessary, since openvpn-gui waits for the pre-up script to complete before attempting to connect. The disadvantage of this method is a console window that constantly hangs in the background. If desired, it can be hidden by the utility
hidcon or similar.
obfsproxy as a service
If OpenVPN is launched as a service, then it makes sense to organize the launch of obfsproxy in the same way.
You can create a service using the MS
srvany utility or some alternative utility like
NSSM . The question of running an application as a Windows service is beyond the scope of the article, so I’ll just point out that this approach will allow you to set dependencies on other services, thereby ensuring that obfsproxy will be available at the time OpenVPN is launched.
This approach can be combined with the previous one, using the bat-file launched by openvpn-gui, to start the created service with the
net start command.
Effect on speed
The last test was carried out on February 7, 2016 through the good old speedtest.net using the same server in London (the OpenVPN server is hosted in Latvia, the client is in the European part of Russia) from a Windows 7 client machine. Measurements were made in tenfold repetition. From the results it follows that, at least in my case, obfsproxy does not have a significant effect on speed. So, if there is a good channel to your VPN server, it will not be worse.
Mode | | Ping ms | Download, MB / s | Upload, MB / s |
---|
direct | the average | 56 | 20.18 | 21.03 |
---|
coeff. variations | 3.6% | 0.6% | 1.2% |
openvpn | the average | 56 | 20.21 | 21.29 |
---|
coeff. variations | 2.3% | 1.0% | 1.0% |
openvpn + obfsproxy | the average | 55 | 20.24 | 21.15 |
---|
coeff. variations | 4.0% | 0.73% | 1.34% |
Run obfs-proxy as init.d service
init.d / obfs-openvpn#! / bin / sh
### BEGIN INIT INFO
# Provides: obfsproxy-openvpn
# Required-Start: $ remote_fs $ syslog
# Required-Stop: $ remote_fs $ syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: obfsproxy wrapper for openvpn
# Description: This file starts up obfsproxy configured to process obfuscated openvpn client connections.
### END INIT INFO
# Author: Vindicar <the.vindicar@gmail.com>
# Do NOT "set -e"
# PATH should only include / usr / * if it runs after the mountnfs.sh script
PATH = "/ sbin: / usr / sbin: / bin: / usr / bin: / usr / local / bin"
DESC = "obfsproxy wrapper for openvpn"
NAME = obfs-openvpn
DAEMON = "/ usr / local / bin / obfsproxy"
OBFSPROXY_KEYFILE = "/ etc / obfsproxy-openvpn.key"
SERVER_IP =?.?.?.? # <<< TODO: insert server address here
OPENVPN_PORT = 443 #port 443 due to use of sslh
OBFSPROXY_PORT = 81
DAEMON_ARGS = "- log-file /var/log/obfs-openvpn.log --log-min-severity warning \
--data-dir / tmp / obfs-openvpn \
scramblesuit --password-file $ OBFSPROXY_KEYFILE \
--dest $ SERVER_IP: $ OPENVPN_PORT server $ SERVER_IP: $ OBFSPROXY_PORT "
PIDFILE = / var / run / $ NAME.pid
SCRIPTNAME = / etc / init.d / $ NAME
# Exit if the package is not installed
[-x "$ DAEMON"] || exit 0
# Read configuration variable file if it is present
[-r / etc / default / $ NAME] &&. / etc / default / $ NAME
# Load the rcS variables
. /lib/init/vars.sh
# Define LSB log_ * functions.
# Depend on lsb-base (> = 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. / lib / lsb / init-functions
#
# Function that starts the daemon / service
#
do_start ()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --pidfile $ PIDFILE --exec $ DAEMON --test> / dev / null \
|| return 1
start-stop-daemon - start - background - quiet - make-pidfile - pidfile $ PIDFILE - exe $ DAEMON - \
$ DAEMON_ARGS \
|| return 2
# Add code here, if necessary, that waits
# to handle requests from services started
# on this one. As a last resort, sleep for some time.
}
#
# Function that stops the daemon / service
#
do_stop ()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
# EDIT: removed --name parameter since ssd matches
# will be relying on the pidfile to stop it.
start-stop-daemon --stop --quiet --retry = TERM / 30 / KILL / 5 --pidfile $ PIDFILE
RETVAL = "$?"
["$ RETVAL" = 2] && return 2
# Wait for children to finish
# and if the daemon is from ever in this script.
# If the conditions above are not satisfied then add some other code
# that waits
# needed by services started subsequently. A last resort is to
# sleep for some time.
# start-stop-daemon --stop --quiet --oknodo --retry = 0/30 / KILL / 5 --exec $ DAEMON
# ["$?" = 2] && return 2
# Many daemons don't exit their pidfiles when they exit.
rm -f $ PIDFILE
return "$ RETVAL"
}
#
# Function that sends a SIGHUP to the daemon / service
#
do_reload () {
#
# If the daemon can reload configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet --pidfile $ PIDFILE
return 0
}
case "$ 1" in
start)
["$ VERBOSE"! = No] && log_daemon_msg "Starting $ DESC" "$ NAME"
do_start
case "$?" in
0 | 1) ["$ VERBOSE"! = No] && log_end_msg 0 ;;
2) ["$ VERBOSE"! = No] && log_end_msg 1 ;;
esac
;;
stop)
["$ VERBOSE"! = No] && log_daemon_msg "Stopping $ DESC" "$ NAME"
do_stop
case "$?" in
0 | 1) ["$ VERBOSE"! = No] && log_end_msg 0 ;;
2) ["$ VERBOSE"! = No] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$ DAEMON" "$ NAME" && exit 0 || exit $?
;;
#reload | force-reload)
#
# Leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg "Reloading $ DESC" "$ NAME"
#do_reload
#log_end_msg $?
# ;;
restart | force-reload)
#
# If the "reload" option is then removed the
# 'force-reload' alias
#
log_daemon_msg "Restarting $ DESC" "$ NAME"
do_stop
case "$?" in
0 | 1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
#echo "Usage: $ SCRIPTNAME {start | stop | restart | reload | force-reload}"> & 2
echo "Usage: $ SCRIPTNAME {start | stop | status | restart | force-reload}"> & 2
exit 3
;;
esac