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:
parent
eb9e4a5c42
commit
05fa0053d8
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user