diff --git a/nselib/ipOps.lua b/nselib/ipOps.lua
index 0749398bc..d7cb6b529 100644
--- a/nselib/ipOps.lua
+++ b/nselib/ipOps.lua
@@ -445,37 +445,78 @@ get_ips_from_range = function( range )
return nil, nil, "Error in ipOps.get_ips_from_range: Expected a range as a string."
end
- local first, last, prefix
- if range:match( "/" ) then
- first, prefix = range:match( "([%x%d:%.]+)/(%d+)" )
- elseif range:match( "-" ) then
- first, last = range:match( "([%x%d:%.]+)%s*%-%s*([%x%d:%.]+)" )
+ local ip, prefix = range:match("^%s*([%x:.]+)/(%d+)%s*$")
+ if ip then
+ return get_first_last_ip(ip, prefix)
end
-
- local err = {}
- if first and ( last or prefix ) then
- first, err[#err+1] = expand_ip( first )
- else
+ local first, last = range:match("^%s*([%x:.]+)%s*%-%s*([%x:.]+)%s*$")
+ if not first then
return nil, nil, "Error in ipOps.get_ips_from_range: The range supplied could not be interpreted."
end
- if last then
- last, err[#err+1] = expand_ip( last )
- elseif first and prefix then
- last, err[#err+1] = get_last_ip( first, prefix )
- end
- if first and last then
- if ( first:match( ":" ) and not last:match( ":" ) ) or ( not first:match( ":" ) and last:match( ":" ) ) then
- return nil, nil, "Error in ipOps.get_ips_from_range: First IP address is of a different address family to last IP address."
+ local err
+ first, err = expand_ip(first)
+ if not err then
+ last, err = expand_ip(last)
+ end
+ if not err then
+ local af = function (ip) return ip:find(":") and 6 or 4 end
+ if af(first) ~= af(last) then
+ err = "Error in ipOps.get_ips_from_range: First IP address is of a different address family to last IP address."
end
- return first, last
- else
- return nil, nil, table.concat( err, " " )
end
-
+ if err then
+ return nil, nil, err
+ end
+ return first, last
end
+---
+-- Calculates the first and last IP addresses of a range of addresses,
+-- given an IP address in the range and a prefix length for that range
+-- @param ip String representing an IPv4 or IPv6 address. Shortened notation
+-- is permitted.
+-- @param prefix Number or a string representing a decimal number corresponding
+-- to a prefix length.
+-- @usage
+-- first, last = ipOps.get_first_last_ip( "192.0.0.0", 26)
+-- @return String representing the first IP address of the range denoted by
+-- the supplied parameters (or nil in case of an error).
+-- @return String representing the last IP address of the range denoted by
+-- the supplied parameters (or nil in case of an error).
+-- @return String error message in case of an error.
+get_first_last_ip = function(ip, prefix)
+ local err
+ ip, err = ip_to_bin(ip)
+ if err then return nil, nil, err end
+ prefix = tonumber(prefix)
+ if not prefix or prefix ~= math.floor(prefix) or prefix < 0 or prefix > #ip then
+ return nil, nil, "Error in ipOps.get_first_last_ip: Invalid prefix."
+ end
+
+ local net = ip:sub(1, prefix)
+ local first = bin_to_ip(net .. ("0"):rep(#ip - prefix))
+ local last = bin_to_ip(net .. ("1"):rep(#ip - prefix))
+ return first, last
+end
+
+---
+-- Calculates the first IP address of a range of addresses given an IP address in
+-- the range and prefix length for that range.
+-- @param ip String representing an IPv4 or IPv6 address. Shortened notation
+-- is permitted.
+-- @param prefix Number or a string representing a decimal number corresponding
+-- to a prefix length.
+-- @usage
+-- first = ipOps.get_first_ip( "192.0.0.0", 26 )
+-- @return String representing the first IP address of the range denoted by the
+-- supplied parameters (or nil in case of an error).
+-- @return String error message in case of an error.
+get_first_ip = function(ip, prefix)
+ local first, last, err = get_first_last_ip(ip, prefix)
+ return first, err
+end
---
-- Calculates the last IP address of a range of addresses given an IP address in
@@ -489,23 +530,9 @@ end
-- @return String representing the last IP address of the range denoted by the
-- supplied parameters (or nil in case of an error).
-- @return String error message in case of an error.
-get_last_ip = function( ip, prefix )
-
- local first, err = ip_to_bin( ip )
- if err then return nil, err end
-
- prefix = tonumber( prefix )
- if not prefix or ( prefix < 0 ) or ( prefix > # first ) then
- return nil, "Error in ipOps.get_last_ip: Invalid prefix length."
- end
-
- local hostbits = string.sub( first, prefix + 1 )
- hostbits = string.gsub( hostbits, "0", "1" )
- local last = string.sub( first, 1, prefix ) .. hostbits
- last, err = bin_to_ip( last )
- if err then return nil, err end
- return last
-
+get_last_ip = function(ip, prefix)
+ local first, last, err = get_first_last_ip(ip, prefix)
+ return last, err
end
---
@@ -807,8 +834,12 @@ do
for _, op in ipairs({
{"192.168.13.1", "192/8", unittest.is_true, "IPv4 CIDR"},
{"193.168.13.1", "192/8", unittest.is_false, "IPv4 CIDR"},
+ {"192.168.13.0", "192.168.13.128/24", unittest.is_true, "IPv4 CIDR"},
+ {"193.168.13.0", "192.168.13.128/24", unittest.is_false, "IPv4 CIDR"},
{"2001:db8::9", "2001:db8/32", unittest.is_true, "IPv6 CIDR"},
{"2001:db7::9", "2001:db8/32", unittest.is_false, "IPv6 CIDR"},
+ {"2001:db8::9", "2001:db8::1:0/32", unittest.is_true, "IPv6 CIDR"},
+ {"2001:db7::9", "2001:db8::1:0/32", unittest.is_false, "IPv6 CIDR"},
{"192.168.13.1", "192.168.10.33-192.168.80.80", unittest.is_true, "IPv4 range"},
{"193.168.13.1", "192.168.1.1 - 192.168.5.0", unittest.is_false, "IPv4 range"},
{"2001:db8::9", "2001:db8::1-2001:db8:1::1", unittest.is_true, "IPv6 range"},