Module:IP: Difference between revisions

From the Croc Wiki, the Croc encyclopedia
Jump to navigationJump to search
1,680 bytes added ,  7 years ago
need to use __index to have a unique key which is really private - if outside code gets uniqueKey with getmetatable then they can set it in another table's __eq metamethod, thus foiling isSubnetObject
(check for nil base IPs in makeSubnet)
(need to use __index to have a unique key which is really private - if outside code gets uniqueKey with getmetatable then they can set it in another table's __eq metamethod, thus foiling isSubnetObject)
 
(12 intermediate revisions by 2 users not shown)
Line 8:
local checkType = libraryUtil.checkType
local checkTypeMulti = libraryUtil.checkTypeMulti
local makeCheckSelfFunction = libraryUtil.makeCheckSelfFunction
 
-- Constants
Line 17 ⟶ 18:
--------------------------------------------------------------------------------
 
local function makeCheckSelfFuncmakeValidationFunction(className, objectName, isSelfFuncisObjectFunc)
-- Makes a function for classes to check that their methods have a valid
-- self parameter.
return function (methodName, selfObject)
if not isSelfFunc(selfObject) then
error(string.format(
'invalid %s object. Did you call %s with a dot instead of a colon, i.e. %s.%s() instead of %s:%s()?',
className, methodName, objectName, methodName, objectName, methodName
), 3)
end
end
end
 
local function makeValidationFunc(className, isObjectFunc)
-- Make a function for validating a specific object.
return function (methodName, argIdx, arg)
Line 368 ⟶ 356:
end
 
validateIPAddress = makeValidationFunction('IPAddress', isIPAddressObject)
-- A function to check whether methods are called with a valid self
-- parameter.
local checkSelf = makeCheckSelfFunc(
'IPAddress',
'ipAddress',
isIPAddressObject
)
 
validateIPAddress = makeValidationFunc('IPAddress', isIPAddressObject)
 
-- Metamethods that don't need upvalues
Line 407 ⟶ 387:
local data = {}
data.rawIP = rawIP
 
-- A function to check whether methods are called with a valid self
-- parameter.
local checkSelf = makeCheckSelfFunction(
'IP',
'ipAddress',
obj,
'IPAddress object'
)
 
-- Public methods
function obj:getIP()
checkSelf(self, 'getIP', self)
return tostring(data.rawIP)
end
 
function obj:getVersion()
checkSelf(self, 'getVersion', self)
return data.rawIP:getVersion()
end
 
function obj:isIPv4()
checkSelf(self, 'isIPv4', self)
return data.rawIP:isIPv4()
end
 
function obj:isIPv6()
checkSelf(self, 'isIPv6', self)
return data.rawIP:isIPv6()
end
 
function obj:isInSubnet(subnet)
checkSelf(self, 'isInSubnet', self)
local tp = type(subnet)
if tp == 'string' then
Line 443 ⟶ 432:
 
function obj:getSubnet(bitLength)
checkSelf(self, 'getSubnet', self)
checkType('getSubnet', 1, bitLength, 'number')
return makeSubnetFromRaw(data.rawIP, bitLength)
Line 449 ⟶ 438:
 
function obj:getNextIP()
checkSelf(self, 'getNextIP', self)
return makeIPAddressFromRaw(data.rawIP:getAdjacent())
end
 
function obj:getPreviousIP()
checkSelf(self, 'getPreviousIP', self)
return makeIPAddressFromRaw(data.rawIP:getAdjacent(true))
end
Line 471 ⟶ 460:
end
end,
__metatable = false, -- Don't allow access to the metatable
})
end
Line 496 ⟶ 486:
 
do
-- uniqueKey is a unique, private key used to test whether a given object
local dataKey = {} -- A unique key for accessing Subnet objects' internal data.
-- is a Subnet object.
local uniqueKey = setmetatable({}, {__metatable = false})
 
-- Private static methods
local function isSubnetObject(val)
-- Return true if val is a Subnet object, and false otherwise.
return type(val) == 'table' and val[dataKey] ~= nil
return getmetatable(val) == uniqueKey
end
 
