mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-21 14:50:08 +03:00
Feature #3175: Improve SG driver
- Refactor and apply new ACCEPT => REJECT strategy - Adds icmp_type support - Do not apply duplicate rules - Specific ipset per protocol - Improve rule types readibility in the driver - Adds support for mac and ip spoofing filtering - Reorder rules
This commit is contained in:
parent
b34dbfd7fc
commit
60634c34f3
@ -389,36 +389,19 @@ var create_security_group_wizard_html =
|
||||
</label>\
|
||||
<select class="security_group_rule_icmp_type">\
|
||||
<option value="" selected="selected">'+tr("All")+'</option>\
|
||||
<option value = "0">'+"0: Echo Reply"+'</option>\
|
||||
<option value = "0">'+"0/0: Echo Reply (pong)"+'</option>\
|
||||
<option value = "3">'+"3: Destination Unreachable"+'</option>\
|
||||
<option value = "4">'+"4: Source Quench"+'</option>\
|
||||
<option value = "4">'+"4/0: Source Quench"+'</option>\
|
||||
<option value = "5">'+"5: Redirect"+'</option>\
|
||||
<option value = "6">'+"6: Alternate Host Address"+'</option>\
|
||||
<option value = "8">'+"8: Echo"+'</option>\
|
||||
<option value = "9">'+"9: Router Advertisement"+'</option>\
|
||||
<option value = "10">'+"10: Router Solicitation"+'</option>\
|
||||
<option value = "8">'+"8/0: Echo Request (ping)"+'</option>\
|
||||
<option value = "9">'+"9/0: Router Advertisement"+'</option>\
|
||||
<option value = "10">'+"10/0: Router Solicitation"+'</option>\
|
||||
<option value = "11">'+"11: Time Exceeded"+'</option>\
|
||||
<option value = "12">'+"12: Parameter Problem"+'</option>\
|
||||
<option value = "13">'+"13: Timestamp"+'</option>\
|
||||
<option value = "14">'+"14: Timestamp Reply"+'</option>\
|
||||
<option value = "15">'+"15: Information Request"+'</option>\
|
||||
<option value = "16">'+"16: Information Reply"+'</option>\
|
||||
<option value = "17">'+"17: Address Mask Request"+'</option>\
|
||||
<option value = "18">'+"18: Address Mask Reply"+'</option>\
|
||||
<option value = "30">'+"30: Traceroute"+'</option>\
|
||||
<option value = "31">'+"31: Datagram Conversion Error"+'</option>\
|
||||
<option value = "32">'+"32: Mobile Host Redirect"+'</option>\
|
||||
<option value = "33">'+"33: IPv6 Where-Are-You"+'</option>\
|
||||
<option value = "34">'+"34: IPv6 I-Am-Here"+'</option>\
|
||||
<option value = "35">'+"35: Mobile Registration Request"+'</option>\
|
||||
<option value = "36">'+"36: Mobile Registration Reply"+'</option>\
|
||||
<option value = "37">'+"37: Domain Name Request"+'</option>\
|
||||
<option value = "38">'+"38: Domain Name Reply"+'</option>\
|
||||
<option value = "39">'+"39: SKIP"+'</option>\
|
||||
<option value = "40">'+"40: Photuris"+'</option>\
|
||||
<option value = "41">'+"41: ICMP messages utilized by experimental mobility protocols such as Seamoby"+'</option>\
|
||||
<option value = "253">'+"253: RFC3692-style Experiment 1"+'</option>\
|
||||
<option value = "254">'+"254: RFC3692-style Experiment 2"+'</option>\
|
||||
<option value = "13">'+"13/0: Timestamp Request"+'</option>\
|
||||
<option value = "14">'+"14/0: Timestamp Reply"+'</option>\
|
||||
<option value = "17">'+"17/0: Address Mask Request"+'</option>\
|
||||
<option value = "18">'+"18/0: Address Mask Reply"+'</option>\
|
||||
</select>\
|
||||
</div>\
|
||||
</div>\
|
||||
@ -918,7 +901,7 @@ function updateSecurityGroupInfo(request,security_group){
|
||||
}
|
||||
|
||||
function insert_sg_rules_table(sg){
|
||||
var html =
|
||||
var html =
|
||||
'<table class="policies_table dataTable">\
|
||||
<thead>\
|
||||
<tr>\
|
||||
|
@ -14,6 +14,10 @@
|
||||
# limitations under the License. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
# TODO: remove
|
||||
require 'rubygems'
|
||||
require 'pp'
|
||||
|
||||
################################################################################
|
||||
# IP and NETMASK Library
|
||||
################################################################################
|
||||
@ -201,11 +205,14 @@ end
|
||||
# SecurityGroups and Rules
|
||||
################################################################################
|
||||
|
||||
# TODO: remove
|
||||
require 'colorator'
|
||||
|
||||
class CommandsError < StandardError; end
|
||||
|
||||
class Commands
|
||||
def initialize
|
||||
@commands = []
|
||||
clear!
|
||||
end
|
||||
|
||||
def add(cmd)
|
||||
@ -228,18 +235,33 @@ class Commands
|
||||
out = ""
|
||||
|
||||
@commands.each{|c|
|
||||
out << `#{c}`
|
||||
|
||||
# TODO: remove
|
||||
puts "=> #{c}".green
|
||||
|
||||
c_out = `#{c}`
|
||||
puts c_out if !c_out.empty?
|
||||
|
||||
out << c_out
|
||||
|
||||
if !$?.success?
|
||||
@commands = []
|
||||
clear!
|
||||
raise CommandsError.new(c), "Command Error: #{c}"
|
||||
end
|
||||
}
|
||||
|
||||
@commands = []
|
||||
clear!
|
||||
out
|
||||
end
|
||||
|
||||
def uniq!
|
||||
@commands.uniq!
|
||||
end
|
||||
|
||||
def clear!
|
||||
@commands = []
|
||||
end
|
||||
|
||||
def to_a
|
||||
@commands
|
||||
end
|
||||
@ -248,6 +270,25 @@ end
|
||||
class RuleError < StandardError; end
|
||||
|
||||
class Rule
|
||||
TYPES = {
|
||||
# PROTOCOL, RULE_TYPE, NET, RANGE, ICMP_TYPE
|
||||
[ 1, 1, 0, 0, 0 ] => :protocol,
|
||||
[ 1, 1, 0, 1, 0 ] => :portrange,
|
||||
[ 1, 1, 0, 0, 1 ] => :icmp_type,
|
||||
[ 1, 1, 1, 0, 0 ] => :net,
|
||||
[ 1, 1, 1, 1, 0 ] => :net_portrange,
|
||||
[ 1, 1, 1, 0, 1 ] => :net_icmp_type
|
||||
}
|
||||
|
||||
ICMP_TYPES = %w{3 5 11 12 0 4 8 9 10 13 14 17 18}
|
||||
|
||||
ICMP_TYPES_EXPANDED = {
|
||||
3 => [0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15],
|
||||
5 => [0, 1, 2, 3],
|
||||
11 => [0, 1],
|
||||
12 => [0, 1]
|
||||
}
|
||||
|
||||
def initialize(rule)
|
||||
@rule = rule
|
||||
@commands = Commands.new
|
||||
@ -273,7 +314,7 @@ class Rule
|
||||
end
|
||||
|
||||
def range
|
||||
@rule[:range] || nil
|
||||
@rule[:range]
|
||||
end
|
||||
|
||||
def net
|
||||
@ -283,13 +324,31 @@ class Rule
|
||||
r.get_nets.collect{|n| n.to_s}
|
||||
end
|
||||
|
||||
def icmp_type
|
||||
@rule[:icmp_type]
|
||||
end
|
||||
|
||||
def icmp_type_expand
|
||||
if (codes = ICMP_TYPES_EXPANDED[icmp_type.to_i])
|
||||
codes.collect{|e| "#{icmp_type}/#{e}"}
|
||||
else
|
||||
["#{icmp_type}/0"]
|
||||
end
|
||||
end
|
||||
|
||||
# Helper
|
||||
|
||||
def valid?
|
||||
valid = true
|
||||
error_message = []
|
||||
|
||||
if !protocol || ![:tcp, :udp, :icmp, :esp].include?(protocol)
|
||||
if type.nil?
|
||||
error_message << "Invalid combination of rule attributes: "
|
||||
error_message << type(true).to_s
|
||||
valid = false
|
||||
end
|
||||
|
||||
if !protocol || ![:all, :tcp, :udp, :icmp, :esp].include?(protocol)
|
||||
error_message << "Invalid protocol: #{protocol}"
|
||||
valid = false
|
||||
end
|
||||
@ -304,8 +363,17 @@ class Rule
|
||||
valid = false
|
||||
end
|
||||
|
||||
if range && protocol == :esp
|
||||
error_message << "IPSEC does not support port ranges"
|
||||
if icmp_type && !ICMP_TYPES.include?(icmp_type)
|
||||
error_message << "ICMP Type '#{icmp_type}' not supported. Valid list is '#{ICMP_TYPES.join(',')}'"
|
||||
end
|
||||
|
||||
if icmp_type && !(protocol == :icmp)
|
||||
error_message << "Protocol '#{protocol}' does not support ICMP TYPES"
|
||||
valid = false
|
||||
end
|
||||
|
||||
if range && ![:tcp, :udp].include?(protocol)
|
||||
error_message << "Protocol '#{protocol}' does not support port ranges"
|
||||
valid = false
|
||||
end
|
||||
|
||||
@ -321,6 +389,50 @@ class Rule
|
||||
@rule[:ip].match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) && \
|
||||
@rule[:size].match(/^\d+$/)
|
||||
end
|
||||
|
||||
# Returns the rule type. Rules currently support these (final and relevant)
|
||||
# attributes.
|
||||
#
|
||||
# PROTOCOL (mandatory)
|
||||
# - Specifies the protocol of the rule
|
||||
# - values: ['ALL', 'TCP', 'UDP', 'ICMP', 'IPSEC']
|
||||
#
|
||||
# RULE_TYPE (mandatory)
|
||||
# - Specifies the direction of application of the rule
|
||||
# - values: ['INBOUND', 'OUTBOUND']
|
||||
#
|
||||
# RANGE (optional)
|
||||
# - only works for protocols ['TCP', 'UDP']
|
||||
# - uses the iptables multiports syntax
|
||||
#
|
||||
# ICMP_TYPE (optional)
|
||||
# - Only works for protocol 'ICMP'
|
||||
# - Is either in the form of '<TYPE>' or '<TYPE>/<CODE>', where both
|
||||
# '<TYPE>' and '<CODE>' are integers. This class has a helper method
|
||||
# tgat expands '<TYPE>' into all the '<TYPE>/<CODE>' subtypes.
|
||||
#
|
||||
# IP and SIZE (optional but must be specified together)
|
||||
# - Can be applied to any protocol
|
||||
# - IP is the first valid IP and SIZE is the number of consecutive IPs
|
||||
#
|
||||
# Depending on the combination of these attributes we can obtaine 4 rule
|
||||
# rule types (some with subtypes):
|
||||
#
|
||||
# ['PROTOCOL', 'RULE_TYPE'] => Type 1: 'protocol'
|
||||
# ['PROTOCOL', 'RULE_TYPE', 'RANGE'] => Type 2A: 'portrange'
|
||||
# ['PROTOCOL', 'RULE_TYPE', 'ICMP_TYPE'] => Type 2B: 'icmp_type'
|
||||
# ['PROTOCOL', 'RULE_TYPE', 'IP', 'SIZE'] => Type 3: 'net'
|
||||
# ['PROTOCOL', 'RULE_TYPE', 'IP', 'SIZE', 'RANGE'] => Type 4A: 'net_portrange'
|
||||
# ['PROTOCOL', 'RULE_TYPE', 'IP', 'SIZE', 'ICMP_TYPE'] => Type 4B: 'net_icmp_type'
|
||||
#
|
||||
# @return [Symbol] The rule type
|
||||
def type(only_key = false)
|
||||
key = [protocol, rule_type, net, range, icmp_type].collect do |e|
|
||||
!!e ? 1 : 0
|
||||
end
|
||||
|
||||
only_key ? key : TYPES[key]
|
||||
end
|
||||
end
|
||||
|
||||
class SecurityGroup
|
||||
@ -343,93 +455,67 @@ end
|
||||
################################################################################
|
||||
|
||||
class SecurityGroupIPTables < SecurityGroup
|
||||
# RULE_CLASS = IPTablesRule
|
||||
GLOBAL_CHAIN = "opennebula"
|
||||
|
||||
def initialize(vm, nic, sg_id, rules)
|
||||
super
|
||||
|
||||
@commands = Commands.new
|
||||
|
||||
chain = "one-sg-#{@sg_id}"
|
||||
@vars = self.class.vars(@vm, @nic, @sg_id)
|
||||
|
||||
vm_id = @vm['ID']
|
||||
nic_id = @nic[:nic_id]
|
||||
|
||||
@chain_in = "one-#{vm_id}-#{nic_id}-i"
|
||||
@chain_out = "one-#{vm_id}-#{nic_id}-o"
|
||||
|
||||
@chain_sg_in = "one-#{vm_id}-#{nic_id}-#{@sg_id}-i"
|
||||
@chain_sg_out = "one-#{vm_id}-#{nic_id}-#{@sg_id}-o"
|
||||
end
|
||||
|
||||
def bootstrap
|
||||
# SG chains
|
||||
@commands.iptables("-N #{@chain_sg_in}")
|
||||
@commands.iptables("-N #{@chain_sg_out}")
|
||||
|
||||
# Redirect Traffic
|
||||
@commands.iptables("-A #{@chain_in} -j #{@chain_sg_in}")
|
||||
@commands.iptables("-A #{@chain_out} -j #{@chain_sg_out}")
|
||||
|
||||
# IPsets
|
||||
@commands.ipset("create #{@chain_sg_in}-n hash:net")
|
||||
@commands.ipset("create #{@chain_sg_out}-n hash:net")
|
||||
@commands.ipset("create #{@chain_sg_in}-nr hash:net,port")
|
||||
@commands.ipset("create #{@chain_sg_out}-nr hash:net,port")
|
||||
@chain_in = @vars[:chain_in]
|
||||
@chain_out = @vars[:chain_out]
|
||||
@set_sg_in = @vars[:set_sg_in]
|
||||
@set_sg_out = @vars[:set_sg_out]
|
||||
end
|
||||
|
||||
def process_rules
|
||||
@rules.each do |rule|
|
||||
if !rule.range && !rule.net
|
||||
# T1 - protocol
|
||||
case rule.type
|
||||
when :protocol
|
||||
chain = rule.rule_type == :inbound ? @chain_in : @chain_out
|
||||
@commands.iptables("-A #{chain} -p #{rule.protocol} -j RETURN")
|
||||
|
||||
when :portrange
|
||||
chain = rule.rule_type == :inbound ? @chain_in : @chain_out
|
||||
@commands.iptables("-A #{chain} -p #{rule.protocol} -m multiport --dports #{rule.range} -j RETURN")
|
||||
|
||||
when :icmp_type
|
||||
chain = rule.rule_type == :inbound ? @chain_in : @chain_out
|
||||
@commands.iptables("-A #{chain} -p icmp --icmp-type #{rule.icmp_type} -j RETURN")
|
||||
|
||||
when :net
|
||||
if rule.rule_type == :inbound
|
||||
chain = @chain_sg_in
|
||||
chain = @chain_in
|
||||
set = "#{@set_sg_in}-#{rule.protocol}-n"
|
||||
dir = "src"
|
||||
else
|
||||
chain = @chain_sg_out
|
||||
chain = @chain_out
|
||||
set = "#{@set_sg_out}-#{rule.protocol}-n"
|
||||
dir = "dst"
|
||||
end
|
||||
|
||||
@commands.iptables("-A #{chain} -p #{rule.protocol} -j ACCEPT")
|
||||
|
||||
elsif rule.range && !rule.net
|
||||
# T2 - port range
|
||||
if rule.rule_type == :inbound
|
||||
chain = @chain_sg_in
|
||||
else
|
||||
chain = @chain_sg_out
|
||||
end
|
||||
@commands.iptables("-A #{chain} -p #{rule.protocol} -m multiport --dports #{rule.range} -j ACCEPT")
|
||||
|
||||
elsif !rule.range && rule.net
|
||||
# T3 - net
|
||||
if rule.rule_type == :inbound
|
||||
chain = @chain_sg_in
|
||||
dir = "src"
|
||||
else
|
||||
chain = @chain_sg_out
|
||||
dir = "dst"
|
||||
end
|
||||
|
||||
set = "#{chain}-n"
|
||||
|
||||
@commands.iptables("-A #{chain} -p #{rule.protocol} -m set --match-set #{set} #{dir} -j ACCEPT")
|
||||
@commands.ipset("create #{set} hash:net")
|
||||
@commands.iptables("-A #{chain} -p #{rule.protocol} -m set --match-set #{set} #{dir} -j RETURN")
|
||||
|
||||
rule.net.each do |n|
|
||||
@commands.ipset("add -exist #{set} #{n}")
|
||||
end
|
||||
|
||||
elsif rule.range && rule.net
|
||||
# T4 - net && port range
|
||||
when :net_portrange
|
||||
if rule.rule_type == :inbound
|
||||
chain = @chain_sg_in
|
||||
chain = @chain_in
|
||||
set = @set_sg_in + "-nr"
|
||||
dir = "src,dst"
|
||||
else
|
||||
chain = @chain_sg_out
|
||||
chain = @chain_in
|
||||
set = @set_sg_in + "-n"
|
||||
dir = "dst,dst"
|
||||
end
|
||||
|
||||
set = "#{chain}-nr"
|
||||
|
||||
@commands.iptables("-A #{chain} -m set --match-set #{set} #{dir} -j ACCEPT")
|
||||
@commands.ipset("create #{set} hash:net,port")
|
||||
@commands.iptables("-A #{chain} -m set --match-set #{set} #{dir} -j RETURN")
|
||||
|
||||
rule.net.each do |n|
|
||||
rule.range.split(",").each do |r|
|
||||
@ -438,13 +524,184 @@ class SecurityGroupIPTables < SecurityGroup
|
||||
@commands.ipset("add -exist #{set} #{net_range}")
|
||||
end
|
||||
end
|
||||
|
||||
when :net_icmp_type
|
||||
if rule.rule_type == :inbound
|
||||
chain = @chain_in
|
||||
set = @set_sg_in + "-nr"
|
||||
dir = "src,dst"
|
||||
else
|
||||
chain = @chain_in
|
||||
set = @set_sg_in + "-n"
|
||||
dir = "dst,dst"
|
||||
end
|
||||
|
||||
@commands.ipset("create #{set} hash:net,port")
|
||||
@commands.iptables("-A #{chain} -m set --match-set #{set} #{dir} -j RETURN")
|
||||
|
||||
rule.net.each do |n|
|
||||
rule.icmp_type_expand.each do |type_code|
|
||||
net_range = "#{n},icmp:#{type_code}"
|
||||
@commands.ipset("add -exist #{set} #{net_range}")
|
||||
end if rule.icmp_type_expand
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@commands.uniq!
|
||||
end
|
||||
|
||||
def run!
|
||||
@commands.run!
|
||||
end
|
||||
|
||||
############################################################################
|
||||
# Static methods
|
||||
############################################################################
|
||||
|
||||
def self.global_bootstrap
|
||||
info = self.info
|
||||
|
||||
if !info[:iptables_s].split("\n").include? "-N #{GLOBAL_CHAIN}"
|
||||
commands = Commands.new
|
||||
|
||||
commands.iptables "-N #{GLOBAL_CHAIN}"
|
||||
commands.iptables "-A FORWARD -m physdev --physdev-is-bridged -j #{GLOBAL_CHAIN}"
|
||||
commands.iptables "-A #{GLOBAL_CHAIN} -j DROP"
|
||||
|
||||
commands.run!
|
||||
end
|
||||
end
|
||||
|
||||
def self.nic_pre(vm, nic)
|
||||
commands = Commands.new
|
||||
|
||||
vars = self.vars(vm, nic)
|
||||
|
||||
chain = vars[:chain]
|
||||
chain_in = vars[:chain_in]
|
||||
chain_out = vars[:chain_out]
|
||||
|
||||
# create chains
|
||||
commands.iptables "-N #{chain_in}" # inbound
|
||||
commands.iptables "-N #{chain_out}" # outbound
|
||||
|
||||
# Send traffic to the NIC chains
|
||||
commands.iptables"-I #{GLOBAL_CHAIN} -m physdev --physdev-out #{nic[:tap]} --physdev-is-bridged -j #{chain_in}"
|
||||
commands.iptables"-I #{GLOBAL_CHAIN} -m physdev --physdev-in #{nic[:tap]} --physdev-is-bridged -j #{chain_out}"
|
||||
|
||||
# Mac-spofing
|
||||
if nic[:filter_mac_spoofing]
|
||||
commands.iptables"-A #{chain_out} -m mac ! --mac-source #{nic[:mac]} -j DROP"
|
||||
end
|
||||
|
||||
# IP-spofing
|
||||
if nic[:filter_ip_spoofing]
|
||||
commands.iptables"-A #{chain_out} ! --source #{nic[:ip]} -j DROP"
|
||||
end
|
||||
|
||||
# Related, Established
|
||||
commands.iptables"-A #{chain_in} -m state --state ESTABLISHED,RELATED -j ACCEPT"
|
||||
commands.iptables"-A #{chain_out} -m state --state ESTABLISHED,RELATED -j ACCEPT"
|
||||
|
||||
commands.run!
|
||||
end
|
||||
|
||||
def self.nic_post(vm, nic)
|
||||
vars = self.vars(vm, nic)
|
||||
chain_in = vars[:chain_in]
|
||||
chain_out = vars[:chain_out]
|
||||
|
||||
commands = Commands.new
|
||||
commands.iptables("-A #{chain_in} -j DROP")
|
||||
commands.iptables("-A #{chain_out} -j DROP")
|
||||
|
||||
commands.run!
|
||||
end
|
||||
|
||||
def self.nic_deactivate(vm, nic)
|
||||
vars = self.vars(vm, nic)
|
||||
chain = vars[:chain]
|
||||
chain_in = vars[:chain_in]
|
||||
chain_out = vars[:chain_out]
|
||||
|
||||
info = self.info
|
||||
iptables_forwards = info[:iptables_forwards]
|
||||
iptables_s = info[:iptables_s]
|
||||
ipset_list = info[:ipset_list]
|
||||
|
||||
commands = Commands.new
|
||||
|
||||
iptables_forwards.lines.reverse_each do |line|
|
||||
fields = line.split
|
||||
if [chain_in, chain_out].include?(fields[1])
|
||||
n = fields[0]
|
||||
commands.iptables("-D #{GLOBAL_CHAIN} #{n}")
|
||||
end
|
||||
end
|
||||
|
||||
remove_chains = []
|
||||
iptables_s.lines.each do |line|
|
||||
if line.match(/^-N #{chain}/)
|
||||
remove_chains << line.split[1]
|
||||
end
|
||||
end
|
||||
remove_chains.each {|c| commands.iptables("-F #{c}") }
|
||||
remove_chains.each {|c| commands.iptables("-X #{c}") }
|
||||
|
||||
ipset_list.lines.each do |line|
|
||||
if line.match(/^#{chain}/)
|
||||
set = line.strip
|
||||
commands.ipset("destroy #{set}")
|
||||
end
|
||||
end
|
||||
|
||||
commands.run!
|
||||
end
|
||||
|
||||
def self.info
|
||||
commands = Commands.new
|
||||
|
||||
commands.iptables("-S")
|
||||
iptables_s = commands.run!
|
||||
|
||||
if iptables_s.match(/^-N #{GLOBAL_CHAIN}$/)
|
||||
commands.iptables("-L #{GLOBAL_CHAIN} --line-numbers")
|
||||
iptables_forwards = commands.run!
|
||||
else
|
||||
iptables_forwards = ""
|
||||
end
|
||||
|
||||
commands.ipset("list -name")
|
||||
ipset_list = commands.run!
|
||||
|
||||
{
|
||||
:iptables_forwards => iptables_forwards,
|
||||
:iptables_s => iptables_s,
|
||||
:ipset_list => ipset_list
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
def self.vars(vm, nic, sg_id = nil)
|
||||
vm_id = vm['ID']
|
||||
nic_id = nic[:nic_id]
|
||||
|
||||
vars = {}
|
||||
|
||||
vars[:vm_id] = vm_id,
|
||||
vars[:nic_id] = nic_id,
|
||||
vars[:chain] = "one-#{vm_id}-#{nic_id}",
|
||||
vars[:chain_in] = "#{vars[:chain]}-i",
|
||||
vars[:chain_out] = "#{vars[:chain]}-o"
|
||||
|
||||
if sg_id
|
||||
vars[:set_sg_in] = "#{vars[:chain]}-#{sg_id}-i"
|
||||
vars[:set_sg_out] = "#{vars[:chain]}-#{sg_id}-o"
|
||||
end
|
||||
|
||||
vars
|
||||
end
|
||||
end
|
||||
|
||||
################################################################################
|
||||
@ -461,23 +718,19 @@ end
|
||||
|
||||
class OpenNebulaSG < OpenNebulaNetwork
|
||||
DRIVER = "sg"
|
||||
XPATH_FILTER = "TEMPLATE/NIC[SECURITY_GROUPS]"
|
||||
XPATH_FILTER = "TEMPLATE/NIC"
|
||||
SECURITY_GROUP_CLASS = SecurityGroupIPTables
|
||||
|
||||
def initialize(vm, deploy_id = nil, hypervisor = nil)
|
||||
super(vm, XPATH_FILTER, deploy_id, hypervisor)
|
||||
@locking = true
|
||||
@commands = Commands.new
|
||||
|
||||
get_security_group_rules
|
||||
end
|
||||
|
||||
def activate
|
||||
deactivate
|
||||
|
||||
lock
|
||||
|
||||
vm_id = @vm['ID']
|
||||
|
||||
security_group_rules = {}
|
||||
|
||||
def get_security_group_rules
|
||||
rules = {}
|
||||
@vm.vm_root.elements.each('TEMPLATE/SECURITY_GROUP_RULE') do |r|
|
||||
security_group_rule = {}
|
||||
|
||||
@ -487,51 +740,35 @@ class OpenNebulaSG < OpenNebulaNetwork
|
||||
end
|
||||
|
||||
id = security_group_rule[:security_group_id]
|
||||
|
||||
security_group_rules[id] = [] if security_group_rules[id].nil?
|
||||
|
||||
security_group_rules[id] << security_group_rule
|
||||
rules[id] = [] if rules[id].nil?
|
||||
rules[id] << security_group_rule
|
||||
end
|
||||
@security_group_rules = rules
|
||||
end
|
||||
|
||||
def activate
|
||||
deactivate
|
||||
lock
|
||||
|
||||
# Global Bootstrap
|
||||
SECURITY_GROUP_CLASS.global_bootstrap
|
||||
|
||||
# Process the rules
|
||||
@vm.nics.each do |nic|
|
||||
commands = Commands.new
|
||||
next if nic[:security_groups].nil? \
|
||||
&& nic[:filter_mac_spoofing].nil? \
|
||||
&& nic[:filter_ip_spoofing].nil?
|
||||
|
||||
nic_id = nic[:nic_id]
|
||||
|
||||
chain = "one-#{vm_id}-#{nic_id}"
|
||||
chain_in = "#{chain}-i"
|
||||
chain_out = "#{chain}-o"
|
||||
|
||||
# create nic chains
|
||||
commands.iptables("-N #{chain_in}") # inbound
|
||||
commands.iptables("-N #{chain_out}") # outbound
|
||||
|
||||
# Send traffic to the NIC chains
|
||||
commands.iptables("-A FORWARD -m physdev --physdev-out #{nic[:tap]} --physdev-is-bridged -j #{chain_in}")
|
||||
commands.iptables("-A FORWARD -m physdev --physdev-in #{nic[:tap]} --physdev-is-bridged -j #{chain_out}")
|
||||
|
||||
# Related, Established
|
||||
commands.iptables("-A #{chain_in} -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT")
|
||||
commands.iptables("-A #{chain_out} -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT")
|
||||
|
||||
begin
|
||||
commands.run!
|
||||
rescue Exception => e
|
||||
unlock
|
||||
raise OpenNebulaSGError.new(:bootstrap, e)
|
||||
end
|
||||
SECURITY_GROUP_CLASS.nic_pre(@vm, nic)
|
||||
|
||||
sg_ids = nic[:security_groups].split(",")
|
||||
|
||||
sg_ids.each do |sg_id|
|
||||
rules = security_group_rules[sg_id]
|
||||
|
||||
rules = @security_group_rules[sg_id]
|
||||
sg = SECURITY_GROUP_CLASS.new(@vm, nic, sg_id, rules)
|
||||
|
||||
sg.bootstrap
|
||||
sg.process_rules
|
||||
|
||||
begin
|
||||
sg.process_rules
|
||||
sg.run!
|
||||
rescue Exception => e
|
||||
unlock
|
||||
@ -539,10 +776,7 @@ class OpenNebulaSG < OpenNebulaNetwork
|
||||
end
|
||||
end
|
||||
|
||||
commands.iptables("-A #{chain_in} -j DROP") # inbound
|
||||
commands.iptables("-A #{chain_out} -j DROP") # outbound
|
||||
|
||||
commands.run!
|
||||
SECURITY_GROUP_CLASS.nic_post(@vm, nic)
|
||||
end
|
||||
|
||||
unlock
|
||||
@ -551,58 +785,14 @@ class OpenNebulaSG < OpenNebulaNetwork
|
||||
def deactivate
|
||||
lock
|
||||
|
||||
vm_id = @vm['ID']
|
||||
|
||||
@vm.nics.each do |nic|
|
||||
commands = Commands.new
|
||||
|
||||
nic_id = nic[:nic_id]
|
||||
|
||||
chain = "one-#{vm_id}-#{nic_id}"
|
||||
chain_in = "#{chain}-i"
|
||||
chain_out = "#{chain}-o"
|
||||
|
||||
# remove everything
|
||||
begin
|
||||
commands.iptables("-L FORWARD --line-numbers")
|
||||
iptables_forwards = commands.run!
|
||||
|
||||
commands.iptables("-S")
|
||||
iptables_s = commands.run!
|
||||
|
||||
commands.ipset("list -name")
|
||||
ipset_list = commands.run!
|
||||
|
||||
iptables_forwards.lines.reverse.each do |line|
|
||||
fields = line.split
|
||||
if [chain_in, chain_out].include?(fields[1])
|
||||
n = fields[0]
|
||||
commands.iptables("-D FORWARD #{n}")
|
||||
end
|
||||
end
|
||||
|
||||
remove_chains = []
|
||||
iptables_s.lines.each do |line|
|
||||
if line.match(/^-N #{chain}/)
|
||||
remove_chains << line.split[1]
|
||||
end
|
||||
end
|
||||
remove_chains.each {|c| commands.iptables("-F #{c}") }
|
||||
remove_chains.each {|c| commands.iptables("-X #{c}") }
|
||||
|
||||
ipset_list.lines.each do |line|
|
||||
if line.match(/^#{chain}/)
|
||||
set = line.strip
|
||||
commands.ipset("destroy #{set}")
|
||||
end
|
||||
end
|
||||
|
||||
commands.run!
|
||||
rescue Exception => e
|
||||
raise OpenNebulaSGError.new(:deactivate, e)
|
||||
begin
|
||||
@vm.nics.each do |nic|
|
||||
SECURITY_GROUP_CLASS.nic_deactivate(@vm, nic)
|
||||
end
|
||||
rescue Exception => e
|
||||
raise OpenNebulaSGError.new(:deactivate, e)
|
||||
ensure
|
||||
unlock
|
||||
end
|
||||
|
||||
unlock
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user