
Show HN: Run SSH and HTTP(S) on the same port - jamescun
https://github.com/jamescun/switcher?readme
======
slyall
You can also do this with haproxy. I ran it for a while (I think it was for
git). Here is a page about how to do it:

[https://dgl.cx/2010/01/haproxy-ssh-and-ssl-on-same-
port](https://dgl.cx/2010/01/haproxy-ssh-and-ssl-on-same-port)

    
    
      defaults
        timeout connect 5s
        timeout client 50s
        timeout server 20s
    
      listen ssl :443
        tcp-request inspect-delay 2s
        acl is_ssl req_ssl_ver 2:3.1
        tcp-request content accept if is_ssl
        use_backend ssh if !is_ssl
        server www-ssl :444
        timeout client 2h
    
      backend ssh
        mode tcp
        server ssh :22
        timeout server 2h

~~~
shanemhansen
haproxy is truly a swiss army knife. I recently worked on a geographically
distributed 300 server deployment, and our ops team ran haproxy on every node
just for ssl termination and the operational insight and flexibility it
provided.

~~~
IgorPartola
AFAIK, it's the only web server that is able to log when a client first
connects. Otherwise, attacks a la slowloris go unlogged as the attack is
happening.

~~~
jimktrains2
HAProxy isn't a webserver, it's a TCP connection proxy.

~~~
IgorPartola
Pardon, an HTTP server. It talks HTTP and HTTPS, as well as raw TCP. If you
define a web server as something that talks HTTP/HTTPS and also is able to
serve static files off the filesystems then, not HAProxy is not that, but this
is really splitting hairs.

~~~
jimktrains2
No, it's not an HTTP server. It has that capability to serve a static is
almost solely for the purpose of maintenance pages and is severely limited,
even to the point of needing to restart the server if you want to update the
page.

It speaks HTTP in as much as it needs to to figure out how to forward
requests. It doesn't generate return headers for content; it doesn't serve
content; it moves streams from A to B.

~~~
IgorPartola
First off, from the HAProxy docs:

> In HTTP mode, it is possible to rewrite, add or delete some of the request
> and response headers based on regular expressions.

Second of, it speaks HTTP, and it serves content that it is able to fetch from
a content producing backend. In my book it's an HTTP server.

Third off, the difference is so pedantic that I don't think it makes any
difference what we call it. We both know what it is, and what it is used for
in the context of hosting web applications.

~~~
jimktrains2
We don't call Varnish a web server, and it does quite a bit more with HTTP
than HAProxy does.

We don't call a car a truck, even if you can haul things around it it.

Pedanticism is never a good argument against someone. 1) It's an ad hominem.
2) It doesn't actually do anything. 3) If everyone knew what it was, they
wouldn't call it a web server.

------
AceJohnny2

      > apt-cache search ssh http
      [...]
      sslh - ssl/ssh multiplexer

