GithubHelp home page GithubHelp logo

python-iptables's Introduction

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

If you are looking for ebtables python bindings, check out python-ebtables.

Python-iptables supports Python 2.6, 2.7 and 3.4.

Flattr

Latest Release

Build Status

Coverage Status

Code Health

Number of Downloads

License

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 python setup.py test
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.

Using a custom iptables install

If you are stuck on a system with an old version of iptables, you can install a more up to date version to a custom location, and ask python-iptables to use libraries at that location.

To install iptables to /tmp/iptables:

% git clone git://git.netfilter.org/iptables && cd iptables
% ./autogen.sh
% ./configure --prefix=/tmp/iptables
% make
% make install

Make sure the dependencies iptables needs are installed.

Now you can point python-iptables to this install path via:

% sudo PATH=$PATH IPTABLES_LIBDIR=/tmp/iptables/lib XTABLES_LIBDIR=/tmp/iptables/lib/xtables python
>>> import iptc
>>>

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.

Examples

High level abstractions

python-iptables implements a low-level interface that tries to closely match the underlying C libraries. The module iptc.easy improves the usability of the library by providing a rich set of high-level functions designed to simplify the interaction with the library, for example:

>>> import iptc
>>> iptc.easy.dump_table('nat', ipv6=False)
{'INPUT': [], 'OUTPUT': [], 'POSTROUTING': [], 'PREROUTING': []}
>>> iptc.easy.dump_chain('filter', 'OUTPUT', ipv6=False)
[{'comment': {'comment': 'DNS traffic to Google'},
  'counters': (1, 56),
  'dst': '8.8.8.8/32',
  'protocol': 'udp',
  'target': 'ACCEPT',
  'udp': {'dport': '53'}}]
>>> iptc.easy.add_chain('filter', 'TestChain')
True
>>> rule_d = {'protocol': 'tcp', 'target': 'ACCEPT', 'tcp': {'dport': '22'}}
>>> iptc.easy.insert_rule('filter', 'TestChain', rule_d)
>>> iptc.easy.dump_chain('filter', 'TestChain')
[{'protocol': 'tcp', 'target': 'ACCEPT', 'tcp': {'dport': '22'}}]
>>> iptc.easy.delete_chain('filter', 'TestChain', flush=True)

>>> # Example of goto rule // iptables -A FORWARD -p gre -g TestChainGoto
>>> iptc.easy.add_chain('filter', 'TestChainGoto')
>>> rule_goto_d = {'protocol': 'gre', 'target': {'goto': 'TestChainGoto'}}
>>> iptc.easy.insert_rule('filter', 'FORWARD', rule_goto_d)

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 <module>
    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)

Certain parameters take a string that optionally consists of multiple words. The comment match is a good 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)

Note that this is still just one parameter value.

However, when a match or a target takes multiple parameter values, that needs to be passed in as a list. Let's assume you have created and set up an ipset called blacklist via the ipset command. To create a rule with a match for this set:

>>> rule = iptc.Rule()
>>> m = rule.create_match("set")
>>> m.match_set = ['blacklist', 'src']

Note how this time a list was used for the parameter value, since the set match match_set parameter expects two values. See the iptables manpages to find out what the extensions you use expect. See ipset for more information.

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

What is more, if you add:

iptables -A OUTPUT -p tcp --sport 80
iptables -A OUTPUT -p tcp --sport 22

you can query rule and chain counters together with the protocol and sport(or dport), e.g.:

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

Autocommit

Python-iptables by default automatically performs an iptables commit after each operation. That is, after you add a rule in python-iptables, that will take effect immediately.

It may happen that you want to batch together certain operations. A typical use case is traversing a chain and removing rules matching a specific criteria. If you do this with autocommit enabled, after the first delete operation, your chain's state will change and you have to restart the traversal. You can do something like this:

>>> import iptc
>>> table = iptc.Table(iptc.Table.FILTER)
>>> removed = True
>>> chain = iptc.Chain(table, "FORWARD")
>>> while removed == True:
>>>     removed = False
>>>     for rule in chain.rules:
>>>         if rule.out_interface and "eth0" in rule.out_interface:
>>>             chain.delete_rule(rule)
>>>             removed = True
>>>             break

This is clearly not ideal and the code is not very readable. An alternative is to disable autocommits, traverse the chain, removing one or more rules, than commit it:

>>> import iptc
>>> table = iptc.Table(iptc.Table.FILTER)
>>> table.autocommit = False
>>> chain = iptc.Chain(table, "FORWARD")
>>> for rule in chain.rules:
>>>     if rule.out_interface and "eth0" in rule.out_interface:
>>>         chain.delete_rule(rule)
>>> table.commit()
>>> table.autocommit = True

The drawback is that Table is a singleton, and if you disable autocommit, it will be disabled for all instances of that Table.

Easy rules with dictionaries

To simplify operations with python-iptables rules we have included support to define and convert Rules object into python dictionaries.

>>> import iptc
>>> table = iptc.Table(iptc.Table.FILTER)
>>> chain = iptc.Chain(table, "INPUT")
>>> # Create an iptc.Rule object from dictionary
>>> rule_d = {'comment': {'comment': 'Match tcp.22'}, 'protocol': 'tcp', 'target': 'ACCEPT', 'tcp': {'dport': '22'}}
>>> rule = iptc.easy.encode_iptc_rule(rule_d)
>>> # Obtain a dictionary representation from the iptc.Rule
>>> iptc.easy.decode_iptc_rule(rule)
{'tcp': {'dport': '22'}, 'protocol': 'tcp', 'comment': {'comment': 'Match tcp.22'}, 'target': 'ACCEPT'}

Known Issues

These issues are mainly caused by complex interaction with upstream's Netfilter implementation, and will require quite significant effort to fix. Workarounds are available.

  • The hashlimit match requires explicitly setting hashlimit_htable_expire. See Issue #201.
  • The NOTRACK target is problematic; use CT --notrack instead. See Issue #204.

python-iptables's People

Contributors

alip avatar azaugg avatar bchatelard avatar benjaminp avatar binhe22 avatar caligatio avatar chruss2 avatar dmitriusan avatar edwardbetts avatar ericvsmith avatar evilaliv3 avatar exarkun avatar fdellwing avatar federicoceratto avatar frankvanbever avatar freddy36 avatar hegusung avatar jimfunk avatar jllorente avatar ldx avatar loli10k avatar majek avatar mmellison avatar ncode avatar palvarezcordoba avatar peakwinter avatar pepoluan avatar santoshankr avatar tomislacker avatar vintozver avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

python-iptables's Issues

Segfault with iptables <=1.4.10

My production machines are currently running CentOS 6.3 which is locked to iptables 1.4.7. After updating to the newest version of iptc (I ran into the issue fixed by 94c1fa7), I began getting seg faults when I inserted, deleted, or appended rules.

I ran your ./tests.py and the results range from segfaulting on test 2 to failing 16 of the 23 tests. I'm attempting to troubleshoot but this is kind of nuts.

Issue with quotes in match parameters (0.3.0)

I bumped into an issue with quotes when I tried to see if there was anything I could do to get double-quotes and single-quotes saved in the comments of my rules.

>>> import iptc
>>> 
>>> chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), "INPUT")
>>> for i in range(1,10):
...       rule = iptc.Rule()
...       rule.dport = i
...       rule.protocol = "tcp"
...       rule.target = iptc.Target(rule, "ACCEPT")
...       match = rule.create_match("comment")
...       match.comment = "\"{}\"".format("Hey ya'll")
...       chain.append_rule(rule)
... 
>>> found = True
>>> while found:
...     found = False
...     for rule in chain.rules:
...         found = True
...         chain.delete_rule(rule)
...         break
... 
Traceback (most recent call last):
  File "<stdin>", line 5, in <module>
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 1323, in delete_rule
    self.table.delete_entry(self.name, rbuf, rule.mask)
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 1348, in new
    ret = fn(*args)
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 1588, in delete_entry
    (chain, self.strerror()))
iptc.ip4tc.IPTCError: can't delete entry from chain INPUT: Bad rule (does a matching rule exist in that chain?))

For now it seems the safer option is to strip all double-quotes and single-quotes from the values.

no "standard" extension found for this protocol

I have this problems on all of my gentoo machines (tested on kernels 3.9.2 - 3.9.6)
iptables v1.4.19.1

0 www05: {118} sudo python 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
test_table6 (iptc.test.test_iptc.TestTable6) ... ok
test_table6_autocommit (iptc.test.test_iptc.TestTable6) ... ok
test_refresh (iptc.test.test_iptc.TestTable) ... ok
test_table (iptc.test.test_iptc.TestTable) ... ok
test_builtin_chain (iptc.test.test_iptc.TestChain) ... ok
test_chain (iptc.test.test_iptc.TestChain) ... ok
test_chain_counters (iptc.test.test_iptc.TestChain) ... ok
test_chain_policy (iptc.test.test_iptc.TestChain) ... ok
test_chains (iptc.test.test_iptc.TestChain) ... ok
test_create_chain (iptc.test.test_iptc.TestChain) ... ok
test_is_chain (iptc.test.test_iptc.TestChain) ... ok
test_rule_address (iptc.test.test_iptc.TestRule6) ... ok
test_rule_compare (iptc.test.test_iptc.TestRule6) ... ok
test_rule_interface (iptc.test.test_iptc.TestRule6) ... ok
test_rule_iterate (iptc.test.test_iptc.TestRule6) ... /usr/lib64/xtables/libxt_standard.so: no "standard" extension
found for this protocol
ok
test_rule_protocol (iptc.test.test_iptc.TestRule6) ... ok
test_rule_standard_target (iptc.test.test_iptc.TestRule6) ... ok
test_rule_address (iptc.test.test_iptc.TestRule) ... ok
test_rule_compare (iptc.test.test_iptc.TestRule) ... ok
test_rule_fragment (iptc.test.test_iptc.TestRule) ... ok
test_rule_interface (iptc.test.test_iptc.TestRule) ... ok
test_rule_iterate (iptc.test.test_iptc.TestRule) ... /usr/lib64/xtables/libxt_standard.so: no "standard" extension
found for this protocol
ok
test_rule_protocol (iptc.test.test_iptc.TestRule) ... ok
test_rule_standard_target (iptc.test.test_iptc.TestRule) ... ok


