--- ../nmap-svn/nselib/dns.lua 2009-11-25 21:55:13.000000000 +0100
+++ nselib/dns.lua 2010-01-13 19:30:10.000000000 +0100
@@ -68,6 +68,12 @@
-- have we even got answers?
if #rPkt.answers > 0 then
+ -- some MDNS implementation incorrectly return an empty question section
+ -- if this is the case return true
+ if rPkt.questions[1] == nil then
+ return true
+ end
+
-- are those answers not just cnames?
if rPkt.questions[1].dtype == types.A then
for _, v in ipairs(rPkt.answers) do
@@ -280,7 +286,11 @@
return false, "No Answers"
else
for _, v in ipairs(dec.answers) do
- if v.data then table.insert(answers, string.sub(v.data, 2)) end
+ if v.TXT and v.TXT.text then
+ for _, v in ipairs( v.TXT.text ) do
+ table.insert(answers, v)
+ end
+ end
end
end
if #answers == 0 then
@@ -373,6 +383,31 @@
return true, answers
end
+-- Answer fetcher for SRV records.
+-- @param dec Decoded DNS response.
+-- @param retAll If true, return all entries, not just the first.
+-- @return True if one or more answers of the required type were found - otherwise false.
+-- @return String first dns SRV record or Table of SRV records or String Error message.
+-- Note that the format of a returned SRV answer is "priority:weight:port:target" where zero
+-- or more IP addresses may be present.
+answerFetcher[types.SRV] = function(dec, retAll)
+ local srv, ip, answers = {}, {}, {}
+ for _, ans in ipairs(dec.answers) do
+ if ans.dtype == types.SRV then
+ if not retAll then
+ return true, ("%s:%s:%s:%s"):format( ans.SRV.prio, ans.SRV.weight, ans.SRV.port, ans.SRV.target )
+ end
+ table.insert( answers, ("%s:%s:%s:%s"):format( ans.SRV.prio, ans.SRV.weight, ans.SRV.port, ans.SRV.target ) )
+ end
+ end
+ if #answers == 0 then
+ stdnse.print_debug(1, "dns.answerFetcher found no records of the required type: SRV")
+ return false, "No Answers"
+ end
+
+ return true, answers
+end
+
---
-- Answer fetcher for NS records.
@@ -416,7 +451,6 @@
return true, answers
end
-
---
-- Calls the answer fetcher for dtype or returns an error code in
-- case of a "no such name" error.
@@ -442,6 +476,136 @@
end
end
+---
+-- Table for additional fetching functions.
+local additionalFetcher = {}
+
+---
+-- Additional fetcher for TXT records.
+-- @param dec Decoded DNS response.
+-- @param retAll If true, return all entries, not just the first.
+-- @return True if one or more answers of the required type were found - otherwise false.
+-- @return String first dns TXT record or Table of TXT records or String Error message.
+additionalFetcher[types.TXT] = function(dec, retAll)
+ local answers = {}
+ if not retAll and dec.add[1].data then
+ return string.sub(dec.add[1].data, 2)
+ elseif not retAll then
+ stdnse.print_debug(1, "dns.aditionalFetcher found no records of the required type: TXT")
+ return false, "No Answers"
+ else
+ for _, v in ipairs(dec.add) do
+ if v.TXT and v.TXT.text then
+ for _, v in ipairs( v.TXT.text ) do
+ table.insert(answers, v)
+ end
+ end
+ end
+ end
+ if #answers == 0 then
+ stdnse.print_debug(1, "dns.answerFetcher found no records of the required type: TXT")
+ return false, "No Answers"
+ end
+ return true, answers
+end
+
+---
+-- Additional fetcher for A records
+-- @param dec Decoded DNS response.
+-- @param retAll If true, return all entries, not just the first.
+-- @return True if one or more answers of the required type were found - otherwise false.
+-- @return String first dns A record or Table of A records or String Error message.
+additionalFetcher[types.A] = function(dec, retAll)
+ local answers = {}
+ for _, ans in ipairs(dec.add) do
+ if ans.dtype == types.A then
+ if not retAll then
+ return true, ans.ip
+ end
+ table.insert(answers, ans.ip)
+ end
+ end
+ if not retAll or #answers == 0 then
+ stdnse.print_debug(1, "dns.answerFetcher found no records of the required type: A")
+ return false, "No Answers"
+ end
+ return true, answers
+end
+
+
+-- Additional fetcher for SRV records.
+-- @param dec Decoded DNS response.
+-- @param retAll If true, return all entries, not just the first.
+-- @return True if one or more answers of the required type were found - otherwise false.
+-- @return String first dns SRV record or Table of SRV records or String Error message.
+-- Note that the format of a returned SRV answer is "priority:weight:port:target" where zero
+-- or more IP addresses may be present.
+additionalFetcher[types.SRV] = function(dec, retAll)
+ local srv, ip, answers = {}, {}, {}
+ for _, ans in ipairs(dec.add) do
+ if ans.dtype == types.SRV then
+ if not retAll then
+ return true, ("%s:%s:%s:%s"):format( ans.SRV.prio, ans.SRV.weight, ans.SRV.port, ans.SRV.target )
+ end
+ table.insert( answers, ("%s:%s:%s:%s"):format( ans.SRV.prio, ans.SRV.weight, ans.SRV.port, ans.SRV.target ) )
+ end
+ end
+ if #answers == 0 then
+ stdnse.print_debug(1, "dns.answerFetcher found no records of the required type: SRV")
+ return false, "No Answers"
+ end
+
+ return true, answers
+end
+
+
+---
+-- Additional fetcher for AAAA records.
+-- @param dec Decoded DNS response.
+-- @param retAll If true, return all entries, not just the first.
+-- @return True if one or more answers of the required type were found - otherwise false.
+-- @return String first dns AAAA record or Table of AAAA records or String Error message.
+additionalFetcher[types.AAAA] = function(dec, retAll)
+ local answers = {}
+ for _, ans in ipairs(dec.add) do
+ if ans.dtype == types.AAAA then
+ if not retAll then
+ return true, ans.ipv6
+ end
+ table.insert(answers, ans.ipv6)
+ end
+ end
+ if not retAll or #answers == 0 then
+ stdnse.print_debug(1, "dns.answerFetcher found no records of the required type: AAAA")
+ return false, "No Answers"
+ end
+ return true, answers
+end
+
+---
+-- Calls the answer fetcher for dtype or returns an error code in
+-- case of a "no such name" error.
+-- @param dtype DNS resource record type.
+-- @param dec Decoded DNS response.
+-- @param retAll If true, return all entries, not just the first.
+-- @return True if one or more answers of the required type were found - otherwise false.
+-- @return Answer according to the answer fetcher for dtype or an Error message.
+function findNiceAdditional(dtype, dec, retAll)
+ if (#dec.add > 0) then
+ if additionalFetcher[dtype] then
+ return additionalFetcher[dtype](dec, retAll)
+ else
+ stdnse.print_debug(1, "dns.findNiceAdditional() does not have an additionalFetcher for dtype %s",
+ (type(dtype) == 'string' and dtype) or type(dtype) or "nil")
+ return false, "Unable to handle response"
+ end
+ elseif (dec.flags.RC3 and dec.flags.RC4) then
+ return false, "No Such Name"
+ else
+ stdnse.print_debug(1, "dns.findNiceAdditional() found zero answers in a response, but got an unexpected flags.replycode")
+ return false, "No Answers"
+ end
+end
---
-- Encodes the question part of a DNS request.
@@ -684,7 +848,27 @@
-- @param entry RR in packet.
-- @param data Complete encoded DNS packet.
-- @param pos Position in packet after RR.
-decoder[types.TXT] = function () end
+decoder[types.TXT] =
+ function (entry, data, pos)
+
+ local len = entry.data:len()
+ local np = pos - #entry.data
+ local txt_len
+ local txt
+
+ if len > 0 then
+ entry.TXT = {}
+ entry.TXT.text = {}
+ end
+
+ while len > 0 do
+ np, txt_len = bin.unpack("C", data, np)
+ np, txt = bin.unpack("A" .. txt_len, data, np )
+ len = len - txt_len - 1
+ table.insert( entry.TXT.text, txt )
+ end
+
+ end
---
-- Decodes MX record, puts it in entry.MX.
@@ -703,6 +887,23 @@
_, entry.MX.server = decStr(data, np)
end
+---
+-- Decodes SRV record, puts it in entry.SRV.
+--
+-- entry.SRV has the fields prio,
+-- weight, port and
+-- target.
+-- @param entry RR in packet.
+-- @param data Complete encoded DNS packet.
+-- @param pos Position in packet after RR.
+decoder[types.SRV] =
+ function(entry, data, pos)
+ local np = pos - #entry.data
+ local _
+ entry.SRV = {}
+ np, entry.SRV.prio, entry.SRV.weight, entry.SRV.port = bin.unpack(">S>S>S", data, np)
+ np, entry.SRV.target = decStr(data, np)
+ end
---
-- Decodes returned resource records (answer, authority, or additional part).