firewall-cmd - add-forward-port don't work
Solution 1:
THE REAL PROBLEM:
The command...
firewall-cmd --permanent --zone=public --direct --add-rule ipv4 filter FORWARD 0 -d 0.0.0.0/0 -j ACCEPT
firewall-cmd --permanent --zone=public --add-forward-port=port=222:proto=tcp:toport=22:toaddr=10.1.0.9
firewall-cmd --reload
... described in "UPDATE II" works just as well as firewalld (used by CentOS 7).
The problem is in the KVM (libvirt) which when starting the "network" virbr0 injects rules (probably via firewalld) which prevents (first match principle) any attempt to port forwarding by conventional ways using firewall-cmd
. The KVM injected (libvirt) rules are at the top of FORWARD and POSTROUTING, before regular firewalld ruleset. Since the netfilter operates on first match principle, these rules.
SOLUTION:
Due to the problems generated by the rules injected by KVM (libvirt) into the firewall the solution is use a hack/workaround called libvirt-hook-qemu as we explained below...
Download and install libvirt-hook-qemu...
yum -y install git-core
cd /usr/local/src
git clone https://github.com/saschpe/libvirt-hook-qemu.git
cd libvirt-hook-qemu
make install
cd ..
rm -rf libvirt-hook-qemu
List your virtual machines (guests)...
virsh list --all
... and copy the name of the target virtual machine.
Turn off the virtual machine...
virsh shutdown "<VM_NAME>" --mode acpi
Open the file "hooks.json", delete its contents...
vi /etc/libvirt/hooks/hooks.json
... and enter your rules as the template below (other ways of setting up are possible)...
{
"<VM_NAME>": {
"interface": "virbr0",
"private_ip": "<VM_IP>",
"port_map": {
"tcp": [[<PORT_ON_HOST>, <PORT_ON_GUEST>]]
}
}
}
Restart libvirtd...
systemctl restart libvirtd.service
... and start the virtual machine...
virsh start "<VM_NAME>"
Done! =D
FURTHER:
This KVM (libvirt) behavior - injects rules which prevents any attempt to port forwarding - is IMPOSITIVE, INVASIVE AND UNNECESSARY... First because since there is no port forwarding on the host no virtual machine will be reachable on the default network (virbr0) and second because it forces us to use a hack/workaround (or "gato"/"gambiarra" as we call it in Brazil =D ).
In our view makes no sense impose the user how he should build his infrastructure or not... This makes no sense! To put it bluntly, we think it would be best if these settings were optional (injects rules...) as other leading hypervisors do. And we go further... If is to KVM (libvirt) controlling this kind of thing then it should also offer ways to map ports to virtual machines.
The KVM (libvirt) is a GREAT tool, but not all users are willing - for various reasons - to place their machines directly on the host machine's network just as not all users are willing to give up all the flexibility/accessibility that the default network (virbr0) offers.
Thanks!
[Refs.: https://bugzilla.redhat.com/show_bug.cgi?id=846810 , https://libvirt.org/firewall.html , https://libvirt.org/formatnetwork.html#examplesRoute, https://saschpe.wordpress.com/2014/03/06/dynamic-iptables-port-forwarding-for-nat-ed-libvirt-networks/ , https://serverfault.com/q/170079/276753 , https://serverfault.com/q/915257/276753 , https://wiki.libvirt.org/page/VirtualNetworking#Routed_mode , https://www.centos.org/forums/viewtopic.php?f=50&t=71454&sid=7f5190a29eebbf755235ec3dc404a47f , https://www.cyberciti.biz/faq/kvm-forward-ports-to-guests-vm-with-ufw-on-linux/ ]
UPDATE:
injects rules which prevents any attempt to port forwarding
-> The current upstream of KVM (libvirt) has resolved the issue!
See this: ...current upstream of KVM (libvirt) has resolved the issue...