Libvirt overwrites the existing iptables rules

From WBITT's Cooker!

(Difference between revisions)
Jump to: navigation, search
(Understanding the rules file created by iptables-save command)
(Understanding the rules file created by iptables-save command)
Line 365: Line 365:
** The default policy of the chain. e.g. ACCEPT or DROP or REJECT. 99% of time, you will see ACCEPT here.
** The default policy of the chain. e.g. ACCEPT or DROP or REJECT. 99% of time, you will see ACCEPT here.
** The two values inside the square brackets are number of packets passed through this chain, so far, as well as the number of bytes. e.g. [364:41916] means 364 packets "or" 41916 bytes, have passed through this chain till this point in time.
** The two values inside the square brackets are number of packets passed through this chain, so far, as well as the number of bytes. e.g. [364:41916] means 364 packets "or" 41916 bytes, have passed through this chain till this point in time.
-
* The lines starting with a - (hyphen/minus sign) are actually the actual rules which you put in here.
+
* The lines starting with a - (hyphen/minus sign) are actually the actual rules which you put in here. "-A" would mean "Add" the rule. "-I" would mean "Insert" the rule.
 +
 
 +
As you notice, these rules are no different than the standard rules you type on the command line, or in the bash shell script. The limitation of this style of writing rules (as shown here) is, that shell scripting is not possible.

Revision as of 18:59, 12 July 2010

Contents

XEN overwrites the existing iptables rules

Not exactly. It is libvirt which is the culprit, not XEN.

Objective / goal of this document

The objective of this document is to identify/clarify the following:

  • What are these specific iptable rules?
  • Why do we care? and, When do we care?
  • Does it matter if we lose these rules?
  • Does it matter when we have our virtual machines on a bridged interface, connecting directly to our physical LAN, xenbr0 or br0?
  • Does it matter when we have our virtual machines connected only on the private network inside the physical host, virbr0?
  • How do we circumvent any problems related to this scenario?

The details

It is observed, that systems which provide KVM or XEN virtualization technologies, sometimes have their iptables firewall rules changed automatically in Dom-0, overwritten by another set of rules.

Note: KVM doesn't have Dom-0. The base OS on the (KVM) physical host will be considered Dom-0 for ease of understanding. (Please. No flame war on this one.). I will use "Physical Host" and "Dom-0" interchangeably for ease of understanding, for a system which hosts one or more virtual machines (i.e. KVM or XEN).

This happens only on those systems, which run libvirtd service. Mistakenly, many people think this is XEN problem. Whereas it is not. First, I would explain, what is the default iptables firewall ruleset on the physical host.

More interestingly this is not much of an issue for the Virtual machines which share the physical ethernet device of the physical host. This is more of an issue, for virutal machines, connected to a virtual (private) network/bridge (192.168.122.0/24) inside the physical host. This means, their traffic passes through NAT configured on the same physical host, whenever they need to go out to the physical interface.

As we are aware that in the shared network device mode, it is easier (aka painless), to access the virtual machines, from the main physical network. This is because they (the virtual machines) have the IP from the same scheme/range/subnet as of the physical device of the physical host they are on. This is ideal for so called server mode, where all the virtual machines, are actually serving some services on the LAN.

On the other hand, in the virtual network mode, it is difficult (aka painful), to access the virtual machines, from the main physical network. It is because, they (the virtual machines) have the IP from a private scheme (192.168.122.0/24), and they sit behind a NAT router which is created by the virtual machine manager, on the physical host. That means, their traffic can go out of the network, NATed, and related traffic can get back in. But, if we want to access these (virtual servers (running on private IPs) from the LAN, we need to configure some traffic redirection (DNAT), on the physical host. This mode, of creating virtual machines on the private network, is ideal for private testing of various type of stuff. BUT, when you are in a situation, where you need your private server to be acccessed from outside, and you cannot use the "shared network device" mode for certain/whatever reasons, then you need to figure out a way to pass your traffic coming from outside to your VM. And when you try to do that, you see your iptables rules of your physical host machine, being clobbered/over-written by the libvirtd's rules, then you get frustrated. And that, is the reason, behind this document.

The default iptables rules on a KVM physical host

Here is a default iptables rule-set from a Fedora13 physical host. The default firewall (iptables service) was stopped when libvirtd service was started, at system boot.

[root@training ~]# iptables -L
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:bootps 

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             192.168.122.0/24    state 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 

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         


[root@training ~]# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  192.168.122.0/24    !192.168.122.0/24    

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Let's save these rules in a file, so we can load the defaults any time we need to.

[root@training ~]# iptables-save > /root/iptables.default.txt

I will show you these rules from this file for easier understanding:

[root@training ~]# cat /root/iptables.default.txt 
*nat
:PREROUTING ACCEPT [661:21364]
:POSTROUTING ACCEPT [58069:3670258]
:OUTPUT ACCEPT [58069:3670258]
-A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE 
COMMIT
*filter
:INPUT ACCEPT [1212620:674141323]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [1518464:780474182]
-A INPUT -i virbr0 -p udp -m udp --dport 53 -j ACCEPT 
-A INPUT -i virbr0 -p tcp -m tcp --dport 53 -j ACCEPT 
-A INPUT -i virbr0 -p udp -m udp --dport 67 -j ACCEPT 
-A INPUT -i virbr0 -p tcp -m tcp --dport 67 -j ACCEPT 
-A FORWARD -d 192.168.122.0/24 -o virbr0 -m state --state RELATED,ESTABLISHED -j ACCEPT 
-A FORWARD -s 192.168.122.0/24 -i virbr0 -j ACCEPT 
-A FORWARD -i virbr0 -o virbr0 -j ACCEPT 
-A FORWARD -o virbr0 -j REJECT --reject-with icmp-port-unreachable 
-A FORWARD -i virbr0 -j REJECT --reject-with icmp-port-unreachable 
COMMIT
[root@training ~]#

Lets start a VM:

[root@training init.d]# virsh start linuxvm
Domain linuxvm started


[root@training init.d]# virsh list
 Id Name                 State
----------------------------------
  2 linuxvm              running

Here is the output of ifconfig command, after a VM is started.

[root@training init.d]# ifconfig | grep -A1 HWaddr
eth0      Link encap:Ethernet  HWaddr 00:26:2D:95:AB:FA  
          inet addr:192.168.1.3  Bcast:192.168.1.255  Mask:255.255.255.0
--
virbr0    Link encap:Ethernet  HWaddr 26:45:88:61:E0:CC  
          inet addr:192.168.122.1  Bcast:192.168.122.255  Mask:255.255.255.0
--
vnet0     Link encap:Ethernet  HWaddr 26:45:88:61:E0:CC  
          inet6 addr: fe80::2445:88ff:fe61:e0cc/64 Scope:Link
[root@training init.d]# 

The default iptables rules on a XEN physical host

Here is the default iptables rules as seen when a XEN physical host boots up with default configurations. Please note that the firewall service was configured to be stopped on system boot. Which means, that these rules were added by some mechanism (libvirtd) on the XEN host.

[root@xenhost ~]# iptables -L
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:bootps 

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             192.168.122.0/24    state 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 

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

[root@xenhost ~]# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  192.168.122.0/24    !192.168.122.0/24    

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
[root@xenhost ~]# 

Save these rules for future reference:

[root@xenhost ~]# iptables-save > /root/iptables-default.txt

Have a look at the resultant file to understand the rules better:

[root@xenhost ~]# cat /root/iptables-default.txt 
*nat
:PREROUTING ACCEPT [5:180]
:POSTROUTING ACCEPT [6:428]
:OUTPUT ACCEPT [6:428]
-A POSTROUTING -s 192.168.122.0/255.255.255.0 -d ! 192.168.122.0/255.255.255.0 -j MASQUERADE 
COMMIT
*filter
:INPUT ACCEPT [168:13693]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [114:13252]
-A INPUT -i virbr0 -p udp -m udp --dport 53 -j ACCEPT 
-A INPUT -i virbr0 -p tcp -m tcp --dport 53 -j ACCEPT 
-A INPUT -i virbr0 -p udp -m udp --dport 67 -j ACCEPT 
-A INPUT -i virbr0 -p tcp -m tcp --dport 67 -j ACCEPT 
-A FORWARD -d 192.168.122.0/255.255.255.0 -o virbr0 -m state --state RELATED,ESTABLISHED -j ACCEPT 
-A FORWARD -s 192.168.122.0/255.255.255.0 -i virbr0 -j ACCEPT 
-A FORWARD -i virbr0 -o virbr0 -j ACCEPT 
-A FORWARD -o virbr0 -j REJECT --reject-with icmp-port-unreachable 
-A FORWARD -i virbr0 -j REJECT --reject-with icmp-port-unreachable 
COMMIT
[root@xenhost ~]# 

Now, let's start a VM on the XEN host, configured to run, while connected to the xen host private network, virbr0.

[root@xenhost ~]# virsh list --all
 Id Name                 State
----------------------------------
  0 Domain-0             running
  - miniweb              shut off

[root@xenhost ~]# virsh start miniweb
Domain miniweb started

[root@xenhost ~]# virsh list --all
 Id Name                 State
----------------------------------
  0 Domain-0             running
  1 miniweb              idle

[root@xenhost ~]# 

Let's look at the rules again, after starting the VM:

[root@xenhost ~]# iptables -L
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:bootps 

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             192.168.122.0/24    state 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 
ACCEPT     all  --  anywhere             anywhere            PHYSDEV match --physdev-in vif1.0 

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
[root@xenhost ~]# 

[root@xenhost ~]# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  192.168.122.0/24    !192.168.122.0/24    

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
[root@xenhost ~]# 

Lets save these rules in another file for comparison.

[root@xenhost ~]# iptables-save > /root/iptables-vm-running.txt

[root@xenhost ~]# cat /root/iptables-vm-running.txt 
*nat
:PREROUTING ACCEPT [34:2932]
:POSTROUTING ACCEPT [18:1292]
:OUTPUT ACCEPT [18:1292]
-A POSTROUTING -s 192.168.122.0/255.255.255.0 -d ! 192.168.122.0/255.255.255.0 -j MASQUERADE 
COMMIT
*filter
:INPUT ACCEPT [549:40513]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [364:41916]
-A INPUT -i virbr0 -p udp -m udp --dport 53 -j ACCEPT 
-A INPUT -i virbr0 -p tcp -m tcp --dport 53 -j ACCEPT 
-A INPUT -i virbr0 -p udp -m udp --dport 67 -j ACCEPT 
-A INPUT -i virbr0 -p tcp -m tcp --dport 67 -j ACCEPT 
-A FORWARD -d 192.168.122.0/255.255.255.0 -o virbr0 -m state --state RELATED,ESTABLISHED -j ACCEPT 
-A FORWARD -s 192.168.122.0/255.255.255.0 -i virbr0 -j ACCEPT 
-A FORWARD -i virbr0 -o virbr0 -j ACCEPT 
-A FORWARD -o virbr0 -j REJECT --reject-with icmp-port-unreachable 
-A FORWARD -i virbr0 -j REJECT --reject-with icmp-port-unreachable 
-A FORWARD -m physdev  --physdev-in vif1.0 -j ACCEPT 
COMMIT

Here I run the diff on the two files on the XEN host and try to see the differences.

[root@xenhost ~]# diff iptables-default.txt iptables-vm-running.txt 
< :PREROUTING ACCEPT [5:180]
< :POSTROUTING ACCEPT [6:428]
< :OUTPUT ACCEPT [6:428]
---
> :PREROUTING ACCEPT [34:2932]
> :POSTROUTING ACCEPT [18:1292]
> :OUTPUT ACCEPT [18:1292]
---
< :INPUT ACCEPT [168:13693]
---
> :INPUT ACCEPT [549:40513]
< :OUTPUT ACCEPT [114:13252]
---
> :OUTPUT ACCEPT [364:41916]
> -A FORWARD -m physdev  --physdev-in vif1.0 -j ACCEPT 
[root@xenhost ~]# 

And just for reference and explanation, here is the output of "ifconfig" command on the XEN host.

[root@xenhost ~]# ifconfig | grep -A1 HWaddr 
eth0      Link encap:Ethernet  HWaddr 54:52:00:73:15:33  
          inet addr:192.168.1.200  Bcast:192.168.1.255  Mask:255.255.255.0
--
peth0     Link encap:Ethernet  HWaddr FE:FF:FF:FF:FF:FF  
          inet6 addr: fe80::fcff:ffff:feff:ffff/64 Scope:Link
--
vif0.0    Link encap:Ethernet  HWaddr FE:FF:FF:FF:FF:FF  
          inet6 addr: fe80::fcff:ffff:feff:ffff/64 Scope:Link
--
vif1.0    Link encap:Ethernet  HWaddr FE:FF:FF:FF:FF:FF  
          inet6 addr: fe80::fcff:ffff:feff:ffff/64 Scope:Link
--
virbr0    Link encap:Ethernet  HWaddr FE:FF:FF:FF:FF:FF  
          inet addr:192.168.122.1  Bcast:192.168.122.255  Mask:255.255.255.0
--
xenbr0    Link encap:Ethernet  HWaddr FE:FF:FF:FF:FF:FF  
          UP BROADCAST RUNNING NOARP  MTU:1500  Metric:1
[root@xenhost ~]#


Understanding the rules file created by iptables-save command

Many people consider the output of iptables-save to be very cryptic. It is not. Here is a brief explanation of the iptables rules file, created by iptables-save command. We will use the file created at a XEN host.

[root@xenhost ~]# iptables-save > /root/iptables-vm-running.txt

[root@xenhost ~]# cat /root/iptables-vm-running.txt 
*nat
:PREROUTING ACCEPT [34:2932]
:POSTROUTING ACCEPT [18:1292]
:OUTPUT ACCEPT [18:1292]
-A POSTROUTING -s 192.168.122.0/255.255.255.0 -d ! 192.168.122.0/255.255.255.0 -j MASQUERADE 
COMMIT
*filter
:INPUT ACCEPT [549:40513]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [364:41916]
-A INPUT -i virbr0 -p udp -m udp --dport 53 -j ACCEPT 
-A INPUT -i virbr0 -p tcp -m tcp --dport 53 -j ACCEPT 
-A INPUT -i virbr0 -p udp -m udp --dport 67 -j ACCEPT 
-A INPUT -i virbr0 -p tcp -m tcp --dport 67 -j ACCEPT 
-A FORWARD -d 192.168.122.0/255.255.255.0 -o virbr0 -m state --state RELATED,ESTABLISHED -j ACCEPT 
-A FORWARD -s 192.168.122.0/255.255.255.0 -i virbr0 -j ACCEPT 
-A FORWARD -i virbr0 -o virbr0 -j ACCEPT 
-A FORWARD -o virbr0 -j REJECT --reject-with icmp-port-unreachable 
-A FORWARD -i virbr0 -j REJECT --reject-with icmp-port-unreachable 
-A FORWARD -m physdev  --physdev-in vif1.0 -j ACCEPT 
COMMIT
  • Lines starting with * (asterisk) are the iptables "tables". Such as "nat" table, and "filter" table, as shown in the output above. Each table has "chains" defined in them.
  • Lines starting with  : (colon) are the name of chains. These lines contain following four pieces of information about a chain. ":ChainName POLICY[Packets:Bytes]
    • The name of the chain right next to the starting colon. e.g. "INPUT" , or "PREROUTING"
    • The default policy of the chain. e.g. ACCEPT or DROP or REJECT. 99% of time, you will see ACCEPT here.
    • The two values inside the square brackets are number of packets passed through this chain, so far, as well as the number of bytes. e.g. [364:41916] means 364 packets "or" 41916 bytes, have passed through this chain till this point in time.
  • The lines starting with a - (hyphen/minus sign) are actually the actual rules which you put in here. "-A" would mean "Add" the rule. "-I" would mean "Insert" the rule.

As you notice, these rules are no different than the standard rules you type on the command line, or in the bash shell script. The limitation of this style of writing rules (as shown here) is, that shell scripting is not possible.

Personal tools