Module:IP: Difference between revisions

From the Croc Wiki, the Croc encyclopedia
Jump to navigationJump to search
save progress on new implentation plan - an internal RawIP object used for bit operations on IP parts
(allow creation of IPAddress objects from their parts with newIPFromParts)
(save progress on new implentation plan - an internal RawIP object used for bit operations on IP parts)
Line 11:
local V6 = 'IPv6'
 
--------------------------------------------------------------------------------
-- Collection class
-- Functions from Module:IPblock follow.
-- A table to hold items. Used internally.
-- TODO Massage following for style consistent with this module.
--------------------------------------------------------------------------------
 
local function collection()Collection
do
-- Return a table to hold items.
returnlocal mt = {
n = 0,
add = function (self, item)
self.n = self.n + 1
Line 26 ⟶ 25:
join = function (self, sep)
return table.concat(self, sep)
end,
sort = function (self, comp)
table.sort(self, comp)
end,
}
Collection = function ()
return setmetatable({n = 0}, mt)
end
end
 
--------------------------------------------------------------------------------
-- RawIP class
-- Numeric representation of an IPv4 or IPv6 address. Used internally.
-- A RawIP object is constructed by adding data to a Collection object and
-- then giving it a new metatable. This is to avoid the memory overhead of
-- copying the data to a new table.
--------------------------------------------------------------------------------
 
local RawIP = {}
RawIP.__index = RawIP
 
function RawIP.newFromIPv4(ipStr)
-- If ipStr is a valid IPv4 string, return a collection of its parts.
-- Otherwise, return nil.
-- This representation is for compatibility with IPv6 addresses.
local octets = Collection()
local s = ipStr:match('^%s*(.-)%s*$') .. '.'
for item in s:gmatch('(.-)%.') do
octets:add(item)
end
if octets.n == 4 then
for i, s in ipairs(octets) do
if s:match('^%d+$') then
local num = tonumber(s)
if 0 <= num and num <= 255 then
if num > 0 and s:match('^0') then
-- A redundant leading zero is for an IP in octal.
return false
end
octets[i] = num
else
return false
end
else
return false
end
end
local parts = Collection()
for i = 1, 3, 2 do
parts:add(octets[i] * 256 + octets[i+1])
end
return setmetatable(parts, RawIP)
end
return nil
end
 
function RawIP.newFromIPv6(ipStr)
-- If ipStr is a valid IPv6 string, return a collection of its parts.
-- Otherwise, return nil.
ipStr = ipStr:match('^%s*(.-)%s*$')
local _, n = ipStr:gsub(':', ':')
if n < 7 then
ipStr, n = ipStr:gsub('::', string.rep(':', 9 - n))
end
local parts = Collection()
for item in (ipStr .. ':'):gmatch('(.-):') do
parts:add(item)
end
if parts.n == 8 then
for i, s in ipairs(parts) do
if s == '' then
parts[i] = 0
else
local num = tonumber('0x' .. s)
if num and 0 <= num and num <= 65535 then
parts[i] = num
else
return false
end
end
end
return setmetatable(parts, RawIP)
end
return nil
end
 
local function RawIP:copyChanged(parts, down)
-- Return a copy of IPv4 or IPv6 parts, incremented or decremented.
-- Will wraparound:
Line 40 ⟶ 115:
-- decrement 0.0.0.0 → 255.255.255.255
-- :: → ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
local result = { n = parts.n }Collection()
result.n = self.n
local carry = down and 0xffff or 1
for i = partsself.n, 1, -1 do
local sum = partsself[i] + carry
if sum >= 0x10000 then
carry = down and 0x10000 or 1
Line 52 ⟶ 128:
result[i] = sum
end
return setmetatable(result, RawIP)
end
 
local function RawIP:copyPrefix(parts, length)
-- Return a copy of IPv4 or IPv6 parts, masked to length.
local result = { n = parts.n }Collection()
for iresult.n = 1, partsself.n do
for i = 1, self.n do
if length > 0 then
if length >= 16 then
result[i] = partsself[i]
length = length - 16
else
result[i] = bit32.band(partsself[i],
bit32.arshift(0xffff8000, length - 1))
length = 0
Line 72 ⟶ 149:
end
end
return setmetatable(result, RawIP)
end
 
