Passing Arguments To IpTables Rope Scripts

! NB: The feature described on this page was introduced on 15 march 2005, and so cannot be used in versions before 20050315.

Rope scripts can be inserted to Linux IpTables firewall rule chains to match network packets based on complex criteria. Sometimes, it is useful to be able to parameterise the actions of a script by passing arguments to it.

For example: the HttpContentLength script checks the first packet of an HTTP transfer to test whether or not the total transfer will exceed a predetermined size. The sample script shown has the size hard-coded into it, however it might be useful to allow the size to be passed as a command line option at the time the "iptables" command was executed. This would allow a single script to be used in different places in the IpTables chains with different transfer sizes being tested for.

Rope provides this feature by allowing values to pushed onto the stack before the script is executed.

To understand this idea, lets see it in action. Here's a script that simply checks that the destination port number of an IP packet is in a specified range..

20 $a put   # the lower bound
100 $b put  # the upper bound

$tcp_dest $a ge
$tcp_dest $b le
   and assert   # "no" unless both tests pass
yes             # "yes" otherwise

Rather than specifying the lower and upper bounds in the script, we can arrange to push them onto the stack before the script even starts. Here's the iptables command that will do this..

 iptables -A INPUT -m rope \
     --rope-script myscript \
     --rope-push-int 20 \
     --rope-push-int 100 \
     -j ACCEPT

When the script has been loaded using the above command, it will already have the numbers 20 and 100 on the stack when it starts, so our script can be modified as follows to use these values instead of hard coded ones..

$b put   # take the upper bound off the stack
$a put   # take the lower bound off the stack

$tcp_dest $a ge
$tcp_dest $b le
   and assert   # "no" unless both tests pass
yes             # "yes" otherwise

The observant will have noticed that the order of the two "put" commands on the first two lines of the script has changed. This is because the arguments are pushed onto the stack in the order they were specified (as you'd expect) which means that the first one to be popped back off is actually the last one to have been pushed on (that's how stacks work - they're "last in first out" things). Bear this in mind when passing multiple paramters to a rope script.

Pushing Strings

We have shown how integer numbers can be pushed onto the stack, but that's not all we can do. It's also possible to push strings (remember that Rope sees strings and integers and different sorts of things - like C but unlike perl [well - almost]).

To push a string, use "--rope-push-str" instead of "--rope-push-int", like this..

iptables -A INPUT -m rope \
   --rope-script=myscript \
   --rope-push-str HELLO \
   --rope-push-str "NICE TO MEET YOU" \
   -j ACCEPT

Be aware that it's the command line shell that sees the quote marks when you use them, so (like all things unix-y) you need to ensure that the iptables command really sees the string you want.

Also be aware that if you save your iptables setup using "iptables-save" and re-read it using "iptables-restore" you will get into trouble if you included quotes or control characters (like new-lines) in your strings. This is because the iptables-restore command doesnt handle such complex constructs. In order to prevent this from being an issue, the iptables command will complain if you try to place any such characters into the string in the first place. This means that you cant put the following into a string passed with --rope-push-str..

If this restriction is a problem for your system, then you can edit the libipt_rope.c source to remove the check (this is the joy of open-source software) but if you do, then please ..

Pushing IPv4 Addresses

As well as allowing you to push integers and strings, Rope also allows you to push IPv4 addresses in the same way. As you'd expect, the option is called "--rope-push-ip". Here's an example of it in use..

iptables -A INPUT -m rope \
    --rope-script myscript \
    --rope-push-ip 192.168.100.2 \
    --rope-push-ip 192.168.100.29 \
    -j ACCEPT

As with the other "push" options, the addresses specified can be popped off the stack in the reverse order to which they were pushed.

The addresses are placed onto the stack (following Rope's normal convention) as four-byte strings (see IpAddress for details) and can be manipulated in the same way as you do the other IPv4 address supplied by the software.

In addition to passing IP address explicitly in this way, Rope also allows you to specify a resolvable host name. If you do this, the iptables command determines the IPv4 address for the name and pushes that onto the stack. If you use this logic, there are some issues you need to be aware of...