Ran 24 tests in 0.178s
OK
test_match_compare (iptc.test.test_matches.TestMatch) ... ok
test_match_create (iptc.test.test_matches.TestMatch) ... ok
test_match_parameters (iptc.test.test_matches.TestMatch) ... ok
test_udp_insert (iptc.test.test_matches.TestXTUdpMatch) ... /usr/lib64/xtables/libxt_standard.so: no "standard"
extension found for this protocol
/usr/lib64/xtables/libxt_udp.so: no "udp" extension found for this protocol
ok
test_udp_port (iptc.test.test_matches.TestXTUdpMatch) ... ok
test_mark (iptc.test.test_matches.TestXTMarkMatch) ... ok
test_mark_insert (iptc.test.test_matches.TestXTMarkMatch) ... ok
test_limit (iptc.test.test_matches.TestXTLimitMatch) ... ok
test_limit_insert (iptc.test.test_matches.TestXTLimitMatch) ... ok
test_comment (iptc.test.test_matches.TestCommentMatch) ... ok
test_iprange (iptc.test.test_matches.TestIprangeMatch) ... ok
test_iprange_tcpdport (iptc.test.test_matches.TestIprangeMatch) ... /usr/lib64/xtables/libxt_tcp.so: no "tcp" extension
found for this protocol
ok


Ran 12 tests in 0.115s

OK
test_target_compare (iptc.test.test_targets.TestTarget) ... ok
test_target_create (iptc.test.test_targets.TestTarget) ... ok
test_target_parameters (iptc.test.test_targets.TestTarget) ... ok
test_insert (iptc.test.test_targets.TestXTClusteripTarget) ... ok
test_mode (iptc.test.test_targets.TestXTClusteripTarget) ... ok
test_insert (iptc.test.test_targets.TestXTTosTarget) ... ok
test_mode (iptc.test.test_targets.TestXTTosTarget) ... ok


Ran 7 tests in 0.079s

OK

iptc.Rule6 does not support icmpv6

hi.
i used to iptc.Rule6
but dose not excute protocol icmpv6-type

test1)

rule6 = iptc.Rule6()
rule6.in_interface = 'eth0'
rule6.protocol = 'icmp' # icmpv6 according to ip6tables
icmpv6_match = iptc.Match(rule6, 'icmp')
icmpv6_match.icmp_type = 'echo-request' # icmpv6_type according to ip6tables
INPUT_chain.insert_rule(rule6)

dose not Create the Rule

Memory leak on Debian wheezy

I'm experiencing memory and CPU issues with iptc in some cases. When iterating over the rules in a chain continuously, a script will gradually use more and more RAM until the python process is killed by the OOM killer. The following script is killed after 25 minutes on a 512MB machine - not exactly an instant problem, but I'm looking to write a long-running service.

import iptc
import time

table = iptc.Table(iptc.Table.FILTER)
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), "INPUT")
while True:
    for rule in chain.rules:
        pass
    print "Sleeping..."
    time.sleep(1)

I'm experiencing this under the current head on master, with iptables 1.4.14.

/lib/xtables/libxt_conntrack.so: no "conntrack" extension found for this protocol

est_rule4 = iptc.Rule()
est_match4 = est_rule4.create_match("conntrack")
est_match4.ctstate = "RELATED,ESTABLISHED"
est_target4 = iptc.Target(est_rule4, 'ACCEPT')
est_rule4.target = est_target4

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

Outputs:
"/lib/xtables/libxt_conntrack.so: no "conntrack" extension found for this protocol"

The rule applies, however my script doesn't execute any instructions below "insert_rule"

I'm running iptables v1.4.12 with the following kernel:
3.5.0-34-generic #55~precise1-Ubuntu SMP Fri Jun 7 16:25:50 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

Thanks!

"Can't find directory with extensions; please set XTABLES_LIBDIR"

Hi there!

I have run into an issue with iptables 1.4.19.1-1 on Arch Linux, with Python2.7.5, using the version of this plugin available via Git. This error is being returned just after install, and I can't do anything with the plugin. I tried Googling what this variable should be set to but I cannot seem to find any information anywhere. While using the version of the plugin available via PIP, I got the same error as #28, so I tried to upgrade to the Git version and that's what happened.

