Skip to content
This repository was archived by the owner on Jan 15, 2025. It is now read-only.

Commit 0a068f6

Browse files
committed
Merge pull request #56 from chantra/ipv6
Support for IPv6
2 parents 15aa483 + 1a37646 commit 0a068f6

File tree

16 files changed

+354
-95
lines changed

16 files changed

+354
-95
lines changed

.kitchen.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,15 @@ suites:
1414
run_list:
1515
- recipe[smoke]
1616
attributes:
17+
- name: ipv6_default
18+
run_list:
19+
- recipe[smoke::ipv6_default]
20+
attributes:
1721
- name: list_of_tables
1822
run_list:
1923
- recipe[smoke::tables]
2024
attributes:
25+
- name: ipv6_list_of_tables
26+
run_list:
27+
- recipe[smoke::ipv6_tables]
28+
attributes:

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,37 @@ COMMIT
220220
# Completed
221221
```
222222

223+
`IPv6` support
224+
--------------
225+
226+
To support IPv6, you will need to add `ipv6` the attribute like:
227+
default["simple_iptables"]["ip_versions"] = ["ipv4", "ipv6"]
228+
229+
When using `simple_iptables_policy` or `simple_iptables_rule` resources, you
230+
can enable the policy/rule for either `:ipv4`, `:ipv6` or `:both` using the
231+
`ip_version` parameter. For example:
232+
233+
simple_iptables_rule "management_interface" do
234+
direction "INPUT"
235+
chain_condition "-i eth1"
236+
rule [ "-p tcp --dport 80", "-p tcp --dport 443" ]
237+
jump "ACCEPT"
238+
ip_version :both
239+
end
240+
241+
will set the rule for both IPv4 and IPv6,
242+
243+
simple_iptables_rule "management_interface" do
244+
direction "INPUT"
245+
chain_condition "-i eth1"
246+
rule [ "-p tcp --dport 80", "-p tcp --dport 443" ]
247+
jump "ACCEPT"
248+
ip_version :ipv6
249+
end
250+
251+
will set it for IPv6 only. The default is to set the rule/policy for ipv4 only.
252+
253+
223254
Example
224255
=======
225256

attributes/default.rb

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
default["simple_iptables"]["rules"] = {"filter" => [], "nat" => [], "mangle" => [], "raw" => []}
2-
default["simple_iptables"]["chains"] = {"filter" => [], "nat" => [], "mangle" => [], "raw" => []}
3-
default["simple_iptables"]["policy"] = {"filter" => {}, "nat" => {}, "mangle" => {}, "raw" => {}}
1+
default["simple_iptables"]["ipv4"]["rules"] = {"filter" => [], "nat" => [], "mangle" => [], "raw" => []}
2+
default["simple_iptables"]["ipv4"]["chains"] = {"filter" => [], "nat" => [], "mangle" => [], "raw" => []}
3+
default["simple_iptables"]["ipv4"]["policy"] = {"filter" => {}, "nat" => {}, "mangle" => {}, "raw" => {}}
4+
default["simple_iptables"]["ipv6"]["rules"] = {"filter" => [], "mangle" => [], "raw" => []}
5+
default["simple_iptables"]["ipv6"]["chains"] = {"filter" => [], "mangle" => [], "raw" => []}
6+
default["simple_iptables"]["ipv6"]["policy"] = {"filter" => {}, "mangle" => {}, "raw" => {}}
47

5-
default["simple_iptables"]["tables"] = %w(filter nat mangle raw)
8+
default["simple_iptables"]["ipv4"]["tables"] = %w(filter nat mangle raw)
9+
default["simple_iptables"]["ipv6"]["tables"] = %w(filter mangle raw)
10+
default["simple_iptables"]["ip_versions"] = ["ipv4"]

providers/policy.rb

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
action :set do
2-
Chef::Log.debug("setting policy for #{new_resource.chain} to #{new_resource.policy}")
3-
node.set["simple_iptables"]["policy"][new_resource.table][new_resource.chain] = new_resource.policy
2+
if [:ipv4, :both].include?(new_resource.ip_version)
3+
handle_policy(new_resource, "ipv4")
4+
end
5+
if [:ipv6, :both].include?(new_resource.ip_version)
6+
handle_policy(new_resource, "ipv6")
7+
end
8+
end
9+
10+
def handle_policy(new_resource, ip_version)
11+
Chef::Log.debug("[#{ip_version}] setting policy for #{new_resource.chain} to #{new_resource.policy}")
12+
node.set["simple_iptables"][ip_version]["policy"][new_resource.table][new_resource.chain] = new_resource.policy
413
new_resource.updated_by_last_action(true)
514
end

providers/rule.rb

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,39 @@
11
require 'chef/mixin/shell_out'
22
include Chef::Mixin::ShellOut
33

4+
45
action :append do
6+
if [:ipv4, :both].include?(new_resource.ip_version)
7+
handle_rule(new_resource, "ipv4")
8+
end
9+
if [:ipv6, :both].include?(new_resource.ip_version)
10+
handle_rule(new_resource, "ipv6")
11+
end
12+
end
13+
14+
def handle_rule(new_resource, ip_version)
515
if new_resource.rule.kind_of?(String)
616
rules = [new_resource.rule]
717
else
818
rules = new_resource.rule
919
end
10-
11-
if not node["simple_iptables"]["chains"][new_resource.table].include?(new_resource.chain)
12-
node.set["simple_iptables"]["chains"][new_resource.table] = node["simple_iptables"]["chains"][new_resource.table].dup << new_resource.chain unless ["PREROUTING", "INPUT", "FORWARD", "OUTPUT", "POSTROUTING"].include?(new_resource.chain)
20+
if not node["simple_iptables"][ip_version]["chains"][new_resource.table].include?(new_resource.chain)
21+
node.set["simple_iptables"][ip_version]["chains"][new_resource.table] = node["simple_iptables"][ip_version]["chains"][new_resource.table].dup << new_resource.chain unless ["PREROUTING", "INPUT", "FORWARD", "OUTPUT", "POSTROUTING"].include?(new_resource.chain)
1322
unless new_resource.chain == new_resource.direction || new_resource.direction == :none
14-
node.set["simple_iptables"]["rules"][new_resource.table] << {:rule => "-A #{new_resource.direction} #{new_resource.chain_condition} --jump #{new_resource.chain}", :weight => new_resource.weight}
23+
node.set["simple_iptables"][ip_version]["rules"][new_resource.table] << {:rule => "-A #{new_resource.direction} #{new_resource.chain_condition} --jump #{new_resource.chain}", :weight => new_resource.weight}
1524
end
1625
end
1726

1827
# Then apply the rules to the node
1928
rules.each do |rule|
2029
new_rule = rule_string(new_resource, rule, false)
21-
if not node["simple_iptables"]["rules"][new_resource.table].include?({:rule => new_rule, :weight => new_resource.weight})
22-
node.set["simple_iptables"]["rules"][new_resource.table] << {:rule => new_rule, :weight => new_resource.weight}
23-
node.set["simple_iptables"]["rules"][new_resource.table].sort! {|a,b| a[:weight] <=> b[:weight]}
30+
if not node["simple_iptables"][ip_version]["rules"][new_resource.table].include?({:rule => new_rule, :weight => new_resource.weight})
31+
node.set["simple_iptables"][ip_version]["rules"][new_resource.table] << {:rule => new_rule, :weight => new_resource.weight}
32+
node.set["simple_iptables"][ip_version]["rules"][new_resource.table].sort! {|a,b| a[:weight] <=> b[:weight]}
2433
new_resource.updated_by_last_action(true)
25-
Chef::Log.debug("added rule '#{new_rule}'")
34+
Chef::Log.debug("[#{ip_version}] added rule '#{new_rule}'")
2635
else
27-
Chef::Log.debug("ignoring duplicate simple_iptables_rule '#{new_rule}'")
36+
Chef::Log.debug("[#{ip_version}] ignoring duplicate simple_iptables_rule '#{new_rule}'")
2837
end
2938
end
3039
end

recipes/default.rb

Lines changed: 62 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,13 @@
3636
# Before executing the simple_iptables_* resources, reset the
3737
# node attributes to their defaults. This gives "action :delete"
3838
# semantics for free by removing a resource from a recipe.
39-
node.set["simple_iptables"]["chains"] = {"filter" => [], "nat" => [], "mangle" => [], "raw" => []}
40-
node.set["simple_iptables"]["rules"] = {"filter" => [], "nat" => [], "mangle" => [], "raw" => []}
41-
node.set["simple_iptables"]["policy"] = {"filter" => {}, "nat" => {}, "mangle" => {}, "raw" => {}}
39+
node.set["simple_iptables"]["ipv4"]["chains"] = {"filter" => [], "nat" => [], "mangle" => [], "raw" => []}
40+
node.set["simple_iptables"]["ipv4"]["rules"] = {"filter" => [], "nat" => [], "mangle" => [], "raw" => []}
41+
node.set["simple_iptables"]["ipv4"]["policy"] = {"filter" => {}, "nat" => {}, "mangle" => {}, "raw" => {}}
4242

43+
node.set["simple_iptables"]["ipv6"]["chains"] = {"filter" => [], "mangle" => [], "raw" => []}
44+
node.set["simple_iptables"]["ipv6"]["rules"] = {"filter" => [], "mangle" => [], "raw" => []}
45+
node.set["simple_iptables"]["ipv6"]["policy"] = {"filter" => {}, "mangle" => {}, "raw" => {}}
4346
# Then run all the simple_iptables_* resources
4447
run_context.resource_collection.each do |resource|
4548
if resource.kind_of?(Chef::Resource::SimpleIptablesRule)
@@ -55,66 +58,73 @@
5558
end
5659
end
5760

58-
case node['platform_family']
59-
when 'debian'
60-
iptable_rules = '/etc/iptables-rules'
61-
when 'rhel', 'fedora'
62-
iptable_rules = '/etc/sysconfig/iptables'
63-
end
61+
# maps protocol version to a character that will be used to differentiate
62+
# iptables* (ipv4) and ip6tables* (ipv6)
63+
v2s = {'ipv4' => '', 'ipv6' => '6'}
6464

65-
ruby_block "test-iptables" do
66-
block do
67-
cmd = Mixlib::ShellOut.new("iptables-restore --test < #{iptable_rules}",
68-
:user => "root")
69-
cmd.run_command
70-
if !Array(cmd.valid_exit_codes).include?(cmd.exitstatus)
71-
msg = <<-eos
72-
iptables-restore exited with code #{cmd.exitstatus} while testing new rules
65+
node["simple_iptables"]["ip_versions"].each do |ip_version|
66+
v = v2s[ip_version]
67+
case node['platform_family']
68+
when 'debian'
69+
iptable_rules = "/etc/ip#{v}tables-rules"
70+
when 'rhel', 'fedora'
71+
iptable_rules = "/etc/sysconfig/ip#{v}tables"
72+
end
73+
74+
ruby_block "test-ip#{v}tables" do
75+
block do
76+
cmd = Mixlib::ShellOut.new("ip#{v}tables-restore --test < #{iptable_rules}",
77+
:user => "root")
78+
cmd.run_command
79+
if !Array(cmd.valid_exit_codes).include?(cmd.exitstatus)
80+
msg = <<-eos
81+
ip#{v}tables-restore exited with code #{cmd.exitstatus} while testing new rules
7382
STDOUT:
7483
#{cmd.stdout}
7584
STDERR:
7685
#{cmd.stderr}
7786
eos
78-
match = cmd.stderr.match /line:?\s*(\d+)/
79-
if match
80-
line_no = match[1].to_i
81-
msg << "Line #{line_no}: #{IO.readlines(iptable_rules)[line_no-1]}"
87+
match = cmd.stderr.match /line:?\s*(\d+)/
88+
if match
89+
line_no = match[1].to_i
90+
msg << "Line #{line_no}: #{IO.readlines(iptable_rules)[line_no-1]}"
91+
end
92+
# Delete the file so that the next Chef run is forced to recreate it
93+
# and retest it. Otherwise, if the rules remain unchanged, the template
94+
# resource won't recreate the file, won't notify the test resource,
95+
# and the Chef run will be allowed to complete successfully despite
96+
# and invalid rule being present.
97+
File.delete(iptable_rules)
98+
raise msg
8299
end
83-
# Delete the file so that the next Chef run is forced to recreate it
84-
# and retest it. Otherwise, if the rules remain unchanged, the template
85-
# resource won't recreate the file, won't notify the test resource,
86-
# and the Chef run will be allowed to complete successfully despite
87-
# and invalid rule being present.
88-
File.delete(iptable_rules)
89-
raise msg
90100
end
101+
notifies :run, "execute[reload-ip#{v}tables]"
102+
action :nothing
91103
end
92-
notifies :run, "execute[reload-iptables]"
93-
action :nothing
94-
end
95-
96-
execute "reload-iptables" do
97-
command "iptables-restore < #{iptable_rules}"
98-
user "root"
99-
action :nothing
100-
end
101104

102-
template iptable_rules do
103-
source "iptables-rules.erb"
104-
cookbook "simple_iptables"
105-
notifies :create, "ruby_block[test-iptables]"
106-
action :create
107-
end
108-
109-
case node['platform_family']
110-
when 'debian'
105+
execute "reload-ip#{v}tables" do
106+
command "ip#{v}tables-restore < #{iptable_rules}"
107+
user "root"
108+
action :nothing
109+
end
111110

112-
# TODO: Generalize this for other platforms somehow
113-
file "/etc/network/if-up.d/iptables-rules" do
114-
owner "root"
115-
group "root"
116-
mode "0755"
117-
content "#!/bin/bash\niptables-restore < #{iptable_rules}\n"
111+
template iptable_rules do
112+
source "ip#{v}tables-rules.erb"
113+
cookbook "simple_iptables"
114+
notifies :create, "ruby_block[test-ip#{v}tables]"
118115
action :create
119116
end
117+
118+
case node['platform_family']
119+
when 'debian'
120+
# TODO: Generalize this for other platforms somehow
121+
file "/etc/network/if-up.d/ip#{v}tables-rules" do
122+
owner "root"
123+
group "root"
124+
mode "0755"
125+
content "#!/bin/bash\nip#{v}tables-restore < #{iptable_rules}\n"
126+
action :create
127+
end
128+
end
120129
end
130+

recipes/redhat.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,47 @@
33

44
simple_iptables_policy "INPUT" do
55
policy "ACCEPT"
6+
ip_version :ipv4
67
end
78

89
simple_iptables_rule "established" do
910
chain "INPUT"
1011
rule "-m conntrack --ctstate ESTABLISHED,RELATED"
1112
jump "ACCEPT"
1213
weight 1
14+
ip_version :ipv4
1315
end
1416

1517
simple_iptables_rule "icmp" do
1618
chain "INPUT"
1719
rule "--proto icmp"
1820
jump "ACCEPT"
1921
weight 2
22+
ip_version :ipv4
2023
end
2124

2225
simple_iptables_rule "loopback" do
2326
chain "INPUT"
2427
rule "--in-interface lo"
2528
jump "ACCEPT"
2629
weight 3
30+
ip_version :ipv4
2731
end
2832

2933
simple_iptables_rule "ssh" do
3034
chain "INPUT"
3135
rule "--proto tcp --dport 22 -m conntrack --ctstate NEW"
3236
jump "ACCEPT"
3337
weight 70
38+
ip_version :ipv4
3439
end
3540

3641
simple_iptables_rule "reject" do
3742
chain "INPUT"
3843
rule ""
3944
jump "REJECT --reject-with icmp-host-prohibited"
4045
weight 90
46+
ip_version :ipv4
4147
end
4248

4349
simple_iptables_rule "reject" do
@@ -46,4 +52,5 @@
4652
rule ""
4753
jump "REJECT --reject-with icmp-host-prohibited"
4854
weight 90
49-
end
55+
ip_version :ipv4
56+
end

resources/policy.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
attribute :chain, :name_attribute => true, :equal_to => ["INPUT", "FORWARD", "OUTPUT", "PREROUTING", "POSTROUTING"], :default => "INPUT"
44
attribute :table, :equal_to => ["filter", "nat", "mangle", "raw"], :default => "filter"
55
attribute :policy, :equal_to => ["ACCEPT", "DROP"], :required => true
6+
attribute :ip_version, :equal_to => [:ipv4, :ipv6, :both], :default => :ipv4
67

78

89
def initialize(*args)

resources/rule.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
attribute :direction, :equal_to => ["INPUT", "FORWARD", "OUTPUT", "PREROUTING", "POSTROUTING", :none], :default => "INPUT"
88
attribute :chain_condition, :kind_of => [String]
99
attribute :weight, :kind_of => Integer, :default => 50
10+
attribute :ip_version, :equal_to => [:ipv4, :ipv6, :both], :default => :ipv4
1011

1112
def initialize(*args)
1213
super

templates/default/ip6tables-rules.erb

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<% if node["simple_iptables"]["ipv6"]["tables"].include?('mangle') %>
2+
# This file generated by Chef. Changes will be overwritten.
3+
*mangle
4+
:PREROUTING <%= node["simple_iptables"]["ipv6"]["policy"]["mangle"]["PREROUTING"] || "ACCEPT" %> [0:0]<% if Gem::Version.new(/\d+(\.\d+(.\d+)?)?/.match(node["kernel"]["release"])[0]) > Gem::Version.new("2.6.35") -%>
5+
:INPUT <%= node["simple_iptables"]["ipv6"]["policy"]["mangle"]["INPUT"] || "ACCEPT" %> [0:0]<% end -%>
6+
:FORWARD <%= node["simple_iptables"]["ipv6"]["policy"]["mangle"]["FORWARD"] || "ACCEPT" %> [0:0]
7+
:OUTPUT <%= node["simple_iptables"]["ipv6"]["policy"]["mangle"]["OUTPUT"] || "ACCEPT" %> [0:0]
8+
:POSTROUTING <%= node["simple_iptables"]["ipv6"]["policy"]["mangle"]["POSTROUTING"] || "ACCEPT" %> [0:0]
9+
<% node["simple_iptables"]["ipv6"]["chains"]["mangle"].each do |chain| -%>
10+
:<%= chain %> - [0:0]
11+
<% end -%>
12+
<% node["simple_iptables"]["ipv6"]["rules"]["mangle"].each do |rule| -%>
13+
<%= rule[:rule] %>
14+
<% end -%>
15+
COMMIT
16+
# Completed
17+
<% end %>
18+
<% if node["simple_iptables"]["ipv6"]["tables"].include?('filter') %>
19+
# This file generated by Chef. Changes will be overwritten.
20+
*filter
21+
:INPUT <%= node["simple_iptables"]["ipv6"]["policy"]["filter"]["INPUT"] || "ACCEPT" %> [0:0]
22+
:FORWARD <%= node["simple_iptables"]["ipv6"]["policy"]["filter"]["FORWARD"] || "ACCEPT" %> [0:0]
23+
:OUTPUT <%= node["simple_iptables"]["ipv6"]["policy"]["filter"]["OUTPUT"] || "ACCEPT" %> [0:0]
24+
<% node["simple_iptables"]["ipv6"]["chains"]["filter"].each do |chain| -%>
25+
:<%= chain %> - [0:0]
26+
<% end -%>
27+
<% node["simple_iptables"]["ipv6"]["rules"]["filter"].each do |rule| -%>
28+
<%= rule[:rule] %>
29+
<% end -%>
30+
COMMIT
31+
# Completed
32+
<% end %>
33+
<% if node["simple_iptables"]["ipv6"]["tables"].include?('raw') %>
34+
# This file generated by Chef. Changes will be overwritten.
35+
*raw
36+
:PREROUTING <%= node["simple_iptables"]["ipv6"]["policy"]["raw"]["PREROUTING"] || "ACCEPT" %> [0:0]
37+
:OUTPUT <%= node["simple_iptables"]["ipv6"]["policy"]["raw"]["OUTPUT"] || "ACCEPT" %> [0:0]
38+
<% node["simple_iptables"]["ipv6"]["chains"]["raw"].each do |chain| -%>
39+
:<%= chain %> - [0:0]
40+
<% end -%>
41+
<% node["simple_iptables"]["ipv6"]["rules"]["raw"].each do |rule| -%>
42+
<%= rule[:rule] %>
43+
<% end -%>
44+
COMMIT
45+
# Completed
46+
<% end %>

0 commit comments

Comments
 (0)