* luci/libs: added Hex() constructor to luci.ip
[project/luci.git] / libs / core / luasrc / ip.lua
index 391dced..15730db 100644 (file)
@@ -46,6 +46,14 @@ local function __mask16(bits)
        )
 end
 
+local function __length(family)
+       if family == FAMILY_INET4 then
+               return 32
+       else
+               return 128
+       end
+end
+
 -- htons(), htonl(), ntohs(), ntohl()
 
 function htons(x)
@@ -77,11 +85,13 @@ ntohl = htonl
 function IPv4(address, netmask)
        address = address or "0.0.0.0/0"
 
+       local obj = __bless({ FAMILY_INET4 })
+
        local data = {}
        local prefix = address:match("/(.+)")
 
        if netmask then
-               prefix = IPv4():prefix(netmask)
+               prefix = obj:prefix(netmask)
        elseif prefix then
                address = address:gsub("/.+","")
                prefix = tonumber(prefix)
@@ -100,24 +110,25 @@ function IPv4(address, netmask)
        if b1 and b1 <= 255 and
           b2 and b2 <= 255 and
           b3 and b3 <= 255 and
-          b4 and b4 <= 255
+          b4 and b4 <= 255 and
+          prefix
        then
-               return __bless({
-                       FAMILY_INET4,
-                       { b1 * 256 + b2, b3 * 256 + b4 },
-                       prefix
-               })
+               table.insert(obj, { b1 * 256 + b2, b3 * 256 + b4 })
+               table.insert(obj, prefix)
+               return obj
        end
 end
 
 function IPv6(address, netmask)
        address = address or "::/0"
 
+       local obj = __bless({ FAMILY_INET6 })
+
        local data = {}
        local prefix = address:match("/(.+)")
 
        if netmask then
-               prefix = IPv6():prefix(netmask)
+               prefix = obj:prefix(netmask)
        elseif prefix then
                address = address:gsub("/.+","")
                prefix = tonumber(prefix)
@@ -180,9 +191,40 @@ function IPv6(address, netmask)
                end
        end
 
-       if #data == 8 then
-               return __bless({ FAMILY_INET6, data, prefix })
+       if #data == 8 and prefix then
+               table.insert(obj, data)
+               table.insert(obj, prefix)
+               return obj
+       end
+end
+
+function Hex( hex, prefix, family, swap )
+       family = ( family ~= nil ) and family or FAMILY_INET4
+       swap   = ( swap   == nil ) and true   or swap
+       prefix = prefix or __length(family)
+
+       local len  = __length(family)
+       local tmp  = ""
+       local data = { }
+
+       for i = 1, (len/4) - #hex do tmp = tmp .. '0' end
+
+       if swap and LITTLE_ENDIAN then
+               for i = #hex, 1, -2 do tmp = tmp .. hex:sub( i - 1, i ) end
+       end
+
+       hex = tmp
+
+       for i = 1, ( len / 4 ), 4 do
+               local n = tonumber( hex:sub( i, i+3 ), 16 )
+               if n then
+                       table.insert( data, n )
+               else
+                       return nil
+               end
        end
+
+       return __bless({ family, data, len })
 end
 
 
@@ -251,8 +293,9 @@ function cidr.prefix( self, mask )
 
        if mask then
                prefix = 0
-
+               local stop = false
                local obj = self:is4() and IPv4(mask) or IPv6(mask)
+
                if not obj then
                        return nil
                end
@@ -261,9 +304,13 @@ function cidr.prefix( self, mask )
                        local pos = bit.lshift(1, 15)
                        for i=15, 0, -1 do
                                if bit.band(block, pos) == pos then
-                                       prefix = prefix + 1
+                                       if not stop then
+                                               prefix = prefix + 1
+                                       else
+                                               return nil
+                                       end
                                else
-                                       return prefix
+                                       stop = true
                                end
                                pos = bit.rshift(pos, 1)
                        end
@@ -286,11 +333,11 @@ function cidr.network( self )
                table.insert( data, 0 )
        end
 
-       return __bless({ self[1], data, self:is4() and 32 or 128 })
+       return __bless({ self[1], data, __length(self[1]) })
 end
 
 function cidr.host( self )
-       return __bless({ self[1], data, self:is4() and 32 or 128 })
+       return __bless({ self[1], data, __length(self[1]) })
 end
 
 function cidr.mask( self, bits )
@@ -307,12 +354,14 @@ function cidr.mask( self, bits )
                table.insert( data, 0 )
        end
 
-       return __bless({ self[1], data, self:is4() and 32 or 128 })
+       return __bless({ self[1], data, __length(self[1]) })
 end
 
 function cidr.contains( self, addr )
-       if self:mask() <= addr:mask() then
-               return self:mask(addr:prefix()) == addr:mask()
+       local mask1 = self:mask()
+       local mask2 = addr:mask()
+       if mask1 <= mask2 then
+               return self:mask(addr:prefix()) == mask2
        end
 
        return false