If you have any hints, I would love to hear them :) Here is the full stacktrace.

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/lib/python2.7/site-packages/iptc/__init__.py", line 10, in <module>
    from ip4tc import (is_table_available, Table, Chain, Rule, Match, Target,
  File "/usr/lib/python2.7/site-packages/iptc/ip4tc.py", line 12, in <module>
    from xtables import (XT_INV_PROTO, NFPROTO_IPV4, XTablesError, xtables,
  File "/usr/lib/python2.7/site-packages/iptc/xtables.py", line 692, in <module>
    raise XTablesError("can't find directory with extensions; "
iptc.xtables.XTablesError: can't find directory with extensions; please set XTABLES_LIBDIR

Thank you!

Python3 support

It would be very useful if this had python3 support as a lot of distros are moving to python3 being the default implementation.

Unable to remove rule created using iptables

I have an issue in which rules I'm unable to remove a rule created using the original iptables utility. This also happens to me for rules created using the module but it's harder to reproduce.

I think the problem is related to the target comparison, specifically the _target_buf comparison in the end.

For example:

os.system('iptables -t filter -A FORWARD -o vlan93 -d 5.5.5.5 -j ACCEPT')

rule = iptc.Rule()
rule.out_interface = 'vlan93'
rule.dst = '5.5.5.5'
rule.target = iptc.Target(rule, "ACCEPT")
tbl = iptc.Table('filter')
chain = iptc.Chain(tbl, 'FORWARD')
chain.delete_rule(rule)

iptc.ip4tc.IPTCError: can't delete entry from chain FORWARD: Bad rule (does a matching rule exist in that chain?))

When I manually compare the rules I find it fails since

chain.rules[-1].target._target_buf[32:40 != rule.target._target_buf[32:40]

[254, 255, 255, 255, 0, 0, 0, 0] != [0, 0, 0, 0, 0, 0, 0, 0]

Thanks!

Issue when deleting rules in a loop (0.3.0)

Deleting rules in a simple loop causes errors which looks like the rule objects contain a fixed "index" that fails to update when things change.

>>> chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), "INPUT")
>>> for i in range(1,10):
...   rule = iptc.Rule()
...   rule.dport = i
...   rule.protocol = "tcp"
...   rule.target = iptc.Target(rule, "ACCEPT")
...   chain.append_rule(rule)
... 
>>> for rule in chain.rules:
...   chain.delete_rule(rule)
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 1323, in delete_rule
    self.table.delete_entry(self.name, rbuf, rule.mask)
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 1348, in new
    ret = fn(*args)
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 1588, in delete_entry
    (chain, self.strerror()))
iptc.ip4tc.IPTCError: can't delete entry from chain INPUT: Bad rule (does a matching rule exist in that chain?))
>>>

This does work however:

>>> found = True
>>> while found:
...   found = False
...   for rule in chain.rules:
...     found = True
...     chain.delete_rule(rule)
...     break
... 

.. but it's a lot uglier construct.

Is there anything to be done about this?

exception fault in garbage collection

I have not built a new version of the helper library if that has changed let me know.

Simple test script to reproduce

!/usr/bin/python

import pprint
import iptc

for chain in iptc.Table(iptc.Table.NAT).chains:
print vars(chain)

table = iptc.Table(iptc.Table.NAT)
inp = iptc.Chain(table, "eth1_masq")

for r in inp.rules:
print "S:", r.src, "-> D:", r.dst

---- iptables in place to test

Generated by iptables-save v1.4.13 on Fri Apr 12 09:32:29 2013

*raw
:PREROUTING ACCEPT [57:5024]
:OUTPUT ACCEPT [42:5188]
COMMIT

Completed on Fri Apr 12 09:32:29 2013

Generated by iptables-save v1.4.13 on Fri Apr 12 09:32:29 2013

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
:Drop - [0:0]
:Reject - [0:0]
:all2all - [0:0]
:dmz12all - [0:0]
:dropBcast - [0:0]
:dropInvalid - [0:0]
:dropNotSyn - [0:0]
:dynamic - [0:0]
:eth0_fwd - [0:0]
:eth0_in - [0:0]
:eth0_out - [0:0]
:eth1_fwd - [0:0]
:eth1_in - [0:0]
:eth1_out - [0:0]
:fw2dmz1 - [0:0]
:fw2loc1 - [0:0]
:loc12dmz1 - [0:0]
:loc12fw - [0:0]
:logdrop - [0:0]
:logreject - [0:0]
:net12dmz2 - [0:0]
:reject - [0:0]
:shorewall - [0:0]
:smurfs - [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth0 -j eth0_in
-A INPUT -i eth1 -j eth1_in
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -j Reject
-A INPUT -j LOG --log-prefix "Shorewall:INPUT:REJECT:" --log-level 6
-A INPUT -j reject
-A FORWARD -i eth0 -j eth0_fwd
-A FORWARD -i eth1 -j eth1_fwd
-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -j Reject
-A FORWARD -j LOG --log-prefix "Shorewall:FORWARD:REJECT:" --log-level 6
-A FORWARD -j reject
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -o eth0 -j eth0_out
-A OUTPUT -o eth1 -j eth1_out
-A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -j Reject
-A OUTPUT -j LOG --log-prefix "Shorewall:OUTPUT:REJECT:" --log-level 6
-A OUTPUT -j reject
-A Drop -p tcp -m tcp --dport 113 -j reject
-A Drop -j dropBcast
-A Drop -p icmp -m icmp --icmp-type 3/4 -j ACCEPT
-A Drop -p icmp -m icmp --icmp-type 11 -j ACCEPT
-A Drop -j dropInvalid
-A Drop -p udp -m multiport --dports 135,445 -j DROP
-A Drop -p udp -m udp --dport 137:139 -j DROP
-A Drop -p udp -m udp --sport 137 --dport 1024:65535 -j DROP
-A Drop -p tcp -m multiport --dports 135,139,445 -j DROP
-A Drop -p udp -m udp --dport 1900 -j DROP
-A Drop -p tcp -j dropNotSyn
-A Drop -p udp -m udp --sport 53 -j DROP
-A Reject -p tcp -m tcp --dport 113 -j reject
-A Reject -j dropBcast
-A Reject -p icmp -m icmp --icmp-type 3/4 -j ACCEPT
-A Reject -p icmp -m icmp --icmp-type 11 -j ACCEPT
-A Reject -j dropInvalid
-A Reject -p udp -m multiport --dports 135,445 -j reject
-A Reject -p udp -m udp --dport 137:139 -j reject
-A Reject -p udp -m udp --sport 137 --dport 1024:65535 -j reject
-A Reject -p tcp -m multiport --dports 135,139,445 -j reject
-A Reject -p udp -m udp --dport 1900 -j DROP
-A Reject -p tcp -j dropNotSyn
-A Reject -p udp -m udp --sport 53 -j DROP
-A all2all -m state --state RELATED,ESTABLISHED -j ACCEPT
-A all2all -j Reject
-A all2all -j LOG --log-prefix "Shorewall:all2all:REJECT:" --log-level 6
-A all2all -j reject
-A dmz12all -m state --state RELATED,ESTABLISHED -j ACCEPT
-A dmz12all -j Drop
-A dmz12all -j LOG --log-prefix "Shorewall:dmz12all:DROP:" --log-level 6
-A dmz12all -j DROP
-A dropBcast -d 255.255.255.255/32 -j DROP
-A dropBcast -d 224.0.0.0/4 -j DROP
-A dropInvalid -m state --state INVALID -j DROP
-A dropNotSyn -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -j DROP
-A eth0_fwd -m state --state INVALID,NEW -j dynamic
-A eth0_fwd -o eth0 -j ACCEPT
-A eth0_fwd -o eth1 -j all2all
-A eth0_in -m state --state INVALID,NEW -j dynamic
-A eth0_in -j all2all
-A eth0_out -j all2all
-A eth1_fwd -m state --state INVALID,NEW -j dynamic
-A eth1_fwd -o eth0 -j net12dmz2
-A eth1_fwd -o eth1 -j ACCEPT
-A eth1_in -m state --state INVALID,NEW -j dynamic
-A eth1_in -j all2all
-A eth1_out -j all2all
-A fw2dmz1 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A fw2dmz1 -j ACCEPT
-A fw2loc1 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A fw2loc1 -j ACCEPT
-A loc12dmz1 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A loc12dmz1 -j ACCEPT
-A loc12fw -m state --state RELATED,ESTABLISHED -j ACCEPT
-A loc12fw -j ACCEPT
-A logdrop -j LOG --log-prefix "Shorewall:logdrop:DROP:" --log-level 6
-A logdrop -j DROP
-A logreject -j LOG --log-prefix "Shorewall:logreject:REJECT:" --log-level 6
-A logreject -j reject
-A net12dmz2 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A net12dmz2 -d 1.1.1.1/32 -p tcp -m tcp --dport 53 -j ACCEPT
-A net12dmz2 -p tcp -m tcp --dport 25 -j ACCEPT
-A net12dmz2 -p tcp -m tcp --dport 80 -j ACCEPT
-A net12dmz2 -j all2all
-A reject -d 255.255.255.255/32 -j DROP
-A reject -d 224.0.0.0/4 -j DROP
-A reject -s 255.255.255.255/32 -j DROP
-A reject -s 224.0.0.0/4 -j DROP
-A reject -p igmp -j DROP
-A reject -p tcp -j REJECT --reject-with tcp-reset
-A reject -p udp -j REJECT --reject-with icmp-port-unreachable
-A reject -p icmp -j REJECT --reject-with icmp-host-unreachable
-A reject -j REJECT --reject-with icmp-host-prohibited
-A smurfs -s 255.255.255.255/32 -j LOG --log-prefix "Shorewall:smurfs:DROP:" --log-level 6
-A smurfs -s 255.255.255.255/32 -j DROP
-A smurfs -s 224.0.0.0/4 -j LOG --log-prefix "Shorewall:smurfs:DROP:" --log-level 6
-A smurfs -s 224.0.0.0/4 -j DROP
COMMIT

Completed on Fri Apr 12 09:32:29 2013

Generated by iptables-save v1.4.13 on Fri Apr 12 09:32:29 2013

*mangle
:PREROUTING ACCEPT [95:7000]
:INPUT ACCEPT [87:4968]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [81:12832]
:POSTROUTING ACCEPT [79:12712]
:tcfor - [0:0]
:tcout - [0:0]
:tcpost - [0:0]
:tcpre - [0:0]
-A PREROUTING -j tcpre
-A FORWARD -j tcfor
-A OUTPUT -j tcout
-A POSTROUTING -j tcpost
COMMIT

Completed on Fri Apr 12 09:32:29 2013

Generated by iptables-save v1.4.13 on Fri Apr 12 09:32:29 2013

*nat
:PREROUTING ACCEPT [8:2032]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [1:60]
:POSTROUTING ACCEPT [1:40]
:eth1_masq - [0:0]
:net1_dnat - [0:0]
-A PREROUTING -i eth1 -j net1_dnat
-A POSTROUTING -o eth1 -j eth1_masq
-A eth1_masq -s 10.10.0.0/16 -j SNAT --to-source 1.2.3.4
-A eth1_masq -s 10.10.0.1/32 -j SNAT --to-source 1.2.3.4
-A net1_dnat -p tcp -m tcp --dport 53 -j DNAT --to-destination 1.1.1.1
COMMIT

Completed on Fri Apr 12 09:32:29 2013


gdb results

Starting program: /usr/bin/python test2.py
{'table': <iptc.ip4tc.Table object at 0x7ffff3d50810>, 'name': 'PREROUTING'}
{'table': <iptc.ip4tc.Table object at 0x7ffff3d50810>, 'name': 'INPUT'}
{'table': <iptc.ip4tc.Table object at 0x7ffff3d50810>, 'name': 'OUTPUT'}
{'table': <iptc.ip4tc.Table object at 0x7ffff3d50810>, 'name': 'POSTROUTING'}
{'table': <iptc.ip4tc.Table object at 0x7ffff3d50810>, 'name': 'eth1_masq'}
{'table': <iptc.ip4tc.Table object at 0x7ffff3d50810>, 'name': 'net1_dnat'}
S: 10.10.0.0/255.255.0.0 -> D: 0.0.0.0/0.0.0.0
S: 10.10.0.1/255.255.255.255 -> D: 0.0.0.0/0.0.0.0

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff6e96d08 in ?? () from /lib/libc.so.6
(gdb) bt
#0 0x00007ffff6e96d08 in ?? () from /lib/libc.so.6
#1 0x00007ffff6e9a38c in free () from /lib/libc.so.6
#2 0x00007ffff7aadb6b in ?? () from /usr/lib/libpython2.7.so.1.0
#3 0x00007ffff7acc774 in ?? () from /usr/lib/libpython2.7.so.1.0
#4 0x00007ffff7aaf37b in PyDict_Clear () from /usr/lib/libpython2.7.so.1.0
#5 0x00007ffff7aaf4d9 in ?? () from /usr/lib/libpython2.7.so.1.0
#6 0x00007ffff7b4aa77 in ?? () from /usr/lib/libpython2.7.so.1.0
#7 0x00007ffff7b4b414 in PyGC_Collect () from /usr/lib/libpython2.7.so.1.0
#8 0x00007ffff7b3be26 in Py_Finalize () from /usr/lib/libpython2.7.so.1.0
#9 0x00007ffff7b4971a in Py_Main () from /usr/lib/libpython2.7.so.1.0
#10 0x00007ffff6e4401d in __libc_start_main () from /lib/libc.so.6
#11 0x0000000000400621 in _start ()

(gdb)

Autocommit is reset to True when building rules in memory

I'm using python iptables to build up rules and chains in memory before committing the changes at the end. I have a large volume of rules to dynamically create and it's necessary to build the whole set before committing so as to provide as minimal a disturbance to the firewall's behaviour as possible.

What I'm seeing is the autocommit propery of the iptc.Table object is being changed from False to True during the building of the rules. After some debugging, I've narrowed it down to the create_target() method on the iptc.Rule object.

See below:

# Run as root or sudo

import iptc

# Retrieve filter table, do not auto commit
table = iptc.Table(iptc.Table.FILTER, False)

# Create chain
chain = iptc.Chain(table, 'EXAMPLE')    
table.create_chain(chain)
table.refresh()

# Create rule
rule = iptc.Rule()
rule.src = "1.2.3.4"
rule.dst = "2.3.4.5"
rule.protocol = "tcp"

print table.autocommit # = False  
rule.create_target('DROP')
print table.autocommit # = True     

match = rule.create_match('tcp')   
match.dport = "80:90"             

chain.append_rule(rule)

I would expect the above code to create the chain within iptables, build the rule in memory but not to commit the rule until commit() or refresh() is called on the iptc.Table object. Running iptables shows the following output:

$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain EXAMPLE (0 references)
target     prot opt source               destination         
DROP       tcp  --  1.2.3.4              alyon-651-1-21-5.w2-3.abo.wanadoo.fr  tcp dpts:http:90

I'd like to know if this behaviour is intentional, or if there is something I'm missing in my client code. So far I've been following the examples on http://ldx.github.io/python-iptables/examples.html and reading through the code and tests for clarification.

Thanks!

Is it possible to manage comments with python-iptables?

I would like to be able to read and write comments to rules, i.e. the same way as you would run:

# iptables -A INPUT -j DROP -p tcp --dport 22 -m comment --comment "limit ssh access"

and

# iptables -L
...
DROP       tcp  --  anywhere             anywhere             tcp dpt:ssh /* limit ssh access */
...

.. I tried to check the code, but the deeper internals are a bit too mystic for me, and I couldn't see anything even hinting towards that direction e.g. in the Rule class.

I am planning to use python-iptables for automating firewall rule management for multiple servers, and I have a dual-purpose with the commenting.

For one, I'd want to write a human readable explanation for every rule, so to validate the rules on the server with just an "iptables -L" without having to think too much about all the destination IP addresses, ports, etc. and their meanings.

Second reason is, that I would want to use it for "tagging" the rules in a way that helps to do smooth automation, create the new rules so there's a timestamp written on the comment, and then delete all the rules that don't have the correct timestamp on them .. if I just flush everything and then add new ones, there is a brief window where there will be problems.

Is there a way to do this currently (e.g. in 0.3.0), or would it be possible to add such functionality?

Issue with rules that include set matches

Unsure if i am doing something stupid here but when i add the the following set, chain, and rule as an example:

ipset -N attk_set iphash maxelem 200000 timeout 3600
iptables -N attk
iptables -A attk -m set --match-set attk_set src -j DROP
iptables -A attk -j RETURN

Listing the rules with:

import iptc


table = iptc.Table(iptc.Table.FILTER)
chain = iptc.Chain(table, "attk")

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

I get the following value error

Traceback (most recent call last):
  File "./manage_iptables.py", line 82, in <module>
    listattackrules()
  File "./manage_iptables.py", line 55, in listattackrules
    for rule in attack_chain.rules:
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 1339, in _get_rules
    return [self.table.create_rule(e, self) for e in entries]
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 1631, in create_rule
    return Rule(entry, chain)
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 814, in __init__
    self.rule = entry
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 1193, in _set_rule
    m = Match(self, match=match)
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 469, in __init__
    self._update_parameters()
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 365, in _update_parameters
    self.__setattr__(k, v)
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 369, in __setattr__
    self.parse(name.replace("_", "-"), value)
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 286, in parse
    self._parse(argv, inv, entry)
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 514, in _parse
    ct.cast(self._ptrptr, ct.POINTER(ct.c_void_p)))
  File "/usr/local/lib/python2.7/dist-packages/iptc/xtables.py", line 736, in new
    ret = fn(*args)
  File "/usr/local/lib/python2.7/dist-packages/iptc/xtables.py", line 1037, in parse_match
    self._parse(m, argv, invert, flags, fw, ptr)
  File "/usr/local/lib/python2.7/dist-packages/iptc/xtables.py", line 944, in _parse
    raise ValueError("invalid value %s" % (argv[1]))
ValueError: invalid value attk_set

At first glance of other issues it looked like it was related to #30 but I don't get an error on import

Unable to create DNAT/SNAT targets in TABLE_NAT

Hello,

I am trying to create some NAT rules, but whenever I am trying to set either 'to_destination' or 'to_source', it fails. Any idea what am I doing wrong?

>>> import iptc
>>> rule = iptc.Rule()
>>> target = iptc.Target(rule, "SNAT")
>>> target.to_source = "5.5.5.5"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 334, in __setattr__
    self.parse(name.replace("_", "-"), value)
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 293, in parse
    self._parse(argv, inv, entry)
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 545, in _parse
    ct.cast(self._ptrptr, ct.POINTER(ct.c_void_p)))
  File "/usr/local/lib/python2.7/dist-packages/iptc/xtables.py", line 344, in parse_target
    self._parse(t, argv, invert, t.tflags, fw, ptr)
  File "/usr/local/lib/python2.7/dist-packages/iptc/xtables.py", line 331, in _parse
    raise ValueError("invalid value %s" % (value))
NameError: global name 'value' is not defined

libxtables has global state

It seems libxtables has some global state: at least afinfo in iptables/xtables.c is something that can mess up things if one process tries to use both IPv6 and IPv4.

This is the problem causing the failure of e.g. the insertion of a rule with a REJECT target via both IPv4 and IPv6 in the test suite.

undefined symbol: iptc_init (libiptc compatibilitly)

If libip4tc doesn't exist but libiptc does the module failes to load with the following error:

Traceback (most recent call last):                                                                                                                                                                                                          
  File "comment.py", line 3, in <module>                                                                                                                                                                                                    
    import iptc                                                                                                                                                                                                                             
  File "/usr/lib/pymodules/python2.6/iptc/__init__.py", line 110, in <module>                                                                                                                                                               
    class iptc(object):                                                                                                                                                                                                                     
  File "/usr/lib/pymodules/python2.6/iptc/__init__.py", line 112, in iptc                                                                                                                                                                   
    iptc_init = _libiptc.iptc_init                                                                                                                                                                                                          
  File "/usr/lib/python2.6/ctypes/__init__.py", line 366, in __getattr__                                                                                                                                                                    
    func = self.__getitem__(name)                                                                                                                                                                                                           
  File "/usr/lib/python2.6/ctypes/__init__.py", line 371, in __getitem__                                                                                                                                                                    
    func = self._FuncPtr((name_or_ordinal, self))                                                                                                                                                                                           
AttributeError: python: undefined symbol: iptc_init

Seems like ctypes.CDLL() doesn't throw an exception in case the lib couldn't be loaded.

Follwoing change should fix the problem:

diff --git a/iptc/__init__.py b/iptc/__init__.py
index 400111c..3d25f29 100644
--- a/iptc/__init__.py
+++ b/iptc/__init__.py
@@ -102,10 +102,15 @@ class ipt_entry_match(xt_entry_match):

 ipt_align = xt_align

-try:
-    _libiptc = ct.CDLL(ctypes.util.find_library("ip4tc"), use_errno = True)
-except:
-    _libiptc = ct.CDLL(ctypes.util.find_library("iptc"), use_errno = True)
+_libiptc_file = ctypes.util.find_library("ip4tc")
+
+if not _libiptc_file:
+    _libiptc_file = ctypes.util.find_library("iptc")
+
+if not _libiptc_file:
+    raise IPTCError("error: libiptc/libip4tc not found")
+
+_libiptc = ct.CDLL(_libiptc_file, use_errno = True)

 class iptc(object):
     """This class contains all libiptc API calls."""

64-bit casting issue

Ive tryed to use match object in a 64-bit machine and got this:

In [62]: m.dport = "22"

ArgumentError Traceback (most recent call last)
/home/leonardo/bin/ in ()
----> 1 m.dport = "22"

/usr/lib/pymodules/python2.7/iptc/init.pyc in setattr(self, name, value)
358 def setattr(self, name, value):
359 if not name.startswith('') and name not in dir(self):
--> 360 self.parse(name.replace("
", "-"), value)
361 else:
362 object.setattr(self, name, value)

/usr/lib/pymodules/python2.7/iptc/init.pyc in parse(self, parameter, value)
318 rv = _wrap_parse(self._module.parse, opt.val, argv, inv,
319 ct.pointer(self._flags), entry,
--> 320 ct.cast(self._ptrptr, ct.POINTER(ct.c_void_p)))
321 if rv != 1:
322 raise ValueError("invalid value %s" % (value))

ArgumentError: argument 5: <type 'exceptions.TypeError'>: expected LP_c_ulong instance instead of LP_c_uint

This patch fixed the problem but i cant test it in 32bits.

EDIT: The patch misformated here: http://pastie.org/4302265

High CPU use when iterating over chain

Hello,
I'm currently experiencing large CPU use spikes in scripts that use python-iptables on my system. The following code features ~100% CPU use every time the chain is iterated over, and ideally I'd like to iterate over chains every few seconds but this isn't an option with this kind of use. I'm wondering if this is a Debian-specific problem or a more general one. I currently have around 600 DROP rules in my INPUT chain - running with less rules and/or no rules eliminates and/or greatly reduces use.

I've been testing with this snippet:

import iptc
import time
table = iptc.Table(iptc.Table.FILTER)
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), "INPUT")

while True:
    for rule in chain.rules:
        pass
    time.sleep(1)

I've done some basic profiling but I'm honestly not quite sure what's valid time use and what's unusual. Here are the top entries from cProfile:

         26799804 function calls (26621366 primitive calls) in 178.964 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
       99   99.122    1.001   99.122    1.001 {time.sleep}
   712801   13.852    0.000   13.852    0.000 ip4tc.py:1373(refresh)
   237602    7.864    0.000    8.210    0.000 {dir}
   712800    4.468    0.000    5.586    0.000 ip4tc.py:1361(_free)
1484999/1306799    3.815    0.000   21.349    0.000 ip4tc.py:362(__setattr__)
   950402    3.523    0.000   25.522    0.000 ip4tc.py:1323(__new__)
   831599    3.183    0.000    3.185    0.000 __init__.py:501(cast)
   594001    2.933    0.000    3.017    0.000 {_ctypes.pointer}
  1069203    2.356    0.000    2.356    0.000 weakref.py:101(get)
   712803    1.836    0.000    1.879    0.000 weakref.py:228(__init__)
   118800    1.627    0.000    1.874    0.000 shlex.py:120(read_token)
    59400    1.490    0.000    2.365    0.000 xtables.py:998(parse_match)
    59400    1.382    0.000   78.560    0.001 ip4tc.py:1105(_set_rule)
   712803    1.379    0.000    4.638    0.000 weakref.py:79(__setitem__)
    59400    1.359    0.000   24.415    0.000 ip4tc.py:424(__init__)
   237600    1.214    0.000    1.214    0.000 xtables.py:839(_restore_globals)
   475200    1.198    0.000   19.235    0.000 ip4tc.py:30(is_table_available)
   118800    1.184    0.000    5.721    0.000 ip4tc.py:337(get_all_parameters)
   712800    1.118    0.000    1.118    0.000 ip4tc.py:1355(commit)
      712801    1.110    0.000   14.963    0.000 ip4tc.py:1335(_init)
    59400    1.061    0.000    8.130    0.000 ip4tc.py:259(parse)
    59400    0.968    0.000   42.973    0.001 ip4tc.py:547(__init__)
   118800    0.951    0.000   31.878    0.000 ip4tc.py:768(_get_tables)
   118800    0.920    0.000   36.077    0.000 ip4tc.py:615(_is_standard_target)
   475200    0.916    0.000    1.130    0.000 ip4tc.py:1384(is_chain)
  1425606    0.854    0.000    0.872    0.000 {built-in method __new__ of type object at 0x87d7e0}
  1960364    0.842    0.000    0.842    0.000 {method 'startswith' of 'str' objects}
    59400    0.790    0.000    1.427    0.000 xtables.py:927(save)
   237601    0.768    0.000    0.768    0.000 xtables.py:824(_save_globals)
   237600    0.716    0.000    7.990    0.000 xtables.py:733(new)
   712803    0.687    0.000    1.380    0.000 weakref.py:223(__new__)
    59400    0.666    0.000    0.666    0.000 {method 'findall' of '_sre.SRE_Pattern' objects}

