Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(Modules 3329) Add support for iptables length and string extensions #630

Merged
merged 4 commits into from
May 5, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -410,12 +410,12 @@ This type enables you to manage firewall rules within Puppet.

* `ip6tables`: Ip6tables type provider
* Required binaries: `ip6tables-save`, `ip6tables`.
* Supported features: `address_type`, `connection_limiting`, `dnat`, `hop_limiting`, `icmp_match`, `interface_match`, `iprange`, `ipsec_dir`, `ipsec_policy`, `ipset`, `iptables`, `isfirstfrag`, `ishasmorefrags`, `islastfrag`, `log_level`, `log_prefix`, `log_uid`, `mark`, `mask`, `mss`, `owner`, `pkttype`, `rate_limiting`, `recent_limiting`, `reject_type`, `snat`, `socket`, `state_match`, `tcp_flags`.
* Supported features: `address_type`, `connection_limiting`, `dnat`, `hop_limiting`, `icmp_match`, `interface_match`, `iprange`, `ipsec_dir`, `ipsec_policy`, `ipset`, `iptables`, `isfirstfrag`, `ishasmorefrags`, `islastfrag`, `length`, `log_level`, `log_prefix`, `log_uid`, `mark`, `mask`, `mss`, `owner`, `pkttype`, `rate_limiting`, `recent_limiting`, `reject_type`, `snat`, `socket`, `state_match`, `string_matching`, `tcp_flags`.

* `iptables`: Iptables type provider
* Required binaries: `iptables-save`, `iptables`.
* Default for `kernel` == `linux`.
* Supported features: `address_type`, `clusterip`, `connection_limiting`, `dnat`, `icmp_match`, `interface_match`, `iprange`, `ipsec_dir`, `ipsec_policy`, `ipset`, `iptables`, `isfragment`, `log_level`, `log_prefix`, `log_uid`, `mark`, `mask`, `mss`, `netmap`, `owner`, `pkttype`, `rate_limiting`, `recent_limiting`, `reject_type`, `snat`, `socket`, `state_match`, `tcp_flags`.
* Supported features: `address_type`, `clusterip`, `connection_limiting`, `dnat`, `icmp_match`, `interface_match`, `iprange`, `ipsec_dir`, `ipsec_policy`, `ipset`, `iptables`, `isfragment`, `length`, `log_level`, `log_prefix`, `log_uid`, `mark`, `mask`, `mss`, `netmap`, `owner`, `pkttype`, `rate_limiting`, `recent_limiting`, `reject_type`, `snat`, `socket`, `state_match`, `string_matching`, `tcp_flags`.

**Autorequires:**

Expand Down Expand Up @@ -455,6 +455,8 @@ If Puppet is managing the iptables or iptables-persistent packages, and the prov

* `islastfrag`: The ability to match the last fragment of an ipv6 packet.

* `length`: The ability to match the length of the layer-3 payload.

* `log_level`: The ability to control the log level.

* `log_prefix`: The ability to add prefixes to log messages.
Expand Down Expand Up @@ -483,6 +485,8 @@ If Puppet is managing the iptables or iptables-persistent packages, and the prov

* `state_match`: The ability to match stateful firewall states.

* `string_matching`: The ability to match a given string by using some pattern matching strategy.

* `tcp_flags`: The ability to match on particular TCP flag settings.

* `netmap`: The ability to map entire subnets via source or destination nat rules.
Expand Down Expand Up @@ -590,6 +594,8 @@ If Puppet is managing the iptables or iptables-persistent packages, and the prov

* `kernel_timezone`: Use the kernel timezone instead of UTC to determine whether a packet meets the time regulations.

* `length`: Set the value for matching the length of the layer-3 payload. Can be a single number or a range using '-' as a separator. Requires the `length` feature.

* `limit`: Rate limiting value for matched packets. The format is: 'rate/[/second/|/minute|/hour|/day]'. Example values are: '50/sec', '40/min', '30/hour', '10/day'. Requires the `rate_limiting` feature.

