DevOps Buzz
Search…
Bash / Shell
Bitbucket
Distros
Elasticsearch
General
Guidelines / Standards
microk8s
Prometheus
RabbitMQ
VirtualBox
Stunnel
Encapsulate VPN connections with plain TLS to workaround firewall restrictions.

The problem

Most of corporate firewalls have a feature called Deep Packet Inspection (DPI), which blocks VPN connections.

Error when using OpenVPN with UDP protocol

When you OpenVPN client is trying to connect to the server using UDP, it returns the following error.
1
OpenVPN 2.4.4 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Sep 5 2018
2
library versions: OpenSSL 1.1.0g 2 Nov 2017, LZO 2.08
3
Outgoing Control Channel Authentication: Using 256 bit message hash 'SHA256' for HMAC authentication
4
Incoming Control Channel Authentication: Using 256 bit message hash 'SHA256' for HMAC authentication
5
TCP/UDP: Preserving recently used remote address: [AF_INET]X.X.X.X:1194
6
Socket Buffers: R=[212992->212992] S=[212992->212992]
7
UDP link local: (not bound)
8
UDP link remote: [AF_INET]X.X.X.X:1194
9
NOTE: UID/GID downgrade will be delayed because of --client, --pull, or --up-delay
10
TLS Error: Unroutable control packet received from [AF_INET]X.X.X.X:1194 (si=3 op=P_ACK_V1)
Copied!

Error when using OpenVPN with TCP protocol

When you OpenVPN client is trying to connect to the server using TCP, it returns the following error.
1
OpenVPN 2.4.4 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Sep 5 2018
2
library versions: OpenSSL 1.1.0g 2 Nov 2017, LZO 2.08
3
Outgoing Control Channel Authentication: Using 256 bit message hash 'SHA256' for HMAC authentication
4
Incoming Control Channel Authentication: Using 256 bit message hash 'SHA256' for HMAC authentication
5
TCP/UDP: Preserving recently used remote address: [AF_INET]X.X.X.X:1294
6
Socket Buffers: R=[87380->87380] S=[16384->16384]
7
Attempting to establish TCP connection with [AF_INET]X.X.X.X:1294 [nonblock]
8
TCP connection established with [AF_INET]X.X.X.X:1294
9
TCP_CLIENT link local: (not bound)
10
TCP_CLIENT link remote: [AF_INET]X.X.X.X:1294
11
NOTE: UID/GID downgrade will be delayed because of --client, --pull, or --up-delay
12
TLS Error: TLS key negotiation failed to occur within 60 seconds (check your network connectivity)
13
TLS Error: TLS handshake failed
14
Fatal TLS error (check_tls_errors_co), restarting
15
SIGUSR1[soft,tls-error] received, process restarting
16
Restart pause, 5 second(s)
Copied!

The solution

To encapsulate VPN connections with plain TLS to workaround firewall restrictions.
The main idea is to create the following architecture:
Server | Client Openvpn (port 1194) <---> Stunnel (port 443) <---> | <---> Stunnel (port 443) <---> Openvpn (port 1194) |

Setup server

You need to have OpenVPN already running with TCP protocol.

Install Stunnel4

1
apt update
2
apt install stunnel4
Copied!

Create Openssl key

1
openssl req -new -newkey rsa:2048 -days 3650 \
2
-nodes -x509 -sha256 -subj '/CN=127.0.0.1/O=localhost/C=US' \
3
-keyout /etc/stunnel/stunnel.pem -out /etc/stunnel/stunnel.pem
Copied!

Config Stunnel

Redirect connections to OpenVPN

Create the file /etc/stunnel/stunnel.conf
1
nano /etc/stunnel/stunnel.conf
Copied!
With the following content:
/etc/stunnel/stunnel.conf
1
[openvpn]
2
client = no
3
accept = 443
4
connect = localhost:1194
5
cert = /etc/stunnel/stunnel.pem
Copied!
What the config does is:
  • Line 3: Stunnel will accept (listen) connections on port 443;
  • Line 4: Stunnel will redirect all connections to Openvpn which is running on localhost port 1194.
Why Stunnel is running on port 443? Because most likely the client will be able to connect to it since most firewalls allow outbout connections on port 443. Although you can change it to any port you want.

Config iptables

Configure iptables to accept incoming traffic on port 443
1
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
Copied!
Make sure your iptables config is persisted:
apt install iptables-persistent

Enable Stunnel to start on boot by default

Edit /etc/default/stunnel4
1
nano /etc/default/stunnel4
Copied!
Replace ENABLED=0 with ENABLED=1

Restart Stunnel

1
systemctl restart stunnel4
2
systemctl enable stunnel4
Copied!

Check Stunnel

Check stunnel process is up and running and listening to the correct port
1
netstat -ntulp |grep stunnel
Copied!
Output example:
1
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 13784/stunnel4
Copied!

Setup client

Install Stunnel

1
apt update
2
apt install stunnel4
Copied!

Create Openssl key

Copy /etc/stunnel/stunnel.pem from your server and paste it in your client in the same path.

Config Stunnel

Redirect connections to Stunnel server

Create the file /etc/stunnel/stunnel.conf
1
nano /etc/stunnel/stunnel.conf
Copied!
With the following content:
/etc/stunnel/stunnel.conf
1
[openvpn]
2
client = yes
3
accept = 443
4
connect = PUT-YOUR-SERVER-HOST-HERE:443
5
cert = /etc/stunnel/stunnel.pem
Copied!
What the config does is:
  • Line 3: Stunnel will accept (listen) connections on port 443;
  • Line 4: Stunnel will redirect all connections to Stunnel server. Replace PUT-YOUR-SERVER-HOST-HERE with your server domain or IP.

Enable Stunnel to start on boot by default

Edit /etc/default/stunnel4
1
nano /etc/default/stunnel4
Copied!
Replace ENABLED=0 with ENABLED=1

Restart Stunnel

1
systemctl restart stunnel4
2
systemctl enable stunnel4
Copied!

Config OpenVPN

Edit your OpenVPN client config as follows:
/etc/openvpn/client.conf
1
...
2
proto tcp
3
...
4
remote localhost 443
5
...
Copied!
Your OpenVPN client will actually connect to Stunnel running localhost on port 443, which will redirect to Stunnel server, then it will redirect to the OpenVPN server.
1
systemctl restart [email protected]
2
systemctl enable [email protected]
Copied!

Test

On your client run ifconfig. You should see your OpenVPN interface tunnel.