3

I have a debian 10 host and I am running a debian 10 guest using NAT. I am using libvirt/KVM/QEMU

host public ip: x.x.x.x guest ip: 192.168.122.99

I am trying to forward port 22221 to port 22 in the guest for me to access the guest via ssh from the outside. I want to connect to the guest via ssh directly using ssh -p 22221 x.x.x.x

I am following this tutorial: https://wiki.libvirt.org/page/Networking#Forwarding_Incoming_Connections

I also tried countless other tutorials, and none worked. In particular I have no idea why the following does not work:

(inside host)

1- I shutdown the guest vm using virt-manager

2- I manually call the hook script ip tables to forward the port

sudo iptables -D FORWARD -o virbr0 -d  192.168.122.99 --dport 22 -j ACCEPT
sudo iptables -t nat -D PREROUTING -p tcp --dport 22221 -j DNAT --to 192.168.122.99:22

3- I start the guest vm and check that ssh 192.168.122.99 is working

4- Now I try to connect using ssh -p 22221 localhost and it refuses connection.

I also tried to check the port nmap -p 22221 localhost and it says it is blocked.

iptables -L (host)

Chain INPUT (policy ACCEPT)
target     prot opt source               destination                                                                       
ACCEPT     udp  --  anywhere             anywhere             udp dpt:domain
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:domain
ACCEPT     udp  --  anywhere             anywhere             udp dpt:bootps
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:67
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:http

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  anywhere             192.168.122.99
ACCEPT     all  --  anywhere             192.168.122.0/24     ctstate RELATED,ESTABLISHED                                                                    
ACCEPT     all  --  192.168.122.0/24     anywhere
ACCEPT     all  --  anywhere             anywhere
REJECT     all  --  anywhere             anywhere             reject-with icmp-port-unreachable                                                              
REJECT     all  --  anywhere             anywhere             reject-with icmp-port-unreachable  

ip a (host)

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: enp2s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:25:90:97:dc:6e brd ff:ff:ff:ff:ff:ff
    inet x.x.x.x/23 brd y.y.y.y scope global enp2s0f0
       valid_lft forever preferred_lft forever
    inet6 fe80::225:90ff:fe97:dc6e/64 scope link 
       valid_lft forever preferred_lft forever
3: enp2s0f1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 00:25:90:97:dc:6f brd ff:ff:ff:ff:ff:ff
4: virbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 52:54:00:60:e8:80 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
       valid_lft forever preferred_lft forever
5: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast master virbr0 state DOWN group default qlen 1000
    link/ether 52:54:00:60:e8:80 brd ff:ff:ff:ff:ff:ff
7: vnet0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master virbr0 state UNKNOWN group default qlen 1000
    link/ether fe:54:00:e4:c2:52 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::fc54:ff:fee4:c252/64 scope link 
       valid_lft forever preferred_lft forever

ip a (guest)

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:e4:c2:52 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.99/24 brd 192.168.122.255 scope global dynamic enp1s0
       valid_lft 2500sec preferred_lft 2500sec
    inet6 fe80::5054:ff:fee4:c252/64 scope link 
       valid_lft forever preferred_lft forever

3 Answers 3

3

The example script on the libvirt wiki seems to be missing "-p" in the FORWARD lines, the proper way to issue it is:

sudo iptables -I FORWARD -o virbr0 -d  192.168.122.99 -p tcp --dport 22 -j ACCEPT
sudo iptables -t nat -I PREROUTING -p tcp --dport 22221 -j DNAT --to 192.168.122.99:22
0

The local-originated connections don't pass through the PREROUTING hooks. So if you want to check the port-forwarding from the host system, you should add the DNAT rule into the nat/OUTPUT chain.

Something like that:

iptables -t nat -I OUTPUT -p tcp --dport 22221 --dst X.X.X.X -j DNAT --to 192.168.122.99:22

To troubleshoot check the counters of rules, the tcpdump and the conntrack tool.

7
  • I guess the problem is that the ports are not being opened. For example, after calling your command, it still doesn't show the port as open when I call netstat -nat. Any idea why the ports are not being opened?
    – rmauter
    Oct 30, 2019 at 16:10
  • The nat and sockets are different subjects. The netstat tool shows you the sockets in the host system, but knows nothing about nat and firewall. The netfilter/conntrack knows nothing about the local sockets, it just rewrites the packets at early processing stages. So, you won't see any additional socket in the netstat output when you add the nat rules for the port-forwarding. Oct 30, 2019 at 16:17
  • Sorry I meant nmap -p 22221 localhost. This should show port 22221 as open or not? If not, what can I use to check if the iptables command worked and is allowing the connection to this port?
    – rmauter
    Oct 30, 2019 at 16:19
  • Simple way: telnet localhost 22221. Then check the rule counters (iptables-save -t nat -c). Then check the traffic with tcpdump(tcpdump -ni virbr0 'tcp port 22'). Oct 30, 2019 at 16:41
  • iptables-save -t nat -c shows the rules correctly set, but telnet localhost 22221 simply refuses immediately. Same with ssh -p 22221 localhost. tcpdump shows nothing.
    – rmauter
    Oct 30, 2019 at 17:04
0

Noticed step after adding to/editing iptable: 3- I start the guest vm and check that ssh 192.168.122.99 is working

Factually iptables are fluid and the system it's self changes iptables on the fly as it sees fit. Arguably iptables are tempermental.

ssh directly to/from 192.168.122.99 CAN cause system to automatically adjust iptables changes you made in previous step.

If i was troubleshooting this i would

# ssh -p 22221 localhost 

or

# ssh 192.168.122.99 -p 22221 

before

#ssh 192.168.122.99

iptables will "perserve" working settings longer than new settings that it sees to conflict "established" connections.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .