[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/WoTTsecurity/python-iptables/python3/README.md [Back]  [Original]

Introduction
============

About python-iptables
---------------------

**Iptables** is the tool that is used to manage **netfilter**, the
standard packet filtering and manipulation framework under Linux. As the
iptables manpage puts it:

> Iptables is used to set up, maintain, and inspect the tables of IPv4
> packet filter rules in the Linux kernel. Several different tables may
> be defined.
>
> Each table contains a number of built-in chains and may also contain
> user- defined chains.
>
> Each chain is a list of rules which can match a set of packets. Each
> rule specifies what to do with a packet that matches. This is called a
> target, which may be a jump to a user-defined chain in the same table.

`Python-iptables` provides a pythonesque wrapper via python bindings to
iptables under Linux. Interoperability with iptables is achieved via
using the iptables C libraries (`libiptc`, `libxtables`, and the
iptables extensions), not calling the iptables binary and parsing its
output. It is meant primarily for dynamic and/or complex routers and
firewalls, where rules are often updated or changed, or Python programs
wish to interface with the Linux iptables framework..

![buildstatus](https://travis-ci.org/ldx/python-iptables.png?branch=master)

![Bitdeli](https://d2weczhvl823v0.cloudfront.net/ldx/python-iptables/trend.png)

Installing via pip
------------------

The usual way:

    pip install --upgrade python-iptables

Compiling from source
---------------------

First make sure you have iptables installed (most Linux distributions
install it by default). `Python-iptables` needs the shared libraries
`libiptc.so` and `libxtables.so` coming with iptables, they are
installed in `/lib` on Ubuntu.

You can compile `python-iptables` in the usual distutils way:

    % cd python-iptables
    % python setup.py build

If you like, `python-iptables` can also be installed into a
`virtualenv`:

    % mkvirtualenv python-iptables
    % python setup.py install

If you install `python-iptables` as a system package, make sure the
directory where `distutils` installs shared libraries is in the dynamic
linker's search path (it's in `/etc/ld.so.conf` or in one of the files
in the folder `/etc/ld.co.conf.d`). Under Ubuntu `distutils` by default
installs into `/usr/local/lib`.

Now you can run the tests:

    % sudo PATH=$PATH ./test.py
    WARNING: this test will manipulate iptables rules.
    Don't do this on a production machine.
    Would you like to continue? y/n y
    [...]

The `PATH=$PATH` part is necessary after `sudo` if you have installed
into a `virtualenv`, since `sudo` will reset your environment to a
system setting otherwise..

Once everything is in place you can fire up python to check whether the
package can be imported:

    % sudo PATH=$PATH python
    >>> import iptc
    >>>

Of course you need to be root to be able to use iptables.

What is supported
-----------------

The basic iptables framework and all the match/target extensions are
supported by `python-iptables`, including IPv4 and IPv6 ones. All IPv4
and IPv6 tables are supported as well.

Full documentation with API reference is available
[here](http://ldx.github.com/python-iptables/).

Examples
========

Rules
-----

In `python-iptables`, you usually first create a rule, and set any
source/destination address, in/out interface and protocol specifiers,
for example:

    >>> import iptc
    >>> rule = iptc.Rule()
    >>> rule.in_interface = "eth0"
    >>> rule.src = "192.168.1.0/255.255.255.0"
    >>> rule.protocol = "tcp"

This creates a rule that will match TCP packets coming in on eth0, with
a source IP address of 192.168.1.0/255.255.255.0.

A rule may contain matches and a target. A match is like a filter
matching certain packet attributes, while a target tells what to do with
the packet (drop it, accept it, transform it somehow, etc). One can
create a match or target via a Rule:

    >>> rule = iptc.Rule()
    >>> m = rule.create_match("tcp")
    >>> t = rule.create_target("DROP")

Match and target parameters can be changed after creating them. It is
also perfectly valid to create a match or target via instantiating them
with their constructor, but you still need a rule and you have to add
the matches and the target to their rule manually:

    >>> rule = iptc.Rule()
    >>> match = iptc.Match(rule, "tcp")
    >>> target = iptc.Target(rule, "DROP")
    >>> rule.add_match(match)
    >>> rule.target = target

Any parameters a match or target might take can be set via the
attributes of the object. To set the destination port for a TCP match:

    >>> rule = iptc.Rule()
    >>> rule.protocol = "tcp"
    >>> match = rule.create_match("tcp")
    >>> match.dport = "80"

To set up a rule that matches packets marked with 0xff:

    >>> rule = iptc.Rule()
    >>> rule.protocol = "tcp"
    >>> match = rule.create_match("mark")
    >>> match.mark = "0xff"

Parameters are always strings. You can supply any string as the
parameter value, but note that most extensions validate their
parameters. For example this:

    >>> rule = iptc.Rule()
    >>> rule.protocol = "tcp"
    >>> rule.target = iptc.Target(rule, "ACCEPT")
    >>> match = iptc.Match(rule, "state")
    >>> chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), "INPUT")
    >>> match.state = "RELATED,ESTABLISHED"
    >>> rule.add_match(match)
    >>> chain.insert_rule(rule)

will work. However, if you change the state parameter:

    >>> rule = iptc.Rule()
    >>> rule.protocol = "tcp"
    >>> rule.target = iptc.Target(rule, "ACCEPT")
    >>> match = iptc.Match(rule, "state")
    >>> chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), "INPUT")
    >>> match.state = "RELATED,ESTABLISHED,FOOBAR"
    >>> rule.add_match(match)
    >>> chain.insert_rule(rule)

`python-iptables` will throw an exception:

    Traceback (most recent call last):
      File "state.py", line 7, in 
        match.state = "RELATED,ESTABLISHED,FOOBAR"
      File "/home/user/Projects/python-iptables/iptc/ip4tc.py", line 369, in __setattr__
        self.parse(name.replace("_", "-"), value)
      File "/home/user/Projects/python-iptables/iptc/ip4tc.py", line 286, in parse
        self._parse(argv, inv, entry)
      File "/home/user/Projects/python-iptables/iptc/ip4tc.py", line 516, in _parse
        ct.cast(self._ptrptr, ct.POINTER(ct.c_void_p)))
      File "/home/user/Projects/python-iptables/iptc/xtables.py", line 736, in new
        ret = fn(*args)
      File "/home/user/Projects/python-iptables/iptc/xtables.py", line 1031, in parse_match
        argv[1]))
    iptc.xtables.XTablesError: state: parameter error -2 (RELATED,ESTABLISHED,FOOBAR)

In certain cases you might need to use quoting inside the parameter
string, for example:

    >>> rule = iptc.Rule()
    >>> rule.src = "127.0.0.1"
    >>> rule.protocol = "udp"
    >>> rule.target = rule.create_target("ACCEPT")
    >>> match = rule.create_match("comment")
    >>> match.comment = "this is a test comment"
    >>> chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), "INPUT")
    >>> chain.insert_rule(rule)

will only add the comment this instead of the expected this is a test
comment. Use quoting inside the comment string itself:

    >>> comment = "this is a test comment"
    >>> match.comment = "\"%s\"" % (comment)

When you are ready constructing your rule, add them to the chain you
want it to show up in:

    >>> chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), "INPUT")
    >>> chain.insert_rule(rule)

This will put your rule into the INPUT chain in the filter table.

Chains and tables
-----------------

You can of course also check what a rule's source/destination address,
in/out inteface etc is. To print out all rules in the FILTER table:

    >>> import iptc
    >>> table = iptc.Table(iptc.Table.FILTER)
    >>> for chain in table.chains:
    >>>     print "======================="
    >>>     print "Chain ", chain.name
    >>>     for rule in chain.rules:
    >>>         print "Rule", "proto:", rule.protocol, "src:", rule.src, "dst:", \
    >>>               rule.dst, "in:", rule.in_interface, "out:", rule.out_interface,
    >>>         print "Matches:",
    >>>         for match in rule.matches:
    >>>             print match.name,
    >>>         print "Target:",
    >>>         print rule.target.name
    >>> print "======================="

As you see in the code snippet above, rules are organized into chains,
and chains are in tables. You have a fixed set of tables; for IPv4:

-   FILTER,
-   NAT,
-   MANGLE and
-   RAW.

For IPv6 the tables are:

-   FILTER,
-   MANGLE,
-   RAW and
-   SECURITY.

To access a table:

    >>> import iptc
    >>> table = iptc.Table(iptc.Table.FILTER)
    >>> print table.name
    filter

To create a new chain in the FILTER table:

    >>> import iptc
    >>> table = iptc.Table(iptc.Table.FILTER)
    >>> chain = table.create_chain("testchain")

    $ sudo iptables -L -n
    [...]
    Chain testchain (0 references)
    target     prot opt source               destination

To access an existing chain:

    >>> import iptc
    >>> table = iptc.Table(iptc.Table.FILTER)
    >>> chain = iptc.Chain(table, "INPUT")
    >>> chain.name
    'INPUT'
    >>> len(chain.rules)
    10
    >>>

More about matches and targets
------------------------------

There are basic targets, such as `DROP` and `ACCEPT`. E.g. to reject
packets with source address `127.0.0.1/255.0.0.0` coming in on any of
the `eth` interfaces:

    >>> import iptc
    >>> chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), "INPUT")
    >>> rule = iptc.Rule()
    >>> rule.in_interface = "eth+"
    >>> rule.src = "127.0.0.1/255.0.0.0"
    >>> target = iptc.Target(rule, "DROP")
    >>> rule.target = target
    >>> chain.insert_rule(rule)

To instantiate a target or match, we can either create an object like
above, or use the `rule.create_target(target_name)` and
`rule.create_match(match_name)` methods. For example, in the code above
target could have been created as:

    >>> target = rule.create_target("DROP")

instead of:

    >>> target = iptc.Target(rule, "DROP")
    >>> rule.target = target

The former also adds the match or target to the rule, saving a call.

Another example, using a target which takes parameters. Let's mark
packets going to `192.168.1.2` UDP port `1234` with `0xffff`:

    >>> import iptc
    >>> chain = iptc.Chain(iptc.Table(iptc.Table.MANGLE), "PREROUTING")
    >>> rule = iptc.Rule()
    >>> rule.dst = "192.168.1.2"
    >>> rule.protocol = "udp"
    >>> match = iptc.Match(rule, "udp")
    >>> match.dport = "1234"
    >>> rule.add_match(match)
    >>> target = iptc.Target(rule, "MARK")
    >>> target.set_mark = "0xffff"
    >>> rule.target = target
    >>> chain.insert_rule(rule)

Matches are optional (specifying a target is mandatory). E.g. to insert
a rule to NAT TCP packets going out via `eth0`:

    >>> import iptc
    >>> chain = iptc.Chain(iptc.Table(iptc.Table.NAT), "POSTROUTING")
    >>> rule = iptc.Rule()
    >>> rule.protocol = "tcp"
    >>> rule.out_interface = "eth0"
    >>> target = iptc.Target(rule, "MASQUERADE")
    >>> target.to_ports = "1234"
    >>> rule.target = target
    >>> chain.insert_rule(rule)

Here only the properties of the rule decide whether the rule will be
applied to a packet.

Matches are optional, but we can add multiple matches to a rule. In the
following example we will do that, using the `iprange` and the `tcp`
matches:

    >>> import iptc
    >>> rule = iptc.Rule()
    >>> rule.protocol = "tcp"
    >>> match = iptc.Match(rule, "tcp")
    >>> match.dport = "22"
    >>> rule.add_match(match)
    >>> match = iptc.Match(rule, "iprange")
    >>> match.src_range = "192.168.1.100-192.168.1.200"
    >>> match.dst_range = "172.22.33.106"
    >>> rule.add_match(match)
    >>> rule.target = iptc.Target(rule, "DROP")
    >>> chain = iptc.Chain(iptc.Table.(iptc.Table.FILTER), "INPUT")
    >>> chain.insert_rule(rule)

This is the `python-iptables` equivalent of the following iptables
command:

    # iptables -A INPUT -p tcp destination-port 22 -m iprange src-range 192.168.1.100-192.168.1.200 dst-range 172.22.33.106 -j DROP

You can of course negate matches, just like when you use `!` in front of
a match with iptables. For example:

    >>> import iptc
    >>> rule = iptc.Rule()
    >>> match = iptc.Match(rule, "mac")
    >>> match.mac_source = "!00:11:22:33:44:55"
    >>> rule.add_match(match)
    >>> rule.target = iptc.Target(rule, "ACCEPT")
    >>> chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), "INPUT")
    >>> chain.insert_rule(rule)

This results in:

    $ sudo iptables -L -n
    Chain INPUT (policy ACCEPT)
    target     prot opt source               destination
    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            MAC ! 00:11:22:33:44:55

    Chain FORWARD (policy ACCEPT)
    target     prot opt source               destination

    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination

Counters
--------

You can query rule and chain counters, e.g.:

    >>> import iptc
    >>> table = iptc.Table(iptc.Table.FILTER)
    >>> chain = iptc.Chain(table, 'OUTPUT')
    >>> for rule in chain.rules:
    >>>         (packets, bytes) = rule.get_counters()
    >>>         print packets, bytes

However, the counters are only refreshed when the underlying low-level
iptables connection is refreshed in `Table` via `table.refresh()`. For
example:

    >>> import time, sys
    >>> import iptc
    >>> table = iptc.Table(iptc.Table.FILTER)
    >>> chain = iptc.Chain(table, 'OUTPUT')
    >>> for rule in chain.rules:
    >>>         (packets, bytes) = rule.get_counters()
    >>>         print packets, bytes
    >>> print "Please send some traffic"
    >>> sys.stdout.flush()
    >>> time.sleep(3)
    >>> for rule in chain.rules:
    >>>         # Here you will get back the same counter values as above
    >>>         (packets, bytes) = rule.get_counters()
    >>>         print packets, bytes

This will show you the same counter values even if there was traffic
hitting your rules. You have to refresh your table to get update your
counters:

    >>> import time, sys
    >>> import iptc
    >>> table = iptc.Table(iptc.Table.FILTER)
    >>> chain = iptc.Chain(table, 'OUTPUT')
    >>> for rule in chain.rules:
    >>>         (packets, bytes) = rule.get_counters()
    >>>         print packets, bytes
    >>> print "Please send some traffic"
    >>> sys.stdout.flush()
    >>> time.sleep(3)
    >>> table.refresh()  # Here: refresh table to update rule counters
    >>> for rule in chain.rules:
    >>>         (packets, bytes) = rule.get_counters()
    >>>         print packets, bytes

Web Proxy Viewer  |  New URL  |  Original Page