Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

http-proxy does not allow to connect ho https-proxy #633

Open
mal19992 opened this issue Oct 25, 2024 · 6 comments
Open

http-proxy does not allow to connect ho https-proxy #633

mal19992 opened this issue Oct 25, 2024 · 6 comments
Labels
enhancement non-trivial change this is a larger code change, not a simple bugfix

Comments

@mal19992
Copy link

mal19992 commented Oct 25, 2024

Currently openvpn --http-proxy option only allows a HTTP proxy, i.e. it directly issues the CONNECT command to http proxy. There is no option to connect to a HTTP proxy not directly, but via TLS/SSL, a so called https-proxy option, a regular HTTP proxy behind TLS/SSL, it is rather easy to setup such with apache or nginx. This suggested --http-proxy-over-TLS option has three very important benefits:

  1. A local ISP cannot be able to eavesdrop the IP of actual VPN server during CONNECT phase and block connection proactively.
  2. Most important. Currently OpenVPN is frequently blocked/throttled by some ISPs. This option would allow to pass ISP blocking. A OpenVPN connection with http-proxy option currently gets blocked by ISP with exactly the same logic as used when it is connected directly. If OpenVPN connection would be encapsulated in HTTPS connection to the proxy -- it would be much more difficult to identify and block such a connection.
  3. A proxy often has basic type of authorization credentials. A connection to such proxy without SSL leaks proxy auth credentials.

This is a request for improvement. Tested on openvpn-2.6.12 and earlier, none support a HTTP proxy over TLS/SSL. This improvement feature is easy to implement and it does not affect other OpenVPN functionality.

@cron2
Copy link
Contributor

cron2 commented Oct 25, 2024

This improvement feature is easy to implement

Such claims should come with actual code that shows that "it is easy to implement".

@cron2 cron2 added enhancement non-trivial change this is a larger code change, not a simple bugfix labels Oct 25, 2024
@mal19992
Copy link
Author

I will try to look,but I am not very familiar with OpenVPN codebase

@ordex
Copy link
Member

ordex commented Oct 28, 2024

I agree with @cron2, however I believe this is an interesting feature and would be nice to have.

@mal19992
Copy link
Author

mal19992 commented Oct 28, 2024

I reviewed the concept

  1. The concept works perfectly. I proved it with stunnel by running a separate TLS tunnel with stunnel.conf
#engine = pkcs11
foreground = yes
[service]
#engine = auto
#engineId = pkcs11
client = yes
accept = 127.0.0.5:7999
sni = proxy.xxxxxxxxxx.com
connect = proxy.xxxxxxxxxx.com:443
debug = 7
# uncomment to enable SSL remote server certificate verification 
#CAfile = /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
#verify = 2
#verifyChain = yes
# to match sni
#checkHost = proxy.xxxxxxxxxx.com

and run it as stunnel stunnel.conf
This example creates SSL connection to remote http proxy behind SSL proxy.xxxxxxxxxx.com:443, the unencrypted stream is then available locally at 127.0.0.5:7999. OpenVPN http proxy is now set to 127.0.0.5:7999

The result -- the ISP sees only regular https connection (from stunnel) to proxy.xxxxxxxxxx.com:443, the OpenVPN TCP goes under this TLS link. The ISP does not recognize this traffic as being from OpenVPN and does not throttle it. No problem whatsoever. This solution is the best to VPN traffic identification https://community.openvpn.net/openvpn/wiki/TrafficObfuscation among several I tried. It really works and is completely separate from OpenVPN internals. All it requires -- run apache http proxy behind SSL. Just one extra line with letsencrypt config.

  1. It is very inconvenient to run an extra tunnel. It is much easier to include to OpenVPN an ability to work with http proxy behind SSL.
    I think the best option would be not a separate proxy setting that I originally described in the first post, but, instead, a single boolean config flag
    http_proxy_over_ssl = true
    which makes to open TLS connection before opening http proxy. This is somewhere in
