diff --git a/nse_nsock.cc b/nse_nsock.cc index 39606b912..0a79f2327 100644 --- a/nse_nsock.cc +++ b/nse_nsock.cc @@ -37,6 +37,7 @@ static int l_nsock_receive(lua_State* l); static int l_nsock_receive_lines(lua_State* l); static int l_nsock_receive_bytes(lua_State* l); static int l_nsock_get_info(lua_State* l); +static int l_nsock_gc(lua_State* l); static int l_nsock_close(lua_State* l); static int l_nsock_set_timeout(lua_State* l); @@ -59,6 +60,7 @@ static luaL_reg l_nsock [] = { {"get_info", l_nsock_get_info}, {"close", l_nsock_close}, {"set_timeout", l_nsock_set_timeout}, + {"__gc",l_nsock_gc}, {NULL, NULL} }; @@ -86,7 +88,6 @@ int l_nsock_new(lua_State* l) { udata->nsiod = NULL; udata->ssl_session = NULL; udata->timeout = DEFAULT_TIMEOUT; - return 1; } @@ -131,6 +132,7 @@ static int l_nsock_connect(lua_State* l) { const char* error; struct addrinfo *dest; int error_id; + error_id = getaddrinfo(addr, NULL, NULL, &dest); if (error_id) { @@ -386,7 +388,16 @@ static int l_nsock_get_info(lua_State* l) { free(ipstring_remote); return 5; } - +static int l_nsock_gc(lua_State* l){ + l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1); + if(udata->nsiod == NULL) { //socket obviously got closed already - so no finalization needed + return 0; + }else{ + //FIXME - check wheter close returned true!! + l_nsock_close(l); + } + return 0; +} static int l_nsock_close(lua_State* l) { l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1); diff --git a/nselib/url.lua b/nselib/url.lua new file mode 100644 index 000000000..e5b7ae999 --- /dev/null +++ b/nselib/url.lua @@ -0,0 +1,352 @@ +--[[ + +URI parsing, composition and relative URL resolution +LuaSocket toolkit. +Author: Diego Nehab +RCS ID: $Id: url.lua,v 1.37 2005/11/22 08:33:29 diego Exp $ + +parse_query() and build_query() added For nmap (Eddie Bell ) + +--]] + +----------------------------------------------------------------------------- +-- Declare module +----------------------------------------------------------------------------- +local string = require("string") +local base = _G +local table = require("table") +module(...,package.seeall) + +_VERSION = "URL 1.0" + + --[[ Internal functions --]] + +----------------------------------------------------------------------------- +-- Protects a path segment, to prevent it from interfering with the +-- url parsing. +-- Input +-- s: binary string to be encoded +-- Returns +-- escaped representation of string binary +----------------------------------------------------------------------------- +local function make_set(t) + local s = {} + for i,v in base.ipairs(t) do + s[t[i]] = 1 + end + return s +end + +-- these are allowed withing a path segment, along with alphanum +-- other characters must be escaped +local segment_set = make_set { + "-", "_", ".", "!", "~", "*", "'", "(", + ")", ":", "@", "&", "=", "+", "$", ",", +} + +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) +end + +----------------------------------------------------------------------------- +-- Builds a path from a base path and a relative path +-- Input +-- base_path +-- relative_path +-- Returns +-- corresponding absolute path +----------------------------------------------------------------------------- +local function absolute_path(base_path, relative_path) + if string.sub(relative_path, 1, 1) == "/" then return relative_path end + local path = string.gsub(base_path, "[^/]*$", "") + path = path .. relative_path + path = string.gsub(path, "([^/]*%./)", function (s) + if s ~= "./" then return s else return "" end + end) + path = string.gsub(path, "/%.$", "/") + local reduced + while reduced ~= path do + reduced = path + path = string.gsub(reduced, "([^/]*/%.%./)", function (s) + if s ~= "../../" then return "" else return s end + end) + end + path = string.gsub(reduced, "([^/]*/%.%.)$", function (s) + if s ~= "../.." then return "" else return s end + end) + return path +end + + + --[[ External functions --]] + +----------------------------------------------------------------------------- +-- Encodes a string into its escaped hexadecimal representation +-- Input +-- s: binary string to be encoded +-- Returns +-- escaped representation of string binary +----------------------------------------------------------------------------- +function escape(s) + return string.gsub(s, "([^A-Za-z0-9_])", function(c) + return string.format("%%%02x", string.byte(c)) + end) +end + + +----------------------------------------------------------------------------- +-- Encodes a string into its escaped hexadecimal representation +-- Input +-- s: binary string to be encoded +-- Returns +-- escaped representation of string binary +----------------------------------------------------------------------------- +function unescape(s) + return string.gsub(s, "%%(%x%x)", function(hex) + return string.char(base.tonumber(hex, 16)) + end) +end + + +----------------------------------------------------------------------------- +-- Parses a url and returns a table with all its parts according to RFC 2396 +-- The following grammar describes the names given to the URL parts +-- ::= :///;?# +-- ::= @: +-- ::= [:] +-- :: = {/} +-- Input +-- url: uniform resource locator of request +-- default: table with default values for each field +-- Returns +-- table with the following fields, where RFC naming conventions have +-- been preserved: +-- scheme, authority, userinfo, user, password, host, port, +-- path, params, query, fragment +-- Obs: +-- the leading '/' in {/} is considered part of +----------------------------------------------------------------------------- +function parse(url, default) + -- initialize default parameters + local parsed = {} + for i,v in base.pairs(default or parsed) do parsed[i] = v end + -- empty url is parsed to nil + if not url or url == "" then return nil, "invalid url" end + -- remove whitespace + -- url = string.gsub(url, "%s", "") + -- get fragment + url = string.gsub(url, "#(.*)$", function(f) + parsed.fragment = f + return "" + end) + -- get scheme + url = string.gsub(url, "^([%w][%w%+%-%.]*)%:", + function(s) parsed.scheme = s; return "" end) + -- get authority + url = string.gsub(url, "^//([^/]*)", function(n) + parsed.authority = n + return "" + end) + -- get query stringing + url = string.gsub(url, "%?(.*)", function(q) + parsed.query = q + return "" + end) + -- get params + url = string.gsub(url, "%;(.*)", function(p) + parsed.params = p + return "" + end) + -- path is whatever was left + if url ~= "" then parsed.path = url end + local authority = parsed.authority + if not authority then return parsed end + authority = string.gsub(authority,"^([^@]*)@", + function(u) parsed.userinfo = u; return "" end) + authority = string.gsub(authority, ":([^:]*)$", + function(p) parsed.port = p; return "" end) + if authority ~= "" then parsed.host = authority end + local userinfo = parsed.userinfo + if not userinfo then return parsed end + userinfo = string.gsub(userinfo, ":([^:]*)$", + function(p) parsed.password = p; return "" end) + parsed.user = userinfo + return parsed +end + +----------------------------------------------------------------------------- +-- Rebuilds a parsed URL from its components. +-- Components are protected if any reserved or unallowed characters are found +-- Input +-- parsed: parsed URL, as returned by parse +-- Returns +-- a stringing with the corresponding URL +----------------------------------------------------------------------------- +function build(parsed) + local ppath = parse_path(parsed.path or "") + local url = build_path(ppath) + if parsed.params then url = url .. ";" .. parsed.params end + if parsed.query then url = url .. "?" .. parsed.query end + local authority = parsed.authority + if parsed.host then + authority = parsed.host + if parsed.port then authority = authority .. ":" .. parsed.port end + local userinfo = parsed.userinfo + if parsed.user then + userinfo = parsed.user + if parsed.password then + userinfo = userinfo .. ":" .. parsed.password + end + end + if userinfo then authority = userinfo .. "@" .. authority end + end + if authority then url = "//" .. authority .. url end + if parsed.scheme then url = parsed.scheme .. ":" .. url end + if parsed.fragment then url = url .. "#" .. parsed.fragment end + -- url = string.gsub(url, "%s", "") + return url +end + +----------------------------------------------------------------------------- +-- Builds a absolute URL from a base and a relative URL according to RFC 2396 +-- Input +-- base_url +-- relative_url +-- Returns +-- corresponding absolute url +----------------------------------------------------------------------------- +function absolute(base_url, relative_url) + if type(base_url) == "table" then + base_parsed = base_url + base_url = build(base_parsed) + else + base_parsed = parse(base_url) + end + local relative_parsed = parse(relative_url) + if not base_parsed then return relative_url + elseif not relative_parsed then return base_url + elseif relative_parsed.scheme then return relative_url + else + relative_parsed.scheme = base_parsed.scheme + if not relative_parsed.authority then + relative_parsed.authority = base_parsed.authority + if not relative_parsed.path then + relative_parsed.path = base_parsed.path + if not relative_parsed.params then + relative_parsed.params = base_parsed.params + if not relative_parsed.query then + relative_parsed.query = base_parsed.query + end + end + else + relative_parsed.path = absolute_path(base_parsed.path or "", + relative_parsed.path) + end + end + return build(relative_parsed) + end +end + +----------------------------------------------------------------------------- +-- Breaks a path into its segments, unescaping the segments +-- Input +-- path +-- Returns +-- segment: a table with one entry per segment +----------------------------------------------------------------------------- +function parse_path(path) + local parsed = {} + path = path or "" + --path = string.gsub(path, "%s", "") + string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end) + for i = 1, table.getn(parsed) do + parsed[i] = unescape(parsed[i]) + end + if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end + if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end + return parsed +end + +----------------------------------------------------------------------------- +-- Builds a path component from its segments, escaping protected characters. +-- Input +-- parsed: path segments +-- unsafe: if true, segments are not protected before path is built +-- Returns +-- path: corresponding path stringing +----------------------------------------------------------------------------- +function build_path(parsed, unsafe) + local path = "" + local n = table.getn(parsed) + if unsafe then + for i = 1, n-1 do + path = path .. parsed[i] + path = path .. "/" + end + if n > 0 then + path = path .. parsed[n] + if parsed.is_directory then path = path .. "/" end + end + else + for i = 1, n-1 do + path = path .. protect_segment(parsed[i]) + path = path .. "/" + end + if n > 0 then + path = path .. protect_segment(parsed[n]) + if parsed.is_directory then path = path .. "/" end + end + end + if parsed.is_absolute then path = "/" .. path end + return path +end + +----------------------------------------------------------------------------- +-- Breaks a query string into name/value pairs +-- Input +-- query string (name=value&name=value ...) +-- Returns +-- table where name=value is table['name'] = value +----------------------------------------------------------------------------- +function parse_query(query) + local parsed = {} + local pos = 0 + + function ginsert(qstr) + local first, last = string.find(qstr, "=") + if first then + parsed[string.sub(qstr, 0, first-1)] = string.sub(qstr, first+1) + end + end + + while true do + local first, last = string.find(query, "&", pos) + if first then + ginsert(string.sub(query, pos, first-1)); + pos = last+1 + else + ginsert(string.sub(query, pos)); + break; + end + end + return parsed +end + +----------------------------------------------------------------------------- +-- Builds a query string from dictionary based table +-- Input +-- dictionary table where table['name'] = value +-- Returns +-- query string (name=value&name=value ...) +----------------------------------------------------------------------------- +function build_query(query) + local qstr = "" + + for i,v in pairs(query) do + qstr = qstr .. i .. '=' .. v .. '&' + end + return string.sub(qstr, 0, string.len(qstr)-1) +end