I'm using the current git HEAD on Debian 7 with iptables 1.4.14.

Thanks!

Problems with --state

I need a rule for statefull firewall but i cant create it:

In [42]: mstate = iptc.Match(r,'state')

In [43]: mstate.state = "RELATED"
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/home/leonardo/python-iptables/<ipython-input-43-6efafb390601> in <module>()
----> 1 mstate.state = "RELATED"

/usr/lib/pymodules/python2.7/iptc/__init__.pyc in __setattr__(self, name, value)
    358     def __setattr__(self, name, value):
    359         if not name.startswith('_') and name not in dir(self):
--> 360             self.parse(name.replace("_", "-"), value)
    361         else:
    362             object.__setattr__(self, name, value)

/usr/lib/pymodules/python2.7/iptc/__init__.pyc in parse(self, parameter, value)
    303         if not self._module.extra_opts:
    304             raise AttributeError("%s: invalid parameter %s" %
--> 305                     (self._module.name, parameter))
    306 
    307         _optarg.value = value

AttributeError: state: invalid parameter state

Unable to traverse tables with iptables 1.4.13

I was also not able to get the modules to load. I modified the code to load like this
_libiptc = ct.CDLL("libip4tc.so", use_errno=True)

I am using an custom embeded distroy with a 3.3.7 kernel. This may be the problem
but I thought I should check as you mentioned that the API changed in 1.4 and needed more testing to confirm.

Below is the exception I get its possible the lines are off by a few from master branch because of my temp hack to get the module to load.

I plan on digging deeper into the C calls but it will likely take a lot longer to figure the API
out and see what could be causing it. Best I can tell _libiptc.iptc_first_rule is return 0
when given what seem to be valid args.

************ test code *************

!/usr/bin/python

import iptc

for chain in iptc.Table(iptc.Table.FILTER).chains:
print vars(chain)

table = iptc.Table(iptc.Table.FILTER)
inp = iptc.Chain(table, "INPUT")
for r in inp.rules:
print r.src, "->", r.dst, "L4:", r.protocol,
for m in r.matches:
print "match:", m.name,
print "target:", r.target.name


==================== iptables ===================
iptables -L INPUT
Chain INPUT (policy DROP)
target prot opt source destination
ACCEPT all -- anywhere anywhere
eth0_in all -- anywhere anywhere
eth1_in all -- anywhere anywhere
ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
Reject all -- anywhere anywhere
LOG all -- anywhere anywhere LOG level info prefix "Shorewall:INPUT:REJECT:"
reject all -- anywhere anywhere

==================== test code results ==================
./test.py
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'INPUT'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'FORWARD'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'OUTPUT'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'Drop'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'Reject'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'all2all'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'dmz22all'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'dmz22fw'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'dmz22net1'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'dropBcast'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'dropInvalid'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'dropNotSyn'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'dynamic'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'eth0_fwd'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'eth0_in'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'eth0_out'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'eth1_fwd'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'eth1_in'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'eth1_out'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'fw2dmz2'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'fw2net1'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'logdrop'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'logreject'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'net12dmz2'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'reject'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'shorewall'}
{'table': <iptc.ip4tc.Table object at 0x7fafff87a890>, 'name': 'smurfs'}
Traceback (most recent call last):
File "./test.py", line 10, in
for r in inp.rules:
File "/usr/lib/python2.7/site-packages/iptc/ip4tc.py", line 1195, in _get_rules
rules.append(Rule(rule, self))
File "/usr/lib/python2.7/site-packages/iptc/ip4tc.py", line 682, in init
self.rule = entry
File "/usr/lib/python2.7/site-packages/iptc/ip4tc.py", line 1060, in _set_rule
self.target = Target(self, target=target)
File "/usr/lib/python2.7/site-packages/iptc/ip4tc.py", line 513, in init
raise XTablesError("can't find target %s" % (name))
iptc.xtables.XTablesError: can't find target

Incompatibility with iptables v1.4.7

Hi,

We're running iptables v1.4.7 which is the version packaged with CentOS (and possibly Debian) but running into errors. We've tried upgrading to v1.4.12 from source and it works, so the problem definitely with the libxtables version. Here's the trace:

Traceback (most recent call last):
  File "commands_test.py", line 4, in <module>
    import iptc
  File "/usr/lib/python2.6/site-packages/python_iptables-0.2.0_dev-py2.6-linux-x86_64.egg/iptc/__init__.py", line 10, in <module>
    from ip4tc import Table, Chain, Rule, Match, Target, Policy, IPTCError
  File "/usr/lib/python2.6/site-packages/python_iptables-0.2.0_dev-py2.6-linux-x86_64.egg/iptc/ip4tc.py", line 11, in <module>
    from xtables import (XT_INV_PROTO, NFPROTO_IPV4, XTablesError, xtables,
  File "/usr/lib/python2.6/site-packages/python_iptables-0.2.0_dev-py2.6-linux-x86_64.egg/iptc/xtables.py", line 744, in <module>
    class xtables(object):
  File "/usr/lib/python2.6/site-packages/python_iptables-0.2.0_dev-py2.6-linux-x86_64.egg/iptc/xtables.py", line 757, in xtables
    _xtables_afinfo = ct.c_void_p.in_dll(_lib_xtables, "afinfo")
ValueError: /lib64/libxtables.so.4: undefined symbol: afinfo

Thanks!

iptc.xtables.XTablesError: conntrack: no such parameter state

On Fedora 19 using v0.2.0 with /usr/lib64/xtables added to path and commit 7a2bdb6 (fix stdout)

[root@ ~]# cat tt.py && python ./tt.py 
#!/usr/bin/python

import iptc

chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), "INPUT")
for r in chain.rules:
    print r

Traceback (most recent call last):
  File "./tt.py", line 6, in <module>
    for r in chain.rules:
  File "/usr/lib64/python2.7/site-packages/iptc/ip4tc.py", line 1278, in _get_rules
    return [self.table.create_rule(e, self) for e in entries]
  File "/usr/lib64/python2.7/site-packages/iptc/ip4tc.py", line 1570, in create_rule
    return Rule(entry, chain)
  File "/usr/lib64/python2.7/site-packages/iptc/ip4tc.py", line 753, in __init__
    self.rule = entry
  File "/usr/lib64/python2.7/site-packages/iptc/ip4tc.py", line 1132, in _set_rule
    m = Match(self, match=match)
  File "/usr/lib64/python2.7/site-packages/iptc/ip4tc.py", line 466, in __init__
    self._update_parameters()
  File "/usr/lib64/python2.7/site-packages/iptc/ip4tc.py", line 366, in _update_parameters
    self.__setattr__(k, v)
  File "/usr/lib64/python2.7/site-packages/iptc/ip4tc.py", line 370, in __setattr__
    self.parse(name.replace("_", "-"), value)
  File "/usr/lib64/python2.7/site-packages/iptc/ip4tc.py", line 284, in parse
    self._parse(argv, inv, entry)
  File "/usr/lib64/python2.7/site-packages/iptc/ip4tc.py", line 492, in _parse
    ct.cast(self._ptrptr, ct.POINTER(ct.c_void_p)))
  File "/usr/lib64/python2.7/site-packages/iptc/xtables.py", line 737, in new
    ret = fn(*args)
  File "/usr/lib64/python2.7/site-packages/iptc/xtables.py", line 1017, in parse_match
    argv[0]))
iptc.xtables.XTablesError: conntrack: no such parameter state

[root@ ~]# rpm -q iptables
iptables-1.4.18-1.fc19.x86_64

[root@ ~]# uname -a
Linux  3.11.8-200.fc19.x86_64 #1 SMP Wed Nov 13 16:29:59 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

IPTCError: can't initialize filter: libiptc version error

Hi, I'm getting an intermittent error when repeatedly calling the following line of code:

chain_name = 'FORWARD'
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), chain_name)

Here is the traceback:

Traceback (most recent call last):
File "/usr/share/pyshared/flask/app.py", line 1518, in call

File "/usr/share/pyshared/flask/app.py", line 1506, in wsgi_app

File "/usr/share/pyshared/flask/app.py", line 1504, in wsgi_app

File "/usr/share/pyshared/flask/app.py", line 1264, in full_dispatch_request

File "/usr/share/pyshared/flask/app.py", line 1262, in full_dispatch_request

File "/usr/share/pyshared/flask/app.py", line 1248, in dispatch_request

File "/srv/kontrolvm-node/main.py", line 58, in index

File "/srv/kontrolvm-node/tasks/iptables.py", line 29, in check_ip

File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 1306, in init

File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 1342, in refresh

IPTCError: can't initialize filter: libiptc version error

Only one rule returned by chain.rules

This code:

# test.py
import iptc
table = iptc.Table(iptc.Table.FILTER)
chain = iptc.Chain(table, 'BLACKLIST')
rule = iptc.Rule()

for idx, r in enumerate(chain.rules, 1):
    print idx, r.src, r.dst

only prints out a single rule, despite the fact that the BLACKLIST chain has 11 rules:

# bin/local-python test.py
1 199.123.100.1/255.255.255.255 0.0.0.0/0.0.0.0

