SSH port filtered on machine only from within local network when using explicit ip address

filterlinux-networkingnetworkingssh

To describe the situation, I need to define three machines. On the local network I have a machine (LAPTOP) and a machine (SERVER) connected over WAN and LAN to the router, respectively. The third machine is an external vps (VPS).

I am trying to SSH into the SERVER from the LAPTOP using an explicit IP address. To accomplish this, I set up openssh servers (all machines are running Ubuntu) listening to port 22. On the router I gave a reserved IP address to SERVER and added a port forwarding rule for incoming port 22 to port 22 of the SERVER.

What is working:
– SSH from VPS to SERVER
– SSH from LAPTOP to SERVER using local hostname internal to local network

What is not working:
– SSH from LAPTOP to SERVER using explicit IP address.

To try and debug I ran nmap to see if the port is being filtered.
I ran the following command on both the VPS and the LAPTOP

nmap -sS -p 22 xx.xx.xx.xx

where the x's denote the literal external IP of the router of the local network. The result is as follows:

VPS: 22/tcp open ssh
LAPTOP: 22/tcp filtered ssh

Just to double check if I use local hostname from the LAPTOP the port is open as it should be. Why is the port filtered when SSH'ing from the LAPTOP when using the explicit external IP?
Is the outgoing request being filtered by my router?

Best Answer

Your problem comes from the fact that your router probably applies the port forwarding rules (DNAT chain in iptables) before the NAT (SNAT chain in iptables).

This stackexchange post explains the problem in details and shows you how to confirm it using tcpdump. Basically you should see that you send your SYN packet to your external IP but receive the SYN/ACK from SERVER's internal IP.

Edit: How to fix it: Do not connect to your external IP from within your internal network. Use SERVER's internal IP directly.