Source code for insights.parsers.iptables

"""
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