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

Feature #3175: Handle IP/SIZE nets

This commit is contained in:
Jaime Melis 2014-11-03 18:15:58 +01:00
parent eb9e4a5c42
commit 05fa0053d8

View File

@ -14,6 +14,189 @@
# limitations under the License. #
#--------------------------------------------------------------------------- #
################################################################################
# IP and NETMASK Library
################################################################################
class IP
include Comparable
attr_accessor :ip
def initialize(ip)
@ip = ip
end
def to_s
@ip
end
def to_i
@ip.split(".").inject(0) {|t,e| (t << 8) + e.to_i }
end
def to_hex
"0x" + to_i.to_s(16).rjust(8, '0')
end
def to_bin
"0b" + to_i.to_s(2).rjust(16, '0')
end
def to_hex_groups(p="")
to_i.to_s(16).rjust(8, '0').scan(/.{2}/).collect{|e| p+e}.join('.')
end
def to_bin_groups(p="")
to_i.to_s(2).rjust(16, '0').scan(/.{8}/).collect{|e| p+e}.join('.')
end
def self.from_i(i)
ip = 3.downto(0).collect {|s| (i >> 8*s) & 0xff }.join('.')
self.new(ip)
end
def &(another_ip)
IP.from_i(self.to_i & another_ip.to_i)
end
def +(size)
IP.from_i(self.to_i + size)
end
def -(e)
if e.instance_of? Fixnum
IP.from_i(self.to_i - e)
else
e.to_i - self.to_i
end
end
def <=>(another_ip)
self.to_i <=> another_ip.to_i
end
end
class Netmask < IP
def self.from_cidr(cidr)
self.from_i(0xffffffff ^ 2**(32-cidr)-1)
end
def to_cidr
32 - Math.log((to_i ^ 0xffffffff) + 1, 2).to_i
end
end
class Net
attr_accessor :ip, :netmask
def initialize(ip, netmask = nil)
if netmask
@ip, @netmask = ip, netmask
else
ip, netmask = ip.split('/')
@ip = IP.new(ip)
@netmask = Netmask.from_cidr(netmask.to_i) if netmask
end
@network_address = network_address
@last_address = last_address
end
def network_address
IP.from_i(@ip.to_i & @netmask.to_i)
end
def last_address
IP.from_i(@ip.to_i | (@netmask.to_i ^ 0xffffffff))
end
def info
s = ""
s << @network_address.to_s.ljust(15)
s << " /"
s << @netmask.to_cidr.to_s.rjust(2)
s << " "
s << @network_address.to_s.ljust(15)
s << " "
s << last_address.to_s.ljust(15)
s
end
def to_s
"#{@network_address}/#{@netmask.to_cidr}"
end
def next_net
next_ip = IP.from_i(last_address.to_i + 1)
Net.new(next_ip, @netmask)
end
def between?(ip_start, ip_end)
network_address >= ip_start && last_address <= ip_end
end
end
class Range
def initialize(ip_start, size)
@ip_start = IP.new(ip_start)
@ip_end = @ip_start + size
end
def get_nets
self.class.get_nets(@ip_start, @ip_end)
end
def largest_subnet
self.class.largest_subnet(@ip_start, @ip_end)
end
def self.get_nets(ip_start, ip_end)
nets = []
net_m = largest_subnet(ip_start, ip_end)
# left scraps
if ip_start < net_m.network_address
nets.concat get_nets(ip_start, net_m.network_address - 1)
end
nets << net_m
# right scraps
if net_m.last_address < ip_end
nets.concat get_nets(net_m.last_address + 1, ip_end)
end
nets
end
def self.largest_subnet(ip_start, ip_end)
size = ip_start - ip_end
# start with the largest subnet
if size > 0
cidr = 32 - Math.log(size, 2).floor
else
cidr = 32
end
fits = false
while !fits
net = Net.new(ip_start, Netmask.from_cidr(cidr))
net = net.next_net if ip_start > net.network_address
cidr += 1
break if cidr > 32
fits = net.between?(ip_start, ip_end)
end
net
end
end
################################################################################
# SecurityGroups and Rules
################################################################################
@ -87,10 +270,11 @@ class Rule
@rule[:range] || nil
end
def net
nets = [@rule[:net]].flatten.compact
nets.empty? ? nil : nets
return nil if @rule[:ip].nil? || @rule[:size].nil?
r = Range.new(@rule[:ip], @rule[:size].to_i)
r.get_nets.collect{|n| n.to_s}
end
# Helper
@ -115,7 +299,7 @@ class Rule
end
if net && !valid_net?
error_message << "Invalid net: #{net}"
error_message << "Invalid net: IP:'#{@rule[:ip]}' SIZE:'#{@rule[:size]}'"
valid = false
end
@ -123,16 +307,8 @@ class Rule
end
def valid_net?
valid = true
net.each do |n|
if !n.match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}$/)
valid = false
break
end
end
valid
@rule[:ip].match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) && \
@rule[:size].match(/^\d+$/)
end
end