# iptables -L BLACKLIST -v -n
Chain BLACKLIST (0 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       all  --  eth1   *       199.123.100.1        0.0.0.0/0           
    0     0 DROP       all  --  *      *       223.4.119.42         0.0.0.0/0           
    0     0 DROP       all  --  *      *       223.4.119.43         0.0.0.0/0           
    0     0 DROP       all  --  *      *       223.4.119.44         0.0.0.0/0           
    0     0 DROP       all  --  *      *       223.4.119.46         0.0.0.0/0           
    0     0 DROP       all  --  *      *       223.4.119.47         0.0.0.0/0           
    0     0 DROP       all  --  *      *       223.4.119.49         0.0.0.0/0           
    0     0 DROP       all  --  *      *       223.4.119.50         0.0.0.0/0           
    0     0 DROP       all  --  *      *       1.1.1.1              0.0.0.0/0           
    0     0 DROP       all  --  *      *       1.1.1.2              0.0.0.0/0           
    0     0 DROP       all  --  *      *       123.157.148.144      0.0.0.0/0          

The problem appears to be in handle management for tables. Because the tables are globally cached, there's only one "filter" table object, so only one handle. But the handle is getting re-opened when another 'filter; table object is being created behind my back, thus overwriting the in-use handle. This causes the handle used for table.first_rule() to be different than the handle used for table.next_rule(), so next_rule returns NULL.

Here's the stack trace when the handle is being re-opened (the line numbers are slightly off because I have some print statements in there):

  /root/local/buildout-tb-blip-server/bin/local-python(42)<module>()
-> execfile(__file__)
  /root/local/buildout-tb-blip-server/test.py(15)<module>()
-> for idx, r in enumerate(chain.rules, 1):
  /usr/local/egg-cache/eggs/python_iptables-0.1.1-py2.7-linux-i686.egg/iptc/ip4tc.py(1162)_get_rules()
-> rules.append(Rule(rule, self))
  /usr/local/egg-cache/eggs/python_iptables-0.1.1-py2.7-linux-i686.egg/iptc/ip4tc.py(647)__init__()
-> self.rule = entry
  /usr/local/egg-cache/eggs/python_iptables-0.1.1-py2.7-linux-i686.egg/iptc/ip4tc.py(1027)_set_rule()
-> self.target = Target(self, target=target)
  /usr/local/egg-cache/eggs/python_iptables-0.1.1-py2.7-linux-i686.egg/iptc/ip4tc.py(474)__init__()
-> for t in rule.tables:
  /usr/local/egg-cache/eggs/python_iptables-0.1.1-py2.7-linux-i686.egg/iptc/ip4tc.py(669)_get_tables()
-> return [Table(t) for t in Table.ALL]
  /usr/local/egg-cache/eggs/python_iptables-0.1.1-py2.7-linux-i686.egg/iptc/ip4tc.py(1233)__init__()
-> self.refresh()
> /usr/local/egg-cache/eggs/python_iptables-0.1.1-py2.7-linux-i686.egg/iptc/ip4tc.py(1265)refresh()
-> if self._handle:

I'm using python-iptables 0.1.1 (from PyPi), with Python 2.7.3 (build from a source distribution) on Fedora 14 (2.6.35.14-106.fc14.i686.PAE),

I tried using 0.2.0-dev from PyPi, but got a missing symbol error when importing iptc.

Any suggestions?

xtables symbol error with Debian 6

Hey there,

Big fan of the module. I've been developing on Debian 7 with no problems, but I've had to make my code compatible with Debian 6. Unfortunately Debian 6's xtables seems to lack the xtables_pending_matches (and xtables_pending_targets) symbol and this causes iptc to fail to import as follows:

>>> import iptc
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/local/lib/python2.6/dist-packages/iptc/__init__.py", line 10, in 
    from ip4tc import (is_table_available, Table, Chain, Rule, Match, Target,
  File "/usr/local/lib/python2.6/dist-packages/iptc/ip4tc.py", line 12, in 
    from xtables import (XT_INV_PROTO, NFPROTO_IPV4, XTablesError, xtables,
  File "/usr/local/lib/python2.6/dist-packages/iptc/xtables.py", line 746, in 
    class xtables(object):
  File "/usr/local/lib/python2.6/dist-packages/iptc/xtables.py", line 766, in xtables
    "xtables_pending_matches"))
ValueError: /lib/libxtables.so.4: undefined symbol: xtables_pending_matches
>>>

I'm trying to backport Wheezy's xtables packages, but can python-iptables function without this symbol? I've commented the references to it out and I don't seem to be hitting any major issues but I'm curious/worried as to whether this will bite me further down the line. For reference this issue appears in the current git HEAD.
Thanks!

Declaring a iptc.Match results in "tcp match options" displaying

I am experiencing a strange error in using this library under Linux 3.11.6-1 with Arch Linux and iptables 1.4.19.1 inside VirtualBox. The code I've written normally functions quite well (it's basically exactly the same as this example) on other distros with older kernels.

As soon as I get to setting up a Match to attach to a rule:
m = iptc.Match(rule, 'tcp')

the screen is interrupted with the following message:

tcp match options:
[!] --tcp-flags mask comp       match when TCP flags & mask == comp
                            (Flags: SYN ACK FIN RST URG PSH ALL NONE)
[!] --syn                       match when only SYN flag set
                            (equivalent to --tcp-flags SYN,RST,ACK,FIN SYN)
[!] --source-port port[:port]
 --sport ...
                            match source port(s)
[!] --destination-port port[:port]
 --dport ...
                            match destination port(s)
[!] --tcp-option number        match if TCP option set

The process continues but the code later tries to attach the match to the rule, and since this first line didn't complete successfully it crashes Python with a segfault.

It doesn't seem to be the iptables version, because I'm using the same version on a Raspberry Pi with an older kernel and it works flawlessly. It also works on Arch in kernel versions as late as 3.9.2, which is as late as I've been able to test until 3.11.6. And I doubt it has anything to do with VirtualBox, but that's the only means I have with which to test this. :/ All iptables modules have been loaded into the kernel prior to testing.

Please let me know if you need additional info. Thanks.

Resource leak

The resources associated with Chain don't seem to being released correctly, resulting in eventual 'Too many open files' errors.

Test code:

import iptc
import sys
import os
import time 
import subprocess

table = iptc.Table(iptc.Table.FILTER)
chain = iptc.Chain(table, sys.argv[1])

pid = str(os.getpid())

while True:
  #table.refresh()
  chain.rules
  time.sleep(1)
  print len(subprocess.check_output(['lsof', '-p', pid]).split('\n'))

Sorry, have had a look at the code and I can't figure it out - so no patch from me... :-S

no "standard" extension found for this protocol

Hi I am running into this issue with python (2.7.3). Seems to be an issue with iptc or the way I am using it. I tried rule.create_target() as well... no luck... Thought I'll ask this question before digging deeper into iptc. Even tried replacing jr.rule.action with "DROP"... No luck... Appreciate any help...

method = POST
client request = insert_rule
insert_rule() called 1
/lib/xtables/libxt_standard.so: no "standard" extension found for this protocol
insert_rule() called 2
exiting insert_rule()
sending response
192.168.1.106 - - [22/Apr/2014 21:39:57] "POST /network-services/firewall HTTP/1.1" 200 -

Here is the code snippet:

def insert_rule(jr):
...
print "%s called 1" % function()

if jr.rule.has_key('action'):
    target = iptc.Target(rule, jr.rule.action)     # <<<<=== this seems to be the issue
    rule.target = target

print "%s called 2" % __function__()
...
print "exiting %s" % __function__()

Feature Request: Rule compare that ignores certain match objects

I don't have a good idea on how exactly to implement this but it would be useful if there was a way to check Rule equivalency while ignoring specified matches.

My use case is I want to check all active rules against a iptc built rule despite the active rules having comments (-m comment --comment "Rule comment"). If only the comment is different, I still want the rules to test to be equal.

Table.flush fails when rules target inner chains

Hi.

I found that Table.flush() will fail if there are rules targeting chains within the table itself. This is caused by the fact that chains are deleted before all other chains are flushed, and it's not possible to delete a chain while there's a rule targeting it ("Too many links" error).
Additionally, the flush method should flush all chains but delete just the non-builtin ones.

atomicity offered by autocommit=False not working as expected

Hi Dhananjay ,

This bug is present in the pypi package 0.2.0-dev as mentioned here - https://pypi.python.org/pypi/python-iptables I don't know if this is the right place to mention the bug as the latest version of code fixes it. Please feel free to redirect me to a relevant place for filing this bug.

I wanted to use python-iptables as a programmatic interface for my firewall and therein I wanted to run a python program which sets the rules. Without python-iptables, I'd set the rules, run iptables-save to a file and then iptables-restore back to reload the rules.

iptables-restore is atomic subject to the conditions mentioned here: http://www.spinics.net/lists/netfilter/msg53232.html

I thought that I would create a table object, set autocommit=False, create a bunch of rules, apply them and then commit so that if there is any other intermediate python code between 2 rules - there is no change in the state of the system's firewall. For example,

import iptc
import os, sys

# define interfaces
local_interface = 'eth1' 
ext_interface = 'eth0' 

# create chains
filter_table = iptc.Table(iptc.Table.FILTER, autocommit = False)

filter_input_chain = iptc.Chain(filter_table, "INPUT")
filter_output_chain = iptc.Chain(filter_table, "OUTPUT")

filter_input_chain.flush()
filter_output_chain.flush()

rules = {
    'input': [],
    'output': [],
}

#### outgoing DNS queries ####

# ---------------------------
# iptables -A INPUT -i eth0 -p udp -m multiport --sports 53 -j ACCEPT
# ---------------------------

rule = iptc.Rule()
rule.in_interface = ext_interface
rule.protocol = 'udp'

match_multiport = iptc.Match(rule, 'multiport')
match_multiport.sports = '53'
rule.add_match(match_multiport)

target = rule.create_target('ACCEPT')
rule.target = target
rules['input'].append(rule)

# ---------------------------
# iptables -A OUTPUT -o eth0 -p udp -m multiport --dports 53 -j ACCEPT
# ---------------------------

rule = iptc.Rule()
rule.out_interface = ext_interface
rule.protocol = 'udp'

match_multiport = iptc.Match(rule, 'multiport')
match_multiport.dports = '53'
rule.add_match(match_multiport)

target = rule.create_target('ACCEPT')
rule.target = target
rules['output'].append(rule)

for rule in rules['input']:
    filter_input_chain.append_rule(rule)

print "\n------ after adding input rules ------------"
os.system("iptables -S")
print "------ after adding input rules ------------"

for rule in rules['output']:
    filter_output_chain.append_rule(rule)

print "\n------ after adding output rules ------------"
os.system("iptables -S")
print "------ after adding output rules ------------"

filter_table.commit()

print "\n------ after commit ------------"
os.system("iptables -S")
print "------ after commit ------------"

