Share a TCP/443 port with SSTP and HTTPS?

Hi, I’m trying to share a TCP/443 port with HTTPS webservers and an SSTP server.

I tried stuff like:

acl SSTP method SSTP_DUPLEX_POST
use_backend SSTPServer if SSTP

But it’s not working - the SSTP client disconnects very quickly after the logon attempt (which seems similar to what happens when there isn’t any of this SSTP config stuff).

I’m basing this from Microsoft’s docs: 4.3 SSTP Layer Establishment.

Is the SSTP_DUPLEX_POST method or large content-length (18446744073709551615) causing problems with HAProxy and there needs to be additional stuff to get HAProxy to allow/ignore it?

I see some others claim success with stuff like:

tcp-request inspect-delay 5s
tcp-request content accept if { req.ssl_hello_type 1 }

What does that do? I get warning messages when I try to add the tcp-request stuff.

Any suggestions?

You can’t distinguish between the two, because SSTP actually is HTTPS.

You can’t distinguish between the two, because SSTP actually is HTTPS.

But very few “normal” HTTPS clients make SSTP_DUPLEX_POST requests. Most do stuff like GET/POST/HEAD ( https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html)

SSTP clients on the other hand supposedly make SSTP_DUPLEX_POST requests: ( SSTP Layer Establishment)

HTTPS is encrypted. That means you cannot access it’s contents, unless you decrypt it first.

You may be able to make routing decisions based on the SNI value in the SSL handshake, this could work if the hostnames are all different and the certificates do not overlap.

HTTPS is encrypted. That means you cannot access it’s contents, unless you decrypt it first.

I may not be able to but HAProxy should since it usually decrypts the stuff. Otherwise how can HAProxy see the methods, hostnames, paths and other stuff supplied by the client?

