How to redirect all ports to one port with nftables

Posted on 2019-11-07 by ungleich

Motivation

Sometimes networks (like hotels or airports) block or filter outgoing traffic and thus prevent you to connect to where you want to connect to. Here at ungleich we are travelling quite a lot, but we always want to be able to access the servers of Data Center Light.

To be able to do so from anywhere in the world, we needed to ensure that we have some way of connecting to them, even if the network filters traffic to the ssh port (tcp/22).

While our main motivation was to enable ssh, the example below can be adjusted to any service, including http, https, smtp, ...

A solution based on nftables

As you might know we are big fans of nftables and this hotel/airport problem motivated us to once again checkout what we can achieve just with nftables.

Typically these networks will still allow outgoing traffic on some ports, but we don't know which ports. So instead of guessing which port we should bind SSH to, we will just use nftables to make ssh available on all TCP ports. Simple idea, isn't it?

How it works

To achieve our goal we need to tell nftables to take the traffic that goes to any port that is not our target port, to be redirected to our target part. If you have other services running on the host, you might want to adjust this logic though (see below). The following nftables snippet will already do the job:

flush ruleset

table ip nat {
    chain prerouting {
        type nat hook prerouting priority 0;

        tcp dport != 22 redirect to 22
    }
    chain postrouting {
        type nat hook postrouting priority 0;
    }
}

You can save this as nftables.conf and run

nft -f nftables.conf

to see it working on your system.

After applying this, we can use ssh -p <port> to choose any port and connect to our server:

ssh -p 80 serverX.placeY.ungleich.ch

Using specific ranges or ports only

If you have other services running on the system, you might want to restrict the ports to be used for ssh. You can either use sets (nftables syntax: { a, b, c, ... }) or intervals (nftables syntax: X - Y) as follows.

        tcp dport 2000-4000 redirect to :ssh
        tcp dport {23, 25, 80, 443 } redirect to :ssh

(just replace the tcp dport != ... line above)!

A note on ports

Over time you will see that there are some ports which are more likely to be open, even if the network filters your traffic. Some well known ports for this are:

  • 80: regular http traffic
  • 53: DNS, uses UDP by default, but TCP is also part of the standard
  • 443: usually has encrypted https traffic
  • 783: smtp submission port for sending out emails

Of course, if the filtering uses deep packet inspection, this will fail, but then there are other solutions for that... stay tuned!

More of it?

If you are interested in more of this, we invite you to join our open infrastructure chat on chat.ungleich.ch.