[http://www.rutschle.net/tech/sslh.shtml](http://www.rutschle.net/tech/sslh.shtml)

I mean, it's cool that you got the exercise of implementing this in Go and
all, but I don't see what's new and interesting about it.

(and another implementation in Perl almost 4 years ago:
[https://news.ycombinator.com/item?id=2395787](https://news.ycombinator.com/item?id=2395787))

Edit: oh whoops, didn't get to OP's "Why not sslh" section :\ "The result is
useful in its own right through use of Go's interfaces for protocol matching
(making adding new protocols trivial), and lightweight goroutines (instead of
forking, which is more CPU intensive under load)."

Well alright, the first point I'll concede, though I'm wary of the "reinvented
wheel" scent, the second point I'm even more uncomfortable with as I think it
makes wild assumptions of the kind of environment this tool could be useful
in.

~~~
bmn_
> and another implementation in Perl

[sslh in Net-Proxy]([https://metacpan.org/pod/release/BOOK/Net-
Proxy-0.03/script/...](https://metacpan.org/pod/release/BOOK/Net-
Proxy-0.03/script/sslh)) predates that even longer - first release in 2006.

------
leni536
I wonder if it hides ssh from an nmap scan. Since it requires a timeout for
ssh "since the server waits for a bit if the client send a http request" then
scanning for this type of hiding ssh would be really time consuming if it's on
a random port hiding behind a fake http server.

I know obscurity can't replace security, but security + some obfuscation could
help you a bit for not getting hacked instantly by 0-days. It's easier to
setup on client side than port knocking (you just have to set the port) but
it's less detectable than sshd on a random port.

~~~
userbinator
It's interesting that SSH requires the server to respond with a message upon
connection, independent of whether the client sends anything - perhaps hiding
the service on a different port was not a strong consideration when it was
designed.

On the other hand, HTTP and SSL/TLS servers will just wait silently for the
client to initiate the conversation.

------
jsd1982
Nice! I wrote my own version of this in Go about 7 months ago. It's running in
production and has been very reliable. You can find it here on my github
account:
[https://github.com/JamesDunne/sslmux](https://github.com/JamesDunne/sslmux)

I notice you haven't set any IO timeouts on your protocol sniffer. I had to
add a read timeout because PuTTY (a Windows SSH client) waits for a packet
from the SSH server first before sending any itself.

------
hardwaresofton
Another interesting and enabling lower-level system tool written in Go.

I don't know if it's because I surf HN , but a lot of really cool "ops" and
system stuff seems to be written in Go lately.

~~~
vertex-four
It's generally the sort of thing that would be written in C a few years ago,
except C is a horrible language, and Go is the first semi-reasonable
replacement. Personally, I dislike coding in Go (far too much of my code ends
up being manual error checking), but Rust is on the horizon which might
subsume a significant part of this space.

~~~
vertex-four
A showdead comment says:

> I'm fairly amused that you want Rust after whining about Go's error
> handling.

Fact is, Rust's error handling story is quite nice, with plans to get nicer.
It has the try! macro which can automatically convert errors into my own error
type with the boilerplate outside the function (thus successfully separating
success and error paths to a large extent), and chainable Options and Results
for when I need those.

With Go, nearly all of my code revolves around handling errors manually,
generally repeating how to handle errors several times over, interleaved with
the success code, when 99% of the time it's "return an error".

EDIT: Another comment: I'm well aware of Option and try!, etc in Rust. But
overall, Rust doesn't mean that you don't have to think about error handling,
it just has different mechanisms for reducing the noise in your code.

Indeed, and I said "most of my code is error handling". I didn't suggest I
don't want to think about it - I'd just prefer that I can read what a function
does without 2/3rds of the lines in that function being error handling, and
thus obscuring what the function does in the success case.

------
mkj
It doesn't appear to set tcp nodelay, as with most of these forwarders.
[https://github.com/stealth/sshttp](https://github.com/stealth/sshttp) does it
at the kernel level, much better.

------
petercooper
I wonder how far you could take this in terms of protocols. I can't think of a
good use case yet, but is it at least technically possible to detect and
quickly proxy away most common protocols?

~~~
fluidcruft
sslh [1] (which is packaged and included in may linux and BSD distributions)
has grown to support HTTP, SSL, SSH, OpenVPN, tinc, XMPP from the same port.
It claims it can be extended to filter anything that can match with a regex.

What I find lacking lately is I've mostly wanted to extend the
forwarding/routing of ssh connections based on username (or better by
identity) to different VMs or hosts, but I have no idea how to achieve that at
the moment (without creating dummy users on the sshd server).

[1]
[http://www.rutschle.net/tech/sslh.shtml](http://www.rutschle.net/tech/sslh.shtml)

Github: [https://github.com/yrutschle/sslh](https://github.com/yrutschle/sslh)

~~~
tombrossman
I had a herp derp moment recently after installing OpenVPN then discovering
that Nginx refused to restart because port 443 was 'bound by another process'
or something like that. This looks like a pretty easy workaround.

~~~
iancarroll
Do note that 443 is typically the web interface for OpenVPN, not the actual
VPN port.

~~~
tombrossman
I didn't have an IPTables rule allowing the VPN traffic (UDP port 1194) and so
OpenVPN falls back to using 443, which triggered the problem. I looked at the
workaround and decided not to bother as I didn't really need a VPN, I was
intending to use the machine as an Nginx server only.

------
antoaravinth
A simple question. How come two programs can run on the same port? How does
this being implemented?

~~~
thedufer
I haven't read it too carefully but typically something like this would be
done by having one program run on the port in question and then it would
determine which protocol a given connection is speaking and hand it off to a
different port based on config. So your https and ssh servers run on, say,
2000 and 3000 and the protocol recognizer runs on 443 and hands off
connections to either 2000 or 3000. See, for example, reverse-proxying with
nginx or haproxy.

~~~
antoaravinth
Ya I guess this is the way that they would have implemented.

------
alexchamberlain
Very interesting, but it's a real shame that you have to stoop to this level
to access in order to access SSH from all networks. Interestingly, I guess
this wouldn't work where HTTPS is MITM'd.

------
h43k3r
Can this help me to ssh to my servers on DO.

I am behind my institute squid proxy which is a HTTP proxy. All the ports are
blocked, all connections has to be through proxy. For https, it uses the
connect request.

------
jasonlfunk
This is neat. What practical applications does it have?

~~~
jzila
From the repo the project creator linked in the README
([https://github.com/yrutschle/sslh](https://github.com/yrutschle/sslh)): "A
typical use case is to allow serving several services on port 443 (e.g. to
connect to SSH from inside a corporate firewall, which almost never block port
443) while still serving HTTPS on that port."

------
yeukhon
I still don't get the practical advantage of this. As someone said below
he/she wrote one and running similar setup in production. Just why? Typicall
you access internal stuff over intranet over VPN. How is running both 22 and
443 on 443 in this multiplexing way help security?

------
gbuk2013
That's cool. :-)

I wrote something very similar in Node.js at work recently: a JSON-RPC server
that accepts TCP and HTTP messages on the same port. I remember being very
excited when I realised this was actually possible!

------
rustyconover
I wonder if you could do this with Nginx and the Upgrade header.

~~~
falcolas
If you could get SSH to negotiate the upgrade header before initializing its
own connection, then you probably could.

I think this could also potentially be done via iptables rules as well, since
iptables is capable of inspecting & rerouting packets.

~~~
shanemhansen
A little known fact is that newer versions of openssh support ProxyUseFDPass
which allows you to do some protocol negotiation before passing the socket
onto to the regular client.
[http://www.openssh.com/txt/release-6.5](http://www.openssh.com/txt/release-6.5)

~~~
falcolas
Nice. I'd love to see that in practice. Might have to dig into that myself...

------
spullara
At weblogic, http, https and t3 (custom protocol) were all on the same port
(since '97). No real need for multiple when they all have different
negotiation protocols.

------
ponytech
Anyone knows how nmap -sV (Version detection) would report the open port?
HTTP, SSH or neither ?

~~~
adnanh
Edit: Looking at the source code [0], looks like all probes that this service
matches will be reported.

[0]
[https://svn.nmap.org/nmap/service_scan.cc](https://svn.nmap.org/nmap/service_scan.cc)

------
ZeWaren
I've been using the same trick with OpenVPN for a while. Perfect to go trough
proxies.

------
blueskin_
It's a nice idea, but far from the only implementation. sslh is nice as it
doesn't need go, and is packaged for most distros:
[http://www.rutschle.net/tech/sslh.shtml](http://www.rutschle.net/tech/sslh.shtml)

~~~
nodata
sslh is linked from his page

------
est
it could perform better by using splice() kernel calls.

------
Pinn2
Liking the Go, not liking the .gitignore.

~~~
sethammons
Why?

~~~
Pinn2
The .gitignore is a good way to see if a project cares about being precise.

