1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-23 07:59:03 +00:00

o [NSE] Added ipv6 support to the wsdd, dnssd and upnp libraries. Applied

patch from Dan Miller that fixes errors in processing and sorting ipv6
  addresses in scripts using these libraries. [Daniel Miller, Patrik]
This commit is contained in:
patrik
2011-06-16 05:29:42 +00:00
parent 78e5fc6ec8
commit 1d7b0c0d98
6 changed files with 99 additions and 77 deletions

View File

@@ -1,5 +1,9 @@
# Nmap Changelog ($Id$); -*-text-*- # Nmap Changelog ($Id$); -*-text-*-
o [NSE] Added ipv6 support to the wsdd, dnssd and upnp libraries. Applied
patch from Dan Miller that fixes errors in processing and sorting ipv6
addresses in scripts using these libraries. [Daniel Miller, Patrik]
o [NSE] Added minimal Service Location Protocol (SLP) library and the script o [NSE] Added minimal Service Location Protocol (SLP) library and the script
broadcast-novell-locate that detects servers running eDirectory. [Patrik] broadcast-novell-locate that detects servers running eDirectory. [Patrik]

View File

@@ -41,31 +41,17 @@ module(... or "dnssd", package.seeall)
require 'dns' require 'dns'
require 'target' require 'target'
require 'ipOps'
Util = { Util = {
--- Converts a string ip to a numeric value suitable for comparing
--
-- @param ip string containing the ip to convert
-- @return number containing the converted ip
ipToNumber = function(ip)
local o1, o2, o3, o4 = ip:match("^(%d*)%.(%d*)%.(%d*)%.(%d*)$")
return (256^3) * o1 + (256^2) * o2 + (256^1) * o3 + (256^0) * o4
end,
--- Compare function used for sorting IP-addresses --- Compare function used for sorting IP-addresses
-- --
-- @param a table containing first item -- @param a table containing first item
-- @param b table containing second item -- @param b table containing second item
-- @return true if the port of a is less than the port of b -- @return true if a is less than b
ipCompare = function(a, b) ipCompare = function(a, b)
local ip_a = Util.ipToNumber(a.name) or 0 return ipOps.compare_ip(a, "lt", b)
local ip_b = Util.ipToNumber(b.name) or 0
if ( tonumber(ip_a) < tonumber(ip_b) ) then
return true
end
return false
end, end,
--- Function used to compare discovered DNS services so they can be sorted --- Function used to compare discovered DNS services so they can be sorted
@@ -229,7 +215,10 @@ Comm = {
if status then address = ip end if status then address = ip end
status, ipv6 = Comm.getRecordType( dns.types.AAAA, response, false ) status, ipv6 = Comm.getRecordType( dns.types.AAAA, response, false )
if status then address = address .. " " .. ipv6 end if status then
address = address or ""
address = address .. " " .. ipv6
end
status, txt = Comm.getRecordType( dns.types.TXT, response, true ) status, txt = Comm.getRecordType( dns.types.TXT, response, true )
if status then if status then
@@ -337,7 +326,8 @@ Helper = {
local status, response local status, response
local mcast = self.mcast local mcast = self.mcast
local port = self.port or 5353 local port = self.port or 5353
local host = mcast and "224.0.0.251" or self.host local family = nmap.address_family()
local host = mcast and (family=="inet6" and "ff02::fb" or "224.0.0.251") or self.host
local service = service or stdnse.get_script_args('dnssd.services') local service = service or stdnse.get_script_args('dnssd.services')
if ( not(service) ) then if ( not(service) ) then

View File

@@ -11,6 +11,7 @@ local tonumber = tonumber
local stdnse = require "stdnse" local stdnse = require "stdnse"
local bit = require "bit" local bit = require "bit"
local bin = require "bin"
module ( "ipOps" ) module ( "ipOps" )
@@ -126,7 +127,7 @@ end
-- --
-- Note: IPv6 addresses are not supported. Currently, numbers in NSE are -- Note: IPv6 addresses are not supported. Currently, numbers in NSE are
-- limited to 10^14, and consequently not all IPv6 addresses can be -- limited to 10^14, and consequently not all IPv6 addresses can be
-- represented. -- represented. Consider using <code>ip_to_str</code> for IPv6 addresses.
-- @param ip String representing an IPv4 address. Shortened notation is -- @param ip String representing an IPv4 address. Shortened notation is
-- permitted. -- permitted.
-- @usage -- @usage
@@ -211,7 +212,8 @@ end
--- ---
-- Compares two IP addresses (from the same address family). -- Compares two IP addresses. When comparing addresses from different families,
-- IPv4 addresses will sort before IPv6 addresses.
-- @param left String representing an IPv4 or IPv6 address. Shortened -- @param left String representing an IPv4 or IPv6 address. Shortened
-- notation is permitted. -- notation is permitted.
-- @param op A comparison operator which may be one of the following -- @param op A comparison operator which may be one of the following
@@ -231,47 +233,36 @@ compare_ip = function( left, op, right )
return nil, "Error in ipOps.compare_ip: Expected IP address as a string." return nil, "Error in ipOps.compare_ip: Expected IP address as a string."
end end
if ( left:match( ":" ) and not right:match( ":" ) ) or ( not left:match( ":" ) and right:match( ":" ) ) then
return nil, "Error in ipOps.compare_ip: IP addresses must be from the same address family."
end
if op == "lt" or op == "le" then
left, right = right, left
elseif op ~= "eq" and op ~= "ge" and op ~= "gt" then
return nil, "Error in ipOps.compare_ip: Invalid Operator."
end
local err ={} local err ={}
left, err[#err+1] = ip_to_bin( left ) left, err[#err+1] = ip_to_str( left )
right, err[#err+1] = ip_to_bin( right ) right, err[#err+1] = ip_to_str( right )
if #err > 0 then if #err > 0 then
return nil, table.concat( err, " " ) return nil, table.concat( err, " " )
end end
if # left ~= # right then if #left > #right then
-- shouldn't happen... left = bin.pack( "CA", 0x06, left )
return nil, "Error in ipOps.compare_ip: Binary IP addresses were of different lengths." right = bin.pack( "CA", 0x04, right )
elseif #right > #left then
right = bin.pack( "CA", 0x06, right )
left = bin.pack( "CA", 0x04, left )
end end
-- equal? if ( op == "eq" ) then
if ( op == "eq" or op == "le" or op == "ge" ) and left == right then return ( left == right )
return true elseif ( op == "ne" ) then
elseif op == "eq" then return ( left ~= right )
return false elseif ( op == "le" ) then
return ( left <= right )
elseif ( op == "ge" ) then
return ( left >= right )
elseif ( op == "lt" ) then
return ( left < right )
elseif ( op == "gt" ) then
return ( left > right )
end end
-- starting from the leftmost bit, subtract the bit in right from the bit in left return nil, "Error in ipOps.compare_ip: Invalid Operator."
local compare
for i = 1, # left , 1 do
compare = tonumber( string.sub( left, i, i ) ) - tonumber( string.sub( right, i, i ) )
if compare == 1 then
return true
elseif compare == -1 then
return false
end
end
return false
end end
@@ -327,12 +318,15 @@ end
-- the IPv4 portion is shortened and does not contain a dot, in which case the -- the IPv4 portion is shortened and does not contain a dot, in which case the
-- address will be treated as IPv6. -- address will be treated as IPv6.
-- @param ip String representing an IPv4 or IPv6 address in shortened or full notation. -- @param ip String representing an IPv4 or IPv6 address in shortened or full notation.
-- @param family String representing the address family to expand to. Only
-- affects IPv4 addresses when "inet6" is provided, causing the function to
-- return an IPv4-mapped IPv6 address.
-- @usage -- @usage
-- local ip = ipOps.expand_ip( "2001::" ) -- local ip = ipOps.expand_ip( "2001::" )
-- @return String representing a fully expanded IPv4 or IPv6 address (or -- @return String representing a fully expanded IPv4 or IPv6 address (or
-- <code>nil</code> in case of an error). -- <code>nil</code> in case of an error).
-- @return String error message in case of an error. -- @return String error message in case of an error.
expand_ip = function( ip ) expand_ip = function( ip, family )
local err local err
if type( ip ) ~= "string" or ip == "" then if type( ip ) ~= "string" or ip == "" then
@@ -355,8 +349,19 @@ expand_ip = function( ip )
while #octets < 4 do while #octets < 4 do
octets[#octets+1] = "0" octets[#octets+1] = "0"
end end
if family == "inet6" then
return ( table.concat( { 0,0,0,0,0,"ffff",
stdnse.tohex( 256*octets[1]+octets[2] ),
stdnse.tohex( 256*octets[3]+octets[4] )
}, ":" ) )
else
return ( table.concat( octets, "." ) ) return ( table.concat( octets, "." ) )
end end
end
if family ~= nil and family ~= "inet6" then
return nil, "Error in ipOps.expand_ip: Cannot convert IPv6 address to IPv4"
end
if ip:match( "[^\.:%x]" ) then if ip:match( "[^\.:%x]" ) then
return nil, ( err4:gsub( "IPv4", "IPv6" ) ) return nil, ( err4:gsub( "IPv4", "IPv6" ) )
@@ -498,6 +503,39 @@ get_last_ip = function( ip, prefix )
end end
---
-- Converts an IP address into an opaque string.
-- @param ip String representing an IPv4 or IPv6 address.
-- @param family (optional) Address family to convert to. "ipv6" converts IPv4
-- addresses to IPv4-mapped IPv6.
-- @usage
-- opaque = ipOps.ip_to_str( "192.168.3.4" )
-- @return 4- or 16-byte string representing IP address (or <code>nil</code>
-- in case of an error).
-- @return String error message in case of an error
ip_to_str = function( ip, family )
local err
ip, err = expand_ip( ip, family )
if err then return nil, err end
local t = {}
if not ip:match( ":" ) then
-- ipv4 string
for octet in string.gmatch( ip, "%d+" ) do
t[#t+1] = bin.pack( ">C", tonumber(octet) )
end
else
-- ipv6 string
for hdt in string.gmatch( ip, "%x+" ) do
t[#t+1] = bin.pack( ">S", tonumber(hdt, 16) )
end
end
return table.concat( t )
end
--- ---

View File

@@ -41,28 +41,14 @@ require("http")
Util = { Util = {
--- Converts a string ip to a numeric value suitable for comparing
--
-- @param ip string containing the ip to convert
-- @return number containing the converted ip
ipToNumber = function(ip)
local o1, o2, o3, o4 = ip:match("^(%d*)%.(%d*)%.(%d*)%.(%d*)$")
return (256^3) * o1 + (256^2) * o2 + (256^1) * o3 + (256^0) * o4
end,
--- Compare function used for sorting IP-addresses --- Compare function used for sorting IP-addresses
-- --
-- @param a table containing first item -- @param a table containing first item
-- @param b table containing second item -- @param b table containing second item
-- @return true if the port of a is less than the port of b -- @return true if a is less than b
ipCompare = function(a, b) ipCompare = function(a, b)
local ip_a = Util.ipToNumber(a.name) return ipOps.compare_ip(a, "lt", b)
local ip_b = Util.ipToNumber(b.name) end,
if ( tonumber(ip_a) < tonumber(ip_b) ) then
return true
end
return false
end
} }
@@ -293,7 +279,8 @@ Comm = {
setMulticast = function( self, mcast ) setMulticast = function( self, mcast )
assert( type(mcast)=="boolean", "mcast has to be either true or false") assert( type(mcast)=="boolean", "mcast has to be either true or false")
self.mcast = mcast self.mcast = mcast
self.host = "239.255.255.250" local family = nmap.address_family()
self.host = (family=="inet6" and "FF02::C" or "239.255.255.250")
self.port = 1900 self.port = 1900
end, end,

View File

@@ -322,8 +322,10 @@ Helper = {
-- @param mcast boolean true if multicast is to be used, false otherwise -- @param mcast boolean true if multicast is to be used, false otherwise
setMulticast = function( self, mcast ) setMulticast = function( self, mcast )
assert( type(mcast)=="boolean", "mcast has to be either true or false") assert( type(mcast)=="boolean", "mcast has to be either true or false")
local family = nmap.address_family()
self.mcast = mcast self.mcast = mcast
self.host, self.port = "239.255.255.250", 3702 self.host = (family=="inet6" and "FF02::C" or "239.255.255.250")
self.port = 3702
end, end,
--- Sets the timeout for socket reads --- Sets the timeout for socket reads

View File

@@ -1059,8 +1059,9 @@ function output_ips(t)
end end
end end
-- IPv6 - for now, no sorting. -- IPv6
-- Rows are allowed to be 71 chars wide -- Rows are allowed to be 71 chars wide
table.sort(t['6'], function(a,b) return ipOps.compare_ip(a, "lt", b) end)
local i = 1 local i = 1
local limit = #t['6'] local limit = #t['6']
while i <= limit do while i <= limit do