sys.exit(0)

The output of the program is:

------ after adding input rules ------------
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -i eth0 -p udp -m multiport --sports 53 -j ACCEPT
------ after adding input rules ------------
---committing---

------ after adding output rules ------------
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -i eth0 -p udp -m multiport --sports 53 -j ACCEPT
-A OUTPUT -o eth0 -p udp -m multiport --dports 53 -j ACCEPT
------ after adding output rules ------------

------ after commit ------------
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -i eth0 -p udp -m multiport --sports 53 -j ACCEPT
-A OUTPUT -o eth0 -p udp -m multiport --dports 53 -j ACCEPT
------ after commit ------------

which means that commits are happening before filter_table.commit()_ is being called. Actually the output should be:

------ after adding input rules ------------
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -i eth0 -p udp -m multiport --sports 53 -j ACCEPT
------ after adding input rules ------------
---committing---

------ after adding output rules ------------
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -i eth0 -p udp -m multiport --sports 53 -j ACCEPT
-A OUTPUT -o eth0 -p udp -m multiport --dports 53 -j ACCEPT
------ after adding output rules ------------

------ after commit ------------
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -i eth0 -p udp -m multiport --sports 53 -j ACCEPT
-A OUTPUT -o eth0 -p udp -m multiport --dports 53 -j ACCEPT
------ after commit ------------

This shows that commit is happening even before filter_table.commit() is being called. So I thought that something somewhere is resetting autocommit to True for filter_input_table. After doing some debugging this is the section where autocommit changes from False to True:

# ---------------------------
# iptables -A INPUT -i eth0 -p udp -m multiport --sports 53 -j ACCEPT
# ---------------------------

rule = iptc.Rule()
rule.in_interface = ext_interface
rule.protocol = 'udp'

match_multiport = iptc.Match(rule, 'multiport')
match_multiport.sports = '53'
rule.add_match(match_multiport)

print "xxxxxxxxxxx"
print filter_table.autocommit
print "xxxxxxxxxxx"

target = rule.create_target('ACCEPT')

print "xxxxxxxxxxx"
print filter_table.autocommit
print "xxxxxxxxxxx"

When rule.create_target is called => this calls the init method of Target class => which has a statement:

 for t in rule.tables:

rule.tables is a property for which Rule._get_tables is called which has the line:

return [Table(t) for t in Table.ALL if is_table_available(t)]

which calls the Table constructor. At this point I thought a new Table object would be created but Table class has a new method which controls the creation of the Table object. It serves the previous Table object that is created - which is good but if it gets the content from the cache, it also adds this line

obj.autocommit = autocommit

and default autcommit is True. Hence this leads to autocommit switching on - in the original table leading to commits before the code calls filter_input_table.commit()

This can be eliminated by commenting out Table.new - which may not give additional benefit of cached Table access but in turn gives predictable commit() functionality and output is as expected (add to input/output chain only after commit happens)

having invalid policy commits iptables inspite of specifying autocommit=False

Hi,

python-iptables is a great tool and has been very well written. I was thinking of contributing some more examples to the doc and in the process I found out a behavior deviating from how userspace iptables behaves.

If my initial "iptables -S" output is:

-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT

and if I feed the file "iptables-restore-data" which contains the following to iptables-restore:

# Generated by iptables-save v1.4.12 on Tue Oct 15 16:17:02 2013
*filter
:INPUT DROP [0:0]
:OUTPUT DROP [0:0]
:FORWARD REJECT [0:0]
COMMIT
# Completed on Tue Oct 15 16:17:02 2013

like so

iptables-restore < iptables-restore-data

the output gives an error because you cannot set REJECT policy on a chain. The error that I get is:

iptables-restore v1.4.12: Can't set policy `REJECT' on `FORWARD' line 5: Bad policy name

and none of the other policies on INPUT, OUTPUT are set. Hence "iptables -S" output is still:

-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT

However when I try replicating the same using python-iptables code snippet as below:

import iptc

filter_table = iptc.Table(iptc.Table.FILTER, autocommit = False)

all_chains = {
    'input': iptc.Chain(filter_table, "INPUT"),
    'output': iptc.Chain(filter_table, "OUTPUT"),
    'forward': iptc.Chain(filter_table, "FORWARD")
}

for chain_name in 'input', 'output', 'forward':
    try:
        if chain_name is 'forward':
            all_chains[chain_name].set_policy('REJECT')
        else:
            all_chains[chain_name].set_policy('DROP')
    except Exception as e:
        raise

filter_table.commit()

Although I do get an exception like so because I am setting 'REJECT' on the 'FORWARD' chain:

traceback (most recent call last):
  File "replicate-policy-bug.py", line 14, in <module>
    all_chains[chain_name].set_policy('REJECT')
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 1188, in set_policy
    self.table.set_policy(self.name, policy, counters)
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 1247, in new
    ret = fn(*args)
  File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 1452, in set_policy
    (policy, chain, self.strerror()))
iptc.ip4tc.IPTCError: can't set policy REJECT on chain FORWARD: libiptc version error)

"iptables -S" command output is:

-P INPUT DROP
-P FORWARD ACCEPT
-P OUTPUT DROP

which indicates that the "set_policy" call on INPUT and OUTPUT chain went through and was committed inspite of autocommit being set to False. After some debugging I found out that when the program exits due to the exception, the python interpreter, as part of cleanup calls the Table object's "del" method which in turns calls "close" and "_free" as follows:

def __del__(self):        
        self.close()

def close(self):
        """Close the underlying connection handle to iptables."""
        if self._handle:       
            self._free()

 def _free(self, ignore_exc=True):
        if self._handle is None:
            raise IPTCError("table is not initialized")
        try:
            self.commit()
        except IPTCError, e:
            if not ignore_exc:
                raise e
        finally:
            self._iptc.iptc_free(self._handle)
            self._handle = None

From what I understood the problem lies in "self.commit()" call in _free which does not check for the autocommit flag. If I change the _free function to include this check as follows:


 def _free(self, ignore_exc=True):
        if self._handle is None:
            raise IPTCError("table is not initialized")
        try:
            if self.autocommit:
                self.commit()
        except IPTCError, e:
            if not ignore_exc:
                raise e
        finally:
            self._iptc.iptc_free(self._handle)
            self._handle = None

then as autocommit is not on - there won't be any commits and "iptables -S" output is as expected in the initial state:

-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT

Do let me know if this fix makes sense or if there is a cleaner way to ensure this.

Thanks.

Error while trying to get rules from a custom chain in nat table

My machine is running a debian jessie/sid with the kernel 3.9.8 and with iptables v1.4.18

I created the chain TESTCHAIN in the nat table using the iptables binary.
Then I added the following rule:
# iptables -t nat -A TESTCHAIN -j DNAT --to-destination 10.0.0.2

My rule has been added properly and I can see it with iptables -t nat -L.

When I try to get all the rules of my custom chain with python-iptables, I get a backtrace from python itself.
This is how I reproduced the bug in ipython :
In [1]: import iptc

In [2]: table = iptc.Table(iptc.Table.NAT)

In [3]: chain = table.chains[4]

In [4]: chain.name
Out[4]: 'TESTCHAIN'

In [5]: chain.rules
*** Error in `/usr/bin/python': corrupted double-linked list: 0x00000000027cf440 ***

I ran the python-iptables tests and there is the output http://snipurl.com/27g5ubz

I hope I give you enough information, feel free to ask for more if needed.

error while running the example

hi i am getting this error while running AttributeError: MASQUERADE: invalid parameter to-ports. I am using the Simple Rule not using any match extension example

Unable de find /proc/sys/kernel/modprobe

Hello, I've got some issues when I'm importing iptc
Here is the output:

Traceback (most recent call last):
File "", line 1, in
File "/usr/local/lib/python2.7/dist-packages/iptc/init.py", line 10, in
from ip4tc import (is_table_available, Table, Chain, Rule, Match, Target,
File "/usr/local/lib/python2.7/dist-packages/iptc/ip4tc.py", line 18, in
load_kernel("ip_tables")
File "/usr/local/lib/python2.7/dist-packages/iptc/util.py", line 24, in load_kernel
rc, err = _load_ko(name)
File "/usr/local/lib/python2.7/dist-packages/iptc/util.py", line 15, in _load_ko
proc = open("/proc/sys/kernel/modprobe")
IOError: [Errno 2] No such file or directory: '/proc/sys/kernel/modprobe'

My system is the latest Debian and /proc/sys/kernel/modprobe does not exists in my system, but /sbin/modprobe exists.

What should I do ?

No RAW table support

root@genesis:~# /home/leonardo/bin/fw.py
Traceback (most recent call last):
  File "/home/leonardo/bin/fw.py", line 102, in <module>
    a = scw_fw()
  File "/home/leonardo/bin/fw.py", line 27, in __init__
    iptc.Table.flush(iptc.TABLE_RAW)    
AttributeError: 'module' object has no attribute 'TABLE_RAW'
root@genesis:~# lsmod | grep iptable_raw
iptable_raw            12678  0
ip_tables              27473  4 iptable_raw,iptable_mangle,iptable_nat,iptable_filter
x_tables               29846  7 iptable_raw,xt_state,xt_tcpudp,iptable_mangle,iptable_nat,iptable_filter,ip_tables
root@genesis:~# iptables-save | grep  "*raw"
*raw
root@genesis:~#

Unable to delete existing rule with "comment" match in every distro; segfault in CentOS

As a test:

iptables -N TEST_CHAIN
iptables -A TEST_CHAIN -m comment --comment "Test comment" -j ACCEPT

import iptc

table = iptc.Table(iptc.Table.FILTER)
test_chain = iptc.Chain(table, "TEST_CHAIN")
test_chain.delete_rule(test_chain.rules[0])

Result in Ubuntu:
iptc.xtables.XTablesError: comment: --comment must be specified

Result in CentOS:
Segmentation Fault

Underlying problem:
When find_match returns with the "comment" match type, the mflags are set to zero since it's a clone (http://git.netfilter.org/iptables/tree/xtables.c?id=v1.4.7, line 566). As a result, the final_check call in the delete_rules call passes the comment final_check a value of zero, which returns an error (http://git.netfilter.org/iptables/tree/extensions/libxt_comment.c?id=v1.4.7, line 67). On Ubuntu, this incorrect error is handled but on CentOS the registered xtables_error handler is off in oblivion and causes a segfault (maybe env isn't being set in https://raw.github.com/ldx/python-iptables/master/libxtwrapper/wrapper.c? I really don't know).

My hacky work around is to remove the final_check call from delete_rule but I'm sure it's not a kosher fix.

Error parsing rules with tcp flag matches

I have iptables rules matching TCP SYN traffic. I can successfully add rules with SYN flag matches. But when I try and parse rules with TCP flag matches, I get a ValueError.

Code to replicate:

import iptc
rule = iptc.Rule()
rule.protocol = "tcp"
rule.dst = "1.1.1.1"
match = iptc.Match(rule, "tcp")
match.syn = "1"
rule.add_match(match)
rule.target = iptc.Target(rule, "ACCEPT")
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), "iptc_test_chain")
iptc.Table(iptc.Table.FILTER).create_chain(chain)
chain.insert_rule(rule)
try:
    print chain.rules[0].matches[0].name