-- Function to validate subnet objects.
validateSubnet = makeValidationFunc('Subnet', isSubnetObject)
-- Params:
-- methodName (string) - the name of the method being validated
-- argIdx (number) - the position of the argument in the argument list
-- arg - the argument to be validated
validateSubnet = makeValidationFunction('Subnet', isSubnetObject)
 
-- Metamethods that don't need upvalues
local function subnetEquals(subnet1, subnet2)
return subnet1:getCIDR() == subnet2:getCIDR()
end
 
local function concatenateSubnets(subnet1, subnet2)
return tostring(subnet1) .. tostring(subnet2)
end
 
local function subnetToString(subnet)
return subnet:getCIDR()
end
 
-- Constructors
Line 513 ⟶ 524:
bitLength = bitLength,
}
 
-- A function to check whether methods are called with a valid self
-- parameter.
local checkSelf = makeCheckSelfFunction(
'IP',
'subnet',
obj,
'Subnet object'
)
 
-- Public methods
function obj:getPrefix()
checkSelf(self, 'getPrefix')
if not data.prefix then
data.prefix = makeIPAddressFromRaw(
Line 525 ⟶ 546:
 
function obj:getHighestIP()
checkSelf(self, 'getHighestIP')
if not data.highestIP then
data.highestIP = makeIPAddressFromRaw(
Line 534 ⟶ 556:
 
function obj:getBitLength()
checkSelf(self, 'getBitLength')
return data.bitLength
end
 
function obj:getCIDR()
checkSelf(self, 'getCIDR')
return string.format(
'%s/%d',
Line 545 ⟶ 569:
 
function obj:getVersion()
checkSelf(self, 'getVersion')
return data.rawIP:getVersion()
end
 
function obj:isIPv4()
checkSelf(self, 'isIPv4')
return data.rawIP:isIPv4()
end
 
function obj:isIPv6()
checkSelf(self, 'isIPv6')
return data.rawIP:isIPv6()
end
 
function obj:containsIP(ip)
checkSelf(self, 'containsIP')
local tp = type(ip)
if tp == 'string' then
ip = makeIPAddress(ip)
elseif tp == 'table' then
validateIPAddress('containsIP', 1, ip)
else
checkTypeMulti('containsIP', 1, ip, {'string', 'table'})
end
if self:getVersion() == ip:getVersion() then
return self:getPrefix() <= ip and ip <= self:getHighestIP()
Line 564 ⟶ 600:
 
function obj:overlapsSubnet(subnet)
checkSelf(self, 'overlapsSubnet')
local tp = type(subnet)
if tp == 'string' then
subnet = makeSubnet(subnet)
elseif tp == 'table' then
validateSubnet('overlapsSubnet', 1, subnet)
else
checkTypeMulti('overlapsSubnet', 1, subnet, {'string', 'table'})
end
if self:getVersion() == subnet:getVersion() then
return (
Line 574 ⟶ 619:
 
function obj:walk()
checkSelf(self, 'walk')
local started
local current = self:getPrefix()
Line 591 ⟶ 637:
return setmetatable(obj, {
__index = function (self, key)
if key == dataKeyuniqueKey then
return datatrue
end
end,
__eq = function (selfsubnetEquals, obj)
__concat = concatenateSubnets,
return self:getCIDR() == obj:getCIDR()
__tostring = subnetToString,
end,
__metatable = false,
__tostring = function (self)
return self:getCIDR()
end,
})
end
 
makeSubnet = function (cidr)
-- Return a Subnet object from a CIDR string. If the CIDR string is
-- invalid, throw an error.
local lhs, rhs = cidr: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 and (n == 0 or not rhs:find('^0')) then
-- The right-hand side is a number between 0 and 32 (for IPv4)
-- or 0 and 128 (for IPv6) and doesn't have any leading zeroes.
local base = RawIP.newFromIP(lhs)
if base then
-- The left-hand side is a valid IP address.
local prefix = base:getPrefix(n)
if base == prefix then
-- The left-hand side is the lowest IP in the subnet.
return makeSubnetFromRaw(prefix, n)
end
Cookies help us deliver our services. By using our services, you agree to our use of cookies.

Navigation menu