Skip to content

Commit a5793b9

Browse files
2faamitkarsale
authored andcommitted
Fix rule parsing
1 parent 69aac41 commit a5793b9

File tree

2 files changed

+343
-3
lines changed

2 files changed

+343
-3
lines changed

lib/puppet/provider/firewall/firewall.rb

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class Puppet::Provider::Firewall::Firewall
1919
# Regex used to retrieve table name
2020
$table_name_regex = %r{^\*(nat|mangle|filter|raw|rawpost|broute|security)}
2121
# Regex used to retrieve Rules
22-
$rules_regex = %r{(-A.*)\n}
22+
$rules_regex = %r{^(-A.*)\n}
2323
# Base command
2424
$base_command = {
2525
'IPv4' => 'iptables -t',
@@ -466,6 +466,9 @@ def self.get_rules(context, basic, protocols = ['IPv4', 'IPv6'])
466466
iptables_list.scan($table_regex).each do |table|
467467
table_name = table[0].scan($table_name_regex)[0][0]
468468
table[0].scan($rules_regex).each do |rule|
469+
# iptables-save escapes ' symbol in it's output for some reason which leads to an incorrect command
470+
# We need to manually replace \' to '
471+
rule[0].gsub!("\\'","'")
469472
raw_rules = if basic
470473
Puppet::Provider::Firewall::Firewall.rule_to_name(context, rule[0], table_name, protocol)
471474
else
@@ -489,7 +492,7 @@ def self.rule_to_name(_context, rule, table_name, protocol)
489492
rule_hash[:table] = table_name
490493
rule_hash[:protocol] = protocol
491494

492-
name_regex = Regexp.new("#{$resource_map[:name]}\\s(?:\"([^\"]*)|([^\"\\s]*))")
495+
name_regex = Regexp.new("#{$resource_map[:name]}\\s+(?:\"(.+?(?<!\\\\))\"|([^\"\\s]+)\\b)(?:\\s|$)")
493496
name_value = rule.scan(name_regex)[0]
494497
# Combine the returned values and remove and trailing or leading whitespace
495498
rule_hash[:name] = [name_value[0], name_value[1]].join(' ').strip if name_value
@@ -527,7 +530,7 @@ def self.rule_to_hash(_context, rule, table_name, protocol)
527530
# When only a single word comment is returned no quotes are given, so we must check for this as well
528531
# First find if flag is present, add a space to ensure accuracy with the more simplistic flags; i.e. `-i`
529532
if rule.match(Regexp.new("#{value}\\s"))
530-
value_regex = Regexp.new("(?:(!\\s))?#{value}\\s(?:\"([^\"]*)|([^\"\\s]*))")
533+
value_regex = Regexp.new("(?:(!\\s))?#{value}\\s+(?:\"(.+?(?<!\\\\))\"|([^\"\\s]+)\\b)(?:\\s|$)")
531534
key_value = rule.scan(value_regex)[0]
532535
# Combine the returned values and remove and trailing or leading whitespace
533536
key_value[1] = [key_value[0], key_value[1], key_value[2]].join
Lines changed: 337 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,337 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper'
4+
require 'puppet/resource_api'
5+
6+
ensure_module_defined('Puppet::Provider::Firewall')
7+
require 'puppet/provider/firewall/firewall'
8+
9+
RSpec.describe Puppet::Provider::Firewall::Firewall do
10+
describe 'iptables-save output parsing' do
11+
subject(:provider) { described_class.new }
12+
13+
let(:type) { Puppet::Type.type('firewall') }
14+
let(:context) { Puppet::ResourceApi::BaseContext.new(type.type_definition.definition) }
15+
16+
describe 'get(_context)' do
17+
let(:iptables) do
18+
'
19+
# Generated by iptables-save v1.8.4 on Thu Aug 10 10:15:14 2023
20+
*filter
21+
:INPUT ACCEPT [62:3308]
22+
:FORWARD ACCEPT [0:0]
23+
:OUTPUT ACCEPT [39:3092]
24+
:TEST_ONE - [0:0]
25+
:TEST-ANOTHER - [0:0]
26+
COMMIT
27+
-A TEST_ONE -p tcp -m comment --comment "001 custom chain test rule"
28+
-A INPUT -p tcp -m comment --comment "002 \"double-quotes\" test rule"
29+
-A INPUT -p tcp -m comment --comment "007 \'single-quotes\' test rule"
30+
-A TEST-ANOTHER -p tcp -m comment --comment "003 test -A in chain name"
31+
-A TEST_ONE -p tcp -m comment --comment "foreign rule test"
32+
# Completed on Thu Aug 10 10:15:14 2023
33+
# Generated by iptables-save v1.8.4 on Thu Aug 10 10:15:14 2023
34+
*raw
35+
:PREROUTING ACCEPT [13222:23455532]
36+
:OUTPUT ACCEPT [12523:852730]
37+
COMMIT
38+
-A OUTPUT -p tcp -m comment --comment "004 test raw table rule"
39+
# Completed on Thu Aug 10 10:15:14 2023
40+
'
41+
end
42+
let(:ip6tables) do
43+
'
44+
# Generated by ip6tables-save v1.8.4 on Thu Aug 10 10:21:55 2023
45+
*filter
46+
:INPUT ACCEPT [0:0]
47+
:FORWARD ACCEPT [0:0]
48+
:OUTPUT ACCEPT [13:824]
49+
:TEST_TWO - [0:0]
50+
COMMIT
51+
-A OUTPUT -p tcp -m comment --comment "005 test ipv6 rule"
52+
# Completed on Thu Aug 10 10:21:55 2023
53+
*raw
54+
:PREROUTING ACCEPT [13222:23455532]
55+
:OUTPUT ACCEPT [12523:852730]
56+
COMMIT
57+
-A TEST_TWO -p tcp -m comment --comment "006 test ipv6 rule in different table"
58+
# Completed on Thu Aug 10 10:21:55 2023
59+
'
60+
end
61+
let(:returned_data) do
62+
[{chain: "TEST_ONE",
63+
checksum_fill: false,
64+
clamp_mss_to_pmtu: false,
65+
clusterip_new: false,
66+
ensure: "present",
67+
ipvs: false,
68+
isfirstfrag: false,
69+
isfragment: false,
70+
ishasmorefrags: false,
71+
islastfrag: false,
72+
kernel_timezone: false,
73+
line: "-A TEST_ONE -p tcp -m comment --comment \"001 custom chain test rule\"",
74+
log_ip_options: false,
75+
log_tcp_options: false,
76+
log_tcp_sequence: false,
77+
log_uid: false,
78+
name: "001 custom chain test rule",
79+
notrack: false,
80+
physdev_is_bridged: false,
81+
physdev_is_in: false,
82+
physdev_is_out: false,
83+
proto: "tcp",
84+
protocol: "IPv4",
85+
queue_bypass: false,
86+
random: false,
87+
random_fully: false,
88+
rdest: false,
89+
reap: false,
90+
rsource: false,
91+
rttl: false,
92+
socket: false,
93+
table: "filter",
94+
time_contiguous: false},
95+
{chain: "INPUT",
96+
checksum_fill: false,
97+
clamp_mss_to_pmtu: false,
98+
clusterip_new: false,
99+
ensure: "present",
100+
ipvs: false,
101+
isfirstfrag: false,
102+
isfragment: false,
103+
ishasmorefrags: false,
104+
islastfrag: false,
105+
kernel_timezone: false,
106+
line: "-A INPUT -p tcp -m comment --comment \"002 \\\"double-quotes\\\" test rule\"",
107+
log_ip_options: false,
108+
log_tcp_options: false,
109+
log_tcp_sequence: false,
110+
log_uid: false,
111+
name: "002 \\\"double-quotes\\\" test rule",
112+
notrack: false,
113+
physdev_is_bridged: false,
114+
physdev_is_in: false,
115+
physdev_is_out: false,
116+
proto: "tcp",
117+
protocol: "IPv4",
118+
queue_bypass: false,
119+
random: false,
120+
random_fully: false,
121+
rdest: false,
122+
reap: false,
123+
rsource: false,
124+
rttl: false,
125+
socket: false,
126+
table: "filter",
127+
time_contiguous: false},
128+
{chain: "INPUT",
129+
checksum_fill: false,
130+
clamp_mss_to_pmtu: false,
131+
clusterip_new: false,
132+
ensure: "present",
133+
ipvs: false,
134+
isfirstfrag: false,
135+
isfragment: false,
136+
ishasmorefrags: false,
137+
islastfrag: false,
138+
kernel_timezone: false,
139+
line: "-A INPUT -p tcp -m comment --comment \"007 'single-quotes' test rule\"",
140+
log_ip_options: false,
141+
log_tcp_options: false,
142+
log_tcp_sequence: false,
143+
log_uid: false,
144+
name: "007 'single-quotes' test rule",
145+
notrack: false,
146+
physdev_is_bridged: false,
147+
physdev_is_in: false,
148+
physdev_is_out: false,
149+
proto: "tcp",
150+
protocol: "IPv4",
151+
queue_bypass: false,
152+
random: false,
153+
random_fully: false,
154+
rdest: false,
155+
reap: false,
156+
rsource: false,
157+
rttl: false,
158+
socket: false,
159+
table: "filter",
160+
time_contiguous: false},
161+
{chain: "TEST-ANOTHER",
162+
checksum_fill: false,
163+
clamp_mss_to_pmtu: false,
164+
clusterip_new: false,
165+
ensure: "present",
166+
ipvs: false,
167+
isfirstfrag: false,
168+
isfragment: false,
169+
ishasmorefrags: false,
170+
islastfrag: false,
171+
kernel_timezone: false,
172+
line: "-A TEST-ANOTHER -p tcp -m comment --comment \"003 test -A in chain name\"",
173+
log_ip_options: false,
174+
log_tcp_options: false,
175+
log_tcp_sequence: false,
176+
log_uid: false,
177+
name: "003 test -A in chain name",
178+
notrack: false,
179+
physdev_is_bridged: false,
180+
physdev_is_in: false,
181+
physdev_is_out: false,
182+
proto: "tcp",
183+
protocol: "IPv4",
184+
queue_bypass: false,
185+
random: false,
186+
random_fully: false,
187+
rdest: false,
188+
reap: false,
189+
rsource: false,
190+
rttl: false,
191+
socket: false,
192+
table: "filter",
193+
time_contiguous: false},
194+
{chain: "TEST_ONE",
195+
checksum_fill: false,
196+
clamp_mss_to_pmtu: false,
197+
clusterip_new: false,
198+
ensure: "present",
199+
ipvs: false,
200+
isfirstfrag: false,
201+
isfragment: false,
202+
ishasmorefrags: false,
203+
islastfrag: false,
204+
kernel_timezone: false,
205+
line: "-A TEST_ONE -p tcp -m comment --comment \"foreign rule test\"",
206+
log_ip_options: false,
207+
log_tcp_options: false,
208+
log_tcp_sequence: false,
209+
log_uid: false,
210+
name: "9005 foreign rule test",
211+
notrack: false,
212+
physdev_is_bridged: false,
213+
physdev_is_in: false,
214+
physdev_is_out: false,
215+
proto: "tcp",
216+
protocol: "IPv4",
217+
queue_bypass: false,
218+
random: false,
219+
random_fully: false,
220+
rdest: false,
221+
reap: false,
222+
rsource: false,
223+
rttl: false,
224+
socket: false,
225+
table: "filter",
226+
time_contiguous: false},
227+
{chain: "OUTPUT",
228+
checksum_fill: false,
229+
clamp_mss_to_pmtu: false,
230+
clusterip_new: false,
231+
ensure: "present",
232+
ipvs: false,
233+
isfirstfrag: false,
234+
isfragment: false,
235+
ishasmorefrags: false,
236+
islastfrag: false,
237+
kernel_timezone: false,
238+
line: "-A OUTPUT -p tcp -m comment --comment \"004 test raw table rule\"",
239+
log_ip_options: false,
240+
log_tcp_options: false,
241+
log_tcp_sequence: false,
242+
log_uid: false,
243+
name: "004 test raw table rule",
244+
notrack: false,
245+
physdev_is_bridged: false,
246+
physdev_is_in: false,
247+
physdev_is_out: false,
248+
proto: "tcp",
249+
protocol: "IPv4",
250+
queue_bypass: false,
251+
random: false,
252+
random_fully: false,
253+
rdest: false,
254+
reap: false,
255+
rsource: false,
256+
rttl: false,
257+
socket: false,
258+
table: "raw",
259+
time_contiguous: false},
260+
{chain: "OUTPUT",
261+
checksum_fill: false,
262+
clamp_mss_to_pmtu: false,
263+
clusterip_new: false,
264+
ensure: "present",
265+
ipvs: false,
266+
isfirstfrag: false,
267+
isfragment: false,
268+
ishasmorefrags: false,
269+
islastfrag: false,
270+
kernel_timezone: false,
271+
line: "-A OUTPUT -p tcp -m comment --comment \"005 test ipv6 rule\"",
272+
log_ip_options: false,
273+
log_tcp_options: false,
274+
log_tcp_sequence: false,
275+
log_uid: false,
276+
name: "005 test ipv6 rule",
277+
notrack: false,
278+
physdev_is_bridged: false,
279+
physdev_is_in: false,
280+
physdev_is_out: false,
281+
proto: "tcp",
282+
protocol: "IPv6",
283+
queue_bypass: false,
284+
random: false,
285+
random_fully: false,
286+
rdest: false,
287+
reap: false,
288+
rsource: false,
289+
rttl: false,
290+
socket: false,
291+
table: "filter",
292+
time_contiguous: false},
293+
{chain: "TEST_TWO",
294+
checksum_fill: false,
295+
clamp_mss_to_pmtu: false,
296+
clusterip_new: false,
297+
ensure: "present",
298+
ipvs: false,
299+
isfirstfrag: false,
300+
isfragment: false,
301+
ishasmorefrags: false,
302+
islastfrag: false,
303+
kernel_timezone: false,
304+
line: "-A TEST_TWO -p tcp -m comment --comment \"006 test ipv6 rule in different table\"",
305+
log_ip_options: false,
306+
log_tcp_options: false,
307+
log_tcp_sequence: false,
308+
log_uid: false,
309+
name: "006 test ipv6 rule in different table",
310+
notrack: false,
311+
physdev_is_bridged: false,
312+
physdev_is_in: false,
313+
physdev_is_out: false,
314+
proto: "tcp",
315+
protocol: "IPv6",
316+
queue_bypass: false,
317+
random: false,
318+
random_fully: false,
319+
rdest: false,
320+
reap: false,
321+
rsource: false,
322+
rttl: false,
323+
socket: false,
324+
table: "raw",
325+
time_contiguous: false}
326+
]
327+
end
328+
329+
it 'processes the resource' do
330+
allow(Puppet::Util::Execution).to receive(:execute).with('iptables-save').and_return(iptables)
331+
allow(Puppet::Util::Execution).to receive(:execute).with('ip6tables-save').and_return(ip6tables)
332+
333+
expect(provider.get(context)).to eq(returned_data)
334+
end
335+
end
336+
end
337+
end

0 commit comments

Comments
 (0)