]>
git.ipfire.org Git - thirdparty/iptables.git/blob - iptables-test.py
3 # (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This software has been sponsored by Sophos Astaro <http://www.sophos.com>
19 IP6TABLES
= "ip6tables"
20 #IPTABLES = "xtables -4"
21 #IP6TABLES = "xtables -6"
23 IPTABLES_SAVE
= "iptables-save"
24 IP6TABLES_SAVE
= "ip6tables-save"
25 #IPTABLES_SAVE = ['xtables-save','-4']
26 #IP6TABLES_SAVE = ['xtables-save','-6']
28 EXTENSIONS_PATH
= "extensions"
29 LOGFILE
="/tmp/iptables-test.log"
42 def print_error(reason
, filename
=None, lineno
=None):
44 Prints an error with nice colors, indicating file and line number.
46 print (filename
+ ": " + Colors
.RED
+ "ERROR" +
47 Colors
.ENDC
+ ": line %d (%s)" % (lineno
, reason
))
50 def delete_rule(iptables
, rule
, filename
, lineno
):
52 Removes an iptables rule
54 cmd
= iptables
+ " -D " + rule
55 ret
= execute_cmd(cmd
, filename
, lineno
)
57 reason
= "cannot delete: " + iptables
+ " -I " + rule
58 print_error(reason
, filename
, lineno
)
64 def run_test(iptables
, rule
, rule_save
, res
, filename
, lineno
):
66 Executes an unit test. Returns the output of delete_rule().
69 :param iptables: string with the iptables command to execute
70 :param rule: string with iptables arguments for the rule to test
71 :param rule_save: string to find the rule in the output of iptables -save
72 :param res: expected result of the rule. Valid values: "OK", "FAIL"
73 :param filename: name of the file tested (used for print_error purposes)
74 :param lineno: line number being tested (used for print_error purposes)
78 cmd
= iptables
+ " -A " + rule
79 ret
= execute_cmd(cmd
, filename
, lineno
)
86 reason
= "cannot load: " + cmd
87 print_error(reason
, filename
, lineno
)
90 # do not report this error
94 reason
= "should fail: " + cmd
95 print_error(reason
, filename
, lineno
)
96 delete_rule(iptables
, rule
, filename
, lineno
)
100 splitted
= iptables
.split(" ")
101 if len(splitted
) == 2:
102 if splitted
[1] == '-4':
103 command
= IPTABLES_SAVE
104 elif splitted
[1] == '-6':
105 command
= IP6TABLES_SAVE
106 elif len(splitted
) == 1:
107 if splitted
[0] == IPTABLES
:
108 command
= IPTABLES_SAVE
109 elif splitted
[0] == IP6TABLES
:
110 command
= IP6TABLES_SAVE
112 proc
= subprocess
.Popen(command
, stdin
=subprocess
.PIPE
,
113 stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
)
114 out
, err
= proc
.communicate()
117 # check for segfaults
119 if proc
.returncode
== -11:
120 reason
= "iptables-save segfaults: " + cmd
121 print_error(reason
, filename
, lineno
)
122 delete_rule(iptables
, rule
, filename
, lineno
)
126 matching
= out
.find(rule_save
)
128 reason
= "cannot find: " + iptables
+ " -I " + rule
129 print_error(reason
, filename
, lineno
)
130 delete_rule(iptables
, rule
, filename
, lineno
)
133 return delete_rule(iptables
, rule
, filename
, lineno
)
136 def execute_cmd(cmd
, filename
, lineno
):
138 Executes a command, checking for segfaults and returning the command exit
141 :param cmd: string with the command to be executed
142 :param filename: name of the file tested (used for print_error purposes)
143 :param lineno: line number being tested (used for print_error purposes)
146 print >> log_file
, "command: %s" % cmd
147 ret
= subprocess
.call(cmd
, shell
=True, universal_newlines
=True,
148 stderr
=subprocess
.STDOUT
, stdout
=log_file
)
151 # generic check for segfaults
153 reason
= "command segfaults: " + cmd
154 print_error(reason
, filename
, lineno
)
158 def run_test_file(filename
):
162 :param filename: name of the file with the test rules
165 # if this is not a test file, skip.
167 if not filename
.endswith(".t"):
170 if "libipt_" in filename
:
172 elif "libip6t_" in filename
:
174 elif "libxt_" in filename
:
177 # default to iptables if not known prefix
185 total_test_passed
= True
187 for lineno
, line
in enumerate(f
):
192 chain_array
= line
.rstrip()[1:].split(",")
195 # external non-iptables invocation, executed as is.
197 external_cmd
= line
.rstrip()[1:]
198 execute_cmd(external_cmd
, filename
, lineno
)
202 table
= line
.rstrip()[1:]
205 if len(chain_array
) == 0:
206 print "broken test, missing chain, leaving"
212 for chain
in chain_array
:
213 item
= line
.split(";")
215 rule
= chain
+ " " + item
[0]
217 rule
= chain
+ " -t " + table
+ " " + item
[0]
220 rule_save
= chain
+ " " + item
[0]
222 rule_save
= chain
+ " " + item
[1]
224 res
= item
[2].rstrip()
226 ret
= run_test(iptables
, rule
, rule_save
,
227 res
, filename
, lineno
+ 1)
230 total_test_passed
= False
236 if total_test_passed
:
237 print filename
+ ": " + Colors
.GREEN
+ "OK" + Colors
.ENDC
245 Show the list of missing test files
247 file_list
= os
.listdir(EXTENSIONS_PATH
)
248 testfiles
= [i
for i
in file_list
if i
.endswith('.t')]
249 libfiles
= [i
for i
in file_list
250 if i
.startswith('lib') and i
.endswith('.c')]
253 return x
[0:-2] + '.t'
254 missing
= [test_name(i
) for i
in libfiles
255 if not test_name(i
) in testfiles
]
257 print '\n'.join(missing
)
264 parser
= argparse
.ArgumentParser(description
='Run iptables tests')
265 parser
.add_argument('filename', nargs
='?',
266 metavar
='path/to/file.t',
267 help='Run only this test')
268 parser
.add_argument('-m', '--missing', action
='store_true',
269 help='Check for missing tests')
270 args
= parser
.parse_args()
273 # show list of missing test files
280 print "You need to be root to run this, sorry"
287 # setup global var log file
290 log_file
= open(LOGFILE
, 'w')
292 print "Couldn't open log file %s" % LOGFILE
295 file_list
= [os
.path
.join(EXTENSIONS_PATH
, i
)
296 for i
in os
.listdir(EXTENSIONS_PATH
)]
298 file_list
= [args
.filename
]
299 for filename
in file_list
:
300 file_tests
, file_passed
= run_test_file(filename
)
303 passed
+= file_passed
306 print ("%d test files, %d unit tests, %d passed" %
307 (test_files
, tests
, passed
))
310 if __name__
== '__main__':