Port Forwarding – How to Forward Traffic from One Port to Another

debian-busterfirewalldport-forwarding

How do I forward all traffic arriving at a given port to another port?

Define the layout and the problem

The layout

Here is the layout of what I am trying to do…

+--------+         +---------------------+         +----------------+
|  WAN   |  <--->  | 6789                |         |                |
| Client |         |       Gateway       |         |      Host      |
|        |         |                4567 |  <--->  |  2345 Service  |
+--------+         +---------------------+         +----------------+

I want to transparently forward all traffic arriving on port 6789 to port 4567. The client on the WAN and the service on the host should know nothing about the gateway.

The gateway is Debian 10 with firewalld.

The problem

I am not able to get traffic arriving at port 6789 on the gateway to forward to port 4567.


The present setup

Step 01 – Expose the port on the firewall and confirm port is open.

Open the port on the gateway

  1. Run the firewall-cmd command: firewall-cmd --add-port=6789

  2. Check the firewall state…

root@gateway:~# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: etho0
  sources: 
  services: dhcpv6-client http https ssh
  ports: 6789/tcp
  protocols: 
  masquerade: yes
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules:
  1. Confirm the port is open.
  • On the gateway, start a listener: nc -vvlp 6789 &
  • Confirm the listener is up…
root@gateway:~# netstat -tulnp | grep 6789
tcp        0      0 0.0.0.0:6789              0.0.0.0:*               LISTEN      2274/nc
  • From the client, attempt to reach the gateway:
client@client123:~$ nc -vvN gateway.example.org 6789
Connection to gateway.example.org 6789 port [tcp/*] succeeded!

Conclusion: Port 6789 is open on the firewall.

Clean up by killing the nc process on both the client and the gateway.

Step 02 – Confirm the connection between the gateway and the service on the host

root@gateway:~# telnet localhost 4567
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 backendhost.backendhost MyService (Debian/GNU)

Conclusion: The tunnel between the gateway and the service on the host is up.

Step 03 – Add the port forward on gateway and check the firewall state

root@gateway:~# firewall-cmd --add-forward-port=port=6789:proto=tcp:toport=4567`
root@gateway:~# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: etho0
  sources: 
  services: dhcpv6-client ssh
  ports: 6789/tcp
  protocols: 
  masquerade: no
  forward-ports: port=6789:proto=tcp:toport=4567:toaddr=
  source-ports: 
  icmp-blocks: 
  rich rules: 

Conclusion: The port forward is in the firewall.


At this point, if I try to telnet the host from the client, I get…

client@client123:~$ telnet gateway.example.org 6789
Trying <IP_of_gateway>...
telnet: Unable to connect to remote host: Connection refused

At this point, I am wanting to see what I saw in Step 02 above.

The Questions

Here is where I am not sure about…

When I run netstat -tulnp on the gateway, it does NOT show anything listening on port 6789. I do not expect it to since I do not have any service running that listens on port 6789.

Do I need some kind of service to listen on the 6789 port? If so, what? Or do I am missing something in the firewall settings? Do I need some kind of transparent proxy as is mentioned here?

I am not going to clutter this post with links to all the stuff I have read in the last couple of weeks, but if there is a post that has the answer, please feel free to point it out.

Edit

In response to @A.B

The host runs behind a firewall. When the host is started, it automatically creates a tunnel to the gateway using an SSH port forward.

Here is the command that the host runs at boot: ssh -N -R 4567:localhost:2345 [email protected]

That tunnel is up as confirmed in Step 02. And while I did not mention is earlier, the client works when it is on the same LAN as the host.

What I am struggling with is getting traffic arriving at the gateway to successfully be passed through to the host. The gateway is to be "transparent." The security certificate is held by the host and the client should think it is speaking directly to the host.

I am still trying to learn the terminologies, so if there is a more correct way to ask this question, I am certainly open to know what it is.

Best Answer

Thanks for the various comments.

There were two things I was missing...

  1. GatewayPorts in /etc/ssh/sshd_config needed to be changed from the default no to clientspecified
  2. The ssh command needed to be changed from listening on the loopback to listening on all addresses. The updated command is looks like this: ssh -N -R 0.0.0.0:4567:localhost:2345 [email protected] (Notice the 0.0.0.0: that was added in front of the 4567 port.)