except:
    print "error parsing rule"

chain.delete_rule(rule)
iptc.Table(iptc.Table.FILTER).delete_chain(chain)

The error:

File "/usr/local/lib/python2.7/dist-packages/python_iptables-0.2.0_dev-py2.7-linux-x86_64.egg/iptc/ip4tc.py", line 1236, in _get_rules
return [self.table.create_rule(e, self) for e in entries]
File "/usr/local/lib/python2.7/dist-packages/python_iptables-0.2.0_dev-py2.7-linux-x86_64.egg/iptc/ip4tc.py", line 1525, in create_rule
return Rule(entry, chain)
File "/usr/local/lib/python2.7/dist-packages/python_iptables-0.2.0_dev-py2.7-linux-x86_64.egg/iptc/ip4tc.py", line 711, in init
self.rule = entry
File "/usr/local/lib/python2.7/dist-packages/python_iptables-0.2.0_dev-py2.7-linux-x86_64.egg/iptc/ip4tc.py", line 1090, in _set_rule
m = Match(self, match=match)
File "/usr/local/lib/python2.7/dist-packages/python_iptables-0.2.0_dev-py2.7-linux-x86_64.egg/iptc/ip4tc.py", line 428, in init
self._update_parameters()
File "/usr/local/lib/python2.7/dist-packages/python_iptables-0.2.0_dev-py2.7-linux-x86_64.egg/iptc/ip4tc.py", line 344, in update_parameters
self.setattr(k, v)
File "/usr/local/lib/python2.7/dist-packages/python_iptables-0.2.0_dev-py2.7-linux-x86_64.egg/iptc/ip4tc.py", line 348, in setattr
self.parse(name.replace("
", "-"), value)
File "/usr/local/lib/python2.7/dist-packages/python_iptables-0.2.0_dev-py2.7-linux-x86_64.egg/iptc/ip4tc.py", line 267, in parse
self._parse(argv, inv, entry)
File "/usr/local/lib/python2.7/dist-packages/python_iptables-0.2.0_dev-py2.7-linux-x86_64.egg/iptc/ip4tc.py", line 450, in _parse
ct.cast(self._ptrptr, ct.POINTER(ct.c_void_p)))
File "/usr/local/lib/python2.7/dist-packages/python_iptables-0.2.0_dev-py2.7-linux-x86_64.egg/iptc/xtables.py", line 735, in new
ret = fn(*args)
File "/usr/local/lib/python2.7/dist-packages/python_iptables-0.2.0_dev-py2.7-linux-x86_64.egg/iptc/xtables.py", line 1024, in parse_match
self._parse(m, argv, invert, flags, fw, ptr)
File "/usr/local/lib/python2.7/dist-packages/python_iptables-0.2.0_dev-py2.7-linux-x86_64.egg/iptc/xtables.py", line 931, in _parse
raise ValueError("invalid value %s" % (argv[1]))
ValueError: invalid value FIN,SYN,RST,ACK SYN

Fedora 16/17: error while running example

Hi,

When I tried to run this example on Fedora 16 or 17:

import iptc
chain = iptc.Chain(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", revision=2) # latest revision
target.set_mark = "0xffff"
rule.target = target
chain.insert_rule(rule)

I got this error:
Traceback (most recent call last):
File "./teste.py", line 40, in
match.dport = "1234"
File "/usr/lib64/python2.7/site-packages/iptc/init.py", line 360, in setattr
self.parse(name.replace("_", "-"), value)
File "/usr/lib64/python2.7/site-packages/iptc/init.py", line 305, in parse
(self._module.name, parameter))
AttributeError: udp: invalid parameter dport

My software:
Kernel: 3.4.2-1.fc16.x86_64 SMP Thu Jun 14 20:17:26 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
iptables: v1.4.12
python-iptables: from github

What can I do to solve this?

Thanks

XTablesError: can't find directory with extensions

After building and installing, I am unable to import the module. Our company does use its own chain of build scripts, but this includes python setup.py install. I have a feeling this is a problem on our end, but I would value your feedback on wehre this is going wrong. My guess is that it's an issue with building/installing the C extension?

In [1]: import iptc
---------------------------------------------------------------------------
XTablesError                              Traceback (most recent call last)
<ipython-input-1-49a367781e85> in <module>()
----> 1 import iptc

/path/to/iptc/__init__.py in <module>()
      8 """
      9 
---> 10 from ip4tc import (is_table_available, Table, Chain, Rule, Match, Target,
     11                    Policy, IPTCError)
     12 from ip6tc import is_table6_available, Table6, Rule6

/path/to/iptc/ip4tc.py in <module>()
     11 
     12 from util import find_library, load_kernel
---> 13 from xtables import (XT_INV_PROTO, NFPROTO_IPV4, XTablesError, xtables,
     14                      xt_align, xt_counters, xt_entry_target, xt_entry_match)
     15 

/path/to/iptc/xtables.py in <module>()
    689             break
    690 if _xtables_libdir is None:
--> 691     raise XTablesError("can't find directory with extensions; "
    692                        "please set XTABLES_LIBDIR")
    693 

XTablesError: can't find directory with extensions; please set XTABLES_LIBDIR

Unable to delete some previously added rules

This code snippet reproduces the bug, I create a rule then I try to iterate over all tables and chains deleting all rules, and it fails to delete the rule.

import iptc

chain = iptc.Chain(iptc.Table('nat'), 'PREROUTING')
rule = iptc.Rule()
rule.position = 1
rule.dst = "127.0.0.1"
rule.protocol = "udp"
rule.dport = "8080"
target = rule.create_target("DNAT")
target.to_destination = '127.0.0.0:80'
chain.insert_rule(rule)

for table in [iptc.Table(t) for t in iptc.Table.ALL]:
    for chain in table.chains:
        if chain.rules:
            for rule in chain.rules:
                chain.delete_rule(rule)

IPTCError: can't initialize tables

when I run ./test.py for the first time.
It erases errors like above:

ERROR: test_rule_standard_target (iptc.test.test_iptc.TestRule)

Traceback (most recent call last):
File "/home/teste/python-iptables/iptc/test/test_iptc.py", line 515, in setUp
self.chain = iptc.Chain(iptc.Table(iptc.Table.FILTER),
File "/home/teste/python-iptables/iptc/ip4tc.py", line 1332, in new
obj._init(name, autocommit)
File "/home/teste/python-iptables/iptc/ip4tc.py", line 1348, in _init
self.refresh()
File "/home/teste/python-iptables/iptc/ip4tc.py", line 1385, in refresh
self.strerror()))

IPTCError: can't initialize filter: iptables who? (do you need to insmod?)

at the second time I run everytinhg go "ok", no error.
what can it is happening? ?

Rule counters don't update during runtime

I'm currently using this module in a long-running daemon. I've noticed that the rules and counters do not seem to update during runtime. I suspect this is because of the caching.

As an example:

import time, sys

import iptc

prerouting = iptc.Chain(iptc.Table(iptc.Table.MANGLE), 'PREROUTING')

for rule in prerouting.rules:
        (packets, bytes) = rule.get_counters()
        print packets, bytes

print "Please send some traffic"
sys.stdout.flush()
time.sleep(30)

for rule in prerouting.rules:
        (packets, bytes) = rule.get_counters()
        print packets, bytes

Output:

# python2.7 counter.py
4 132
Please send some traffic
4 132

# python2.7 counter.py
9 297
Please send some traffic

Note that I sent some packets matching the rules during the first 'Please send some traffic' line, but it didn't appear in the counters until the second run of the script.

Comments with spaces are cut off

With the latest git version (8def4a9) parsing comments which contain spaces are cut off after at the first space.

I'm currently using a quick&dirty hack as a workaround (Apparently the value variable is passed to the parse() method without quotes resulting in shlex.split() splitting it up into multiple arguments and only the first one will end up as the comment.

This is actually a regression as in an older version this was working fine.

Workaround:

diff --git a/iptc/ip4tc.py b/iptc/ip4tc.py
index c48ad10..bce6a42 100644
--- a/iptc/ip4tc.py
+++ b/iptc/ip4tc.py
@@ -259,6 +259,8 @@ class IPTCModule(object):
         else:
             inv = ct.c_int(0)

+       if parameter == "comment":
+           value = '"'+value+'"'
         args = shlex.split(value)
         if not args:
             args = [value]

comment match not working

Extracting comments always results in an empty string.
Tested with commit 9d63c85

To reproduce the issue see the follwoing example.
A workaround is also included.

import iptc

# example code to demonstrate comment extraction failure
# All comments of all chains in the filter table should be printed
# 
# iptables -A INPUT -m comment --comment "example comment"

chains = iptc.TABLE_FILTER.chains

for chain in chains:
  print "Chain: %s" % (chain.name)
  for rule in chain.rules:
    for match in rule.matches:
      if match.name == "comment":
        print "comment1: %s" % match.comment # match.comment is always an empty string

        # manually extract comment from the buffer
        # tested on kernel 2.6.32 (amd64)
        comment = "".join(map(chr, match.match_buf[32:]))
        print "comment2: %s" % comment # works

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.