]>
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>
13 from __future__
import print_function
20 IP6TABLES
= "ip6tables"
21 ARPTABLES
= "arptables"
24 IPTABLES_SAVE
= "iptables-save"
25 IP6TABLES_SAVE
= "ip6tables-save"
26 ARPTABLES_SAVE
= "arptables-save"
27 EBTABLES_SAVE
= "ebtables-save"
28 #IPTABLES_SAVE = ['xtables-save','-4']
29 #IP6TABLES_SAVE = ['xtables-save','-6']
31 EXTENSIONS_PATH
= "extensions"
32 LOGFILE
="/tmp/iptables-test.log"
45 def print_error(reason
, filename
=None, lineno
=None):
47 Prints an error with nice colors, indicating file and line number.
49 print(filename
+ ": " + Colors
.RED
+ "ERROR" +
50 Colors
.ENDC
+ ": line %d (%s)" % (lineno
, reason
))
53 def delete_rule(iptables
, rule
, filename
, lineno
):
55 Removes an iptables rule
57 cmd
= iptables
+ " -D " + rule
58 ret
= execute_cmd(cmd
, filename
, lineno
)
60 reason
= "cannot delete: " + iptables
+ " -I " + rule
61 print_error(reason
, filename
, lineno
)
67 def run_test(iptables
, rule
, rule_save
, res
, filename
, lineno
, netns
):
69 Executes an unit test. Returns the output of delete_rule().
72 :param iptables: string with the iptables command to execute
73 :param rule: string with iptables arguments for the rule to test
74 :param rule_save: string to find the rule in the output of iptables -save
75 :param res: expected result of the rule. Valid values: "OK", "FAIL"
76 :param filename: name of the file tested (used for print_error purposes)
77 :param lineno: line number being tested (used for print_error purposes)
81 cmd
= iptables
+ " -A " + rule
83 cmd
= "ip netns exec ____iptables-container-test " + EXECUTEABLE
+ " " + cmd
85 ret
= execute_cmd(cmd
, filename
, lineno
)
92 reason
= "cannot load: " + cmd
93 print_error(reason
, filename
, lineno
)
96 # do not report this error
100 reason
= "should fail: " + cmd
101 print_error(reason
, filename
, lineno
)
102 delete_rule(iptables
, rule
, filename
, lineno
)
106 splitted
= iptables
.split(" ")
107 if len(splitted
) == 2:
108 if splitted
[1] == '-4':
109 command
= IPTABLES_SAVE
110 elif splitted
[1] == '-6':
111 command
= IP6TABLES_SAVE
112 elif len(splitted
) == 1:
113 if splitted
[0] == IPTABLES
:
114 command
= IPTABLES_SAVE
115 elif splitted
[0] == IP6TABLES
:
116 command
= IP6TABLES_SAVE
117 elif splitted
[0] == ARPTABLES
:
118 command
= ARPTABLES_SAVE
119 elif splitted
[0] == EBTABLES
:
120 command
= EBTABLES_SAVE
122 path
= os
.path
.abspath(os
.path
.curdir
) + "/iptables/" + EXECUTEABLE
123 command
= path
+ " " + command
126 command
= "ip netns exec ____iptables-container-test " + command
129 proc
= subprocess
.Popen(command
, shell
=True,
130 stdin
=subprocess
.PIPE
,
131 stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
)
132 out
, err
= proc
.communicate()
135 # check for segfaults
137 if proc
.returncode
== -11:
138 reason
= "iptables-save segfaults: " + cmd
139 print_error(reason
, filename
, lineno
)
140 delete_rule(iptables
, rule
, filename
, lineno
)
144 matching
= out
.find(rule_save
.encode('utf-8'))
146 reason
= "cannot find: " + iptables
+ " -I " + rule
147 print_error(reason
, filename
, lineno
)
148 delete_rule(iptables
, rule
, filename
, lineno
)
151 # Test "ip netns del NETNS" path with rules in place
155 return delete_rule(iptables
, rule
, filename
, lineno
)
157 def execute_cmd(cmd
, filename
, lineno
):
159 Executes a command, checking for segfaults and returning the command exit
162 :param cmd: string with the command to be executed
163 :param filename: name of the file tested (used for print_error purposes)
164 :param lineno: line number being tested (used for print_error purposes)
167 if cmd
.startswith('iptables ') or cmd
.startswith('ip6tables ') or cmd
.startswith('ebtables ') or cmd
.startswith('arptables '):
168 cmd
= os
.path
.abspath(os
.path
.curdir
) + "/iptables/" + EXECUTEABLE
+ " " + cmd
170 print("command: {}".format(cmd
), file=log_file
)
171 ret
= subprocess
.call(cmd
, shell
=True, universal_newlines
=True,
172 stderr
=subprocess
.STDOUT
, stdout
=log_file
)
175 # generic check for segfaults
177 reason
= "command segfaults: " + cmd
178 print_error(reason
, filename
, lineno
)
182 def run_test_file(filename
, netns
):
186 :param filename: name of the file with the test rules
189 # if this is not a test file, skip.
191 if not filename
.endswith(".t"):
194 if "libipt_" in filename
:
196 elif "libip6t_" in filename
:
198 elif "libxt_" in filename
:
200 elif "libarpt_" in filename
:
201 # only supported with nf_tables backend
202 if EXECUTEABLE
!= "xtables-nft-multi":
205 elif "libebt_" in filename
:
206 # only supported with nf_tables backend
207 if EXECUTEABLE
!= "xtables-nft-multi":
211 # default to iptables if not known prefix
219 total_test_passed
= True
222 execute_cmd("ip netns add ____iptables-container-test", filename
, 0)
224 for lineno
, line
in enumerate(f
):
229 chain_array
= line
.rstrip()[1:].split(",")
232 # external non-iptables invocation, executed as is.
234 external_cmd
= line
.rstrip()[1:]
236 external_cmd
= "ip netns exec ____iptables-container-test " + external_cmd
237 execute_cmd(external_cmd
, filename
, lineno
)
240 # external iptables invocation, executed as is.
242 external_cmd
= line
.rstrip()[1:]
244 external_cmd
= "ip netns exec ____iptables-container-test " + EXECUTEABLE
+ " " + external_cmd
245 execute_cmd(external_cmd
, filename
, lineno
)
249 table
= line
.rstrip()[1:]
252 if len(chain_array
) == 0:
253 print("broken test, missing chain, leaving")
259 for chain
in chain_array
:
260 item
= line
.split(";")
262 rule
= chain
+ " " + item
[0]
264 rule
= chain
+ " -t " + table
+ " " + item
[0]
267 rule_save
= chain
+ " " + item
[0]
269 rule_save
= chain
+ " " + item
[1]
271 res
= item
[2].rstrip()
272 ret
= run_test(iptables
, rule
, rule_save
,
273 res
, filename
, lineno
+ 1, netns
)
277 total_test_passed
= False
284 execute_cmd("ip netns del ____iptables-container-test", filename
, 0)
285 if total_test_passed
:
286 print(filename
+ ": " + Colors
.GREEN
+ "OK" + Colors
.ENDC
)
294 Show the list of missing test files
296 file_list
= os
.listdir(EXTENSIONS_PATH
)
297 testfiles
= [i
for i
in file_list
if i
.endswith('.t')]
298 libfiles
= [i
for i
in file_list
299 if i
.startswith('lib') and i
.endswith('.c')]
302 return x
[0:-2] + '.t'
303 missing
= [test_name(i
) for i
in libfiles
304 if not test_name(i
) in testfiles
]
306 print('\n'.join(missing
))
313 parser
= argparse
.ArgumentParser(description
='Run iptables tests')
314 parser
.add_argument('filename', nargs
='?',
315 metavar
='path/to/file.t',
316 help='Run only this test')
317 parser
.add_argument('-l', '--legacy', action
='store_true',
318 help='Test iptables-legacy')
319 parser
.add_argument('-m', '--missing', action
='store_true',
320 help='Check for missing tests')
321 parser
.add_argument('-n', '--nftables', action
='store_true',
322 help='Test iptables-over-nftables')
323 parser
.add_argument('-N', '--netns', action
='store_true',
324 help='Test netnamespace path')
325 args
= parser
.parse_args()
328 # show list of missing test files
335 EXECUTEABLE
= "xtables-legacy-multi"
337 EXECUTEABLE
= "xtables-nft-multi"
340 print("You need to be root to run this, sorry")
343 os
.putenv("XTABLES_LIBDIR", os
.path
.abspath(EXTENSIONS_PATH
))
344 os
.putenv("PATH", "%s/iptables:%s" % (os
.path
.abspath(os
.path
.curdir
), os
.getenv("PATH")))
350 # setup global var log file
353 log_file
= open(LOGFILE
, 'w')
355 print("Couldn't open log file %s" % LOGFILE
)
358 file_list
= [os
.path
.join(EXTENSIONS_PATH
, i
)
359 for i
in os
.listdir(EXTENSIONS_PATH
)]
361 file_list
= [args
.filename
]
362 for filename
in file_list
:
363 file_tests
, file_passed
= run_test_file(filename
, args
.netns
)
366 passed
+= file_passed
369 print("%d test files, %d unit tests, %d passed" % (test_files
, tests
, passed
))
372 if __name__
== '__main__':