1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-22 18:50:08 +03:00

F #4159: Make use of IPAddr class for uniform IP Management. Some formatting. Homogenous intialization of ip-spoofing rules for ipv6 and ipv4 (use always an ipset)

This commit is contained in:
Ruben S. Montero 2016-12-29 00:57:02 +01:00
parent 599e32a44d
commit fe84d376ac
5 changed files with 142 additions and 132 deletions

View File

@ -411,7 +411,7 @@ bool SecurityGroup::isValidRule(const VectorAttribute * rule, string& error) con
if (inet_pton(AF_INET6, ip.c_str(), static_cast<void*>(&ip_addr)) != 1)
{
if (inet_pton(AF_INET, ip.c_str(), static_cast<void*>(&ip_addr)) != 1)
if (inet_pton(AF_INET,ip.c_str(),static_cast<void*>(&ip_addr)) != 1)
{
error = "Wrong format for IP value.";
return false;

View File

@ -29,48 +29,42 @@ module VNMNetwork
def self.to_nets(ip_start, size)
nets = Array.new
if ip_start.match(/:/)
family = "inet6"
else
family = "inet"
begin
ipaddr = IPAddr.new ip_start
rescue
return
end
if family == "inet"
ip_i = IPv4.to_i(ip_start)
ip_totalLength = 32
ip_i = ipaddr.to_i
if ipaddr.ipv4?
ip_length = 32
elsif ipaddr.ipv6?
ip_length = 128
else
ip_i = IPv6.to_i(ip_start)
ip_totalLength = 128
return
end
# Find the largest address block (look for the first 1-bit)
lblock = 0
lblock += 1 while (ip_i[lblock] == 0 && lblock < ip_totalLength )
lblock += 1 while (ip_i[lblock] == 0 && lblock < ip_length )
# Allocate whole blocks till the size fits
while ( size >= 2**lblock )
if family == "inet"
nets << "#{IPv4.to_s(ip_i)}/#{ip_totalLength-lblock}"
else
nets << "#{IPv6.to_s(ip_i)}/#{ip_totalLength-lblock}"
end
nets << "#{IPAddr.new(ip_i, ipaddr.family).to_s}/#{ip_length-lblock}"
ip_i += 2**lblock
size -= 2**lblock
lblock += 1 while (ip_i[lblock] == 0 && lblock < ip_totalLength )
lblock += 1 while (ip_i[lblock] == 0 && lblock < ip_length )
end
# Fit remaining address blocks
ip_totalLength.downto(0) { |i|
ip_length.downto(0) { |i|
next if size[i] == 0
if family == "inet"
nets << "#{IPv4.to_s(ip_i)}/#{ip_totalLength-i}"
else
nets << "#{IPv6.to_s(ip_i)}/#{ip_totalLength-i}"
end
nets << "#{IPAddr.new(ip_i, ipaddr.family).to_s}/#{ip_length-i}"
ip_i += 2**i
}
@ -78,43 +72,6 @@ module VNMNetwork
return nets
end
# This implementation module includes IPv4 management functions
# It MUST NOT be used in other VNMAD classes
module IPv4
# Returns the binary equivalent of a IP address
# @param ip [String] IP in dot notation
# @return [Fixnum] IP as an integer
def self.to_i(ip)
ip.split(".").inject(0) {|t,e| (t << 8) + e.to_i }
end
# Returns the string equivalent of a IP address
# @param ip [Fixnum] IP as an integer
# @return [String] IP in dot notation
def self.to_s(ip)
ip = 3.downto(0).collect {|s| (ip >> 8*s) & 0xff }.join('.')
end
end
module IPv6
# Returns the binary equivalent of a IP address
# @param ip [String] IP in dot notation
# @return [Fixnum] IP as an integer
def self.to_i(ip)
ipaddr = IPAddr.new ip, Socket::AF_INET6
return ipaddr.to_i
end
# Returns the string equivalent of a IP address
# @param ip [Fixnum] IP as an integer
# @return [String] IP in dot notation
def self.to_s(ip)
ipaddr = IPAddr.new ip, Socket::AF_INET6
return ipaddr.to_s
end
end
end
end

View File

@ -123,21 +123,36 @@ module VNMNetwork
end
end
# Expand the ICMP type with associated codes if any
# Expand the ICMP type with associated codes if any
# @return [Array<String>] expanded ICMP types to include all codes
def icmpv6_type_expand
# XXX:TODO: Implement expansion of codes for IPv6 types
["#{@icmpv6_type}/0"]
if (codes = ICMPv6_TYPES_EXPANDED[@icmpv6_type.to_i])
codes.collect{|e| "#{@icmpv6_type}/#{e}"}
else
["#{@icmpv6_type}/0"]
end
end
private
# ICMP Codes for each ICMP type
# ICMP Codes for each ICMP type as in:
# http://www.iana.org/assignments/icmp-parameters/
# http://www.iana.org/assignments/icmpv6-parameters/
ICMP_TYPES_EXPANDED = {
3 => [0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15],
5 => [0, 1, 2, 3],
9 => [0, 16],
11 => [0, 1],
12 => [0, 1]
12 => [0, 1, 2]
}
ICMPv6_TYPES_EXPANDED = {
1 => [0, 1, 2, 3, 4, 5, 6, 7],
3 => [0, 1],
4 => [0, 1, 2, 3],
138=> [0, 1, 255],
139=> [0, 1, 2],
140=> [0, 1, 2]
}
# Depending on the combination of the rule attributes derive the

View File

@ -36,6 +36,7 @@ module SGIPTables
if @protocol != :icmpv6
cmds.add :iptables, "-A #{chain} -p #{@protocol} -j RETURN"
end
if @protocol != :icmp
cmds.add :ip6tables, "-A #{chain} -p #{@protocol} -j RETURN"
end
@ -54,25 +55,26 @@ module SGIPTables
# Implements the :icmp_type rule. Example:
# iptables -A one-3-0-o -p icmp --icmp-type 8 -j RETURN
def process_icmp_type(cmds, vars)
def process_icmp_type(cmds, vars)
chain = @rule_type == :inbound ? vars[:chain_in] : vars[:chain_out]
cmds.add :iptables, "-A #{chain} -p icmp --icmp-type #{@icmp_type}" \
cmds.add :iptables, "-A #{chain} -p icmp --icmp-type #{@icmp_type}"\
" -j RETURN"
end
# Implements the :icmpv6_type rule. Example:
# ip6tables -A one-3-0-o -p icmpv6 --icmpv6-type 128 -j RETURN
def process_icmpv6_type(cmds, vars)
def process_icmpv6_type(cmds, vars)
chain = @rule_type == :inbound ? vars[:chain_in] : vars[:chain_out]
cmds.add :ip6tables, "-A #{chain} -p icmpv6 --icmpv6-type #{@icmpv6_type}" \
" -j RETURN"
cmds.add :ip6tables, "-A #{chain} -p icmpv6 --icmpv6-type "\
"#{@icmpv6_type} -j RETURN"
end
# Implements the :net rule. Example:
# ipset create one-3-0-1-i-tcp-n-inet hash:net family inet
# iptables -A one-3-0-i -p tcp -m set --match-set one-3-0-1-i-tcp-n-inet src -j RETURN
# iptables -A one-3-0-i -p tcp -m set --match-set \
# one-3-0-1-i-tcp-n-inet src -j RETURN
# ipset add -exist one-3-0-1-i-tcp-n-inet 10.0.0.0/24
def process_net(cmds, vars)
["inet", "inet6"].each do |family|
@ -97,7 +99,7 @@ module SGIPTables
" --match-set #{set} #{dir} -j RETURN"
net.each do |n|
if n.match(/:/)
if IPAddr.new(n).ipv6?
n_family = "inet6"
else
n_family = "inet"
@ -139,7 +141,7 @@ module SGIPTables
" #{set} #{dir} -j RETURN"
net.each do |n|
if n.match(/:/)
if IPAddr.new(n).ipv6?
n_family = "inet6"
else
n_family = "inet"
@ -194,7 +196,7 @@ module SGIPTables
dir = "src,dst"
else
chain = vars[:chain_out]
set = "#{vars[:set_sg_out]}-ni6"
set = "#{vars[:set_sg_out]}-ni6"
dir = "dst,dst"
end
@ -278,22 +280,23 @@ module SGIPTables
def self.global_bootstrap
info = SGIPTables.info
if info[:iptables_s].split("\n").include? "-N #{GLOBAL_CHAIN}"
if info[:ip6tables_s].split("\n").include? "-N #{GLOBAL_CHAIN}"
return
end
end
commands = VNMNetwork::Commands.new
commands.add :iptables, "-N #{GLOBAL_CHAIN}"
commands.add :iptables, "-A FORWARD -m physdev --physdev-is-bridged -j #{GLOBAL_CHAIN}"
commands.add :iptables, "-A #{GLOBAL_CHAIN} -j ACCEPT"
commands.add :ip6tables, "-N #{GLOBAL_CHAIN}"
commands.add :ip6tables, "-A FORWARD -m physdev --physdev-is-bridged -j #{GLOBAL_CHAIN}"
commands.add :ip6tables, "-A #{GLOBAL_CHAIN} -j ACCEPT"
if !info[:iptables_s].split("\n").include?("-N #{GLOBAL_CHAIN}")
commands.add :iptables, "-N #{GLOBAL_CHAIN}"
commands.add :iptables, "-A FORWARD -m physdev "\
"--physdev-is-bridged -j #{GLOBAL_CHAIN}"
commands.add :iptables, "-A #{GLOBAL_CHAIN} -j ACCEPT"
end
commands.run!
if !info[:ip6tables_s].split("\n").include?("-N #{GLOBAL_CHAIN}")
commands.add :ip6tables, "-N #{GLOBAL_CHAIN}"
commands.add :ip6tables, "-A FORWARD -m physdev "\
"--physdev-is-bridged -j #{GLOBAL_CHAIN}"
commands.add :ip6tables, "-A #{GLOBAL_CHAIN} -j ACCEPT"
end
commands.run! if !commands.empty?
end
# Returns the base chain and ipset names for the VM
@ -332,8 +335,10 @@ module SGIPTables
# Example, for VM 3 and NIC 0
# iptables -N one-3-0-i
# iptables -N one-3-0-o
# iptables -I opennebula -m physdev --physdev-out vnet0 --physdev-is-bridged -j one-3-0-i"
# iptables -I opennebula -m physdev --physdev-in vnet0 --physdev-is-bridged -j one-3-0-o"
# iptables -I opennebula -m physdev --physdev-out vnet0
# --physdev-is-bridged -j one-3-0-i"
# iptables -I opennebula -m physdev --physdev-in vnet0
# --physdev-is-bridged -j one-3-0-o"
# iptables -A one-3-0-i -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A one-3-0-o -m state --state ESTABLISHED,RELATED -j ACCEPT
#
@ -358,80 +363,105 @@ module SGIPTables
commands.add :ip6tables, "-N #{chain_out}" # outbound
# Send traffic to the NIC chains
commands.add :iptables, "-I #{GLOBAL_CHAIN} -m physdev --physdev-out #{nic[:tap]} --physdev-is-bridged -j #{chain_in}"
commands.add :iptables, "-I #{GLOBAL_CHAIN} -m physdev --physdev-in #{nic[:tap]} --physdev-is-bridged -j #{chain_out}"
commands.add :ip6tables, "-I #{GLOBAL_CHAIN} -m physdev --physdev-out #{nic[:tap]} --physdev-is-bridged -j #{chain_in}"
commands.add :ip6tables, "-I #{GLOBAL_CHAIN} -m physdev --physdev-in #{nic[:tap]} --physdev-is-bridged -j #{chain_out}"
commands.add :iptables, "-I #{GLOBAL_CHAIN} -m physdev "\
"--physdev-out #{nic[:tap]} --physdev-is-bridged -j #{chain_in}"
commands.add :iptables, "-I #{GLOBAL_CHAIN} -m physdev "\
"--physdev-in #{nic[:tap]} --physdev-is-bridged -j #{chain_out}"
commands.add :ip6tables, "-I #{GLOBAL_CHAIN} -m physdev "\
"--physdev-out #{nic[:tap]} --physdev-is-bridged -j #{chain_in}"
commands.add :ip6tables, "-I #{GLOBAL_CHAIN} -m physdev "\
"--physdev-in #{nic[:tap]} --physdev-is-bridged -j #{chain_out}"
# ICMPv6 Neighbor Discovery Protocol (ARP replacement for IPv6)
## Allow routers to send router advertisements
commands.add :ip6tables, "-A #{chain_in} -p icmpv6 --icmpv6-type 134 -j ACCEPT"
commands.add :ip6tables, "-A #{chain_in} -p icmpv6 --icmpv6-type 134 "\
"-j ACCEPT"
## Allow neighbor solicitations to reach the host
commands.add :ip6tables, "-A #{chain_in} -p icmpv6 --icmpv6-type 135 -j ACCEPT"
commands.add :ip6tables, "-A #{chain_in} -p icmpv6 --icmpv6-type 135 "\
"-j ACCEPT"
## Allow routers to send Redirect messages
commands.add :ip6tables, "-A #{chain_in} -p icmpv6 --icmpv6-type 137 -j ACCEPT"
commands.add :ip6tables, "-A #{chain_in} -p icmpv6 --icmpv6-type 137 "\
"-j ACCEPT"
## Allow the host to send a router solicitation
commands.add :ip6tables, "-A #{chain_out} -p icmpv6 --icmpv6-type 133 -j ACCEPT"
commands.add :ip6tables, "-A #{chain_out} -p icmpv6 --icmpv6-type 133 "\
"-j ACCEPT"
## Allow the host to send neighbor solicitation replies
commands.add :ip6tables, "-A #{chain_out} -p icmpv6 --icmpv6-type 136 -j ACCEPT"
commands.add :ip6tables, "-A #{chain_out} -p icmpv6 --icmpv6-type 136 "\
"-j ACCEPT"
# Mac-spofing
if nic[:filter_mac_spoofing] == "YES"
commands.add :iptables, "-A #{chain_out} -m mac ! --mac-source #{nic[:mac]} -j DROP"
commands.add :ip6tables, "-A #{chain_out} -m mac ! --mac-source #{nic[:mac]} -j DROP"
commands.add :iptables, "-A #{chain_out} -m mac ! "\
"--mac-source #{nic[:mac]} -j DROP"
commands.add :ip6tables, "-A #{chain_out} -m mac ! "\
"--mac-source #{nic[:mac]} -j DROP"
end
# IP-spofing
if nic[:filter_ip_spoofing] == "YES"
if !nic[:ip].nil? and !nic[:ip].empty?
commands.add :iptables, "-A #{chain_out} -p udp --source 0.0.0.0/32 --sport 68 --destination 255.255.255.255/32 --dport 67 -j ACCEPT"
ipv4s = Array.new
[:ip, :vrouter_ip].each do |key|
ipv4s << nic[key] if !nic[key].nil? && !nic[key].empty?
end
if !ipv4s.empty?
#bootp
commands.add :iptables, "-A #{chain_out} -p udp "\
"--source 0.0.0.0/32 --sport 68 --destination "\
"255.255.255.255/32 --dport 67 -j ACCEPT"
set = "#{vars[:chain]}-ip-spoofing"
commands.add :ipset, "create #{set} hash:ip"
commands.add :ipset, "add -exist #{set} #{nic[:ip]}"
commands.add :ipset, "add -exist #{set} #{nic[:vrouter_ip]}" if nic[:vrouter_ip]
commands.add :ipset, "create #{set} hash:ip family inet"
commands.add :iptables, "-A #{chain_out} -m set ! --match-set #{set} src -j DROP"
else
# If there are no IPv4 addresses allowed, block all IPv4 addresses
commands.add :ip6tables, "-A #{chain_out} --source 0.0.0.0/0 -j DROP"
end
ip6_addrs = Array.new
[:ip6_global, :ip6_link, :ip6_ula].each do |keyName|
if !nic[keyName].nil? and !nic[keyName].empty?
ip6_addrs << nic[keyName]
ipv4s.each do |ip|
commands.add :ipset, "add -exist #{set} #{ip}"
end
commands.add :iptables, "-A #{chain_out} -m set ! "\
"--match-set #{set} src -j DROP"
else # If there are no IPv4 addresses allowed, block all
commands.add :iptables, "-A #{chain_out} --source 0.0.0.0/0 "\
"-j DROP"
end
if ip6_addrs.length > 1
set = "#{chain_out}-ip6-spoofing"
ipv6s = Array.new
[:ip6_global, :ip6_link, :ip6_ula].each do |key|
ipv6s << nic[key] if !nic[key].nil? && !nic[key].empty?
end
if !ipv6s.empty?
set = "#{vars[:chain]}-ip6-spoofing"
commands.add :ipset, "create #{set} hash:ip family inet6"
ip6_addrs.each do |ip6_addr|
commands.add :ipset, "add -exist #{set} #{ip6_addr}"
ipv6s.each do |ip|
commands.add :ipset, "add -exist #{set} #{ip}"
end
commands.add :ip6tables, "-A #{chain_out} -m set ! --match-set #{set} src -j DROP"
elsif ip6_addrs.length == 1
commands.add :ip6tables, "-A #{chain_out} ! --source #{ip6_addrs[0]} -j DROP"
else
# If there are no IPv6 addresses allowed, block all IPv6 addresses
commands.add :ip6tables, "-A #{chain_out} -m set ! "\
"--match-set #{set} src -j DROP"
else # If there are no IPv6 addresses allowed, block all
commands.add :ip6tables, "-A #{chain_out} --source ::/0 -j DROP"
end
end
# Related, Established
commands.add :iptables, "-A #{chain_in} -m state --state ESTABLISHED,RELATED -j ACCEPT"
commands.add :iptables, "-A #{chain_out} -m state --state ESTABLISHED,RELATED -j ACCEPT"
commands.add :ip6tables, "-A #{chain_in} -m state --state ESTABLISHED,RELATED -j ACCEPT"
commands.add :ip6tables, "-A #{chain_out} -m state --state ESTABLISHED,RELATED -j ACCEPT"
commands.add :iptables, "-A #{chain_in} -m state"\
" --state ESTABLISHED,RELATED -j ACCEPT"
commands.add :iptables, "-A #{chain_out} -m state"\
" --state ESTABLISHED,RELATED -j ACCEPT"
commands.add :ip6tables, "-A #{chain_in} -m state"\
" --state ESTABLISHED,RELATED -j ACCEPT"
commands.add :ip6tables, "-A #{chain_out} -m state"\
" --state ESTABLISHED,RELATED -j ACCEPT"
commands.run!
end
@ -463,7 +493,7 @@ module SGIPTables
info = self.info
iptables_forwards = info[:iptables_forwards]
iptables_s = info[:iptables_s]
ip6tables_forwards = info[:ip6tables_forwards]
ip6tables_forwards= info[:ip6tables_forwards]
ip6tables_s = info[:ip6tables_s]
ipset_list = info[:ipset_list]

View File

@ -15,6 +15,7 @@
#--------------------------------------------------------------------------- #
require 'vnmmad'
require 'ipaddr'
################################################################################
# This driver tag VM traffic with a VLAN_ID using VXLAN protocol. Features:
@ -43,8 +44,15 @@ class VXLANDriver < VNMMAD::VLANDriver
# This function creates and activate a VLAN device
############################################################################
def create_vlan_dev
mc = VNMMAD::VNMNetwork::IPv4.to_i(CONF[:vxlan_mc]) + @nic[:vlan_id].to_i
mcs = VNMMAD::VNMNetwork::IPv4.to_s(mc)
begin
ipaddr = IPAddr.new CONF[:vxlan_mc]
rescue
ipaddr = IPAddr.new "239.0.0.0"
end
mc = ipaddr.to_i + @nic[:vlan_id].to_i
mcs = IPAddr.new(mc, Socket::AF_INET).to_s
mtu = @nic[:mtu] ? "mtu #{@nic[:mtu]}" : "mtu #{CONF[:vxlan_mtu]}"
ttl = CONF[:vxlan_ttl] ? "ttl #{CONF[:vxlan_ttl]}" : ""