Tuesday, May 18, 2004
iptables : Master of the rules
Today I feel very good. I swimed for half an hour at 07:30 am, drank a big glass of milk and ate well.
I have 3-4 hours to work on netfilter. So lets start by understanding how iptables command works because without seeing the full picture we have no chance to fix a small bug. Our small bug (as mentioned before) is: iptables lets same rule to be inserted twice one after another. Actually this has no big negative effect but it is useless and unmeaningful. ...So before a modification in iptables we have to check if the modification will cause a "same rule one after another" problem.
When we enter a rule by typing "iptables -A INPUT -s 10.1.1.1 -i eth0 -j REJECT", iptables parses the parameters (-A INPUT -s 10.1.1.1 -i eth0 -j REJECT) it gets from the command line interface (CLI). do_command function does well with all the string we entered. iptables.c has 2297 line of code (at the time of writing) and 647 lines of it is for do_command function. Guess how much work do_command handles.
In do_command with the help of (*)getopt_long funciton (described in getopt.h) -A and -s like parameters are easily read. In iptables capital letters (like -A) are for commands and small letters (like -s) are for options. There are 13 commands and 12 options available in iptables.
In a switch statement commands and options are parsed with add_command and set_option functions.
add_command takes four arguments, command (as variable) is one of them. command (as variable) holds the hex value of the command which is defined in the early parts of iptables.c. Some commands takes another command by default or an invert option may be set so a possible incompability problem is checked. If there is no problem add_command sets command (as variable) with a hex value.
set_option function takes four arugments. option (as variable) behaves like command (as variable) and holds the value of an option which are defined with #DEFINE.
After some checks in a switch statement of command, key functions (I call them key functions because they modify the rules) are executed. These are append_entry, insert_entry, delete_entry, replace_entry.
(*)getopt_long uses an array of "struct option" called original_opts[] to identify the long name and the value of the command also if command has an argument. has_arg the int value of option struct which identifies if the command has an option takes three values. 0 for no arguments, 1 for required argument, 2 for optional argument.For example append (-A) has a required arugment which must be given but list (-L) has an optional argument which my be null. Verbose (is an option and) has no arguments. These are defined in command_v_options which is a two dimensional array.
getopt_long`s another argument is an interesting one named optstring. optstring is a string containing the legitimate option characters. If such a character is followed by a colon, the option requires an argument, so getopt (which is defined as extern char * in getopt.h) places a pointer to the following text in the same argv-element, or the text of the following argv-element, in optarg. Two colons mean an option takes an optional arg; if there is text in the current argv-element, it is returned in optarg, otherwise optarg is set to zero.
According to our example iptables command you can think optarg for A as INPUT. In iptables.c there are some checks like if command is "A" and chain (optarg) is "INPUT" then there can`t be an "o" option. But...
...INPUT chain has no output interface but you can create a custom chain, give it an output interface and jump a rule in INPUT to your custom chain. This is not correct but iptables can not decide if it is correct or not. For example;
I have 3-4 hours to work on netfilter. So lets start by understanding how iptables command works because without seeing the full picture we have no chance to fix a small bug. Our small bug (as mentioned before) is: iptables lets same rule to be inserted twice one after another. Actually this has no big negative effect but it is useless and unmeaningful. ...So before a modification in iptables we have to check if the modification will cause a "same rule one after another" problem.
When we enter a rule by typing "iptables -A INPUT -s 10.1.1.1 -i eth0 -j REJECT", iptables parses the parameters (-A INPUT -s 10.1.1.1 -i eth0 -j REJECT) it gets from the command line interface (CLI). do_command function does well with all the string we entered. iptables.c has 2297 line of code (at the time of writing) and 647 lines of it is for do_command function. Guess how much work do_command handles.
In do_command with the help of (*)getopt_long funciton (described in getopt.h) -A and -s like parameters are easily read. In iptables capital letters (like -A) are for commands and small letters (like -s) are for options. There are 13 commands and 12 options available in iptables.
In a switch statement commands and options are parsed with add_command and set_option functions.
add_command takes four arguments, command (as variable) is one of them. command (as variable) holds the hex value of the command which is defined in the early parts of iptables.c. Some commands takes another command by default or an invert option may be set so a possible incompability problem is checked. If there is no problem add_command sets command (as variable) with a hex value.
set_option function takes four arugments. option (as variable) behaves like command (as variable) and holds the value of an option which are defined with #DEFINE.
After some checks in a switch statement of command, key functions (I call them key functions because they modify the rules) are executed. These are append_entry, insert_entry, delete_entry, replace_entry.
(*)getopt_long uses an array of "struct option" called original_opts[] to identify the long name and the value of the command also if command has an argument. has_arg the int value of option struct which identifies if the command has an option takes three values. 0 for no arguments, 1 for required argument, 2 for optional argument.For example append (-A) has a required arugment which must be given but list (-L) has an optional argument which my be null. Verbose (is an option and) has no arguments. These are defined in command_v_options which is a two dimensional array.
getopt_long`s another argument is an interesting one named optstring. optstring is a string containing the legitimate option characters. If such a character is followed by a colon, the option requires an argument, so getopt (which is defined as extern char * in getopt.h) places a pointer to the following text in the same argv-element, or the text of the following argv-element, in optarg. Two colons mean an option takes an optional arg; if there is text in the current argv-element, it is returned in optarg, otherwise optarg is set to zero.
According to our example iptables command you can think optarg for A as INPUT. In iptables.c there are some checks like if command is "A" and chain (optarg) is "INPUT" then there can`t be an "o" option. But...
...INPUT chain has no output interface but you can create a custom chain, give it an output interface and jump a rule in INPUT to your custom chain. This is not correct but iptables can not decide if it is correct or not. For example;
iptables -N TEST
iptables -A TEST -o eth0 -j ACCEPT
iptables -A INPUT -j TEST