* `line`: Read-only property for caching the rule line.
Expand Down Expand Up @@ -743,6 +749,14 @@ firewall { '101 blacklist strange traffic':

* `state`: Matches a packet based on its state in the firewall stateful inspection table. Valid values are: 'INVALID', 'ESTABLISHED', 'NEW', 'RELATED'. Requires the `state_match` feature.

* `string`: Set the pattern for string matching. Requires the `string_matching` feature.

* `string_algo`: Used in conjunction with `string`, select the pattern matching strategy. Valid values are: 'bm', 'kmp' (bm = Boyer-Moore, kmp = Knuth-Pratt-Morris). Requires the `string_matching` feature.

* `string_from`: Used in conjunction with `string`, set the offset from which it starts looking for any matching. Requires the `string_matching` feature.

* `string_to`: Used in conjunction with `string`, set the offset up to which should be scanned. Requires the `string_matching` feature.

* `table`: Table to use. Valid values are: 'nat', 'mangle', 'filter', 'raw', 'rawpost'. By default the setting is 'filter'. Requires the `iptables` feature.

* `tcp_flags`: Match when the TCP flags are as specified. Set as a string with a list of comma-separated flag names for the mask, then a space, then a comma-separated list of flags that should be set. The flags are: 'SYN', 'ACK', 'FIN', 'RST', 'URG', 'PSH', 'ALL', 'NONE'.
Expand Down
12 changes: 10 additions & 2 deletions lib/puppet/provider/firewall/ip6tables.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
has_feature :ipsec_policy
has_feature :mask
has_feature :ipset
has_feature :length
has_feature :string_matching

optional_commands({
:ip6tables => 'ip6tables',
Expand Down Expand Up @@ -89,6 +91,7 @@ def self.iptables_save(*args)
:ishasmorefrags => "-m frag --fragid 0 --fragmore",
:islastfrag => "-m frag --fragid 0 --fraglast",
:jump => "-j",
:length => "-m length --length",
:limit => "-m limit --limit",
:log_level => "--log-level",
:log_prefix => "--log-prefix",
Expand Down Expand Up @@ -125,6 +128,10 @@ def self.iptables_save(*args)
:stat_packet => '--packet',
:stat_probability => '--probability',
:state => "-m state --state",
:string => "-m string --string",
:string_algo => "--algo",
:string_from => "--from",
:string_to => "--to",
:table => "-t",
:tcp_flags => "-m tcp --tcp-flags",
:todest => "--to-destination",
Expand Down Expand Up @@ -221,8 +228,9 @@ def self.iptables_save(*args)
:physdev_out, :physdev_is_bridged, :proto, :ishasmorefrags, :islastfrag, :isfirstfrag, :src_range, :dst_range,
:tcp_flags, :uid, :gid, :mac_source, :sport, :dport, :port, :src_type,
:dst_type, :socket, :pkttype, :name, :ipsec_dir, :ipsec_policy, :state,
:ctstate, :icmp, :hop_limit, :limit, :burst, :recent, :rseconds, :reap,
:rhitcount, :rttl, :rname, :mask, :rsource, :rdest, :ipset, :jump, :clamp_mss_to_pmtu, :gateway, :todest,
:ctstate, :icmp, :hop_limit, :limit, :burst, :length, :recent, :rseconds, :reap,
:rhitcount, :rttl, :rname, :mask, :rsource, :rdest, :ipset, :string, :string_algo,
:string_from, :string_to, :jump, :clamp_mss_to_pmtu, :gateway, :todest,
:tosource, :toports, :checksum_fill, :log_level, :log_prefix, :log_uid, :reject, :set_mss, :set_dscp, :set_dscp_class, :mss,
:set_mark, :match_mark, :connlimit_above, :connlimit_mask, :connmark, :time_start, :time_stop, :month_days, :week_days, :date_start, :date_stop, :time_contiguous, :kernel_timezone]

Expand Down
15 changes: 13 additions & 2 deletions lib/puppet/provider/firewall/iptables.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
has_feature :mask
has_feature :ipset
has_feature :clusterip
has_feature :length
has_feature :string_matching

optional_commands({
:iptables => 'iptables',
Expand Down Expand Up @@ -74,6 +76,7 @@
:isfragment => "-f",
:jump => "-j",
:goto => "-g",
:length => "-m length --length",
:limit => "-m limit --limit",
:log_level => "--log-level",
:log_prefix => "--log-prefix",
Expand Down Expand Up @@ -111,6 +114,10 @@
:stat_packet => '--packet',
:stat_probability => '--probability',
:state => "-m state --state",
:string => "-m string --string",
:string_algo => "--algo",
:string_from => "--from",
:string_to => "--to",
:table => "-t",
:tcp_flags => "-m tcp --tcp-flags",
:todest => "--to-destination",
Expand Down Expand Up @@ -255,8 +262,9 @@ def munge_resource_map_from_resource(resource_map_original, compare)
:stat_mode, :stat_every, :stat_packet, :stat_probability,
:src_range, :dst_range, :tcp_flags, :uid, :gid, :mac_source, :sport, :dport, :port,
:src_type, :dst_type, :socket, :pkttype, :name, :ipsec_dir, :ipsec_policy,
:state, :ctstate, :icmp, :limit, :burst, :recent, :rseconds, :reap,
:rhitcount, :rttl, :rname, :mask, :rsource, :rdest, :ipset, :jump, :goto, :clusterip_new, :clusterip_hashmode,
:state, :ctstate, :icmp, :limit, :burst, :length, :recent, :rseconds, :reap,
:rhitcount, :rttl, :rname, :mask, :rsource, :rdest, :ipset, :string, :string_algo,
:string_from, :string_to, :jump, :goto, :clusterip_new, :clusterip_hashmode,
:clusterip_clustermac, :clusterip_total_nodes, :clusterip_local_node, :clusterip_hash_init,
:clamp_mss_to_pmtu, :gateway, :set_mss, :set_dscp, :set_dscp_class, :todest, :tosource, :toports, :to, :checksum_fill, :random, :log_prefix,
:log_level, :log_uid, :reject, :set_mark, :match_mark, :mss, :connlimit_above, :connlimit_mask, :connmark, :time_start, :time_stop,
Expand Down Expand Up @@ -487,6 +495,9 @@ def self.rule_to_hash(line, table, counter)
elem.gsub(/:/,'-')
end
end
if hash[:length]
hash[:length].gsub!(/:/,'-')
end

# Invert any rules that are prefixed with a '!'
[
Expand Down
62 changes: 62 additions & 0 deletions lib/puppet/type/firewall.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
feature :mask, "Ability to match recent rules based on the ipv4 mask"
feature :ipset, "Match against specified ipset list"
feature :clusterip, "Configure a simple cluster of nodes that share a certain IP and MAC address without an explicit load balancer in front of them."
feature :length, "Match the length of layer-3 payload"
feature :string_matching, "String matching features"

# provider specific features
feature :iptables, "The provider provides iptables features."
Expand Down Expand Up @@ -1386,6 +1388,66 @@ def insync?(is)
EOS
end

newproperty(:length, :required_features => :length) do
desc <<-EOS
Sets the length of layer-3 payload to match.
EOS

munge do |value|
match = value.to_s.match("^([0-9]+)(-)?([0-9]+)?$")
if match.nil?
raise ArgumentError, "Length value must either be an integer or a range"
end

low = match[1].to_i
if !match[3].nil?
high = match[3].to_i
end

if (low < 0 or low > 65535) or \
(!high.nil? and (high < 0 or high > 65535 or high < low))
raise ArgumentError, "Length values must be between 0 and 65535"
end

value = low.to_s
if !high.nil?
value << ":" << high.to_s
end
value
end
end

newproperty(:string, :required_features => :string_matching) do
desc <<-EOS
String matching feature. Matches the packet against the pattern
given as an argument.
EOS

munge do |value|
value = "'" + value + "'"
end
end

newproperty(:string_algo, :required_features => :string_matching) do
desc <<-EOS
String matching feature, pattern matching strategy.
EOS

newvalues(:bm, :kmp)
end

newproperty(:string_from, :required_features => :string_matching) do
desc <<-EOS
String matching feature, offset from which we start looking for any matching.
EOS
end

newproperty(:string_to, :required_features => :string_matching) do
desc <<-EOS
String matching feature, offset up to which we should scan.
EOS
end


autorequire(:firewallchain) do
reqs = []
Expand Down
80 changes: 80 additions & 0 deletions spec/fixtures/iptables/conversion_hash.rb
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,43 @@
:chain => 'foo-filter',
},
},
'length_1' => {
:line => '-A INPUT -m length --length 42000',
:table => 'filter',
:params => {
:length => '42000',
},
},
'length_2' => {
:line => '-A INPUT -m length --length 1492:65535',
:table => 'filter',
:params => {
:length => '1492-65535',
},
},
'string_matching_1' => {
:line => '-A INPUT -m string --string "GET /index.html"',
:table => 'filter',
:params => {
:string => 'GET /index.html',
},
},
'string_matching_2' => {
:line => '-A INPUT -m string --string "GET /index.html" --algo bm',
:table => 'filter',
:params => {
:string => 'GET /index.html',
:string_algo => 'bm',
},
},
'string_matching_3' => {
:line => '-A INPUT -m string --string "GET /index.html" --from 1',
:table => 'filter',
:params => {
:string => 'GET /index.html',
:string_from => '1',
},
},
}

# This hash is for testing converting a hash to an argument line.
Expand Down Expand Up @@ -1126,4 +1163,47 @@
},
:args => ["-t", :mangle, "-p", :tcp, "-m", "multiport", '--ports', '997', "-m", "comment", "--comment", "068 set dscp class to EF", "-j", "DSCP", "--set-dscp-class", "ef"],
},
'length_1' => {
:params => {
:name => '000 length',
:table => 'filter',
:length => '42000',
},
:args => ["-t", :filter, "-p", :tcp, "-m", "comment", "--comment", "000 length", "-m", "length", "--length", "42000"],
},
'length_2' => {
:params => {
:name => '000 length',
:table => 'filter',
:length => '1492-65535',
},
:args => ["-t", :filter, "-p", :tcp, "-m", "comment", "--comment", "000 length", "-m", "length", "--length", "1492:65535"],
},
'string_matching_1' => {
:params => {
:name => '000 string_matching',
:table => 'filter',
:string => 'GET /index.html',
},
:args => ["-t", :filter, "-p", :tcp, "-m", "comment", "--comment", "000 string_matching", "-m", "string", "--string", "'GET /index.html'"],
},
'string_matching_2' => {
:params => {
:name => '000 string_matching',
:table => 'filter',
:string => 'GET /index.html',
:string_algo => 'bm',
},
:args => ["-t", :filter, "-p", :tcp, "-m", "comment", "--comment", "000 string_matching", "-m", "string", "--string", "'GET /index.html'", "--algo", :bm],
},
'string_matching_3' => {
:params => {
:name => '000 string_matching',
:table => 'filter',
:string => 'GET /index.html',
:string_from => '1',
:string_to => '65535',
},
:args => ["-t", :filter, "-p", :tcp, "-m", "comment", "--comment", "000 string_matching", "-m", "string", "--string", "'GET /index.html'", "--from", "1", "--to", "65535"],
},
}