python-iptables icon indicating copy to clipboard operation
python-iptables copied to clipboard

Bug - target.to_destination need to be inoked otherise issue happen in iptc/ip4tc.py

Open hetii opened this issue 7 years ago • 6 comments

Hi. I use such prerouting method to set my rule. There is odd issue that happens in iptc/ip4tc.py when I don`t invoke target.to_destination by print() or type(), whatever.

Otherwise in function get_all_parameters() of iptc/ip4tc.py res.pop() return None and that`s why required key is undefined.

This issue happen just on my centos system.

 
def set_prerouting(in_interface, protocol, dst_ip, dst_port):
    table = iptc.Table(iptc.Table.NAT, autocommit = False)
    chain = iptc.Chain(table, "PREROUTING")
    rule = iptc.Rule()
    ## rule.in_interface = in_interface
    rule.protocol = protocol
    match = iptc.Match(rule, protocol)
    match.dport = dst_port
    rule.add_match(match)
    target = iptc.Target(rule, "DNAT")
    target.to_destination = "%s:%s" % (dst_ip, dst_port.replace(':','-'))
    #type(target.to_destination)
    rule.target = target
    table.refresh()
    table.commit()
    table.autocommit = True
    if not rule in chain.rules:
        chain.insert_rule(rule)

  File "/root/workspace/myapp/src/dnat_tunnel.py", line 28, in set_port_forwarding
    set_prerouting(in_interface, protocol, dst_ip, dst_port)
  File "/root/workspace/myapp/src/dnat_tunnel.py", line 58, in set_prerouting
    chain.insert_rule(rule)
  File "/root/.local/share/virtualenvs/myapp-HrmQp8ck/lib/python3.6/site-packages/iptc/ip4tc.py", line 1470, in insert_rule
    rule.final_check()
  File "/root/.local/share/virtualenvs/myapp-HrmQp8ck/lib/python3.6/site-packages/iptc/ip4tc.py", line 984, in final_check
    self.target.final_check()
  File "/root/.local/share/virtualenvs/myapp-HrmQp8ck/lib/python3.6/site-packages/iptc/ip4tc.py", line 339, in final_check
    self._update_parameters()
  File "/root/.local/share/virtualenvs/myapp-HrmQp8ck/lib/python3.6/site-packages/iptc/ip4tc.py", line 441, in _update_parameters
    params = self.get_all_parameters().items()
  File "/root/.local/share/virtualenvs/myapp-HrmQp8ck/lib/python3.6/site-packages/iptc/ip4tc.py", line 437, in get_all_parameters
    params[key].append(x)  # This is a parameter value.
UnboundLocalError: local variable 'key' referenced before assignment

hetii avatar May 16 '18 11:05 hetii

Did you install python-iptables via pip? Can you check what version it is?

ldx avatar May 24 '18 00:05 ldx

I install it always by pipenv in latest version, no clue now on with version it was when I put this issue here... :/

hetii avatar Aug 07 '18 07:08 hetii

Hey everyone,

I have the same error when creating a nat rule using target.to_destination for the prerouting chain

UnboundLocalError: local variable 'key' referenced before assignment

python-iptables version: 0.13.0 Kernel: 4.13.0-46-generic

hheennrryy21 avatar Sep 05 '18 15:09 hheennrryy21

So I just looked at it a bit more. After multiple attempts to debug it. I started to a see a clue.

I saw bits and pieces of my stdout in the python-iptables variable x (line 423, ip4tc.py).

My parent program, which called on python-itpables, was writing to stdout. I had hundreds of print statement, and other stdout related activity. I ran my parent program with unbuffered print, and now python-iptables now magically works.

I noticed in ip4tc.py that function __get_saved_buf reads from stdout. So I am not wrong at all. Something is getting overwritten.

Can someone else confirm this?

Thanks

Update

Still having the issue. stdout is being pushed into variables in ip4tc.py. Unbuffered print didn't do anything. Though it is much less common now.

hheennrryy21 avatar Sep 05 '18 18:09 hheennrryy21

@hheennrryy21 I couldn't reproduce your issue on my test installation from my ipython3 interpreter.

OS: Debian GNU/Linux 9.9 (stretch) Kernel: 4.19.0-0.bpo.4-amd64 #1 SMP Debian 4.19.28-2~bpo9+1 (2019-03-27) x86_64 GNU/Linux python-iptables version: 0.13.0

If I may ask, in your script you first disable autocommit on the table, then without doing any alterations to the table/chain, you then refresh(), commit() and enable autocommit again, before attempting to insert your rule, why is that?

On another note, there is a new module added in master, iptc.easy that would allow you to do something like this:

def set_prerouting_easy(in_interface, protocol, dst_ip, dst_port):
    to_destination = '{}:{}'.format(dst_ip, dst_port)
    rule_d = {'in-interface':in_interface, 'protocol':protocol, protocol:{'dport':dst_port},
              'target': {'DNAT': {'to-destination': to_destination}}}
    if not iptc.easy.has_rule('nat', 'PREROUTING', rule_d):
        iptc.easy.insert_rule('nat', 'PREROUTING', rule_d)

jllorente avatar May 19 '19 20:05 jllorente

Hi jllorente,

There is no reason why I had autocommit=False in the beginning. I was assuming this was the default when the iptc.Table object gets created. I wanted to let the team know that I've still been seeing this stdout issue for some time now since this ticket was created. Occasionally, when my program runs I am able to cause iptc to interpret an stdout message from my program as a valid entry. When I get a chance I will build a script that will replicate this problem. I am using python2.7, so I don't know what kind of issue that can cause. I may be looking at two different errors. I will be a bit more descriptive when I come back to this.

hheennrryy21 avatar May 28 '19 17:05 hheennrryy21