Module:IP: Difference between revisions

From the Croc Wiki, the Croc encyclopedia
Jump to navigationJump to search
add more methods to RawIP and rework IPAddress and Subnet to use them
m (comment and variable tweaks)
(add more methods to RawIP and rework IPAddress and Subnet to use them)
Line 3:
 
-- Load modules
require('Module:No globals')
local bit32 = require('bit32')
local libraryUtil = require('libraryUtil')
Line 45 ⟶ 46:
-- Constructors
function RawIP.newFromIPv4(ipStr)
-- IfReturns a RawIP object if ipStr is a valid IPv4 string. Otherwise, return a collection of its parts.
-- Otherwise, returnreturns nil.
-- This representation is for compatibility with IPv6 addresses.
local octets = Collection()
Line 100 ⟶ 101:
parts[i] = num
else
return falsenil
end
end
Line 107 ⟶ 108:
end
return nil
end
 
function RawIP.newFromIP(ipStr)
-- Return a new RawIP object from either an IPv4 string or an IPv6
-- string. If ipStr is not a valid IPv4 or IPv6 string, then return
-- nil.
return RawIP.newFromIPv4(ipStr) or RawIP.newFromIPv6(ipStr)
end
 
-- Methods
function RawIP:getVersion()
return self.n == 2 and V4 or V6
end
 
function RawIP:isIPv4()
return self.n == 2
end
 
function RawIP:isIPv6()
return self.n == 8
end
 
function RawIP:getAdjacent(previous)
-- Return a RawIP object for an adjacent IP address. If previous is true
Line 185 ⟶ 205:
end
end
return setmetatable(result, rawIPRawIP)
end
 
Line 280 ⟶ 300:
 
--------------------------------------------------------------------------------
-- Set up classes to be exported
-- IPAddress class
-- Represents a single IPv4 or IPv6 address.
--------------------------------------------------------------------------------
 
-- The IPAddress class and the Subnet class should be accessible from each
local IPAddress = {}
-- other, but should not be accessible from the RawIP class, so initialize them
-- here.
local IPAddress, Subnet = {}, {}
 
-- IPAddress needs to create Subnet objects using its RawIP data, and Subnet
local newIPFromRaw
-- newIPFromRawneeds constructsto a newcreate IPAddress objectobjects fromwith aits rawIPRawIP object.data Itas needswell. However,
-- other modules shouldn't have to worry about RawIP data, so the constructors
-- to be accessible from the Subnet class but it should not be public.
-- need to be private. Hence the variables holding the constructor functions
-- need to be initialized here as well.
local makeIPAddress, makeSubnet
 
--------------------------------------------------------------------------------
-- IPAddress class
-- Represents a single IPv4 or IPv6 address.
--------------------------------------------------------------------------------
 
do
Line 311 ⟶ 341:
 
-- Constructors
newIPFromRawmakeIPAddress = function (rawIP)
-- Constructs a new IPAddress object from a rawIP object. This function
-- is for internal use; it is called by IPAddress.new and from other
Line 320 ⟶ 350:
-- Set up structure
local obj = {}
local data = {}
data.rawIP = rawIP,
version = rawIP.n == 2 and V4 or V6,
}
 
-- Public methods
Line 331 ⟶ 359:
 
function obj:getVersion()
return data.versionrawIP:getVersion()
end
 
function obj:getHighestIP(bitLength)
return newIPFromRaw(setHostBits(data.rawIP, bitLength))
end
 
function obj:getPrefix(bitLength)
return newIPFromRaw(copyPrefix(data.rawIP, bitLength))
end
 
function obj:isIPv4()
return data.version == V4rawIP:isIPv4()
end
 
function obj:isIPv6()
return data.version == V6rawIP:isIPv6()
end
 
