diff --git a/nselib/bin.lua b/nselib/bin.lua index 41320beb5..ac8290610 100644 --- a/nselib/bin.lua +++ b/nselib/bin.lua @@ -78,6 +78,10 @@ local function clamp (args, i, j, mask) end end +local function _fromhex (s) + return char(tonumber(s, 16)) +end + --- Returns a binary packed string. -- -- The format string describes how the parameters (p1, @@ -107,7 +111,7 @@ function _ENV.pack (format, ...) assert(n > 0, "n cannot be 0") -- original bin library allowed this, it doesn't make sense local new = "=" -- !! in original bin library, hex strings are always native for j = i, i+n-1 do - args[j] = tostring(args[j]):gsub("%s*(%S%S?)%s*", function (s) return char(tonumber(s, 16)) end) + args[j] = tostring(args[j]):gsub("%s*(%S%S?)%s*", _fromhex) new = new .. ("c%d"):format(#args[j]) end new = new .. endianness -- restore old endianness @@ -208,15 +212,24 @@ do assert(_ENV.pack(""00:23:ae:5d:3b:10") to -- a raw six-byte long. -- @param str MAC address string. @@ -453,9 +456,7 @@ function mactobin(str) if not str then return nil, "MAC was not specified." end - return (str:gsub("(%x%x)[^%x]?", function (x) - return string.char(tonumber(x, 16)) - end)) + return (str:gsub("(%x%x)[^%x]?", _hex_str)) end --- Generate the link-local IPv6 address from the MAC address. diff --git a/nselib/stringaux.lua b/nselib/stringaux.lua index 797473f14..96417b19c 100644 --- a/nselib/stringaux.lua +++ b/nselib/stringaux.lua @@ -70,6 +70,9 @@ end -- This pattern must match the percent sign '%' since it is used in -- escaping. local FILESYSTEM_UNSAFE = "[^a-zA-Z0-9._-]" +local function _escape_helper (c) + return format("%%%02x", byte(c)) +end --- -- Escape a string to remove bytes and strings that may have meaning to -- a filesystem, such as slashes. @@ -97,9 +100,7 @@ function filename_escape(s) elseif s == ".." then return "%2e%2e" else - return (gsub(s, FILESYSTEM_UNSAFE, function (c) - return format("%%%02x", byte(c)) - end)) + return (gsub(s, FILESYSTEM_UNSAFE, _escape_helper)) end end diff --git a/nselib/url.lua b/nselib/url.lua index 241753842..737a1ea29 100644 --- a/nselib/url.lua +++ b/nselib/url.lua @@ -57,12 +57,17 @@ local function make_set(t) return s end +local function hex_esc (c) + return string.format("%%%02x", string.byte(c)) +end + -- these are allowed within a path segment, along with alphanum -- other characters must be escaped local segment_set = make_set { "-", "_", ".", "!", "~", "*", "'", "(", ")", ":", "@", "&", "=", "+", "$", ",", } +setmetatable(segment_set, { __index = hex_esc }) --- -- Protects a path segment, to prevent it from interfering with the @@ -70,10 +75,7 @@ local segment_set = make_set { -- @param s Binary string to be encoded. -- @return Escaped representation of string. local function protect_segment(s) - return string.gsub(s, "([^A-Za-z0-9_.~-])", function (c) - if segment_set[c] then return c - else return string.format("%%%02x", string.byte(c)) end - end) + return string.gsub(s, "([^A-Za-z0-9_.~-])", segment_set) end --- @@ -115,25 +117,26 @@ end -- @return Escaped representation of string. ----------------------------------------------------------------------------- function escape(s) - local ret = string.gsub(s, "([^A-Za-z0-9_.~-])", function(c) - return string.format("%%%02x", string.byte(c)) - end) - return ret + return (string.gsub(s, "([^A-Za-z0-9_.~-])", hex_esc)) end +local function hex_unesc (hex) + return string.char(base.tonumber(hex, 16)) +end + --- -- Decodes an escaped hexadecimal string. -- @param s Hexadecimal-encoded string. -- @return Decoded string. ----------------------------------------------------------------------------- function unescape(s) - local ret = string.gsub(s, "%%(%x%x)", function(hex) - return string.char(base.tonumber(hex, 16)) - end) - return ret + return (string.gsub(s, "%%(%x%x)", hex_unesc)) end +local function normalize_escape (s) + return escape(unescape(s)) +end --- -- Parses a URL and returns a table with all its parts according to RFC 3986. @@ -171,14 +174,7 @@ function parse(url, default) -- remove whitespace -- url = string.gsub(url, "%s", "") -- Decode unreserved characters - url = string.gsub(url, "%%(%x%x)", function(hex) - local char = string.char(base.tonumber(hex, 16)) - if string.match(char, "[a-zA-Z0-9._~-]") then - return char - end - -- Hex encodings that are not unreserved must be preserved. - return nil - end) + url = string.gsub(url, "%%%x%x", normalize_escape) -- get fragment url = string.gsub(url, "#(.*)$", function(f) parsed.fragment = f @@ -353,6 +349,11 @@ function build_path(parsed, unsafe) return table.concat(path) end +local entities = { + ["amp"] = "&", + ["lt"] = "<", + ["gt"] = ">" +} --- -- Breaks a query string into name/value pairs. -- @@ -369,9 +370,7 @@ function parse_query(query) local parsed = {} local pos = 1 - query = string.gsub(query, "&", "&") - query = string.gsub(query, "<", "<") - query = string.gsub(query, ">", ">") + query = string.gsub(query, "&([ampltg]+);", entities) local function ginsert(qstr) local pos = qstr:find("=", 1, true)