* luci/libs: fix off-by-one bug in luci.ip
[project/luci.git] / libs / core / luasrc / ip.lua
index ea243f9..2fe7129 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)
@@ -190,6 +198,37 @@ function IPv6(address, netmask)
        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
+       else
+               tmp = tmp .. hex
+       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
+
 
 cidr = luci.util.class()
 
@@ -283,24 +322,27 @@ function cidr.prefix( self, mask )
        return prefix
 end
 
-function cidr.network( self )
+function cidr.network( self, bits )
        local data = { }
+       bits = bits or self[3]
 
-       for i = 1, math.floor( self[3] / 16 ) do
+       for i = 1, math.floor( bits / 16 ) do
                table.insert( data, self[2][i] )
        end
 
-       table.insert( data, bit.band( self[2][1+#data], __mask16(self[3]) ) )
+       if #data < #self[2] then
+               table.insert( data, bit.band( self[2][1+#data], __mask16(bits) ) )
 
-       for i = #data, #self[2] do
-               table.insert( data, 0 )
+               for i = #data + 1, #self[2] do
+                       table.insert( data, 0 )
+               end
        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 )
@@ -311,20 +353,22 @@ function cidr.mask( self, bits )
                table.insert( data, 0xFFFF )
        end
 
-       table.insert( data, __mask16(bits) )
+       if #data < #self[2] then
+               table.insert( data, __mask16(bits) )
 
-       for i = #data + 1, #self[2] do
-               table.insert( data, 0 )
+               for i = #data + 1, #self[2] do
+                       table.insert( data, 0 )
+               end
        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 )
-       local mask1 = self:mask()
-       local mask2 = addr:mask()
-       if mask1 <= mask2 then
-               return self:mask(addr:prefix()) == mask2
+       assert( self[1] == addr[1], "Can't compare IPv4 and IPv6 addresses" )
+
+       if self:prefix() <= addr:prefix() then
+               return self:network() == addr:network(self:prefix())
        end
 
        return false