1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 04:31:29 +00:00

Update dnssd.lua and related scripts

* Structured output
* Fix adding new targets: was adding the multicast address, not the
  discovered unicast address.
* Extract service name and host name from responses
* broadcast-dns-service-discovery now lists services under each unicast
  address instead of under the single multicast/broadcast address.
This commit is contained in:
dmiller
2024-06-07 16:34:07 +00:00
parent 0671064cf9
commit f43878f0f5
3 changed files with 61 additions and 58 deletions

View File

@@ -46,6 +46,7 @@ local string = require "string"
local stringaux = require "stringaux" local stringaux = require "stringaux"
local table = require "table" local table = require "table"
local target = require "target" local target = require "target"
local outlib = require "outlib"
_ENV = stdnse.module("dnssd", stdnse.seeall) _ENV = stdnse.module("dnssd", stdnse.seeall)
Util = { Util = {
@@ -67,8 +68,8 @@ Util = {
serviceCompare = function(a, b) serviceCompare = function(a, b)
-- if no port is found use 999999 for comparing, this way all services -- if no port is found use 999999 for comparing, this way all services
-- without ports and device information gets printed at the end -- without ports and device information gets printed at the end
local port_a = a.name:match("^(%d+)") or 999999 local port_a = a:match("^(%d+)") or 999999
local port_b = b.name:match("^(%d+)") or 999999 local port_b = b:match("^(%d+)") or 999999
if ( tonumber(port_a) < tonumber(port_b) ) then if ( tonumber(port_a) < tonumber(port_b) ) then
return true return true
@@ -210,61 +211,60 @@ Comm = {
-- @param response as returned by <code>queryService</code> -- @param response as returned by <code>queryService</code>
-- @param result table into which the decoded output should be stored -- @param result table into which the decoded output should be stored
decodeRecords = function( response, result ) decodeRecords = function( response, result )
local service, deviceinfo = {}, {} local service = stdnse.output_table()
local txt = {} local txt = {}
local ipv6, srv, address, port, proto
local record = ( #response.questions > 0 and response.questions[1].dname ) and response.questions[1].dname or "" local record = ( #response.questions > 0 and response.questions[1].dname ) and response.questions[1].dname or ""
local status, ip = Comm.getRecordType( dns.types.A, response, false ) local status, ipv4 = Comm.getRecordType( dns.types.A, response, false )
if status then address = ip end if status then service.ipv4 = ipv4 end
status, ipv6 = Comm.getRecordType( dns.types.AAAA, response, false ) local status, ipv6 = Comm.getRecordType( dns.types.AAAA, response, false )
if status then service.ipv6 = ipv6 end
local status, name = Comm.getRecordType( dns.types.PTR, response, false )
if status then if status then
address = address or "" local i = name:find("." .. record, 1, true)
address = address .. " " .. ipv6 if i then
name = name:sub(1, i - 1)
end
service.name = name
end end
status, txt = Comm.getRecordType( dns.types.TXT, response, true ) local name, port
if status then local status, srv = Comm.getRecordType( dns.types.SRV, response, false )
for _, v in ipairs(txt) do
if v:len() > 0 then
table.insert(service, v)
end
end
end
status, srv = Comm.getRecordType( dns.types.SRV, response, false )
if status then if status then
local srvparams = stringaux.strsplit( ":", srv ) local srvparams = stringaux.strsplit( ":", srv )
if #srvparams > 3 then if #srvparams > 3 then
name = srvparams[4]:gsub("%.local$", "")
port = srvparams[3] port = srvparams[3]
if service.name ~= name then
service.hostname = name
end
end end
end end
if address then status, txt = Comm.getRecordType( dns.types.TXT, response, true )
table.insert( service, ("Address=%s"):format( address ) ) if status then
for _, t in ipairs(txt) do
if #t > 0 then
service.TXT = txt
break
end
end
end end
if record == "_device-info._tcp.local" then if record == "_device-info._tcp.local" then
service.name = "Device Information" result["Device Information"] = service
deviceinfo = service
table.insert(result, deviceinfo)
else else
local serviceparams = stringaux.strsplit("[.]", record) local heading
local servicename, proto = record:match("^_([^.]+)%._([^.]+)%.")
if #serviceparams > 2 then if port and servicename then
local servicename = serviceparams[1]:sub(2) heading = string.format( "%s/%s %s", port, proto, servicename)
local proto = serviceparams[2]:sub(2)
if port == nil or proto == nil or servicename == nil then
service.name = record
else else
service.name = string.format( "%s/%s %s", port, proto, servicename) heading = record
end end
end result[heading] = service
table.insert( result, service )
end end
end, end,
@@ -360,36 +360,41 @@ Helper = {
-- Wait for all threads to finish running -- Wait for all threads to finish running
while Util.threadCount(threads)>0 do condvar("wait") end while Util.threadCount(threads)>0 do condvar("wait") end
local ipsvctbl = {}
if ( mcast ) then if ( mcast ) then
-- Process all records that were returned -- Process all records that were returned
local addr1, addr2
if nmap.address_family() == "inet" then
addr1 = "ipv4"
addr2 = "ipv6"
else
addr1 = "ipv6"
addr2 = "ipv4"
end
local ipsvctbl = {}
for svcname, response in pairs(svcresponse) do for svcname, response in pairs(svcresponse) do
for _, r in ipairs( response ) do for _, r in ipairs( response ) do
ipsvctbl[r.peer] = ipsvctbl[r.peer] or {} local key = r[addr1]
Comm.decodeRecords( r.output, ipsvctbl[r.peer] ) if key then
target.add(key)
else
key = r[addr2] or r.peer
end
ipsvctbl[key] = ipsvctbl[key] or {}
Comm.decodeRecords( r.output, ipsvctbl[key] )
end end
end end
for k, svc in pairs(ipsvctbl) do
ipsvctbl[k] = outlib.sorted_by_key(svc, Util.serviceCompare)
end
return true, outlib.sorted_by_key(ipsvctbl, Util.ipCompare)
else else
-- Process all records that were returned -- Process all records that were returned
for svcname, response in pairs(svcresponse) do for svcname, response in pairs(svcresponse) do
Comm.decodeRecords( response, result ) Comm.decodeRecords( response, result )
end end
return true, outlib.sorted_by_key(result, Util.serviceCompare)
end end
return false
if ( mcast ) then
-- Restructure and build our output table
for ip, svctbl in pairs( ipsvctbl ) do
table.sort(svctbl, Util.serviceCompare)
svctbl.name = ip
if target.ALLOW_NEW_TARGETS then target.add(ip) end
table.insert( result, svctbl )
end
table.sort( result, Util.ipCompare )
else
-- sort the tables per port
table.sort( result, Util.serviceCompare )
end
return true, result
end, end,
} }

View File

@@ -1,5 +1,6 @@
local dnssd = require "dnssd" local dnssd = require "dnssd"
local stdnse = require "stdnse" local stdnse = require "stdnse"
local oops = require "oops"
description=[[ description=[[
Attempts to discover hosts' services using the DNS Service Discovery protocol. It sends a multicast DNS-SD query and collects all the responses. Attempts to discover hosts' services using the DNS Service Discovery protocol. It sends a multicast DNS-SD query and collects all the responses.
@@ -50,8 +51,5 @@ action = function()
local helper = dnssd.Helper:new( ) local helper = dnssd.Helper:new( )
helper:setMulticast(true) helper:setMulticast(true)
local status, result = helper:queryServices() oops.output(helper:queryServices())
if ( status ) then
return stdnse.format_output(true, result)
end
end end

View File

@@ -61,7 +61,7 @@ action = function(host, port)
if ( status ) then if ( status ) then
-- set port to open -- set port to open
nmap.set_port_state(host, port, "open") nmap.set_port_state(host, port, "open")
return stdnse.format_output(true, result) return result
end end
end end