function obj:isInSubnet(subnet)
return subnet:containsIP(self)
-- TODO Consider alternative of checking:
-- (ipFirst <= self and self <= ipLast)
if self:getVersion() == subnet:getVersion() then
local prefix = self:getPrefix(subnet:getBitLength())
return prefix == subnet:getPrefix()
end
return false
end
 
function obj:getNextIP()
return newIPFromRawmakeIPAddress(data.rawIP:getAdjacent())
end
 
function obj:getPreviousIP()
return newIPFromRawmakeIPAddress(data.rawIP:getAdjacent(true))
end
 
Line 384 ⟶ 398:
function IPAddress.new(ip)
checkType('IPAddress.new', 1, ip, 'string')
local rawIP = RawIP.newFromIPv4String(ip) or RawIP.newFromIPv6StringnewFromIP(ip)
if not rawIP then
error(string.format("'%s' is an invalid IP'", ip), 2)
end
return newIPFromRawmakeIPAddress(rawIP)
end
end
 
local function makeSubnet(data, cidrStr)
-- If cidrStr is a valid IPv4 or IPv6 CIDR specification, store its
-- information in data and return its version. Otherwise, return nil.
local lhs, rhs = cidrStr:match('^%s*(.-)/(%d+)%s*$')
if lhs then
local bits = lhs:find(':', 1, true) and 128 or 32
local n = tonumber(rhs)
if n and n <= bits then
local base = IPAddress.new(lhs)
local prefix = base:getPrefix(n)
if base == prefix then
data.bitLength = n
data.prefix = prefix
data.highestIP = base:getHighestIP(n)
return bits == 32 and V4 or V6
end
end
end
return nil
end
 
Line 417 ⟶ 410:
-- Represents a block of IPv4 or IPv6 addresses.
--------------------------------------------------------------------------------
 
local Subnet = {}
 
do
Line 424 ⟶ 415:
local mt = {}
 
-- ConstructorConstructors
makeSubnet = function Subnet.new(cidrrawIP, bitLength)
-- Set up structure
local obj = setmetatable({}, mt)
local data = {}
rawIP = rawIP,
bitLength = bitLength,
}
 
-- Public methods
function obj:getPrefix()
if not data.prefix then
data.prefix = makeIPAddress(
data.rawIP:getPrefix(data.bitLength)
)
end
return data.prefix
end
 
function obj:getHighestIP()
if not data.highestIP then
data.highestIP = makeIPAddress(
data.rawIP:getHighestHost(data.bitLength)
)
end
return data.highestIP
end
Line 444 ⟶ 448:
 
function obj:getCIDR()
return string.format('%s/%d', self:getPrefix(), self:getBitLength())
'%s/%d',
tostring(self:getPrefix()), self:getBitLength()
)
end
 
function obj:getVersion()
return data.versionrawIP:getVersion()
end
 
function obj:isIPv4()
return data.version == V4rawIP:isIPv4()
end
 
function obj:isIPv6()
return data.version == V6rawIP:isIPv6()
end
 
function obj:containsIP(ip)
-- TODO See ip:isInSubnet(subnet); use this technique there?
if self:getVersion() == ip:getVersion() then
return self:getPrefix() <= ip and ip <= self:getHighestIP()
Line 477 ⟶ 483:
end
 
return obj
-- Set initial values
end
 
function Subnet.new(cidr)
checkType('Subnet.new', 1, cidr, 'string')
local lhs, rhs = cidr:match('^%s*(.-)/(%d+)%s*$')
data.version = makeSubnet(data, cidr)
if not data.versionlhs then
local bits = lhs:find(':', 1, true) and 128 or 32
error('invalid CIDR', 2)
local n = tonumber(rhs)
if n and n <= bits then
local base = RawIP.newFromIP(lhs)
local prefix = base:getPrefix(n)
if base == prefix then
return makeSubnet(prefix, n)
end
end
end
error(string.format("'%s' is an invalid CIDR string", cidr), 2)
 
return obj
end
 
Cookies help us deliver our services. By using our services, you agree to our use of cookies.

Navigation menu