Dynamic port forwarding based on hostname or originating ip

At the IP level, there is no such thing as a hostname. A hostname is an application-level abstraction of an IP address, and at the Internet or Transport layers they hold no meaning.

In HTTP shared hosting, this trick is abstracted in the process of handling the HTTP conversation, which happens after the TCP conversation is started. It is for this reason that running an SSL server required a dedicated IP address for so long, as the SSL conversation takes place before the HTTP one (this has since been fixed in newer TLS releases where HOSTNAME can now included as part of the SSL negotiation).

For a shared-hosting HTTP instance the protocols are negotiated in roughly this order:

TCP -> SSL -> HTTP

Each protocol can not be started until the earlier ones are completed. Until recently, only the last step in the chain was aware of hostnames, which is why it was up to the webserver software to handle a many-to-one association of hostnames to IP.

For a dynamic port forward, this is only doable if the application protocol is somehow aware of hostnames. Some device (be it software or hardware) handles the initial TCP connection with clients and the first steps of the application protocol (whatever that is) and forwards the connection on to its ultimate destination based on what it received.

The exact steps needed vary based on the application protocol itself. Some, like HTTP, include a HOSTNAME header indicating the hostname the client expects to be talking to. Others, like some Microsoft protocols, leverage DNS-based SRV records to determine a precise IP and port combination. Since it sounds like you may be designing your own application protocol from the bolts out, I'd suggest following HTTP's lead and include a HOSTNAME header in your initial protocol negotiation steps.


You can achieve this most easily using SRV records in your DNS:

http://en.wikipedia.org/wiki/SRV_record


Can you describe in clearer terms what you're trying to do and why? The "Why" will help greatly. What are the clients? What is the protocol?

There are many ways to do this based on the protocols and data streams.

Consider pf, iptables or ebtables injection, see "ssh blacklist" for examples. Look at LVS, HAproxy and other load balancers for general redirection.

An old trick is a "wake-up" system. This works great for SSH or other encrypted protocols that make it more cpu intensive to determine source domain.(decode the header) This leaves only a single port running when no one is connected.

  • SSH in to a single open port (no terminal support necessary)
  • log into system as userX (preferably using keys), this runs a script that starts up another instance of the server on port XXXXX and replies to the client with the new port number
  • "port XXXXX is open" message is transferred back to client, initial ssh session is closed
  • client or client app then re-connects using the now open port XXXXX
  • when client disconnects the alternate instance on port XXXXX is closed and/or port XXXXX is closed.

Specific ports can be assigned based on keys/users, reverse lookup, message passing, etc. Some just leave the instances running and open/close using pf/iptables firewall injection. Others extend this using a firewall rule to trigger the service startup and have no initial SSH (or other service) running until a specified port is pinged with a specific type of packet. I prefer a "recently matched" custom firewall rule to block stray packets and stopping/starting the server instances for less dynamic interaction with the firewall.

This idea can work with any protocol and service that can be coded or scripted.

Reading materials for TCP/IP Networking: Anything written or recommended by W. Richard Stevens. http://www.kohala.com/start/

Don't discount using SSH tunnels as a in-development stopgap. These could achieve everything you need with no code. What is your app? Shouldn't it's communication be secure? How are you going to blacklist script kiddie hackers? That's more you'll have to write and debug. You should be compartmentalizing your code anyway, so develop everything else using SSH as the transport, port forwarding, encryption, usage logging, blacklisting, etc.. Then when everything else is done write your own network protocol mechanism to replace SSH. There is no need for terminal access for users on the gateway SSH server to use tunnels.