--- a/src/openvpn/socket.c
+++ b/src/openvpn/socket.c
@@ -2068,8 +2068,15 @@ phase2_tcp_client(struct link_socket *sock, struct signal_info *sig_info)
 
         if (sock->http_proxy)
         {
+           int proxy_sd=sock->sd
+           if(sock->http_proxy && sock->http_proxy->options &&  sock->http_proxy->options->http_proxy_over_ssl){
+               // FIXME wrap with SSL
+               // we have connection open to proxy. now wrap it with TLS
+               // proxy_sd= // FIXME open TLS connection to socket sock->sd. The  obtained fd gives an unencrypted stream. Pass it as it were a http proxy socket. 
+           }
+
             proxy_retry = establish_http_proxy_passthru(sock->http_proxy,
-                                                        sock->sd,
+                                                        proxy_sd,
                                                         sock->proxy_dest_host,
                                                         sock->proxy_dest_port,
                                                         sock->server_poll_timeout,

It just replaces fd passed to establish_http_proxy_passthru in socket.c. With a regular http proxy -- just pass it as is. When http proxy is behind SSL -- it opens SSL connection to proxy destination, then use obtained fd of unencrypted contents is passes through.

  1. Basically a single boolean option http_proxy_over_ssl is sufficient for this feature. I would add a few more options affecting the TLS connection to http proxy --- just for convenience (and as a replacement to http basic auth)
# Enable http proxy over SSL
http_proxy_over_ssl = true
# SSL host name to verify, do not verify host name if empty.  The same name is used as SNI for server request
http_proxy_over_ssl_server_SNI = proxy.xxxxxxxxxx.com
# Client certificate for proxy auth. Optionally use it instead of basic proxy auth 
http_proxy_over_ssl_client_auth_cert = /etc/client.pem
# http_proxy server SSL certificate to verify locally 
http_proxy_over_ssl_server_cert = /etc/proxyserver.pem
# Set Host: name for proxy. In virtual host environment often set the same as http_proxy_over_ssl_server_SNI 
# The same host is used for sni and for http Host: to work with multiple virtual http servers on port 443 
http_proxy_over_ssl_CONNECT_Host = proxy.xxxxxxxxxx.com

Actually only a single option http_proxy_over_ssl = true is important, the other controls are to auth the proxy connection, this is a glorified "basic auth" for proxy sever. The options http_proxy_over_ssl_CONNECT_Host sets Host: field for http proxy when doing CONNECT, see #635

@ordex
Copy link
Member

ordex commented Oct 29, 2024

http_proxy_over_ssl_CONNECT_Host

this is not specific to httpS. However, in #635 it was found out that Host: should contain the target hostname, no?

@mal19992
Copy link
Author

mal19992 commented Oct 29, 2024

It may be very beneficial to violate existing "traditions" for CONNECT and Host: having identical information. For example -- if a http proxy over TLS is running in a multi-host environment on a single IP port 443.

Then OpenVPN TLS link to is IP:443 may need to put "non-traditional" Host: from the parameter http_proxy_over_ssl_CONNECT_Host to help web server to identify specific virtual host (the proxy one) to use. If the parameter http_proxy_over_ssl_CONNECT_Host is absent -- the Host: is "traditionally" matching to CONNECT. If a user wants specific Host: to select a virtual server on a web server -- this option may be very handy. It is not needed if a TLS http proxy has its own IP or port, but useful in virtual host environment. By default it is not set and thus does not affect anything. If set --- it would allow to run multiple TLS http proxy on the same IP port 443. It has its own use cases.

In a multi-host virtual server environment this parameter need to be the same as http_proxy_over_ssl_server_SNI for apache httpd to identify the proper virtual host with a proxy server to use.

The parameters http_proxy_over_ssl_server_SNI (to send SNI and the same name to verify SSL certificate) and http_proxy_over_ssl_CONNECT_Host (the parameter to send Host: in HTTP header) must be identical in virtual host server setup with SSL (many web sites and proxies on a single IP port 443), otherwise the following error is possible:
[Error] Hostname example.com provided via SNI and hostname www.example.com provided via HTTP are different
There is no such issues for a proxy server running on its own IP adderess

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement non-trivial change this is a larger code change, not a simple bugfix
Projects
None yet
Development

No branches or pull requests

3 participants