2 LuCI - Iptables parser and query library
4 Copyright 2008 Jo-Philipp Wich <freifunk@wwsnet.net>
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
22 module("luci.sys.iptparser", package.seeall)
26 IptParser = luci.util.class()
29 IptParser.__init__( ... )
31 The class constructor, initializes the internal lookup table.
34 function IptParser.__init__( self, ... )
42 IptParser.find( args )
44 Find all firewall rules that match the given criteria. Expects a table with search criteria as only argument.
45 If args is nil or an empty table then all rules will be returned.
47 The following keys in the args table are recognized:
49 - table Match rules that are located within the given table
50 - chain Match rules that are located within the given chain
51 - target Match rules with the given target
52 - protocol Match rules that match the given protocol, rules with protocol "all" are always matched
53 - source Match rules with the given source, rules with source "0.0.0.0/0" are always matched
54 - destination Match rules with the given destination, rules with destination "0.0.0.0/0" are always matched
55 - inputif Match rules with the given input interface, rules with input interface "*" (=all) are always matched
56 - outputif Match rules with the given output interface, rules with output interface "*" (=all) are always matched
57 - flags Match rules that match the given flags, current supported values are "-f" (--fragment) and "!f" (! --fragment)
58 - options Match rules containing all given options
60 The return value is a list of tables representing the matched rules.
61 Each rule table contains the following fields:
63 - index The index number of the rule
64 - table The table where the rule is located, can be one of "filter", "nat" or "mangle"
65 - chain The chain where the rule is located, e.g. "INPUT" or "postrouting_wan"
66 - target The rule target, e.g. "REJECT" or "DROP"
67 - protocol The matching protocols, e.g. "all" or "tcp"
68 - flags Special rule options ("--", "-f" or "!f")
69 - inputif Input interface of the rule, e.g. "eth0.0" or "*" for all interfaces
70 - outputif Output interface of the rule, e.g. "eth0.0" or "*" for all interfaces
71 - source The source ip range, e.g. "0.0.0.0/0"
72 - destination The destination ip range, e.g. "0.0.0.0/0"
73 - options A list of specific options of the rule, e.g. { "reject-with", "tcp-reset" }
74 - packets The number of packets matched by the rule
75 - bytes The number of total bytes matched by the rule
79 ip = luci.sys.iptparser.IptParser()
83 options={ "reject-with", "tcp-reset" }
86 This will match all rules with target "-j REJECT", protocol "-p tcp" (or "-p all") and the option "--reject-with tcp-reset".
90 function IptParser.find( self, args )
92 local args = args or { }
95 for i, rule in ipairs(self._rules) do
99 if not ( not args.table or args.table == rule.table ) then
104 if not ( match == true and ( not args.chain or args.chain == rule.chain ) ) then
109 if not ( match == true and ( not args.target or args.target == rule.target ) ) then
114 if not ( match == true and ( not args.protocol or rule.protocol == "all" or args.protocol == rule.protocol ) ) then
118 -- match source (XXX: implement ipcalc stuff so that 192.168.1.0/24 matches 0.0.0.0/0 etc.)
119 if not ( match == true and ( not args.source or rule.source == "0.0.0.0/0" or rule.source == args.source ) ) then
123 -- match destination (XXX: implement ipcalc stuff so that 192.168.1.0/24 matches 0.0.0.0/0 etc.)
124 if not ( match == true and ( not args.destination or rule.destination == "0.0.0.0/0" or rule.destination == args.destination ) ) then
128 -- match input interface
129 if not ( match == true and ( not args.inputif or rule.inputif == "*" or args.inputif == rule.inputif ) ) then
133 -- match output interface
134 if not ( match == true and ( not args.outputif or rule.outputif == "*" or args.outputif == rule.outputif ) ) then
138 -- match flags (the "opt" column)
139 if not ( match == true and ( not args.flags or rule.flags == args.flags ) ) then
143 -- match specific options
144 if not ( match == true and ( not args.options or self:_match_options( rule.options, args.options ) ) ) then
150 if match == true then
151 table.insert( rv, rule )
162 Rebuild the internal lookup table, for example when rules have changed through external commands.
165 function IptParser.resync( self )
173 IptParser._parse_rules()
175 [internal] Parse iptables output from all tables.
178 function IptParser._parse_rules( self )
180 for i, tbl in ipairs({ "filter", "nat", "mangle" }) do
182 for i, rule in ipairs(luci.util.execl("iptables -t " .. tbl .. " --line-numbers -nxvL")) do
184 if rule:find( "Chain " ) == 1 then
186 self._chain = rule:gsub("Chain ([^%s]*) .*", "%1")
189 if rule:find("%d") == 1 then
191 local rule_parts = luci.util.split( rule, "%s+", nil, true )
192 local rule_details = { }
194 rule_details["table"] = tbl
195 rule_details["chain"] = self._chain
196 rule_details["index"] = tonumber(rule_parts[1])
197 rule_details["packets"] = tonumber(rule_parts[2])
198 rule_details["bytes"] = tonumber(rule_parts[3])
199 rule_details["target"] = rule_parts[4]
200 rule_details["protocol"] = rule_parts[5]
201 rule_details["flags"] = rule_parts[6]
202 rule_details["inputif"] = rule_parts[7]
203 rule_details["outputif"] = rule_parts[8]
204 rule_details["source"] = rule_parts[9]
205 rule_details["destination"] = rule_parts[10]
206 rule_details["options"] = { }
208 for i = 11, #rule_parts - 1 do
209 rule_details["options"][i-10] = rule_parts[i]
212 table.insert( self._rules, rule_details )
223 IptParser._match_options( optlist1, optlist2 )
225 [internal] Return true if optlist1 contains all elements of optlist2. Return false in all other cases.
228 function IptParser._match_options( self, o1, o2 )
230 -- construct a hashtable of first options list to speed up lookups
232 for i, opt in ipairs( o1 ) do oh[opt] = true end
234 -- iterate over second options list
235 -- each string in o2 must be also present in o1
236 -- if o2 contains a string which is not found in o1 then return false
237 for i, opt in ipairs( o2 ) do