9

I've got multiple game servers TCP ports on my single host machine. The goal is to have users be able to connect to server1.domain.net and have their directed based on that subdomain. My first instinct wrote the following but then I realised that TCP traffic isn't going to have any header to read. Using HAProxy 1.5.8. I tried doing this same thing using multiple backends, use_backend and full ACL lines but got the same result (understandably).

listen game-listener
  bind x.x.x.x:22222
  mode  tcp
  use-server  server1 if { hdr(host) -i server1.domain.net }
  use-server  server2 if { hdr(host) -i server2.domain.net }
  server server1 localhost:22201 check
  server server2 localhost:22202 check

Is there a check like hdr(host) that I can use for TCP connections? Or am I doing it right and the game just isn't playing nice?

Thanks!

shaun m
  • 363
  • 1
  • 2
  • 8
  • This isn't even possible unless the protocol being proxied supports it, and most do not. – Michael Hampton Nov 09 '14 at 21:16
  • 1
    Are these games `SRV` aware? That would open a possibility of solving it in DNS, eliminating the need for proxying at all. – Håkan Lindqvist Nov 09 '14 at 22:00
  • That is not something I'd considered. These are Minecraft servers and some quick Googling turned up this post which seems like a good answer: http://serverfault.com/questions/474225/minecraft-dns-srv-record-correct-setup Thanks! If you make your comment an answer, I'll accept it. – shaun m Nov 10 '14 at 20:12

2 Answers2

5

Dispatching connections to different backends depending on the hostname which the client connected to is impossible to do on the TCP layer.

You will have to either use separate IP addresses for each hostname or implement the proxying at the application layer with protocol specific code to detect the hostname.

Such a proxy is possible for certain protocols but not for others. Ranging from easy to impossible, the protocols I know enough about are:

  • HTTP is easy to support. All HTTP/1.1 clients and most HTTP/1.0 clients will send a host header before expecting any answer answer from the server. Clients without host header are likely long gone, since many sites these days will not work without it.
  • HTTPS can be supported for all clients with SNI support. SNI was standardized much more recently than HTTP/1.1, there are still a few clients around without SNI support.
  • DNS is possible to support but slightly tricky. In most cases you'd just operate your authoritative DNS server directly on a public IP address instead of proxying.
  • SMTP is possible to support but also tricky. A proxy for SMTP would likely end up looking more like an SMTP relay than like a proxy.
  • SSH is impossible to support. The concept of hostnames simply doesn't exist in the protocol. The client may use DNS to resolve the IP address of the server, and it may associate stored host keys with their host names, but this is entirely an implementation detail on the client side. This would not be visible to the proxy, so it cannot be used to dispatch connections. Moreover no useful information is send in cleartext, and even the few pieces of information that are send in cleartext at the start of the SSH protocol are authenticated later in the protocol, so if you get any part of that wrong, the communication breaks. What makes this even more impossible to handle is the fact that the client does not send even one byte of payload until the server has send a banner back to the client. So the proxy would have literally no information to work with.

I am not aware of any other protocol with a hostname, which could be used for such purposes. So I am guessing that most protocols not on the above list are impossible to proxy by hostname.

kasperd
  • 29,894
  • 16
  • 72
  • 122
  • ...a workaround for SSH is setting up a singular bastion server on a particular port for SSH. From there it is a simple TCP forward for that port. Once you are inside, then you have full access to the machines your bastion server can reach. SSH'ception'... "We have to go deeper!" – BradChesney79 Aug 28 '19 at 17:17
5

As an alternative to proxying (where it depends on the application protocol if it's possible to do based on hostnames) you may want to check if the client software is SRV aware, in which case you should be able to set this up in DNS alone.

An SRV record has the following format:

_Service._Proto.Name TTL Class SRV Priority Weight Port Target

In your specific example where you mentioned multiple instances of Minecraft it should be possible to do this based on SRV records and the records could look something like this:

_minecraft._tcp.foo.example.com. 86400 IN SRV 0 5 25565 server1.example.com.
_minecraft._tcp.bar.example.com. 86400 IN SRV 0 5 25566 server1.example.com.
Håkan Lindqvist
  • 33,741
  • 5
  • 65
  • 90