So it can be parsed when specified mutliple times, as well as being configured.
The destination IP range is must in 'IP1-IP2' format. Values in the range must be valid IPv4 or IPv6 addresses. Requires the `iprange` feature.
-* `dst_type`: The destination address type. For example: `dst_type => 'LOCAL'`.
+* `dst_type`: The destination address type. Will accept a single element or an array. For example: `dst_type => ['LOCAL']`.
Valid values are:
* 'THROW': an unroutable address
* 'XRESOLVE: an unresolvable address
+ In addition, it accepts '--limit-iface-in' and '--limit-iface-out' flags. For example: `dst_type => ['LOCAL --limit-iface-in']`.
+
+ It can also be negated using '!'. For example: `dst_type => ['! LOCAL']`.
+
Requires the `address_type` feature.
* `ensure`: Ensures that the resource is present. Valid values are 'present', 'absent'. The default is 'present'.
* `src_range`: The source IP range. For example: `src_range => '192.168.1.1-192.168.1.10'`. The source IP range must be in 'IP1-IP2' format. Values in the range must be valid IPv4 or IPv6 addresses. Requires the `iprange` feature.
-* `src_type`: Specify the source address type. For example: `src_type => 'LOCAL'`.
+* `src_type`: Specify the source address type. Will accept a single element or an array. For example: `src_type => ['LOCAL']`.
Valid values are:
* 'THROW': an unroutable address.
* 'XRESOLVE': an unresolvable address.
+ In addition, it accepts '--limit-iface-in' and '--limit-iface-out' flags. For example: `dst_type => ['LOCAL --limit-iface-in']`.
+
+ It can also be negated using '!'. For example: `dst_type => ['! LOCAL']`.
+
Requires the `address_type` feature.
* `stat_every`: Match one packet every nth packet. Requires `stat_mode => 'nth'`
values = values.gsub(%r{-m comment --comment ([^"].*?)[ $]}, '')
values.insert(ind, "-m comment --comment \"#{comments.join(';')}\" ")
end
+ if values =~ %r{-m addrtype (!\s+)?--src-type}
+ values = values.gsub(%r{(!\s+)?--src-type (\S*)(\s--limit-iface-(in|out))?}, '--src-type \1\2\3')
+ ind = values.index('-m addrtype --src-type')
+ types = values.scan(%r{-m addrtype --src-type ((?:!\s+)?\S*(?: --limit-iface-(?:in|out))?)})
+ values = values.gsub(%r{-m addrtype --src-type ((?:!\s+)?\S*(?: --limit-iface-(?:in|out))?) ?}, '')
+ values.insert(ind, "-m addrtype --src-type \"#{types.join(';')}\" ")
+ end
+ if values =~ %r{-m addrtype (!\s+)?--dst-type}
+ values = values.gsub(%r{(!\s+)?--dst-type (\S*)(\s--limit-iface-(in|out))?}, '--dst-type \1\2\3')
+ ind = values.index('-m addrtype --dst-type')
+ types = values.scan(%r{-m addrtype --dst-type ((?:!\s+)?\S*(?: --limit-iface-(?:in|out))?)})
+ values = values.gsub(%r{-m addrtype --dst-type ((?:!\s+)?\S*(?: --limit-iface-(?:in|out))?) ?}, '')
+ values.insert(ind, "-m addrtype --dst-type \"#{types.join(';')}\" ")
+ end
# the actual rule will have the ! mark before the option.
values = values.gsub(%r{(!)\s*(-\S+)\s*(\S*)}, '\2 "\1 \3"')
# we do a similar thing for negated address masks (source and destination).
hash[prop] = hash[prop].split(',') unless hash[prop].nil?
end
- hash[:ipset] = hash[:ipset].split(';') unless hash[:ipset].nil?
+ [:ipset, :dst_type, :src_type].each do |prop|
+ hash[prop] = hash[prop].split(';') unless hash[prop].nil?
+ end
## clean up DSCP class to HEX mappings
valid_dscp_classes = {
:destination,
:dport,
:dst_range,
- :dst_type,
:port,
:physdev_is_bridged,
:physdev_is_in,
:source,
:sport,
:src_range,
- :src_type,
:state,
].each do |prop|
if hash[prop] && hash[prop].is_a?(Array)
raise "#{nflog_feature} is not available on iptables version #{iptables_version}" if resource[nflog_feature] && (iptables_version && iptables_version < '1.3.7')
end
+ [:dst_type, :src_type].each do |prop|
+ next unless resource[prop]
+
+ resource[prop].each do |type|
+ if type =~ %r{--limit-iface-(in|out)} && (iptables_version && iptables_version < '1.4.1')
+ raise '--limit-iface-in and --limit-iface-out are available from iptables version 1.4.1'
+ end
+ end
+
+ raise "Multiple #{prop} elements are available from iptables version 1.4.1" if resource[prop].length > 1 && (iptables_version && iptables_version < '1.4.1')
+ raise "#{prop} elements must be unique" if resource[prop].map { |type| type.to_s.gsub(%r{--limit-iface-(in|out)}, '') }.uniq.length != resource[prop].length
+ end
+
resource_list.each do |res|
resource_value = nil
if resource[res]
# ruby 1.8.7 can't .match Symbols ------------------ ^
resource_value = resource_value.to_s.sub!(%r{^!\s*}, '').to_sym
args.insert(-2, '!')
- elsif resource_value.is_a?(Array) && res != :ipset
+ elsif resource_value.is_a?(Array) && ![:ipset, :dst_type, :src_type].include?(res)
should_negate = resource_value.index do |value|
# ruby 1.8.7 can't .match symbols
value.to_s.match(%r{^(!)\s+})
end
# ipset can accept multiple values with weird iptables arguments
- if res == :ipset
+ if [:ipset, :dst_type, :src_type].include?(res)
resource_value.join(" #{[resource_map[res]].flatten.first} ").split(' ').each do |a|
if a.sub!(%r{^!\s*}, '')
# Negate ipset options
end
end
- newproperty(:dst_type, required_features: :address_type) do
+ newproperty(:dst_type, required_features: :address_type, array_matching: :all) do
desc <<-PUPPETCODE
The destination address type. For example:
- dst_type => 'LOCAL'
+ dst_type => ['LOCAL']
Can be one of:
* THROW - undocumented
* NAT - undocumented
* XRESOLVE - undocumented
+
+ In addition, it accepts '--limit-iface-in' and '--limit-iface-out' flags, specified as:
+
+ dst_type => ['LOCAL --limit-iface-in']
+
+ It can also be negated using '!':
+
+ dst_type => ['! LOCAL']
+
+ Will accept a single element or an array.
PUPPETCODE
newvalues(*[:UNSPEC, :UNICAST, :LOCAL, :BROADCAST, :ANYCAST, :MULTICAST,
:BLACKHOLE, :UNREACHABLE, :PROHIBIT, :THROW, :NAT, :XRESOLVE].map { |address_type|
- [address_type, "! #{address_type}".to_sym]
+ [
+ address_type,
+ "! #{address_type}".to_sym,
+ "#{address_type} --limit-iface-in".to_sym,
+ "#{address_type} --limit-iface-out".to_sym,
+ "! #{address_type} --limit-iface-in".to_sym,
+ "! #{address_type} --limit-iface-out".to_sym,
+ ]
}.flatten)
end
- newproperty(:src_type, required_features: :address_type) do
+ newproperty(:src_type, required_features: :address_type, array_matching: :all) do
desc <<-PUPPETCODE
The source address type. For example:
- src_type => 'LOCAL'
+ src_type => ['LOCAL']
Can be one of:
* THROW - undocumented
* NAT - undocumented
* XRESOLVE - undocumented
+
+ In addition, it accepts '--limit-iface-in' and '--limit-iface-out' flags, specified as:
+
+ src_type => ['LOCAL --limit-iface-in']
+
+ It can also be negated using '!':
+
+ src_type => ['! LOCAL']
+
+ Will accept a single element or an array.
PUPPETCODE
newvalues(*[:UNSPEC, :UNICAST, :LOCAL, :BROADCAST, :ANYCAST, :MULTICAST,
:BLACKHOLE, :UNREACHABLE, :PROHIBIT, :THROW, :NAT, :XRESOLVE].map { |address_type|
- [address_type, "! #{address_type}".to_sym]
+ [
+ address_type,
+ "! #{address_type}".to_sym,
+ "#{address_type} --limit-iface-in".to_sym,
+ "#{address_type} --limit-iface-out".to_sym,
+ "! #{address_type} --limit-iface-in".to_sym,
+ "! #{address_type} --limit-iface-out".to_sym,
+ ]
}.flatten)
end
end
end
end
+
+ context 'when LOCAL --limit-iface-in', unless: (fact('operatingsystem') == 'RedHat' && fact('operatingsystemmajrelease') <= '5') ||
+ (fact('operatingsystem') == 'CentOS' && fact('operatingsystemmajrelease') <= '5') do
+ pp97 = <<-PUPPETCODE
+ class { '::firewall': }
+ firewall { '613 - test':
+ proto => tcp,
+ action => accept,
+ #{type} => 'LOCAL --limit-iface-in',
+ }
+ PUPPETCODE
+ it 'applies' do
+ apply_manifest(pp97, catch_failures: true)
+ end
+
+ it 'contains the rule' do
+ shell('iptables-save') do |r|
+ expect(r.stdout).to match(%r{-A INPUT -p tcp -m addrtype\s.*\sLOCAL --limit-iface-in -m comment --comment "613 - test" -j ACCEPT})
+ end
+ end
+ end
+
+ context 'when LOCAL --limit-iface-in fail', if: (fact('operatingsystem') == 'RedHat' && fact('operatingsystemmajrelease') <= '5') ||
+ (fact('operatingsystem') == 'CentOS' && fact('operatingsystemmajrelease') <= '5') do
+ pp98 = <<-PUPPETCODE
+ class { '::firewall': }
+ firewall { '614 - test':
+ proto => tcp,
+ action => accept,
+ #{type} => 'LOCAL --limit-iface-in',
+ }
+ PUPPETCODE
+ it 'fails' do
+ apply_manifest(pp98, expect_failures: true) do |r|
+ expect(r.stderr).to match(%r{--limit-iface-in and --limit-iface-out are available from iptables version})
+ end
+ end
+
+ it 'does not contain the rule' do
+ shell('iptables-save') do |r|
+ expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m addrtype\s.*\sLOCAL --limit-iface-in -m comment --comment "614 - test" -j ACCEPT})
+ end
+ end
+ end
+
+ context 'when duplicated LOCAL', unless: (fact('operatingsystem') == 'RedHat' && fact('operatingsystemmajrelease') <= '5') ||
+ (fact('operatingsystem') == 'CentOS' && fact('operatingsystemmajrelease') <= '5') do
+ pp99 = <<-PUPPETCODE
+ class { '::firewall': }
+ firewall { '615 - test':
+ proto => tcp,
+ action => accept,
+ #{type} => ['LOCAL', 'LOCAL'],
+ }
+ PUPPETCODE
+ it 'fails' do
+ apply_manifest(pp99, expect_failures: true) do |r|
+ expect(r.stderr).to match(%r{#{type} elements must be unique})
+ end
+ end
+
+ it 'does not contain the rule' do
+ shell('iptables-save') do |r|
+ expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m addrtype --#{type.tr('_', '-')} LOCAL -m addrtype --#{type.tr('_', '-')} LOCAL -m comment --comment "615 - test" -j ACCEPT})
+ end
+ end
+ end
+
+ context 'when multiple addrtype', unless: (fact('operatingsystem') == 'RedHat' && fact('operatingsystemmajrelease') <= '5') ||
+ (fact('operatingsystem') == 'CentOS' && fact('operatingsystemmajrelease') <= '5') do
+ pp100 = <<-PUPPETCODE
+ class { '::firewall': }
+ firewall { '616 - test':
+ proto => tcp,
+ action => accept,
+ #{type} => ['LOCAL', '! LOCAL'],
+ }
+ PUPPETCODE
+ it 'applies' do
+ apply_manifest(pp100, catch_failures: true)
+ end
+
+ it 'contains the rule' do
+ shell('iptables-save') do |r|
+ expect(r.stdout).to match(%r{-A INPUT -p tcp -m addrtype --#{type.tr('_', '-')} LOCAL -m addrtype ! --#{type.tr('_', '-')} LOCAL -m comment --comment "616 - test" -j ACCEPT})
+ end
+ end
+ end
+
+ context 'when multiple addrtype fail', if: (fact('operatingsystem') == 'RedHat' && fact('operatingsystemmajrelease') <= '5') ||
+ (fact('operatingsystem') == 'CentOS' && fact('operatingsystemmajrelease') <= '5') do
+ pp101 = <<-PUPPETCODE
+ class { '::firewall': }
+ firewall { '616 - test':
+ proto => tcp,
+ action => accept,
+ #{type} => ['LOCAL', '! LOCAL'],
+ }
+ PUPPETCODE
+ it 'fails' do
+ apply_manifest(pp101, expect_failures: true) do |r|
+ expect(r.stderr).to match(%r{Multiple #{type} elements are available from iptables version})
+ end
+ end
+
+ it 'does not contain the rule' do
+ shell('iptables-save') do |r|
+ expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m addrtype --#{type.tr('_', '-')} LOCAL -m addrtype ! --#{type.tr('_', '-')} LOCAL -m comment --comment "616 - test" -j ACCEPT})
+ end
+ end
+ end
end
end
end
end
end
+
+ context 'when LOCAL --limit-iface-in', unless: (fact('operatingsystem') == 'RedHat' && fact('operatingsystemmajrelease') <= '5') ||
+ (fact('operatingsystem') == 'CentOS' && fact('operatingsystemmajrelease') <= '5') do
+ pp102 = <<-PUPPETCODE
+ class { '::firewall': }
+ firewall { '617 - test':
+ proto => tcp,
+ action => accept,
+ #{type} => 'LOCAL --limit-iface-in',
+ }
+ PUPPETCODE
+ it 'applies' do
+ apply_manifest(pp102, catch_failures: true)
+ end
+
+ it 'contains the rule' do
+ shell('iptables-save') do |r|
+ expect(r.stdout).to match(%r{-A INPUT -p tcp -m addrtype\s.*\sLOCAL --limit-iface-in -m comment --comment "617 - test" -j ACCEPT})
+ end
+ end
+ end
+
+ context 'when LOCAL --limit-iface-in fail', if: (fact('operatingsystem') == 'RedHat' && fact('operatingsystemmajrelease') <= '5') ||
+ (fact('operatingsystem') == 'CentOS' && fact('operatingsystemmajrelease') <= '5') do
+ pp103 = <<-PUPPETCODE
+ class { '::firewall': }
+ firewall { '618 - test':
+ proto => tcp,
+ action => accept,
+ #{type} => 'LOCAL --limit-iface-in',
+ }
+ PUPPETCODE
+ it 'fails' do
+ apply_manifest(pp103, expect_failures: true) do |r|
+ expect(r.stderr).to match(%r{--limit-iface-in and --limit-iface-out are available from iptables version})
+ end
+ end
+
+ it 'does not contain the rule' do
+ shell('iptables-save') do |r|
+ expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m addrtype\s.*\sLOCAL --limit-iface-in -m comment --comment "618 - test" -j ACCEPT})
+ end
+ end
+ end
+
+ context 'when duplicated LOCAL', unless: (fact('operatingsystem') == 'RedHat' && fact('operatingsystemmajrelease') <= '5') ||
+ (fact('operatingsystem') == 'CentOS' && fact('operatingsystemmajrelease') <= '5') do
+ pp104 = <<-PUPPETCODE
+ class { '::firewall': }
+ firewall { '619 - test':
+ proto => tcp,
+ action => accept,
+ #{type} => ['LOCAL', 'LOCAL'],
+ provider => 'ip6tables',
+ }
+ PUPPETCODE
+ it 'fails' do
+ apply_manifest(pp104, expect_failures: true) do |r|
+ expect(r.stderr).to match(%r{#{type} elements must be unique})
+ end
+ end
+
+ it 'does not contain the rule' do
+ shell('ip6tables-save') do |r|
+ expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m addrtype\s.*\sLOCAL -m addrtype\s.*\sLOCAL -m comment --comment "619 - test" -j ACCEPT})
+ end
+ end
+ end
+
+ context 'when multiple addrtype', unless: (fact('operatingsystem') == 'RedHat' && fact('operatingsystemmajrelease') <= '5') ||
+ (fact('operatingsystem') == 'CentOS' && fact('operatingsystemmajrelease') <= '5') do
+ pp105 = <<-PUPPETCODE
+ class { '::firewall': }
+ firewall { '620 - test':
+ proto => tcp,
+ action => accept,
+ #{type} => ['LOCAL', '! LOCAL'],
+ provider => 'ip6tables',
+ }
+ PUPPETCODE
+ it 'applies' do
+ apply_manifest(pp105, catch_failures: true)
+ end
+
+ it 'contains the rule' do
+ shell('ip6tables-save') do |r|
+ expect(r.stdout).to match(%r{-A INPUT -p tcp -m addrtype --#{type.tr('_', '-')} LOCAL -m addrtype ! --#{type.tr('_', '-')} LOCAL -m comment --comment "620 - test" -j ACCEPT})
+ end
+ end
+ end
+
+ context 'when multiple addrtype fail', if: (fact('operatingsystem') == 'RedHat' && fact('operatingsystemmajrelease') <= '5') ||
+ (fact('operatingsystem') == 'CentOS' && fact('operatingsystemmajrelease') <= '5') do
+ pp106 = <<-PUPPETCODE
+ class { '::firewall': }
+ firewall { '616 - test':
+ proto => tcp,
+ action => accept,
+ #{type} => ['LOCAL', '! LOCAL'],
+ provider => 'ip6tables',
+ }
+ PUPPETCODE
+ it 'fails' do
+ apply_manifest(pp106, expect_failures: true) do |r|
+ expect(r.stderr).to match(%r{Multiple #{type} elements are available from iptables version})
+ end
+ end
+
+ it 'does not contain the rule' do
+ shell('ip6tables-save') do |r|
+ expect(r.stdout).not_to match(%r{-A INPUT -p tcp -m addrtype --#{type.tr('_', '-')} LOCAL -m addrtype ! --#{type.tr('_', '-')} LOCAL -m comment --comment "616 - test" -j ACCEPT})
+ end
+ end
+ end
end
end
end
line: '-A INPUT -m addrtype --dst-type LOCAL',
table: 'filter',
params: {
- dst_type: 'LOCAL',
+ dst_type: ['LOCAL'],
},
},
'src_type_1' => {
line: '-A INPUT -m addrtype --src-type LOCAL',
table: 'filter',
params: {
- src_type: 'LOCAL',
+ src_type: ['LOCAL'],
},
},
'dst_range_1' => {
action: 'drop',
},
},
+ 'addrtype_limit_iface_out' => {
+ line: '-A cali-POSTROUTING -o tunl0 -m comment --comment "000 cali:JHlpT-eSqR1TvyYm" -m addrtype --src-type LOCAL --limit-iface-out -j MASQUERADE',
+ table: 'filter',
+ params: {
+ chain: 'cali-POSTROUTING',
+ outiface: 'tunl0',
+ name: '000 cali:JHlpT-eSqR1TvyYm',
+ jump: 'MASQUERADE',
+ src_type: ['LOCAL --limit-iface-out'],
+ },
+ },
+ 'addrtype_negated' => {
+ line: '-A cali-POSTROUTING -o tunl0 -m comment --comment "000 cali:JHlpT-eSqR1TvyYm" -m addrtype ! --src-type LOCAL -j MASQUERADE',
+ table: 'filter',
+ params: {
+ chain: 'cali-POSTROUTING',
+ outiface: 'tunl0',
+ name: '000 cali:JHlpT-eSqR1TvyYm',
+ jump: 'MASQUERADE',
+ src_type: ['! LOCAL'],
+ },
+ },
+ 'addrtype_multiple' => {
+ line: '-A cali-POSTROUTING -o tunl0 -m comment --comment "000 cali:JHlpT-eSqR1TvyYm" -m addrtype ! --src-type LOCAL --limit-iface-out -m addrtype --src-type LOCAL -j MASQUERADE',
+ table: 'filter',
+ params: {
+ chain: 'cali-POSTROUTING',
+ outiface: 'tunl0',
+ name: '000 cali:JHlpT-eSqR1TvyYm',
+ jump: 'MASQUERADE',
+ src_type: ['! LOCAL --limit-iface-out', 'LOCAL'],
+ },
+ },
'iniface_1_negated' => {
line: '-A INPUT ! -i eth0 -j DROP -m comment --comment "060 iniface"',
table: 'filter',
table: 'filter',
dst_type: 'LOCAL',
},
- args: ['-t', :filter, '-p', :tcp, '-m', 'addrtype', '--dst-type', :LOCAL, '-m', 'comment', '--comment', '000 dst_type'],
+ args: ['-t', :filter, '-p', :tcp, '-m', 'addrtype', '--dst-type', 'LOCAL', '-m', 'comment', '--comment', '000 dst_type'],
+ },
+ 'dst_type_as_array' => {
+ params: {
+ name: '000 dst_type',
+ table: 'filter',
+ dst_type: ['LOCAL'],
+ },
+ args: ['-t', :filter, '-p', :tcp, '-m', 'addrtype', '--dst-type', 'LOCAL', '-m', 'comment', '--comment', '000 dst_type'],
+ },
+ 'dst_type_multiple' => {
+ params: {
+ name: '000 dst_type',
+ table: 'filter',
+ dst_type: ['LOCAL', '! LOCAL'],
+ },
+ args: ['-t', :filter, '-p', :tcp, '-m', 'addrtype', '--dst-type', 'LOCAL', '-m', 'addrtype', '!', '--dst-type', 'LOCAL', '-m', 'comment', '--comment', '000 dst_type'],
+ },
+ 'dst_type_limit' => {
+ params: {
+ name: '000 dst_type',
+ table: 'filter',
+ dst_type: ['LOCAL --limit-iface-in'],
+ },
+ args: ['-t', :filter, '-p', :tcp, '-m', 'addrtype', '--dst-type', 'LOCAL', '--limit-iface-in', '-m', 'comment', '--comment', '000 dst_type'],
},
'src_type_1' => {
params: {
table: 'filter',
src_type: 'LOCAL',
},
- args: ['-t', :filter, '-p', :tcp, '-m', 'addrtype', '--src-type', :LOCAL, '-m', 'comment', '--comment', '000 src_type'],
+ args: ['-t', :filter, '-p', :tcp, '-m', 'addrtype', '--src-type', 'LOCAL', '-m', 'comment', '--comment', '000 src_type'],
+ },
+ 'src_type_as_array' => {
+ params: {
+ name: '000 src_type',
+ table: 'filter',
+ src_type: ['LOCAL'],
+ },
+ args: ['-t', :filter, '-p', :tcp, '-m', 'addrtype', '--src-type', 'LOCAL', '-m', 'comment', '--comment', '000 src_type'],
+ },
+ 'src_type_multiple' => {
+ params: {
+ name: '000 src_type',
+ table: 'filter',
+ src_type: ['LOCAL', '! LOCAL'],
+ },
+ args: ['-t', :filter, '-p', :tcp, '-m', 'addrtype', '--src-type', 'LOCAL', '-m', 'addrtype', '!', '--src-type', 'LOCAL', '-m', 'comment', '--comment', '000 src_type'],
},
'dst_range_1' => {
params: {
[:UNSPEC, :UNICAST, :LOCAL, :BROADCAST, :ANYCAST, :MULTICAST, :BLACKHOLE,
:UNREACHABLE, :PROHIBIT, :THROW, :NAT, :XRESOLVE].each do |type|
- it "should accept #{addrtype} value #{type}" do
- resource[addrtype] = type
- expect(resource[addrtype]).to eql type
+ ['! ', ''].each do |negation|
+ ['', ' --limit-iface-in', ' --limit-iface-out'].each do |limit|
+ it "should accept #{addrtype} value #{negation}#{type}#{limit}" do
+ resource[addrtype] = type
+ expect(resource[addrtype]).to eql [type]
+ end
+ end
end
end