You yourself have said stuff like: ( PROPFIND - http-request deny unless METH_GET - #2 by lukastribus ):

acl METH_PROPFIND method PROPFIND

So how would HAProxy know the method is PROPFIND and not SSTP_DUPLEX_POST if it doesn’t decrypt stuff?

OK I have decrypted it:

dissect_ssl enter frame #17 (already visited)
packet_from_server: is from server - FALSE
  conversation = 0000000009C024E0, ssl_session = 0000000000000000
  record: offset = 0, reported_length_remaining = 234
dissect_ssl3_record: content_type 23 Application Data
dissect_ssl_payload decrypted len 205
decrypted app data fragment[205]:
| 53 53 54 50 5f 44 55 50 4c 45 58 5f 50 4f 53 54 |SSTP_DUPLEX_POST|
| 20 2f 73 72 61 5f 7b 42 41 31 39 35 39 38 30 2d | /sra_{BA195980-|
| 43 44 34 39 2d 34 35 38 62 2d 39 45 32 33 2d 43 |CD49-458b-9E23-C|
| 38 34 45 45 30 41 44 43 44 37 35 7d 2f 20 48 54 |84EE0ADCD75}/ HT|
| 54 50 2f 31 2e 31 0d 0a 53 53 54 50 43 4f 52 52 |TP/1.1..SSTPCORR|
| 45 4c 41 54 49 4f 4e 49 44 3a 20 7b 36 39 35 38 |ELATIONID: {6958|
| 43 30 43 42 2d 37 34 35 44 2d 34 30 34 36 2d 39 |C0CB-745D-4046-9|
| 37 33 45 2d 42 36 30 32 45 42 45 36 45 30 35 41 |73E-B602EBE6E05A|
| 7d 0d 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 |}..Content-Lengt|
| 68 3a 20 31 38 34 34 36 37 34 34 30 37 33 37 30 |h: 1844674407370|
| 39 35 35 31 36 31 35 0d 0a 48 6f 73 74 3a 20 XX |9551615..Host: X|
| XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX |XXXXXXXXXXXXXXXX|
| XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX |XXXXXXXXXXXXXXXX|
process_ssl_payload: found handle 00000000082FC690 (http-over-tls)
packet_from_server: is from server - FALSE

dissect_ssl enter frame #19 (already visited)
packet_from_server: is from server - TRUE
  conversation = 0000000009C024E0, ssl_session = 0000000000000000
  record: offset = 0, reported_length_remaining = 216
dissect_ssl3_record: content_type 23 Application Data
dissect_ssl_payload decrypted len 187
decrypted app data fragment[187]:
| 48 54 54 50 2f 31 2e 30 20 34 30 30 20 42 61 64 |HTTP/1.0 400 Bad|
| 20 72 65 71 75 65 73 74 0d 0a 43 61 63 68 65 2d | request..Cache-|
| 43 6f 6e 74 72 6f 6c 3a 20 6e 6f 2d 63 61 63 68 |Control: no-cach|
| 65 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 63 |e..Connection: c|
| 6c 6f 73 65 0d 0a 43 6f 6e 74 65 6e 74 2d 54 79 |lose..Content-Ty|
| 70 65 3a 20 74 65 78 74 2f 68 74 6d 6c 0d 0a 0d |pe: text/html...|
| 0a 3c 68 74 6d 6c 3e 3c 62 6f 64 79 3e 3c 68 31 |.<html><body><h1|
| 3e 34 30 30 20 42 61 64 20 72 65 71 75 65 73 74 |>400 Bad request|
| 3c 2f 68 31 3e 0a 59 6f 75 72 20 62 72 6f 77 73 |</h1>.Your brows|
| 65 72 20 73 65 6e 74 20 61 6e 20 69 6e 76 61 6c |er sent an inval|
| 69 64 20 72 65 71 75 65 73 74 2e 0a 3c 2f 62 6f |id request..</bo|
| 64 79 3e 3c 2f 68 74 6d 6c 3e 0a                |dy></html>.     |

The logs say: -1/-1/-1/-1/0 400 187 - - PR-- 1/1/0/0/0 0/0 “SSTP_DUPLEX_POST /sra_{BA195980-CD49-458b-9E23-C84EE0ADCD75}/ HTTP/1.1”

My understanding of PR-- and NOSRV means the 400 is the proxy’s decision not the backend (and there’s no traffic to the backend)…

So my guess is HAProxy doesn’t like the request for some reason and says it’s an invalid request. Is there a way to get HAProxy to accept that request? Add SSTP_DUPLEX_POST to an allowed method, ignore/accept the 18446744073709551615 Content-Length?

After doing some tests with openssl s_client it seems that HAProxy will talk to the backend if the method is SSTP_DUPLEX_POST AND the content-length is omitted or the content-length is a small enough number. But HAProxy will not talk to the backend if the Content-Length is 18446744073709551615.

However the Content-Length has to be 18446744073709551615 for SSTP. Any suggestions on getting HAProxy to work with or ignore and pass through such a Content-Length?

Not sure what you are doing with openssl s_client. What I mean is that you need to configure haproxy to intercept SSL, by installing a SSL certificate on haproxy. Reencrypt in the backend section if necessary.

Then haproxy needs to be in TCP mode, because SSTP is not HTTP (that’s why you see PR, it means invalid HTTP syntax).

You should be able to make a routing decision based on ACL’s like HTTP.

use_backend blabla if HTTP

Basically HA Proxy talks to the backend if I connect via openssl s_client and send something like this:

SSTP_DUPLEX_POST /sra_{BA195980-CD49-458b-9E23-C84EE0ADCD75}/ HTTP/1.1
SSTPCORRELATIONID: {829C620A-5B8A-4A4A-9D04-54ED2423A8E6}
Content-Length: 9223372036854775807
Host: vpn.host

But it doesn’t if I send this:

SSTP_DUPLEX_POST /sra_{BA195980-CD49-458b-9E23-C84EE0ADCD75}/ HTTP/1.1
SSTPCORRELATIONID: {829C620A-5B8A-4A4A-9D04-54ED2423A8E6}
Content-Length: 9223372036854775808
Host: vpn.host

The limit appears to be 9223372036854775807 is there a way for me to increase/bypass the Content-Length limit for HAProxy so it accepts 18446744073709551615?

Like I said, you need mode tcp

How do I share a single TCP/443 port for multiple HTTPS servers and SSTP servers with mode tcp?

OK haven’t figured out a way to do it while letting the backends know the client IPs.

But the current workaround for those who are desperate enough to do it is to do something like this:

        tcp-request inspect-delay 100ms
        tcp-request content capture req.payload(0,16) len 16
        acl SSTP req.payload(0,16) -m str SSTP_DUPLEX_POST
        use_backend SSTPVPN if SSTP
        default_backend HAProxy-FrontEnd-For-WebStuff

Basically I created a TLS/TCP front end that checks the TCP request, if it matches SSTP_DUPLEX_POST then use the SSTP backend. If it doesn’t match then use the “normal” HAProxy frontend for websites.

I suspect it would also work (and work better) if HAProxy has an option to ignore or accept a Content-Length of 18446744073709551615.

I’m trying to do the same thing but it doesn’t work. all requests are sent to the default backend. Did you perform an ssl offloading to decrypt on frontend and re-encrypt on the backend server before you are able to route SSTP request?

I’m using haproxy on pfsense and I had to set a custom acl… in the config file I can find this:

frontend FrontendTCP-Agenzia
bind 10.3.5.35:443 name 10.3.5.35:443
bind /tmp/haproxy_chroot/FrontendTCP-Agenzia.socket name unixsocket uid 80 accept-proxy
mode tcp
log global
timeout client 360000
tcp-request inspect-delay 100ms
tcp-request content capture req.payload(0,16) len 16
acl SSTP req.payload(0,16) -m str SSTP_DUPLEX_POST
use_backend SSTPSERVER_ipvANY if SSTP
default_backend WAPSERVER_ipvANY