X-Git-Url: https://git.openstreetmap.org./chef.git/blobdiff_plain/96c566d024d5a3fb1d97a5ceff3d7230ca048c30..7e75c0595594b2b5ddac50991f6cd0f7e61633ad:/cookbooks/networking/resources/firewall_rule.rb diff --git a/cookbooks/networking/resources/firewall_rule.rb b/cookbooks/networking/resources/firewall_rule.rb index 348272af7..22bde6ca9 100644 --- a/cookbooks/networking/resources/firewall_rule.rb +++ b/cookbooks/networking/resources/firewall_rule.rb @@ -17,59 +17,132 @@ # limitations under the License. # +require "ipaddr" + resource_name :firewall_rule provides :firewall_rule +unified_mode true + default_action :nothing property :rule, :kind_of => String, :name_property => true -property :family, :kind_of => [String, Symbol] -property :source, :kind_of => String, :required => true -property :dest, :kind_of => String, :required => true -property :proto, :kind_of => String, :required => true -property :dest_ports, :kind_of => [String, Integer], :default => "-" -property :source_ports, :kind_of => [String, Integer], :default => "-" -property :rate_limit, :kind_of => String, :default => "-" -property :connection_limit, :kind_of => String, :default => "-" -property :helper, :kind_of => String, :default => "-" +property :context, :kind_of => Symbol, :required => true, :is => [:incoming, :outgoing] +property :protocol, :kind_of => Symbol, :required => true, :is => [:udp, :tcp] +property :source, :kind_of => [String, Symbol, Array] +property :dest, :kind_of => [String, Symbol, Array] +property :dest_ports, :kind_of => [String, Integer, Array] +property :source_ports, :kind_of => [String, Integer, Array] +property :rate_limit, :kind_of => String +property :connection_limit, :kind_of => [String, Integer] +property :helper, :kind_of => String + +property :compile_time, TrueClass, :default => true action :accept do - add_rule :accept + add_rule(:accept, "ip") + add_rule(:accept, "ip6") end action :drop do - add_rule :drop + add_rule(:drop, "ip") + add_rule(:drop, "ip6") end action :reject do - add_rule :reject + add_rule(:reject, "ip") + add_rule(:reject, "ip6") end action_class do - def add_rule(action) - rule = { - :action => action.to_s.upcase, - :source => new_resource.source, - :dest => new_resource.dest, - :proto => new_resource.proto, - :dest_ports => new_resource.dest_ports.to_s, - :source_ports => new_resource.source_ports.to_s, - :rate_limit => new_resource.rate_limit, - :connection_limit => new_resource.connection_limit, - :helper => new_resource.helper - } - - if new_resource.family.nil? - node.default[:networking][:firewall][:inet] << rule - node.default[:networking][:firewall][:inet6] << rule - elsif new_resource.family.to_s == "inet" - node.default[:networking][:firewall][:inet] << rule - elsif new_resource.family.to_s == "inet6" - node.default[:networking][:firewall][:inet6] << rule + def add_rule(action, ip) + rule = [] + + protocol = new_resource.protocol.to_s + + source = addresses(new_resource.source, ip) + dest = addresses(new_resource.dest, ip) + + return if new_resource.source && source.empty? + return if new_resource.dest && dest.empty? + + rule << "#{protocol} sport #{format_ports(new_resource.source_ports)}" if new_resource.source_ports + rule << "#{protocol} dport #{format_ports(new_resource.dest_ports)}" if new_resource.dest_ports + rule << "#{ip} saddr #{format_addresses(source, ip)}" if new_resource.source + rule << "#{ip} daddr #{format_addresses(dest, ip)}" if new_resource.dest + rule << "ct state new" if new_resource.protocol == :tcp + + if new_resource.connection_limit + set = "connlimit-#{new_resource.rule}-#{ip}" + + node.default[:networking][:firewall][:sets] << { + :name => set, :type => set_type(ip), :flags => %w[dynamic] + } + + rule << "add @#{set} { #{ip} saddr ct count #{new_resource.connection_limit} }" + end + + if new_resource.rate_limit =~ %r{^s:(\d+)/sec:(\d+)$} + set = "ratelimit-#{new_resource.rule}-#{ip}" + rate = Regexp.last_match(1) + burst = Regexp.last_match(2) + + node.default[:networking][:firewall][:sets] << { + :name => set, :type => set_type(ip), :flags => %w[dynamic], :timeout => 120 + } + + rule << "update @#{set} { #{ip} saddr limit rate #{rate}/second burst #{burst} packets }" + end + + if new_resource.helper + helper = "#{new_resource.rule}-#{new_resource.helper}" + + node.default[:networking][:firewall][:helpers] << { + :name => helper, :helper => new_resource.helper, :protocol => protocol + } + + rule << "ct helper set #{helper}" + end + + rule << case action + when :accept then "accept" + when :drop then "jump log-and-drop" + when :reject then "jump log-and-reject" + end + + node.default[:networking][:firewall][new_resource.context] << rule.join(" ") + end + + def addresses(addresses, ip) + if addresses.is_a?(Symbol) + addresses + else + Array(addresses).map do |address| + if ip == "ip" && IPAddr.new(address.to_s).ipv4? + address + elsif ip == "ip6" && IPAddr.new(address.to_s).ipv6? + address + end + end.compact + end + end + + def format_ports(ports) + "{ #{Array(ports).map(&:to_s).join(', ')} }" + end + + def format_addresses(addresses, ip) + if addresses.is_a?(Symbol) + "@#{ip}-#{addresses}-addresses" else - log "Unsupported network family" do - level :error - end + "{ #{Array(addresses).map(&:to_s).join(', ')} }" + end + end + + def set_type(ip) + case ip + when "ip" then "ipv4_addr" + when "ip6" then "ipv6_addr" end end end