local function RawIP:setHostBits(parts, length)
-- Return a copy of IPv4 or IPv6 parts, with the least-significant bits
-- (host bits) set to 1.
-- The most-significant length bits identify the network.
local bits = partsself.n * 16
local width
if length <= 0 then
Line 88 ⟶ 165:
width = bits - length
end
local result = { n = parts.n }Collection()
for iresult.n = partsself.n, 1, -1 do
for i = self.n, 1, -1 do
if width > 0 then
if width >= 16 then
Line 95 ⟶ 173:
width = width - 16
else
result[i] = bit32.replace(partsself[i], 0xffff, width - 1, width)
width = 0
end
else
result[i] = partsself[i]
end
end
return setmetatable(result, rawIP)
end
 
local function ipv6StringRawIP:_makeIPv6String(ip)
-- Return aan IPv6 string equivalentrepresentation toof the givenobject. IPv6Behavior address.is undefined
-- if the current object is IPv4.
local z1, z2 -- indices of run of zeros to be displayed as "::"
local zstart, zcount
for i = 1, 9 do
-- Find left-most occurrence of longest run of two or more zeros.
if i < 9 and ipself[i] == 0 then
if zstart then
zcount = zcount + 1
Line 129 ⟶ 208:
end
end
local parts = collectionCollection()
for i = 1, 8 do
if z1 and z1 <= i and i <= z2 then
Line 143 ⟶ 222:
end
else
parts:add(string.format('%x', ipself[i]))
end
end
return table.concat(parts, :join(':')
end
 
local function ipStringRawIP:_makeIPv4String(ip)
-- Return an IPv4 string representation of the object. Behavior is undefined
-- if the current object is IPv6.
local parts = Collection()
for i = 1, 2 do
local w = self[i]
parts:add(math.floor(w / 256))
parts:add(w % 256)
end
return parts:join('.')
end
 
function RawIP:__tostring()
-- Return a string equivalent to given IP address (IPv4 or IPv6).
if ipself.n == 2 then
return self:_makeIPv4String()
-- IPv4.
else
local parts = {}
return self:_makeIPv6String()
for i = 1, 2 do
local w = ip[i]
local q = i == 1 and 1 or 3
parts[q] = math.floor(w / 256)
parts[q+1] = w % 256
end
return table.concat(parts, '.')
end
return ipv6String(ip)
end
 
Line 178 ⟶ 262:
do
local dataKey = {} -- A unique key to access objects' internal data.
 
-- Private static methods
local function parseIPv4(ipStr)
-- If ipStr is a valid IPv4 string, return a collection of its parts.
-- Otherwise, return nil.
-- This representation is for compatibility with IPv6 addresses.
local octets = collection()
local s = ipStr:match('^%s*(.-)%s*$') .. '.'
for item in s:gmatch('(.-)%.') do
octets:add(item)
end
if octets.n == 4 then
for i, s in ipairs(octets) do
if s:match('^%d+$') then
local num = tonumber(s)
if 0 <= num and num <= 255 then
if num > 0 and s:match('^0') then
-- A redundant leading zero is for an IP in octal.
return false
end
octets[i] = num
else
return false
end
else
return false
end
end
local parts = collection()
for i = 1, 3, 2 do
parts:add(octets[i] * 256 + octets[i+1])
end
return parts
end
return nil
end
 
local function parseIPv6(ipStr)
-- If ipStr is a valid IPv6 string, return a collection of its parts.
-- Otherwise, return nil.
ipStr = ipStr:match('^%s*(.-)%s*$')
local _, n = ipStr:gsub(':', ':')
if n < 7 then
ipStr, n = ipStr:gsub('::', string.rep(':', 9 - n))
end
local parts = collection()
for item in (ipStr .. ':'):gmatch('(.-):') do
parts:add(item)
end
if parts.n == 8 then
for i, s in ipairs(parts) do
if s == '' then
parts[i] = 0
else
local num = tonumber('0x' .. s)
if num and 0 <= num and num <= 65535 then
parts[i] = num
else
return false
end
end
end
return parts
end
return nil
end
 
-- Metamethods that don't need upvalues
Cookies help us deliver our services. By using our services, you agree to our use of cookies.

Navigation menu