From fe84d376acb079c1c1a357e9e69834fcbba2502d Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Thu, 29 Dec 2016 00:57:02 +0100 Subject: [PATCH] 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) --- src/secgroup/SecurityGroup.cc | 2 +- src/vnm_mad/remotes/lib/address.rb | 75 ++------ src/vnm_mad/remotes/lib/security_groups.rb | 25 ++- .../remotes/lib/security_groups_iptables.rb | 160 +++++++++++------- src/vnm_mad/remotes/vxlan/vxlan_driver.rb | 12 +- 5 files changed, 142 insertions(+), 132 deletions(-) diff --git a/src/secgroup/SecurityGroup.cc b/src/secgroup/SecurityGroup.cc index 80910db133..ee8a0a40b2 100644 --- a/src/secgroup/SecurityGroup.cc +++ b/src/secgroup/SecurityGroup.cc @@ -411,7 +411,7 @@ bool SecurityGroup::isValidRule(const VectorAttribute * rule, string& error) con if (inet_pton(AF_INET6, ip.c_str(), static_cast(&ip_addr)) != 1) { - if (inet_pton(AF_INET, ip.c_str(), static_cast(&ip_addr)) != 1) + if (inet_pton(AF_INET,ip.c_str(),static_cast(&ip_addr)) != 1) { error = "Wrong format for IP value."; return false; diff --git a/src/vnm_mad/remotes/lib/address.rb b/src/vnm_mad/remotes/lib/address.rb index b2790fdc79..b431232f2d 100644 --- a/src/vnm_mad/remotes/lib/address.rb +++ b/src/vnm_mad/remotes/lib/address.rb @@ -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 diff --git a/src/vnm_mad/remotes/lib/security_groups.rb b/src/vnm_mad/remotes/lib/security_groups.rb index bdb4d1d2e2..40867de70a 100644 --- a/src/vnm_mad/remotes/lib/security_groups.rb +++ b/src/vnm_mad/remotes/lib/security_groups.rb @@ -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] 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 diff --git a/src/vnm_mad/remotes/lib/security_groups_iptables.rb b/src/vnm_mad/remotes/lib/security_groups_iptables.rb index b0357761c8..9bb7e0f011 100644 --- a/src/vnm_mad/remotes/lib/security_groups_iptables.rb +++ b/src/vnm_mad/remotes/lib/security_groups_iptables.rb @@ -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] diff --git a/src/vnm_mad/remotes/vxlan/vxlan_driver.rb b/src/vnm_mad/remotes/vxlan/vxlan_driver.rb index 051198338b..7eadf92473 100644 --- a/src/vnm_mad/remotes/vxlan/vxlan_driver.rb +++ b/src/vnm_mad/remotes/vxlan/vxlan_driver.rb @@ -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]}" : ""