mirror of
https://github.com/nmap/nmap.git
synced 2026-01-19 20:59:01 +00:00
Merge from /nmap-exp/david/nmap-unconnected. This adds unconnected
socket support to NSE, with updates in scripts and libraries.
o [NSE] Added the ability to send and receive on unconnected sockets.
This can be used, for example, to receive UDP broadcasts without
using pcap. A number of scripts have been changed so that they can
work as prerule scripts to discover services by UDP broadcasting,
optionally add the discovered targets to the scanning queue:
- ms-sql-info
- upnp-info
- dns-service-discovery
The nmap.new_socket function can now optionally take a default
protocol and address family, which will be used if the socket is not
connected. There is a new nmap.sendto function to be used with
unconnected UDP sockets. [David, Patrik]
This commit is contained in:
138
nselib/dns.lua
138
nselib/dns.lua
@@ -40,21 +40,51 @@ types = {
|
||||
-- @param port Port to connect to.
|
||||
-- @param timeout Number of ms to wait for a response.
|
||||
-- @param cnt Number of tries.
|
||||
-- @param multiple If true, keep reading multiple responses until timeout.
|
||||
-- @return Status (true or false).
|
||||
-- @return Response (if status is true).
|
||||
local function sendPackets(data, host, port, timeout, cnt)
|
||||
local socket = nmap.new_socket()
|
||||
socket:set_timeout(timeout)
|
||||
socket:connect(host, port, "udp")
|
||||
local function sendPackets(data, host, port, timeout, cnt, multiple)
|
||||
local socket = nmap.new_socket("udp")
|
||||
local responses = {}
|
||||
|
||||
socket:set_timeout(timeout)
|
||||
|
||||
if ( not(multiple) ) then
|
||||
socket:connect( host, port, "udp" )
|
||||
end
|
||||
|
||||
for i = 1, cnt do
|
||||
local status, err
|
||||
|
||||
if ( multiple ) then
|
||||
status, err = socket:sendto(host, port, data)
|
||||
else
|
||||
status, err = socket:send(data)
|
||||
end
|
||||
|
||||
if (not(status)) then return false, err end
|
||||
|
||||
for i = 1, cnt do
|
||||
socket:send(data)
|
||||
local response
|
||||
local status, response = socket:receive_bytes(1)
|
||||
|
||||
if (status) then
|
||||
|
||||
if ( multiple ) then
|
||||
while(true) do
|
||||
status, response = socket:receive()
|
||||
if( not(status) ) then break end
|
||||
|
||||
local status, _, _, ip, _ = socket:get_info()
|
||||
table.insert(responses, { data = response, peer = ip } )
|
||||
end
|
||||
else
|
||||
status, response = socket:receive()
|
||||
if ( status ) then
|
||||
local status, _, _, ip, _ = socket:get_info()
|
||||
table.insert(responses, { data = response, peer = ip } )
|
||||
end
|
||||
end
|
||||
|
||||
if (#responses>0) then
|
||||
socket:close()
|
||||
return true, response
|
||||
return true, responses
|
||||
end
|
||||
end
|
||||
socket:close()
|
||||
@@ -130,6 +160,42 @@ local function getAuthDns(rPkt)
|
||||
return false
|
||||
end
|
||||
|
||||
local function processResponse( response, dname, dtype, options )
|
||||
|
||||
local rPkt = decode(response)
|
||||
-- is it a real answer?
|
||||
if gotAnswer(rPkt) then
|
||||
if (options.retPkt) then
|
||||
return true, rPkt
|
||||
else
|
||||
return findNiceAnswer(dtype, rPkt, options.retAll)
|
||||
end
|
||||
else -- if not, ask the next server in authority
|
||||
|
||||
local next_server = getAuthDns(rPkt)
|
||||
|
||||
-- if we got a CNAME, ask for the CNAME
|
||||
if type(next_server) == 'table' and next_server.cname then
|
||||
options.tries = option.tries - 1
|
||||
return query(next_server.cname, options)
|
||||
end
|
||||
|
||||
-- only ask next server in authority, if
|
||||
-- we got an auth dns and
|
||||
-- it isn't the one we just asked
|
||||
if next_server and next_server ~= host and options.tries > 1 then
|
||||
options.host = next_server
|
||||
options.tries = option.tries - 1
|
||||
return query(dname, options)
|
||||
end
|
||||
end
|
||||
|
||||
-- nothing worked
|
||||
stdnse.print_debug(1, "dns.query() failed to resolve the requested query%s%s", dname and ": " or ".", dname or "")
|
||||
return false, "No Answers"
|
||||
|
||||
end
|
||||
|
||||
---
|
||||
-- Query DNS servers for a DNS record.
|
||||
-- @param dname Desired domain name entry.
|
||||
@@ -141,6 +207,7 @@ end
|
||||
-- * <code>retAll</code>: Return all answers, not just the first.
|
||||
-- * <code>retPkt</code>: Return the packet instead of using the answer-fetching mechanism.
|
||||
-- * <code>norecurse</code> If true, do not set the recursion (RD) flag.
|
||||
-- * <code>multiple</code> If true, expects multiple hosts to respond to multicast request
|
||||
-- @return True if a dns response was received and contained an answer of the requested type,
|
||||
-- or the decoded dns response was requested (retPkt) and is being returned - or False otherwise.
|
||||
-- @return String answer of the requested type, Table of answers or a String error message of one of the following:
|
||||
@@ -148,9 +215,9 @@ end
|
||||
function query(dname, options)
|
||||
if not options then options = {} end
|
||||
|
||||
local dtype, host, port, tries = options.dtype, options.host, options.port, options.tries
|
||||
local dtype, host, port = options.dtype, options.host, options.port
|
||||
|
||||
if not tries then tries = 10 end -- don't get into an infinite loop
|
||||
if not options.tries then options.tries = 10 end -- don't get into an infinite loop
|
||||
|
||||
if not options.sendCount then options.sendCount = 2 end
|
||||
|
||||
@@ -182,7 +249,7 @@ function query(dname, options)
|
||||
|
||||
local data = encode(pkt)
|
||||
|
||||
local status, response = sendPackets(data, host, port, options.timeout, options.sendCount)
|
||||
local status, response = sendPackets(data, host, port, options.timeout, options.sendCount, options.multiple)
|
||||
|
||||
|
||||
-- if working with know nameservers, try the others
|
||||
@@ -194,37 +261,18 @@ function query(dname, options)
|
||||
|
||||
-- if we got any response:
|
||||
if status then
|
||||
local rPkt = decode(response)
|
||||
-- is it a real answer?
|
||||
if gotAnswer(rPkt) then
|
||||
if (options.retPkt) then
|
||||
return true, rPkt
|
||||
else
|
||||
return findNiceAnswer(dtype, rPkt, options.retAll)
|
||||
end
|
||||
else -- if not, ask the next server in authority
|
||||
|
||||
local next_server = getAuthDns(rPkt)
|
||||
|
||||
-- if we got a CNAME, ask for the CNAME
|
||||
if type(next_server) == 'table' and next_server.cname then
|
||||
options.tries = tries - 1
|
||||
return query(next_server.cname, options)
|
||||
end
|
||||
|
||||
-- only ask next server in authority, if
|
||||
-- we got an auth dns and
|
||||
-- it isn't the one we just asked
|
||||
if next_server and next_server ~= host and tries > 1 then
|
||||
options.host = next_server
|
||||
options.tries = tries - 1
|
||||
return query(dname, options)
|
||||
end
|
||||
end
|
||||
|
||||
-- nothing worked
|
||||
stdnse.print_debug(1, "dns.query() failed to resolve the requested query%s%s", dname and ": " or ".", dname or "")
|
||||
return false, "No Answers"
|
||||
if ( options.multiple ) then
|
||||
local multiresponse = {}
|
||||
for _, r in ipairs( response ) do
|
||||
local status, presponse = processResponse( r.data, dname, dtype, options )
|
||||
if( status ) then
|
||||
table.insert( multiresponse, { ['output']=presponse, ['peer']=r.peer } )
|
||||
end
|
||||
end
|
||||
return true, multiresponse
|
||||
else
|
||||
return processResponse( response[1].data, dname, dtype, options)
|
||||
end
|
||||
else
|
||||
stdnse.print_debug(1, "dns.query() got zero responses attempting to resolve query%s%s", dname and ": " or ".", dname or "")
|
||||
return false, "No Answers"
|
||||
@@ -348,7 +396,7 @@ answerFetcher[types.CNAME] = function(dec, retAll)
|
||||
stdnse.print_debug(1, "dns.answerFetcher found no records of the required type: NS, PTR or CNAME")
|
||||
return false, "No Answers"
|
||||
end
|
||||
return true, answers
|
||||
return true, answers
|
||||
end
|
||||
|
||||
-- Answer fetcher for MX records.
|
||||
|
||||
Reference in New Issue
Block a user