DPI-resistant tunnels and VPNs

    We live in an interesting time. I would even say amazing. On one side, we see some people who really want to know what other people are talking about among themselves, and they really want to tell them what to read and what not. On the other hand, citizens who want to defend their rights of secrecy of personal correspondence and the free receipt of information, and do not want the facts of this correspondence and the receipt of this very information to be used against them. The bonus suffers a huge number of third-party sites, services and businesses that are touched by “carpet locks”.

    But no, this article is not about society, but about technology.


    Technical literacy of people, thanks to everything that is happening, is also growing. If earlier the words “VPN” and “proxy” were familiar only to IT-specialists, now even housewives know them, and moreover - they use what these words mean.

    In general, the news recently come very interesting. For example, the provision of VPN and similar services to encrypt traffic and bypass blocking is now punishable , and in China they are imprisoned for it . Not long ago, the RKN began using packet analysis to block the MTProxy protocol. You can also refer to the experience of fellow countries that are most successful in such matters: China, Iran, Kazakhstan, Venezuela. In Venezuela, for example, quite specifically blockdirect connections to Tor and obfuscated traffic to bridges. Based on all this, we can assume that the future is also very interesting for us, especially if the "responsible persons" stop making stupid fakapy over and over again, and they act smarter and more sophisticated.

    On Habré, many times in the comments voiced predictions of how further the fight against encryption technologies for ordinary citizens can occur. Analyzing the voiced thoughts and looking at the evidence from other countries, I tried to suggest in which direction the measures to restrict communication could move further. DistortNeo and shifttstas planted some more interesting ideas, and in the end I promised el777 to still finish this article.

    With filters on ACL everything is generally clear. They act now, and it turns out with varying success and it is impossible to fight (although there are quite pessimistic forecasts ). With DPI everything is more interesting.

    Methods of "determining" the type of traffic in DPI can be divided into two groups:

    • Signature analysis. Namely, sorting the package “by bone”, comparing the headers and structure with the samples, and thus determining its purpose. This way many tunnels are detected, for example, OpenVPN, L2TP / IPSec, SOCKS, etc.
    • A preliminary analysis of traffic exchange patterns, for example, the ratio of incoming / outgoing flow, the frequency of requests and responses, and other criteria will allow to separate the “real traffic” of a protocol and a tunnel that only disguises itself.


    You can break traffic into several groups and assume what they will do with each of them.

    1. Explicit VPNs, tunnels, and proxies (OpenVPN, L2TP / IPSec, SOCKS, and others.) Ordinary VPNs and tunnels may well be automatically blocked, such as in China and Venezuela. If some organizations or companies need it for work, let them be registered and certified, which is exactly what the Russian law mentioned above says. With a proxy, it is still simpler - that HTTP, that SOCKS transmit addresses and content in clear form, which does not create any problems for selectively “cutting” requests and listening to the transmitted information.
    2. Dual-use technologies, such as SSH . After a short time after the session is established, the speed is cut to a snail, so that you can still work somehow in the console, but to surf and swing something is no longer there. The fact that this creates problems in normal work does not bother anyone (which has been demonstrated to us by the RKN more than once in recent times).
    3. Highly specific protocols such as messengers, game clients, etc.
    4. Compounds whose type cannot be determined .

    For points 3 and 4, whitelists are quite possible (in which, for example, the subnets of the official game servers or the “correct” messengers are entered, and all that the owners of the servers wish to declare and arrange as necessary so that they are not touched, by analogy with those that already have at RKN for domains and IP addresses). And those who are not in these lists are waiting for the same fate as Clause 1 or Clause 2, although it is quite possible not to stupidly block or cut off the speed, but the previously mentioned analysis of exchange patterns in order to determine whether traffic is “clean” Or suspicious.

    That is, if you wish to disguise as special protocols, or obfuscate connections, so that it is impossible to determine their type, you will also have to take care of creating a “noise” that prevents the actual identification of exchange patterns. So far, such developments have not come across my eyes.

    You can even ignore the different ICMP and DNS tunnels - a large amount of traffic “where not necessary” for them also automatically causes suspicions.

    5. TLS and SSL, HTTPS. It is impossible to cut clean because it automatically means blocking the entire Internet. Analysis of patterns does not make sense, since surfing the web is the main purpose of using HTTPS. Of all of the above, SSL / TLS on port 443 looks like the most “unsuspicious” and reliable option. Therefore, let's try and disguise it.



    For consideration, it was decided to choose solutions Streisand and SoftEther.

    Streisand is a whole set of different services: OpenConnect / AnyConnect, OpenVPN, stunnel, Shadowsocks, WireGuard. All this is put in automatic or semi-automatic mode on a turnkey basis, and the user gets a configured server, as well as files and detailed documentation for setting up clients, at the output.

    SoftEther is a VPN server that can enable L2TP / IPsec, OpenVPN, SSTP, and other protocols, and also has its own SSL-VPN protocol, which, according to the authors, is indistinguishable from normal HTTPS traffic.

    So ...

    OpenConnect / AnyConnect.Open source implementation of the AnyConnect SSL protocol from Cisco. When establishing a connection, not only TLS (TCP) packets are visible, but also DTLS (UDP). DTLS, in principle, is also used a lot for “peaceful purposes”, but this is not at all like “ordinary HTTPS”. However, if you cut the UDP traffic on the firewall, AnyConnect immediately switches back to TCP and looks, again, completely and completely like regular TLS, and even the authentication inside the encrypted tunnel goes almost as in HTTP.

    Shadowsocks . Encrypted SOCKS proxy. Apparently, if desired, can be detected , but there are plugins that mask it under "pure HTTPS" .

    Wireguard. Judging by the description, it has a well-twisted encryption and session setup mechanism, but the entire exchange takes place via UDP. Wireshark defines the type of packets as something completely unintelligible, and what kind of opinion about everything that happens will be formed in third-party DPI is a very, very big question.

    obfs3, obfs4 . Obfuci packages so that from the outside they look completely random set of values. That is, fall under paragraph 4 of the list above.

    SoftEther . It looks like HTTPS, but with one catch. In addition to TLS over TCP itself, it actively sends UDP packets in bursts. As it was possible to find out in the documentation, UDP can be used to speed up data transmission in the case when it is not slaughtered on the firewall. This functionality is disabled in the configuration, and after it is turned off, everything becomes as it should.

    Sstp. VPN puncture from Microsoft. Natively supported in Windows, auxiliary software in GNU / Linux. From the side it looks like HTTPS, and Wireshark fully confirms this.

    But that is not all

    Suppose you install a VPN server or end of a tunnel on a host and configure it to listen to port 443. It would seem that everything is fine, but there is one BUT: if we mask under HTTPS, check that it actually hangs on port 443 you can simply try to dig into this port with a simple browser or CURL, or in any other way. In some articles, this method is called "forward connection", and, as mentioned, is already fully used in China.

    Therefore, we need to have the most ordinary and decent web server on port 443. And here comes an interesting problem.

    None of the above services in the main documentation found a description of the working mechanism of port sharing. Option with SSLHnot suitable, if only because sslh is not able to divide traffic between HTTPS and the above services. At least, because if the type of traffic without full decryption could distinguish sslh, then DPI will be able to.

    Most manus, like this , suggest using a Server Name Indication (SNI) - TLS extension, which allows you to specify a host name, and then use HAProxy, sniproxy, and other bodies to scatter connections by service. The problem is that in modern implementations of TLS, the hostname specified when using SNI is transferred to plain text, that is, in unencrypted form, and, therefore, can also be peeped and used in the future.

    Therefore, we will improvise, and here two options came to my mind.

    Port knocking


    Port knocking is just designed to activate the "hidden services" on the server. For example, in this way, the port on which the SSH daemon hangs is often closed out to avoid brute force and the use of 0-day vulnerabilities. In the classic version (see, for example, the implementation of the knockd daemon), knocking usually means trying to establish a connection or sending packets to certain ports of a host in a certain sequence, as a result of which the daemon “recognizes” itself and activates the firewall rule that opens only from your IP.

    In our case, this option is not quite acceptable. Firstly, the “non-standard” ports themselves may be blocked somewhere along the way, and secondly, the procedure itself may look suspicious when analyzed from the outside. Since we are disguised as HTTPS, then we need to “knock” on HTTPS.

    Surprisingly, HTTP / HTTPS nokers with the required functionality were not found, and therefore a noker with the romantic name Labean was born (hussars, be silent!).

    It is given: our server, where Nginx with correctly configured certificates is running on port 443 and provides some kind of innocuous content, for example, GIFs with cats, ISO images of GNU / Linux distributions, or a mirror of Wikipedia and the Moshkov library.

    At the same time, the following lines are hidden in the Nginx config file

    location~ ^/somesecret/(.*) {
        auth_basic"Administrator Login";
        auth_basic_user_file  /var/www/.htpasswd;
        proxy_set_header  X-Real-IP  $remote_addr;

    When we want to connect to a hidden service, we go through the browser or make a request with CURL at the type address, we go
    through standard authorization, after which the nocker, having received and processed our request, will execute the command to open access to the hidden service for our IP address, for example something like
    iptables -t nat -A PREROUTING -p tcp -s {clientIP} --dport 443 -j REDIRECT --to-port 4443
    after which we raise the tunnel.

    Further, after N seconds (yes, an automatic timeout is maintained), the command that cancels the above firewall rule is executed, and thus our established connection remains to hang, but to connect to the service again even from our IP without re-pulling the nocker will not work.

    Or you can not use the automatic timeout, and manually deactivate the service by requesting a URL like the one above, only with / off at the end.

    Thus, you can even configure several different services, including using IPv6 (v6 addresses in the X-Real-IP type header are also supported).

    Noker is written in Go, does not require external dependencies, is simple as an ax, and works quite well for itself. Sources, a detailed description and examples of the nginx config and init scripts can be found on Gihub:



    The second idea lit up even more unexpectedly: the best way to disguise a tunnel inside HTTPS is to use common standard tools. Modern Web technologies have long been a solution for establishing a connection over TCP between the browser and the server, and its name is Websocket ( RFC 6455 ). The client generates a special HTTP request to which the server responds in a certain way, and after a small handshake we can start sending data over the same TCP connection. From the side, respectively, everything looks exactly like regular HTTPS and no additional connections are required.

    There are several implementations of WS-tunnels (there is even a variant on Haskell), I took wstunnel made on nodejs for the test and didn’t lose it, everything went easy and the first time.

    Only one nuance was not clarified in the documentation. To start the client it is proposed to specify simply wss: // - address, type

    wstunnel -t 33 wss://server:443

    In our case, it is necessary to “separate” ws connections to the tunneling server from requests from a “normal” site. After examining the wstunnel sources, I came to the conclusion that it would not hurt anything to extend the URI after the host name with some unique identifier:

    wstunnel -t 33 wss://ourserver.org:443/hiddenws/

    and it turned out to be right: everything worked the first time.

    Again, consider our server, on which Nginx is running on port 443 on some innocuous site.

    In the config you need to add proxy-forwarding for our Websockets-tunnel:

    location /hiddenws {
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";

    Then we can secretly raise our websockets-tunnel. You can connect to a normal SOCKS proxy (for example, Dante), or OpenVPN over the tunnel, although, as for me, it will be redundant.

    About selinux
    If you have a similar distribution to RHEL, and SELinux is turned on, and nginx logs show errors like
    2018/07/05 13:28:03 [crit] 7724#0: *11 connect() to failed (13: Permission denied) while connecting to upstream, client: IP_ADDRES, server: _, request: «GET /hiddenws/?dst=localhost:22 HTTP/1.1», upstream: «»,

    that, you need to allow the daemon to connect to the required port:

    semanage port -a -t http_port_t -p tcp 22
    semanage port -m -t http_port_t -p tcp 22
    semanage port -a -t http_port_t -p tcp 8081

    Спасибо Renatk за то что обратил внимание и предложил решение.

    The only disadvantage of this approach is that besides the SOCKS or VPN client itself, you also need to have a wstunnel client on the device, which can be difficult if you use a smartphone or other “non-stop” device.

    Instead of conclusion


    As a matter of fact, the social and technical confrontation will develop, we cannot know - just assume. Whether the assumptions outlined in the article will be realized will not be realized - we will find out in time how and what will happen next. Yes, masking under HTTPS is not a panacea for everything either - for example, it can be dangerous if any real penalties are introduced for “using non-certified encryption tools” / familiarization with blocked resources / etc., Or it is useless if everyone is obliged to install a kind of "security certificate", as some time ago they wanted to do in Kazakhstan .

    Fortunately, so far, neither has come to any other state known to us, and if it happens, it is a sign that it’s time to evacuate, not from a country, but from the planet.
    Take care of yourself.

    Also popular now: