"""
IPTables configuration
======================
Module for processing output of the ``iptables-save`` and ``ip6tables-save``
commands. Parsers included are:
IPTables - command ``iptables-save``
------------------------------------
IP6Tables - command ``ip6tables-save``
--------------------------------------
IPTabPermanent - file ``/etc/sysconfig/iptables``
-------------------------------------------------
IP6TabPermanent - file ``/etc/sysconfig/ip6tables``
---------------------------------------------------
Sample input data looks like::
# Generated by iptables-save v1.4.7 on Tue Aug 16 10:18:43 2016
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [769:196899]
:REJECT-LOG - [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -s 192.168.0.0/24 -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A REJECT-LOG -p tcp -j REJECT --reject-with tcp-reset
COMMIT
# Completed on Tue Aug 16 10:18:43 2016
# Generated by iptables-save v1.4.7 on Tue Aug 16 10:18:43 2016
*mangle
:PREROUTING ACCEPT [451:22060]
:INPUT ACCEPT [451:22060]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [594:47151]
:POSTROUTING ACCEPT [594:47151]
COMMIT
# Completed on Tue Aug 16 10:18:43 2016
# Generated by iptables-save v1.4.7 on Tue Aug 16 10:18:43 2016
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [3:450]
:OUTPUT ACCEPT [3:450]
COMMIT
# Completed on Tue Aug 16 10:18:43 2016
* Each table of iptables starts with a ``# Generated by ...`` line.
* Each table starts with ``*<table-name>``, for example ``*filter``.
* Each chain specifications starts with a ``:`` sign.
* A chain specification looks like ``:<chain-name> <chain-policy> [<packet-counter>:<byte-counter>]``
* The chain-name may be for example ``INPUT``.
* Each ``iptables`` rule starts with a `-` sign.
Examples:
>>> ipt.rules[0] == {'target': 'ACCEPT', 'chain': 'INPUT', 'rule': '-m state --state RELATED,ESTABLISHED -j ACCEPT', 'table': 'filter', 'target_options': None, 'target_action': 'jump', 'constraints': '-m state --state RELATED,ESTABLISHED'}
True
>>> ipt.get_chain('INPUT')[1] == {'target': 'ACCEPT', 'chain': 'INPUT', 'rule': '-s 192.168.0.0/24 -j ACCEPT', 'table': 'filter', 'target_options': None, 'target_action': 'jump', 'constraints': '-s 192.168.0.0/24'}
True
>>> ipt.table_chains('mangle') == {'FORWARD': [], 'INPUT': [], 'POSTROUTING': [], 'PREROUTING': [], 'OUTPUT': []}
True
>>> ipt.get_table('nat')[-1] == {'policy': 'ACCEPT', 'table': 'nat', 'byte_counter': 450, 'name': 'OUTPUT', 'packet_counter': 3}
True
"""
from .. import Parser, parser, get_active_lines, CommandParser
from insights.specs import Specs
[docs]
class IPTablesConfiguration(Parser):
"""
A general class for parsing iptables configuration in the
``iptables-save``-like format.
"""
[docs]
def parse_content(self, content):
self.chains = []
self.rules = []
current_table = None
for line in get_active_lines(content):
if line.startswith("*"):
current_table = line[1:].strip()
elif line.startswith(":"):
name, policy, counter = line[1:].split()
packet_counter, byte_counter = counter.strip("[]").split(":")
self.chains.append({
"policy": policy if policy != "-" else None,
"table": current_table,
"name": name,
"packet_counter": int(packet_counter),
"byte_counter": int(byte_counter),
})
elif line.startswith("-"):
line_spl = line[3:].split(None, 1)
if not line_spl:
continue
chain_name = line_spl[0]
rule = line_spl[1] if len(line_spl) == 2 else ''
target_option = [i for i in (' -j', '-j ', ' -g', '-g ') if i in rule]
if target_option:
constraints, target = [i.strip() for i in rule.split(target_option[-1])]
if " " in target:
target, target_options = target.split(None, 1)
else:
target_options = None
self.rules.append({
"table": current_table,
"chain": chain_name,
"rule": rule,
"target_action": "jump" if target_option[-1].strip() == "-j" else "goto",
"constraints": constraints,
"target": target,
"target_options": target_options
})
else:
self.rules.append({
"table": current_table,
"chain": chain_name,
"rule": rule
})
[docs]
def get_chain(self, name, table="filter"):
"""
Get the list of rules for a particular chain. Chain order is kept intact.
Args:
name (str): chain name, e.g. ``
table (str): table name, defaults to ``filter``
Returns:
list: rules
"""
return [r for r in self.rules if r["table"] == table and r["chain"] == name]
[docs]
def get_table(self, name="filter"):
"""
Get the list of chains for a particular table.
Args:
name (str): table name, defaults to ``filter``
Returns:
list: chains
"""
return [c for c in self.chains if c["table"] == name]
[docs]
def table_chains(self, table="filter"):
"""
Get a dict where the keys are all the chains for the given table
and each value is the set of rules defined for the given chain.
Args:
table (str): table name, defaults to ``filter``
Returns:
dict: chains with set of defined rules
"""
return dict((c["name"], self.get_chain(c["name"], table)) for c in self.get_table(table))
[docs]
def get_rule(self, s):
"""
Get the list of rules that contain the given string.
Args:
s (str): string to look for in iptables rules
Returns:
list: rules containing given string
"""
return [r for r in self.rules if s in r["rule"]]
def __contains__(self, s):
return any(s in r["rule"] for r in self.rules)
[docs]
@parser(Specs.iptables)
class IPTables(CommandParser, IPTablesConfiguration):
"""
Process output of the ``iptables-save`` command.
See the :py:class:`insights.parsers.iptables.IPTablesConfiguration` base
class for additional information.
"""
pass
[docs]
@parser(Specs.ip6tables)
class IP6Tables(CommandParser, IPTablesConfiguration):
"""
Process output of the ``ip6tables-save`` command.
See the :py:class:`insights.parsers.iptables.IPTablesConfiguration` base
class for additional information.
"""
pass
[docs]
@parser(Specs.iptables_permanent)
class IPTabPermanent(IPTablesConfiguration):
"""
Process ``iptables`` configuration saved in file ``/etc/sysconfig/iptables``.
The configuration in this file is loaded by the ``iptables`` service when the system boots.
New configuration is saved by using the ``service iptables save`` command. This configuration
file is not available on a system with ``firewalld`` service.
See the :py:class:`insights.parsers.iptables.IPTablesConfiguration` base
class for additional information.
"""
pass
[docs]
@parser(Specs.ip6tables_permanent)
class IP6TabPermanent(IPTablesConfiguration):
"""
Process ``ip6tables`` configuration saved in file ``/etc/sysconfig/ip6tables``.
The configuration in this file is loaded by the ``ip6tables`` service when the system boots.
New configuration is saved by using the ``service ip6tables save`` command. This configuration
file is not available on a system with ``firewalld`` service.
See the :py:class:`insights.parsers.iptables.IPTablesConfiguration` base
class for additional information.
"""
pass