1
0
mirror of https://github.com/nmap/nmap.git synced 2026-02-07 22:16:33 +00:00

Use bdecode function to parse buffer instead of reimplementing. Fixes #1203

This commit is contained in:
dmiller
2018-05-04 05:10:52 +00:00
parent 6f648be471
commit 16e061ec2b

View File

@@ -152,6 +152,7 @@ bdecode = function(buf)
cur.ref = t
table.insert(stack, cur)
cur.ref.type="list"
cur.ref.start = pos
while true do
if pos == len or (len-pos)==-1 then break end
@@ -180,6 +181,7 @@ bdecode = function(buf)
cur = {}
cur.type = "list"
cur.ref = new_list
cur.ref.start = pos
table.insert(stack, cur)
pos = pos+1
@@ -192,11 +194,13 @@ bdecode = function(buf)
cur = {}
cur.type = "dict"
cur.ref = new_dict
cur.ref.start = pos
table.insert(stack, cur)
pos = pos+1
--escape from the list
elseif "e" == string.char(buf:byte(pos)) then
stack[#stack].ref.endpos = pos
table.remove(stack, #stack)
cur = stack[#stack]
if not cur then return nil, "Problem with list closure:", pos end
@@ -218,6 +222,7 @@ bdecode = function(buf)
if not str then return nil, "Error parsing string.", pos end
item.key = str
elseif "e" == string.char(buf:byte(pos)) then
stack[#stack].ref.endpos = pos
table.remove(stack, #stack)
cur = stack[#stack]
if not cur then return nil, "Problem with list closure:", pos end
@@ -256,6 +261,7 @@ bdecode = function(buf)
cur = {}
cur.type = "list"
cur.ref = item.value
cur.ref.start = pos
table.insert(stack, cur)
pos = pos+1
@@ -269,12 +275,14 @@ bdecode = function(buf)
cur = {}
cur.type = "dict"
cur.ref = item.value
cur.ref.start = pos
table.insert(stack, cur)
pos = pos+1
--escape from the dict
elseif "e" == string.char(buf:byte(pos)) then
stack[#stack].ref.endpos = pos
table.remove(stack, #stack)
cur = stack[#stack]
if not cur then return false, "Problem with dict closure", pos end
@@ -752,200 +760,18 @@ Torrent =
-- This function is similar to the bdecode function but it has a few
-- additions for calculating torrent file specific fields
parse_buffer = function(self)
local buf = self.buffer
local len = #buf
-- the main table
local t = {}
self.tor_struct = t
local stack = {}
local pos = 1
local cur = {}
cur.type = "list"
cur.ref = t
table.insert(stack, cur)
cur.ref.type="list"
-- starting and ending position of the info dict
local info_pos_start, info_pos_end, info_buf_count = nil, nil, 0
while true do
if pos == len or (len-pos)==-1 then break end
if cur.type == "list" then
-- next element is a string
if tonumber( string.char( buf:byte(pos) ) ) then
local str
str, pos = bdec_string(buf, pos)
if not str then return nil, "Error parsing string", pos end
table.insert(cur.ref, str)
-- next element is a number
elseif "i" == string.char(buf:byte(pos)) then
local num
num, pos = bdec_number(buf, pos)
if not num then return nil, "Error parsing number", pos end
table.insert(cur.ref, num)
-- next element is a list
elseif "l" == string.char(buf:byte(pos)) then
if info_pos_start and (not info_pos_end) then
info_buf_count = info_buf_count +1
end
local new_list = {}
new_list.type="list"
table.insert(cur.ref, new_list)
cur = {}
cur.type = "list"
cur.ref = new_list
table.insert(stack, cur)
pos = pos+1
--next element is a dict
elseif "d" == string.char(buf:byte(pos)) then
if info_pos_start and (not info_pos_end) then
info_buf_count = info_buf_count +1
end
local new_dict = {}
new_dict.type = "dict"
table.insert(cur.ref, new_dict)
cur = {}
cur.type = "dict"
cur.ref = new_dict
table.insert(stack, cur)
pos = pos+1
--escape from the list
elseif "e" == string.char(buf:byte(pos)) then
if info_buf_count == 0 then
info_pos_end = pos-1
end
if info_pos_start and (not info_pos_end) then
info_buf_count = info_buf_count -1
end
table.remove(stack, #stack)
cur = stack[#stack]
if not cur then return nil, "Problem with list closure:", pos end
pos = pos+1
else
return nil, "Unknown type found.", pos
end
elseif cur.type == "dict" then
local item = {} -- {key = <string>, value = <.*>}
-- key
if tonumber( string.char( buf:byte(pos) ) ) then
local str
local tmp_pos = pos
str, pos = bdec_string(buf, pos)
if not str then return nil, "Error parsing string.", pos end
item.key = str
-- fill the info_pos_start
if item.key == "info" and not info_pos_start then info_pos_start = pos end
elseif "e" == string.char(buf:byte(pos)) then
if info_buf_count == 0 then
info_pos_end = pos-1
end
if info_pos_start and (not info_pos_end) then
info_buf_count = info_buf_count -1
end
table.remove(stack, #stack)
cur = stack[#stack]
if not cur then return nil, "Problem with list closure:", pos end
pos = pos+1
else
return nil, "A dict key has to be a string or escape.", pos
end
-- value
-- next element is a string
if tonumber( string.char( buf:byte(pos) ) ) then
local str
str, pos = bdec_string(buf, pos)
if not str then return nil, "Error parsing string.", pos end
item.value = str
table.insert(cur.ref, item)
--next element is a number
elseif "i" == string.char(buf:byte(pos)) then
local num
num, pos = bdec_number(buf, pos)
if not num then return nil, "Error parsing number.", pos end
item.value = num
table.insert(cur.ref, item)
-- next element is a list
elseif "l" == string.char(buf:byte(pos)) then
if info_pos_start and (not info_pos_end) then
info_buf_count = info_buf_count +1
end
item.value = {}
item.value.type = "list"
table.insert(cur.ref, item)
cur = {}
cur.type = "list"
cur.ref = item.value
table.insert(stack, cur)
pos = pos+1
--next element is a dict
elseif "d" == string.char(buf:byte(pos)) then
if info_pos_start and (not info_pos_end) then
info_buf_count = info_buf_count +1
end
item.value = {}
item.value.type = "dict"
table.insert(cur.ref, item)
cur = {}
cur.type = "dict"
cur.ref = item.value
table.insert(stack, cur)
pos = pos+1
--escape from the dict
elseif "e" == string.char(buf:byte(pos)) then
if info_buf_count == 0 then
info_pos_end = pos-1
end
if info_pos_start and (not info_pos_end) then
info_buf_count = info_buf_count -1
end
table.remove(stack, #stack)
cur = stack[#stack]
if not cur then return false, "Problem with dict closure", pos end
pos = pos+1
else
return false, "Error parsing file, unknown type found", pos
end
else
return false, "Invalid type of structure. Fix the code."
end
end -- while(true)
-- next(stack) is never gonna be nil because we're always in the main list
-- next(stack, next(stack)) should be nil if we're in the main list
if next(stack, next(stack)) then
return false, "Probably file incorrect format"
local status, t = bdecode(self.buffer)
if not status then
return status, t
end
self.tor_struct = t
self.info_buf = buf:sub(info_pos_start, info_pos_end)
for _, i in ipairs(t[1]) do
if i.key == "info" then
self.info_buf = self.buffer:sub(i.value.start, i.value.endpos)
break
end
end
return true
end,