PageRenderTime 55ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/nselib/http.lua

https://github.com/prakashgamit/nmap
Lua | 2631 lines | 2341 code | 60 blank | 230 comment | 100 complexity | 3ff393fff2b09af3b55b259727e3d697 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0, LGPL-2.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. ---Implements the HTTP client protocol in a standard form that Nmap scripts can
  2. -- take advantage of.
  3. --
  4. -- Because HTTP has so many uses, there are a number of interfaces to this library.
  5. -- The most obvious and common ones are simply <code>get</code>, <code>post</code>,
  6. -- and <code>head</code>; or, if more control is required, <code>generic_request</code>
  7. -- can be used. These functions do what one would expect. The <code>get_url</code>
  8. -- helper function can be used to parse and retrieve a full URL.
  9. --
  10. -- These functions return a table of values, including:
  11. -- * <code>status-line</code> - A string representing the status, such as "HTTP/1.1 200 OK". In case of an error, a description will be provided in this line.
  12. -- * <code>status</code>: The HTTP status value; for example, "200". If an error occurs during a request, then this value is going to be nil.
  13. -- * <code>header</code> - An associative array representing the header. Keys are all lowercase, and standard headers, such as 'date', 'content-length', etc. will typically be present.
  14. -- * <code>rawheader</code> - A numbered array of the headers, exactly as the server sent them. While header['content-type'] might be 'text/html', rawheader[3] might be 'Content-type: text/html'.
  15. -- * <code>cookies</code> - A numbered array of the cookies the server sent. Each cookie is a table with the following keys: <code>name</code>, <code>value</code>, <code>path</code>, <code>domain</code>, and <code>expires</code>.
  16. -- * <code>body</code> - The full body, as returned by the server.
  17. --
  18. -- If a script is planning on making a lot of requests, the pipelining functions can
  19. -- be helpful. <code>pipeline_add</code> queues requests in a table, and
  20. -- <code>pipeline</code> performs the requests, returning the results as an array,
  21. -- with the responses in the same order as the queries were added. As a simple example:
  22. --<code>
  23. -- -- Start by defining the 'all' variable as nil
  24. -- local all = nil
  25. --
  26. -- -- Add two 'GET' requests and one 'HEAD' to the queue. These requests are not performed
  27. -- -- yet. The second parameter represents the 'options' table, which we don't need.
  28. -- all = http.pipeline_add('/book', nil, all)
  29. -- all = http.pipeline_add('/test', nil, all)
  30. -- all = http.pipeline_add('/monkeys', nil, all)
  31. --
  32. -- -- Perform all three requests as parallel as Nmap is able to
  33. -- local results = http.pipeline('nmap.org', 80, all)
  34. --</code>
  35. --
  36. -- At this point, <code>results</code> is an array with three elements. Each element
  37. -- is a table containing the HTTP result, as discussed above.
  38. --
  39. -- One more interface provided by the HTTP library helps scripts determine whether or not
  40. -- a page exists. The <code>identify_404</code> function will try several URLs on the
  41. -- server to determine what the server's 404 pages look like. It will attempt to identify
  42. -- customized 404 pages that may not return the actual status code 404. If successful,
  43. -- the function <code>page_exists</code> can then be used to determine whether or not
  44. -- a page existed.
  45. --
  46. -- Some other miscellaneous functions that can come in handy are <code>response_contains</code>,
  47. -- <code>can_use_head</code>, and <code>save_path</code>. See the appropriate documentation
  48. -- for them.
  49. --
  50. -- The response to each function is typically a table with the following keys:
  51. -- <code>status-line</code>: The HTTP status line; for example, "HTTP/1.1 200 OK" (note: this is followed by a newline). In case of an error, a description will be provided in this line.
  52. -- <code>status</code>: The HTTP status value; for example, "200". If an error occurs during a request, then this value is going to be nil.
  53. -- <code>header</code>: A table of header values, where the keys are lowercase and the values are exactly what the server sent
  54. -- <code>rawheader</code>: A list of header values as "name: value" strings, in the exact format and order that the server sent them
  55. -- <code>cookies</code>: A list of cookies that the server is sending. Each cookie is a table containing the keys <code>name</code>, <code>value</code>, and <code>path</code>. This table can be sent to the server in subsequent responses in the <code>options</code> table to any function (see below).
  56. -- <code>body</code>: The body of the response
  57. --
  58. -- Many of the functions optionally allow an 'options' table. This table can alter the HTTP headers
  59. -- or other values like the timeout. The following are valid values in 'options' (note: not all
  60. -- options will necessarily affect every function):
  61. -- * <code>timeout</code>: A timeout used for socket operations.
  62. -- * <code>header</code>: A table containing additional headers to be used for the request. For example, <code>options['header']['Content-Type'] = 'text/xml'</code>
  63. -- * <code>content</code>: The content of the message (content-length will be added -- set header['Content-Length'] to override). This can be either a string, which will be directly added as the body of the message, or a table, which will have each key=value pair added (like a normal POST request).
  64. -- * <code>cookies</code>: A list of cookies as either a string, which will be directly sent, or a table. If it's a table, the following fields are recognized:
  65. -- ** <code>name</code>
  66. -- ** <code>value</code>
  67. -- ** <code>path</code>
  68. -- ** <code>expires</code>
  69. -- Only <code>name</code> and <code>value</code> fields are required.
  70. -- * <code>auth</code>: A table containing the keys <code>username</code> and <code>password</code>, which will be used for HTTP Basic authentication.
  71. -- If a server requires HTTP Digest authentication, then there must also be a key <code>digest</code>, with value <code>true</code>.
  72. -- * <code>bypass_cache</code>: Do not perform a lookup in the local HTTP cache.
  73. -- * <code>no_cache</code>: Do not save the result of this request to the local HTTP cache.
  74. -- * <code>no_cache_body</code>: Do not save the body of the response to the local HTTP cache.
  75. -- * <code>redirect_ok</code>: Closure that overrides the default redirect_ok used to validate whether to follow HTTP redirects or not. False, if no HTTP redirects should be followed.
  76. -- The following example shows how to write a custom closure that follows 5 consecutive redirects:
  77. -- <code>
  78. -- redirect_ok = function(host,port)
  79. -- local c = 5
  80. -- return function(url)
  81. -- if ( c==0 ) then return false end
  82. -- c = c - 1
  83. -- return true
  84. -- end
  85. -- end
  86. -- </code>
  87. --
  88. -- @args http.max-cache-size The maximum memory size (in bytes) of the cache.
  89. --
  90. -- @args http.useragent The value of the User-Agent header field sent with
  91. -- requests. By default it is
  92. -- <code>"Mozilla/5.0 (compatible; Nmap Scripting Engine; http://nmap.org/book/nse.html)"</code>.
  93. -- A value of the empty string disables sending the User-Agent header field.
  94. --
  95. -- @args http.pipeline If set, it represents the number of HTTP requests that'll be
  96. -- sent on one connection. This can be set low to make debugging easier, or it
  97. -- can be set high to test how a server reacts (its chosen max is ignored).
  98. -- @args http.max-pipeline If set, it represents the number of outstanding HTTP requests
  99. -- that should be pipelined. Defaults to <code>http.pipeline</code> (if set), or to what
  100. -- <code>getPipelineMax</code> function returns.
  101. --
  102. -- TODO
  103. -- Implement cache system for http pipelines
  104. --
  105. local base64 = require "base64"
  106. local comm = require "comm"
  107. local coroutine = require "coroutine"
  108. local nmap = require "nmap"
  109. local os = require "os"
  110. local sasl = require "sasl"
  111. local stdnse = require "stdnse"
  112. local string = require "string"
  113. local table = require "table"
  114. local url = require "url"
  115. _ENV = stdnse.module("http", stdnse.seeall)
  116. ---Use ssl if we have it
  117. local have_ssl, openssl = pcall(require,'openssl')
  118. USER_AGENT = stdnse.get_script_args('http.useragent') or "Mozilla/5.0 (compatible; Nmap Scripting Engine; http://nmap.org/book/nse.html)"
  119. local MAX_REDIRECT_COUNT = 5
  120. -- Recursively copy a table.
  121. -- Only recurs when a value is a table, other values are copied by assignment.
  122. local function tcopy (t)
  123. local tc = {};
  124. for k,v in pairs(t) do
  125. if type(v) == "table" then
  126. tc[k] = tcopy(v);
  127. else
  128. tc[k] = v;
  129. end
  130. end
  131. return tc;
  132. end
  133. --- Recursively copy into a table any elements from another table whose key it
  134. -- doesn't have.
  135. local function table_augment(to, from)
  136. for k, v in pairs(from) do
  137. if type( to[k] ) == 'table' then
  138. table_augment(to[k], from[k])
  139. else
  140. to[k] = from[k]
  141. end
  142. end
  143. end
  144. --- Get a value suitable for the Host header field.
  145. -- See RFC 2616 sections 14.23 and 5.2.
  146. local function get_host_field(host, port)
  147. return stdnse.get_hostname(host)
  148. end
  149. -- Skip *( SP | HT ) starting at offset. See RFC 2616, section 2.2.
  150. -- @return the first index following the spaces.
  151. -- @return the spaces skipped over.
  152. local function skip_space(s, offset)
  153. local _, i, space = s:find("^([ \t]*)", offset)
  154. return i + 1, space
  155. end
  156. -- Get a token starting at offset. See RFC 2616, section 2.2.
  157. -- @return the first index following the token, or nil if no token was found.
  158. -- @return the token.
  159. local function get_token(s, offset)
  160. -- All characters except CTL and separators.
  161. local _, i, token = s:find("^([^()<>@,;:\\\"/%[%]?={} \0\001-\031\127]+)", offset)
  162. if i then
  163. return i + 1, token
  164. else
  165. return nil
  166. end
  167. end
  168. -- Get a quoted-string starting at offset. See RFC 2616, section 2.2. crlf is
  169. -- used as the definition for CRLF in the case of LWS within the string.
  170. -- @return the first index following the quoted-string, or nil if no
  171. -- quoted-string was found.
  172. -- @return the contents of the quoted-string, without quotes or backslash
  173. -- escapes.
  174. local function get_quoted_string(s, offset, crlf)
  175. local result = {}
  176. local i = offset
  177. assert(s:sub(i, i) == "\"")
  178. i = i + 1
  179. while i <= s:len() do
  180. local c = s:sub(i, i)
  181. if c == "\"" then
  182. -- Found the closing quote, done.
  183. return i + 1, table.concat(result)
  184. elseif c == "\\" then
  185. -- This is a quoted-pair ("\" CHAR).
  186. i = i + 1
  187. c = s:sub(i, i)
  188. if c == "" then
  189. -- No character following.
  190. error(string.format("\\ escape at end of input while parsing quoted-string."))
  191. end
  192. -- Only CHAR may follow a backslash.
  193. if c:byte(1) > 127 then
  194. error(string.format("Unexpected character with value > 127 (0x%02X) in quoted-string.", c:byte(1)))
  195. end
  196. else
  197. -- This is qdtext, which is TEXT except for '"'.
  198. -- TEXT is "any OCTET except CTLs, but including LWS," however "a CRLF is
  199. -- allowed in the definition of TEXT only as part of a header field
  200. -- continuation." So there are really two definitions of quoted-string,
  201. -- depending on whether it's in a header field or not. This function does
  202. -- not allow CRLF.
  203. c = s:sub(i, i)
  204. if c ~= "\t" and c:match("^[\0\001-\031\127]$") then
  205. error(string.format("Unexpected control character in quoted-string: 0x%02X.", c:byte(1)))
  206. end
  207. end
  208. result[#result + 1] = c
  209. i = i + 1
  210. end
  211. return nil
  212. end
  213. -- Get a ( token | quoted-string ) starting at offset.
  214. -- @return the first index following the token or quoted-string, or nil if
  215. -- nothing was found.
  216. -- @return the token or quoted-string.
  217. local function get_token_or_quoted_string(s, offset, crlf)
  218. if s:sub(offset, offset) == "\"" then
  219. return get_quoted_string(s, offset)
  220. else
  221. return get_token(s, offset)
  222. end
  223. end
  224. -- Returns the index just past the end of LWS.
  225. local function skip_lws(s, pos)
  226. local _, e
  227. while true do
  228. while string.match(s, "^[ \t]", pos) do
  229. pos = pos + 1
  230. end
  231. _, e = string.find(s, "^\r?\n[ \t]", pos)
  232. if not e then
  233. return pos
  234. end
  235. pos = e + 1
  236. end
  237. end
  238. ---Validate an 'options' table, which is passed to a number of the HTTP functions. It is
  239. -- often difficult to track down a mistake in the options table, and requires fiddling
  240. -- with the http.lua source, but this should make that a lot easier.
  241. local function validate_options(options)
  242. local bad = false
  243. if(options == nil) then
  244. return true
  245. end
  246. for key, value in pairs(options) do
  247. if(key == 'timeout') then
  248. if(type(tonumber(value)) ~= 'number') then
  249. stdnse.print_debug(1, 'http: options.timeout contains a non-numeric value')
  250. bad = true
  251. end
  252. elseif(key == 'header') then
  253. if(type(value) ~= 'table') then
  254. stdnse.print_debug(1, "http: options.header should be a table")
  255. bad = true
  256. end
  257. elseif(key == 'content') then
  258. if(type(value) ~= 'string' and type(value) ~= 'table') then
  259. stdnse.print_debug(1, "http: options.content should be a string or a table")
  260. bad = true
  261. end
  262. elseif(key == 'cookies') then
  263. if(type(value) == 'table') then
  264. for _, cookie in ipairs(value) do
  265. for cookie_key, cookie_value in pairs(cookie) do
  266. if(cookie_key == 'name') then
  267. if(type(cookie_value) ~= 'string') then
  268. stdnse.print_debug(1, "http: options.cookies[i].name should be a string")
  269. bad = true
  270. end
  271. elseif(cookie_key == 'value') then
  272. if(type(cookie_value) ~= 'string') then
  273. stdnse.print_debug(1, "http: options.cookies[i].value should be a string")
  274. bad = true
  275. end
  276. elseif(cookie_key == 'path') then
  277. if(type(cookie_value) ~= 'string') then
  278. stdnse.print_debug(1, "http: options.cookies[i].path should be a string")
  279. bad = true
  280. end
  281. elseif(cookie_key == 'expires') then
  282. if(type(cookie_value) ~= 'string') then
  283. stdnse.print_debug(1, "http: options.cookies[i].expires should be a string")
  284. bad = true
  285. end
  286. else
  287. stdnse.print_debug(1, "http: Unknown field in cookie table: %s", cookie_key)
  288. bad = true
  289. end
  290. end
  291. end
  292. elseif(type(value) ~= 'string') then
  293. stdnse.print_debug(1, "http: options.cookies should be a table or a string")
  294. bad = true
  295. end
  296. elseif(key == 'auth') then
  297. if(type(value) == 'table') then
  298. if(value['username'] == nil or value['password'] == nil) then
  299. stdnse.print_debug(1, "http: options.auth should contain both a 'username' and a 'password' key")
  300. bad = true
  301. end
  302. else
  303. stdnse.print_debug(1, "http: options.auth should be a table")
  304. bad = true
  305. end
  306. elseif (key == 'digestauth') then
  307. if(type(value) == 'table') then
  308. local req_keys = {"username","realm","nonce","digest-uri","response"}
  309. for _,k in ipairs(req_keys) do
  310. if not value[k] then
  311. stdnse.print_debug(1, "http: options.digestauth missing key: %s",k)
  312. bad = true
  313. break
  314. end
  315. end
  316. else
  317. bad = true
  318. stdnse.print_debug(1, "http: options.digestauth should be a table")
  319. end
  320. elseif(key == 'bypass_cache' or key == 'no_cache' or key == 'no_cache_body') then
  321. if(type(value) ~= 'boolean') then
  322. stdnse.print_debug(1, "http: options.bypass_cache, options.no_cache, and options.no_cache_body must be boolean values")
  323. bad = true
  324. end
  325. elseif(key == 'redirect_ok') then
  326. if(type(value)~= 'function' and type(value)~='boolean') then
  327. stdnse.print_debug(1, "http: options.redirect_ok must be a function or boolean")
  328. bad = true
  329. end
  330. else
  331. stdnse.print_debug(1, "http: Unknown key in the options table: %s", key)
  332. end
  333. end
  334. return not(bad)
  335. end
  336. -- The following recv functions, and the function <code>next_response</code>
  337. -- follow a common pattern. They each take a <code>partial</code> argument
  338. -- whose value is data that has been read from the socket but not yet used in
  339. -- parsing, and they return as their second return value a new value for
  340. -- <code>partial</code>. The idea is that, for example, in reading from the
  341. -- socket to get the Status-Line, you will probably read too much and read part
  342. -- of the header. That part (the "partial") has to be retained when you go to
  343. -- parse the header. The common use pattern is this:
  344. -- <code>
  345. -- local partial
  346. -- status_line, partial = recv_line(socket, partial)
  347. -- ...
  348. -- header, partial = recv_header(socket, partial)
  349. -- ...
  350. -- </code>
  351. -- On error, the functions return <code>nil</code> and the second return value
  352. -- is an error message.
  353. -- Receive a single line (up to <code>\n</code>).
  354. local function recv_line(s, partial)
  355. local _, e
  356. local status, data
  357. local pos
  358. partial = partial or ""
  359. pos = 1
  360. while true do
  361. _, e = string.find(partial, "\n", pos, true)
  362. if e then
  363. break
  364. end
  365. status, data = s:receive()
  366. if not status then
  367. return status, data
  368. end
  369. pos = #partial
  370. partial = partial .. data
  371. end
  372. return string.sub(partial, 1, e), string.sub(partial, e + 1)
  373. end
  374. local function line_is_empty(line)
  375. return line == "\r\n" or line == "\n"
  376. end
  377. -- Receive up to and including the first blank line, but return everything up
  378. -- to and not including the final blank line.
  379. local function recv_header(s, partial)
  380. local lines = {}
  381. partial = partial or ""
  382. while true do
  383. local line
  384. line, partial = recv_line(s, partial)
  385. if not line then
  386. return line, partial
  387. end
  388. if line_is_empty(line) then
  389. break
  390. end
  391. lines[#lines + 1] = line
  392. end
  393. return table.concat(lines), partial
  394. end
  395. -- Receive until the connection is closed.
  396. local function recv_all(s, partial)
  397. local parts
  398. partial = partial or ""
  399. parts = {partial}
  400. while true do
  401. local status, part = s:receive()
  402. if not status then
  403. break
  404. else
  405. parts[#parts + 1] = part
  406. end
  407. end
  408. return table.concat(parts), ""
  409. end
  410. -- Receive exactly <code>length</code> bytes. Returns <code>nil</code> if that
  411. -- many aren't available.
  412. local function recv_length(s, length, partial)
  413. local parts, last
  414. partial = partial or ""
  415. parts = {}
  416. last = partial
  417. length = length - #last
  418. while length > 0 do
  419. local status
  420. parts[#parts + 1] = last
  421. status, last = s:receive()
  422. if not status then
  423. return nil
  424. end
  425. length = length - #last
  426. end
  427. -- At this point length is 0 or negative, and indicates the degree to which
  428. -- the last read "overshot" the desired length.
  429. if length == 0 then
  430. return table.concat(parts) .. last, ""
  431. else
  432. return table.concat(parts) .. string.sub(last, 1, length - 1), string.sub(last, length)
  433. end
  434. end
  435. -- Receive until the end of a chunked message body, and return the dechunked
  436. -- body.
  437. local function recv_chunked(s, partial)
  438. local chunks, chunk
  439. local chunk_size
  440. local pos
  441. chunks = {}
  442. repeat
  443. local line, hex, _, i
  444. line, partial = recv_line(s, partial)
  445. if not line then
  446. return nil, partial
  447. end
  448. pos = 1
  449. pos = skip_space(line, pos)
  450. -- Get the chunk-size.
  451. _, i, hex = string.find(line, "^([%x]+)", pos)
  452. if not i then
  453. return nil, string.format("Chunked encoding didn't find hex; got %q.", string.sub(line, pos, pos + 10))
  454. end
  455. pos = i + 1
  456. chunk_size = tonumber(hex, 16)
  457. if not chunk_size or chunk_size < 0 then
  458. return nil, string.format("Chunk size %s is not a positive integer.", hex)
  459. end
  460. -- Ignore chunk-extensions that may follow here.
  461. -- RFC 2616, section 2.1 ("Implied *LWS") seems to allow *LWS between the
  462. -- parts of a chunk-extension, but that is ambiguous. Consider this case:
  463. -- "1234;a\r\n =1\r\n...". It could be an extension with a chunk-ext-name
  464. -- of "a" (and no value), and a chunk-data beginning with " =", or it could
  465. -- be a chunk-ext-name of "a" with a value of "1", and a chunk-data
  466. -- starting with "...". We don't allow *LWS here, only ( SP | HT ), so the
  467. -- first interpretation will prevail.
  468. chunk, partial = recv_length(s, chunk_size, partial)
  469. if not chunk then
  470. return nil, partial
  471. end
  472. chunks[#chunks + 1] = chunk
  473. line, partial = recv_line(s, partial)
  474. if not line then
  475. -- this warning message was initially an error but was adapted
  476. -- to support broken servers, such as the Citrix XML Service
  477. stdnse.print_debug(2, "Didn't find CRLF after chunk-data.")
  478. elseif not string.match(line, "^\r?\n") then
  479. return nil, string.format("Didn't find CRLF after chunk-data; got %q.", line)
  480. end
  481. until chunk_size == 0
  482. return table.concat(chunks), partial
  483. end
  484. -- Receive a message body, assuming that the header has already been read by
  485. -- <code>recv_header</code>. The handling is sensitive to the request method
  486. -- and the status code of the response.
  487. local function recv_body(s, response, method, partial)
  488. local connection_close, connection_keepalive
  489. local version_major, version_minor
  490. local transfer_encoding
  491. local content_length
  492. local err
  493. partial = partial or ""
  494. -- First check for Connection: close and Connection: keep-alive. This is
  495. -- necessary to handle some servers that don't follow the protocol.
  496. connection_close = false
  497. connection_keepalive = false
  498. if response.header.connection then
  499. local offset, token
  500. offset = 0
  501. while true do
  502. offset, token = get_token(response.header.connection, offset + 1)
  503. if not offset then
  504. break
  505. end
  506. if string.lower(token) == "close" then
  507. connection_close = true
  508. elseif string.lower(token) == "keep-alive" then
  509. connection_keepalive = true
  510. end
  511. end
  512. end
  513. -- The HTTP version may also affect our decisions.
  514. version_major, version_minor = string.match(response["status-line"], "^HTTP/(%d+)%.(%d+)")
  515. -- See RFC 2616, section 4.4 "Message Length".
  516. -- 1. Any response message which "MUST NOT" include a message-body (such as
  517. -- the 1xx, 204, and 304 responses and any response to a HEAD request) is
  518. -- always terminated by the first empty line after the header fields...
  519. --
  520. -- Despite the above, some servers return a body with response to a HEAD
  521. -- request. So if an HTTP/1.0 server returns a response without Connection:
  522. -- keep-alive, or any server returns a response with Connection: close, read
  523. -- whatever's left on the socket (should be zero bytes).
  524. if string.upper(method) == "HEAD"
  525. or (response.status >= 100 and response.status <= 199)
  526. or response.status == 204 or response.status == 304 then
  527. if connection_close or (version_major == "1" and version_minor == "0" and not connection_keepalive) then
  528. return recv_all(s, partial)
  529. else
  530. return "", partial
  531. end
  532. end
  533. -- 2. If a Transfer-Encoding header field (section 14.41) is present and has
  534. -- any value other than "identity", then the transfer-length is defined by
  535. -- use of the "chunked" transfer-coding (section 3.6), unless the message
  536. -- is terminated by closing the connection.
  537. if response.header["transfer-encoding"]
  538. and response.header["transfer-encoding"] ~= "identity" then
  539. return recv_chunked(s, partial)
  540. end
  541. -- The Citrix XML Service sends a wrong "Transfer-Coding" instead of
  542. -- "Transfer-Encoding".
  543. if response.header["transfer-coding"]
  544. and response.header["transfer-coding"] ~= "identity" then
  545. return recv_chunked(s, partial)
  546. end
  547. -- 3. If a Content-Length header field (section 14.13) is present, its decimal
  548. -- value in OCTETs represents both the entity-length and the
  549. -- transfer-length. The Content-Length header field MUST NOT be sent if
  550. -- these two lengths are different (i.e., if a Transfer-Encoding header
  551. -- field is present). If a message is received with both a
  552. -- Transfer-Encoding header field and a Content-Length header field, the
  553. -- latter MUST be ignored.
  554. if response.header["content-length"] and not response.header["transfer-encoding"] then
  555. content_length = tonumber(response.header["content-length"])
  556. if not content_length then
  557. return nil, string.format("Content-Length %q is non-numeric", response.header["content-length"])
  558. end
  559. return recv_length(s, content_length, partial)
  560. end
  561. -- 4. If the message uses the media type "multipart/byteranges", and the
  562. -- ransfer-length is not otherwise specified, then this self- elimiting
  563. -- media type defines the transfer-length. [sic]
  564. -- Case 4 is unhandled.
  565. -- 5. By the server closing the connection.
  566. return recv_all(s, partial)
  567. end
  568. -- Sets response["status-line"] and response.status.
  569. local function parse_status_line(status_line, response)
  570. local version, status, reason_phrase
  571. response["status-line"] = status_line
  572. version, status, reason_phrase = string.match(status_line,
  573. "^HTTP/(%d%.%d) *(%d+) *(.*)\r?\n$")
  574. if not version then
  575. return nil, string.format("Error parsing status-line %q.", status_line)
  576. end
  577. -- We don't have a use for the version; ignore it.
  578. response.status = tonumber(status)
  579. if not response.status then
  580. return nil, string.format("Status code is not numeric: %s", status)
  581. end
  582. return true
  583. end
  584. -- Sets response.header and response.rawheader.
  585. local function parse_header(header, response)
  586. local pos
  587. local name, words
  588. local s, e
  589. response.header = {}
  590. response.rawheader = stdnse.strsplit("\r?\n", header)
  591. pos = 1
  592. while pos <= #header do
  593. -- Get the field name.
  594. e, name = get_token(header, pos)
  595. if not name or e > #header or string.sub(header, e, e) ~= ":" then
  596. return nil, string.format("Can't get header field name at %q", string.sub(header, pos, pos + 30))
  597. end
  598. pos = e + 1
  599. -- Skip initial space.
  600. pos = skip_lws(header, pos)
  601. -- Get non-space words separated by LWS, then join them with a single space.
  602. words = {}
  603. while pos <= #header and not string.match(header, "^\r?\n", pos) do
  604. s = pos
  605. while not string.match(header, "^[ \t]", pos) and
  606. not string.match(header, "^\r?\n", pos) do
  607. pos = pos + 1
  608. end
  609. words[#words + 1] = string.sub(header, s, pos - 1)
  610. pos = skip_lws(header, pos)
  611. end
  612. -- Set it in our table.
  613. name = string.lower(name)
  614. if response.header[name] then
  615. response.header[name] = response.header[name] .. ", " .. table.concat(words, " ")
  616. else
  617. response.header[name] = table.concat(words, " ")
  618. end
  619. -- Next field, or end of string. (If not it's an error.)
  620. s, e = string.find(header, "^\r?\n", pos)
  621. if not e then
  622. return nil, string.format("Header field named %q didn't end with CRLF", name)
  623. end
  624. pos = e + 1
  625. end
  626. return true
  627. end
  628. -- Parse the contents of a Set-Cookie header field. The result is an array
  629. -- containing tables of the form
  630. --
  631. -- { name = "NAME", value = "VALUE", Comment = "...", Domain = "...", ... }
  632. --
  633. -- Every key except "name" and "value" is optional.
  634. --
  635. -- This function attempts to support the cookie syntax defined in RFC 2109
  636. -- along with the backwards-compatibility suggestions from its section 10,
  637. -- "HISTORICAL". Values need not be quoted, but if they start with a quote they
  638. -- will be interpreted as a quoted string.
  639. local function parse_set_cookie(s)
  640. local cookies
  641. local name, value
  642. local _, pos
  643. cookies = {}
  644. pos = 1
  645. while true do
  646. local cookie = {}
  647. -- Get the NAME=VALUE part.
  648. pos = skip_space(s, pos)
  649. pos, cookie.name = get_token(s, pos)
  650. if not cookie.name then
  651. return nil, "Can't get cookie name."
  652. end
  653. pos = skip_space(s, pos)
  654. if pos > #s or string.sub(s, pos, pos) ~= "=" then
  655. return nil, string.format("Expected '=' after cookie name \"%s\".", cookie.name)
  656. end
  657. pos = pos + 1
  658. pos = skip_space(s, pos)
  659. if string.sub(s, pos, pos) == "\"" then
  660. pos, cookie.value = get_quoted_string(s, pos)
  661. else
  662. _, pos, cookie.value = string.find(s, "([^;]*)[ \t]*", pos)
  663. pos = pos + 1
  664. end
  665. if not cookie.value then
  666. return nil, string.format("Can't get value of cookie named \"%s\".", cookie.name)
  667. end
  668. pos = skip_space(s, pos)
  669. -- Loop over the attributes.
  670. while pos <= #s and string.sub(s, pos, pos) == ";" do
  671. pos = pos + 1
  672. pos = skip_space(s, pos)
  673. pos, name = get_token(s, pos)
  674. if not name then
  675. return nil, string.format("Can't get attribute name of cookie \"%s\".", cookie.name)
  676. end
  677. pos = skip_space(s, pos)
  678. if pos <= #s and string.sub(s, pos, pos) == "=" then
  679. pos = pos + 1
  680. pos = skip_space(s, pos)
  681. if string.sub(s, pos, pos) == "\"" then
  682. pos, value = get_quoted_string(s, pos)
  683. else
  684. -- account for the possibility of the expires attribute being empty or improperly formatted
  685. local last_pos = pos
  686. if string.lower(name) == "expires" then
  687. -- For version 0 cookies we must allow one comma for "expires".
  688. _, pos, value = string.find(s, "([^,]*,[^;,]*)[ \t]*", pos)
  689. else
  690. _, pos, value = string.find(s, "([^;,]*)[ \t]*", pos)
  691. end
  692. -- account for the possibility of the expires attribute being empty or improperly formatted
  693. if ( not(pos) ) then
  694. _, pos, value = s:find("([^;]*)", last_pos)
  695. end
  696. pos = pos + 1
  697. end
  698. if not value then
  699. return nil, string.format("Can't get value of cookie attribute \"%s\".", name)
  700. end
  701. else
  702. value = true
  703. end
  704. cookie[name:lower()] = value
  705. pos = skip_space(s, pos)
  706. end
  707. cookies[#cookies + 1] = cookie
  708. if pos > #s then
  709. break
  710. end
  711. if string.sub(s, pos, pos) ~= "," then
  712. return nil, string.format("Syntax error after cookie named \"%s\".", cookie.name)
  713. end
  714. pos = pos + 1
  715. pos = skip_space(s, pos)
  716. end
  717. return cookies
  718. end
  719. -- Read one response from the socket <code>s</code> and return it after
  720. -- parsing.
  721. local function next_response(s, method, partial)
  722. local response
  723. local status_line, header, body
  724. local status, err
  725. partial = partial or ""
  726. response = {
  727. status=nil,
  728. ["status-line"]=nil,
  729. header={},
  730. rawheader={},
  731. body=""
  732. }
  733. status_line, partial = recv_line(s, partial)
  734. if not status_line then
  735. return nil, partial
  736. end
  737. status, err = parse_status_line(status_line, response)
  738. if not status then
  739. return nil, err
  740. end
  741. header, partial = recv_header(s, partial)
  742. if not header then
  743. return nil, partial
  744. end
  745. status, err = parse_header(header, response)
  746. if not status then
  747. return nil, err
  748. end
  749. body, partial = recv_body(s, response, method, partial)
  750. if not body then
  751. return nil, partial
  752. end
  753. response.body = body
  754. -- We have the Status-Line, header, and body; now do any postprocessing.
  755. response.cookies = {}
  756. if response.header["set-cookie"] then
  757. response.cookies, err = parse_set_cookie(response.header["set-cookie"])
  758. if not response.cookies then
  759. -- Ignore a cookie parsing error.
  760. response.cookies = {}
  761. end
  762. end
  763. return response, partial
  764. end
  765. --- Tries to extract the max number of requests that should be made on
  766. -- a keep-alive connection based on "Keep-Alive: timeout=xx,max=yy" response
  767. -- header.
  768. --
  769. -- If the value is not available, an arbitrary value is used. If the connection
  770. -- is not explicitly closed by the server, this same value is attempted.
  771. --
  772. -- @param response The http response - Might be a table or a raw response
  773. -- @return The max number of requests on a keep-alive connection
  774. local function getPipelineMax(response)
  775. -- Allow users to override this with a script-arg
  776. local pipeline = stdnse.get_script_args({'http.pipeline', 'pipeline'})
  777. if(pipeline) then
  778. return tonumber(pipeline)
  779. end
  780. if response then
  781. if response.header and response.header.connection ~= "close" then
  782. if response.header["keep-alive"] then
  783. local max = string.match( response.header["keep-alive"], "max=(%d*)")
  784. if(max == nil) then
  785. return 40
  786. end
  787. return tonumber(max)
  788. else
  789. return 40
  790. end
  791. end
  792. end
  793. return 1
  794. end
  795. --- Builds a string to be added to the request mod_options table
  796. --
  797. -- @param cookies A cookie jar just like the table returned parse_set_cookie.
  798. -- @param path If the argument exists, only cookies with this path are included to the request
  799. -- @return A string to be added to the mod_options table
  800. local function buildCookies(cookies, path)
  801. local cookie = ""
  802. if type(cookies) == 'string' then return cookies end
  803. for _, ck in ipairs(cookies or {}) do
  804. local ckpath = ck["path"]
  805. if not path or not ckpath
  806. or ckpath == path
  807. or ckpath:sub(-1) == "/" and ckpath == path:sub(1, ckpath:len())
  808. or ckpath .. "/" == path:sub(1, ckpath:len()+1)
  809. then
  810. cookie = cookie .. ck["name"] .. "=" .. ck["value"] .. "; "
  811. end
  812. end
  813. return cookie:gsub("; $","")
  814. end
  815. -- HTTP cache.
  816. -- Cache of GET and HEAD requests. Uses <"host:port:path", record>.
  817. -- record is in the format:
  818. -- result: The result from http.get or http.head
  819. -- last_used: The time the record was last accessed or made.
  820. -- get: Was the result received from a request to get or recently wiped?
  821. -- size: The size of the record, equal to #record.result.body.
  822. local cache = {size = 0};
  823. local function check_size (cache)
  824. local max_size = tonumber(stdnse.get_script_args({'http.max-cache-size', 'http-max-cache-size'}) or 1e6);
  825. local size = cache.size;
  826. if size > max_size then
  827. stdnse.print_debug(1,
  828. "Current http cache size (%d bytes) exceeds max size of %d",
  829. size, max_size);
  830. table.sort(cache, function(r1, r2)
  831. return (r1.last_used or 0) < (r2.last_used or 0);
  832. end);
  833. for i, record in ipairs(cache) do
  834. if size <= max_size then break end
  835. local result = record.result;
  836. if type(result.body) == "string" then
  837. size = size - record.size;
  838. record.size, record.get, result.body = 0, false, "";
  839. end
  840. end
  841. cache.size = size;
  842. end
  843. stdnse.print_debug(2, "Final http cache size (%d bytes) of max size of %d",
  844. size, max_size);
  845. return size;
  846. end
  847. -- Unique value to signal value is being retrieved.
  848. -- Also holds <mutex, thread> pairs, working thread is value
  849. local WORKING = setmetatable({}, {__mode = "v"});
  850. local function lookup_cache (method, host, port, path, options)
  851. if(not(validate_options(options))) then
  852. return nil
  853. end
  854. options = options or {};
  855. local bypass_cache = options.bypass_cache; -- do not lookup
  856. local no_cache = options.no_cache; -- do not save result
  857. local no_cache_body = options.no_cache_body; -- do not save body
  858. if type(port) == "table" then port = port.number end
  859. local key = stdnse.get_hostname(host)..":"..port..":"..path;
  860. local mutex = nmap.mutex(tostring(lookup_cache)..key);
  861. local state = {
  862. mutex = mutex,
  863. key = key,
  864. method = method,
  865. bypass_cache = bypass_cache,
  866. no_cache = no_cache,
  867. no_cache_body = no_cache_body,
  868. };
  869. while true do
  870. mutex "lock";
  871. local record = cache[key];
  872. if bypass_cache or record == nil or method ~= record.method then
  873. WORKING[mutex] = coroutine.running();
  874. cache[key], state.old_record = WORKING, record;
  875. return nil, state;
  876. elseif record == WORKING then
  877. local working = WORKING[mutex];
  878. if working == nil or coroutine.status(working) == "dead" then
  879. -- thread died before insert_cache could be called
  880. cache[key] = nil; -- reset
  881. end
  882. mutex "done";
  883. else
  884. mutex "done";
  885. record.last_used = os.time();
  886. return tcopy(record.result), state;
  887. end
  888. end
  889. end
  890. local function response_is_cacheable(response)
  891. -- if response.status is nil, then an error must have occured during the request
  892. -- and we probably don't want to cache the response
  893. if not response.status then
  894. return false
  895. end
  896. -- 206 Partial Content. RFC 2616, 1.34: "...a cache that does not support the
  897. -- Range and Content-Range headers MUST NOT cache 206 (Partial Content)
  898. -- responses."
  899. if response.status == 206 then
  900. return false
  901. end
  902. -- RFC 2616, 13.4. "A response received with any [status code other than 200,
  903. -- 203, 206, 300, 301 or 410] (e.g. status codes 302 and 307) MUST NOT be
  904. -- returned in a reply to a subsequent request unless there are cache-control
  905. -- directives or another header(s) that explicitly allow it."
  906. -- We violate the standard here and allow these other codes to be cached,
  907. -- with the exceptions listed below.
  908. -- 401 Unauthorized. Caching this would prevent us from retrieving it later
  909. -- with the correct credentials.
  910. if response.status == 401 then
  911. return false
  912. end
  913. return true
  914. end
  915. local function insert_cache (state, response)
  916. local key = assert(state.key);
  917. local mutex = assert(state.mutex);
  918. if response == nil or state.no_cache or not response_is_cacheable(response) then
  919. cache[key] = state.old_record;
  920. else
  921. local record = {
  922. result = tcopy(response),
  923. last_used = os.time(),
  924. method = state.method,
  925. size = type(response.body) == "string" and #response.body or 0,
  926. };
  927. response = record.result; -- only modify copy
  928. cache[key], cache[#cache+1] = record, record;
  929. if state.no_cache_body then
  930. response.body = "";
  931. end
  932. if type(response.body) == "string" then
  933. cache.size = cache.size + #response.body;
  934. check_size(cache);
  935. end
  936. end
  937. mutex "done";
  938. end
  939. -- Return true if the given method requires a body in the request. In case no
  940. -- body was supplied we must send "Content-Length: 0".
  941. local function request_method_needs_content_length(method)
  942. return method == "POST"
  943. end
  944. -- For each of the following request functions, <code>host</code> may either be
  945. -- a string or a table, and <code>port</code> may either be a number or a
  946. -- table.
  947. --
  948. -- The format of the return value is a table with the following structure:
  949. -- {status = 200, status-line = "HTTP/1.1 200 OK", header = {}, rawheader = {}, body ="<html>...</html>"}
  950. -- The header table has an entry for each received header with the header name
  951. -- being the key. The table also has an entry named "status" which contains the
  952. -- http status code of the request.
  953. -- In case of an error, the status is nil and status-line describes the problem.
  954. local function http_error(status_line)
  955. return {
  956. status = nil,
  957. ["status-line"] = status_line,
  958. header = {},
  959. rawheader = {},
  960. body = nil,
  961. }
  962. end
  963. --- Build an HTTP request from parameters and return it as a string.
  964. --
  965. -- @param host The host this request is intended for.
  966. -- @param port The port this request is intended for.
  967. -- @param method The method to use.
  968. -- @param path The path for the request.
  969. -- @param options A table of options, which may include the keys:
  970. -- * <code>header</code>: A table containing additional headers to be used for the request.
  971. -- * <code>content</code>: The content of the message (content-length will be added -- set header['Content-Length'] to override)
  972. -- * <code>cookies</code>: A table of cookies in the form returned by <code>parse_set_cookie</code>.
  973. -- * <code>auth</code>: A table containing the keys <code>username</code> and <code>password</code>.
  974. -- @return A request string.
  975. -- @see generic_request
  976. local function build_request(host, port, method, path, options)
  977. if(not(validate_options(options))) then
  978. return nil
  979. end
  980. options = options or {}
  981. -- Private copy of the options table, used to add default header fields.
  982. local mod_options = {
  983. header = {
  984. Connection = "close",
  985. Host = get_host_field(host, port),
  986. ["User-Agent"] = USER_AGENT
  987. }
  988. }
  989. if options.cookies then
  990. local cookies = buildCookies(options.cookies, path)
  991. if #cookies > 0 then
  992. mod_options.header["Cookie"] = cookies
  993. end
  994. end
  995. if options.auth and not options.auth.digest then
  996. local username = options.auth.username
  997. local password = options.auth.password
  998. local credentials = "Basic " .. base64.enc(username .. ":" .. password)
  999. mod_options.header["Authorization"] = credentials
  1000. end
  1001. if options.digestauth then
  1002. local order = {"username", "realm", "nonce", "digest-uri", "algorithm", "response", "qop", "nc", "cnonce"}
  1003. local no_quote = {algorithm=true, qop=true, nc=true}
  1004. local creds = {}
  1005. for _,k in ipairs(order) do
  1006. local v = options.digestauth[k]
  1007. if v then
  1008. if no_quote[k] then
  1009. table.insert(creds, ("%s=%s"):format(k,v))
  1010. else
  1011. if k == "digest-uri" then
  1012. table.insert(creds, ('%s="%s"'):format("uri",v))
  1013. else
  1014. table.insert(creds, ('%s="%s"'):format(k,v))
  1015. end
  1016. end
  1017. end
  1018. end
  1019. local credentials = "Digest "..table.concat(creds, ", ")
  1020. mod_options.header["Authorization"] = credentials
  1021. end
  1022. local body
  1023. -- Build a form submission from a table, like "k1=v1&k2=v2".
  1024. if type(options.content) == "table" then
  1025. local parts = {}
  1026. local k, v
  1027. for k, v in pairs(options.content) do
  1028. parts[#parts + 1] = url.escape(k) .. "=" .. url.escape(v)
  1029. end
  1030. body = table.concat(parts, "&")
  1031. mod_options.header["Content-Type"] = "application/x-www-form-urlencoded"
  1032. elseif options.content then
  1033. body = options.content
  1034. elseif request_method_needs_content_length(method) then
  1035. body = ""
  1036. end
  1037. if body then
  1038. mod_options.header["Content-Length"] = #body
  1039. end
  1040. -- Add any other header fields into the local copy.
  1041. table_augment(mod_options, options)
  1042. -- We concat this string manually to allow null bytes in requests
  1043. local request_line = method.." "..path.." HTTP/1.1"
  1044. local header = {}
  1045. for name, value in pairs(mod_options.header) do
  1046. -- we concat this string manually to allow null bytes in requests
  1047. header[#header + 1] = name..": "..value
  1048. end
  1049. return request_line .. "\r\n" .. stdnse.strjoin("\r\n", header) .. "\r\n\r\n" .. (body or "")
  1050. end
  1051. --- Send a string to a host and port and return the HTTP result. This function
  1052. -- is like <code>generic_request</code>, to be used when you have a ready-made
  1053. -- request, not a collection of request parameters.
  1054. --
  1055. -- @param host The host to connect to.
  1056. -- @param port The port to connect to.
  1057. -- @param options A table of other parameters. It may have any of these fields:
  1058. -- * <code>timeout</code>: A timeout used for socket operations.
  1059. -- * <code>header</code>: A table containing additional headers to be used for the request.
  1060. -- * <code>content</code>: The content of the message (content-length will be added -- set header['Content-Length'] to override)
  1061. -- * <code>cookies</code>: A table of cookies in the form returned by <code>parse_set_cookie</code>.
  1062. -- * <code>auth</code>: A table containing the keys <code>username</code> and <code>password</code>.
  1063. -- @return A response table, see module documentation for description.
  1064. -- @see generic_request
  1065. local function request(host, port, data, options)
  1066. if(not(validate_options(options))) then
  1067. return http_error("Options failed to validate.")
  1068. end
  1069. local method
  1070. local header
  1071. local response
  1072. options = options or {}
  1073. if type(port) == 'table' then
  1074. if port.protocol and port.protocol ~= 'tcp' then
  1075. stdnse.print_debug(1, "http.request() supports the TCP protocol only, your request to %s cannot be completed.", host)
  1076. return http_error("Unsupported protocol.")
  1077. end
  1078. end
  1079. method = string.match(data, "^(%S+)")
  1080. local socket, partial, opts = comm.tryssl(host, port, data, { timeout = options.timeout })
  1081. if not socket then
  1082. return http_error("Error creating socket.")
  1083. end
  1084. repeat
  1085. response, partial = next_response(socket, method, partial)
  1086. if not response then
  1087. return http_error("There was an error in next_response function.")
  1088. end
  1089. -- See RFC 2616, sections 8.2.3 and 10.1.1, for the 100 Continue status.
  1090. -- Sometimes a server will tell us to "go ahead" with a POST body before
  1091. -- sending the real response. If we got one of those, skip over it.
  1092. until not (response.status >= 100 and response.status <= 199)
  1093. socket:close()
  1094. -- if SSL was used to retrieve the URL mark this in the response
  1095. response.ssl = ( opts == 'ssl' )
  1096. return response
  1097. end
  1098. ---Do a single request with a given method. The response is returned as the standard
  1099. -- response table (see the module documentation).
  1100. --
  1101. -- The <code>get</code>, <code>head</code>, and <code>post</code> functions are simple
  1102. -- wrappers around <code>generic_request</code>.
  1103. --
  1104. -- Any 1XX (informational) responses are discarded.
  1105. --
  1106. -- @param host The host to connect to.
  1107. -- @param port The port to connect to.
  1108. -- @param method The method to use; for example, 'GET', 'HEAD', etc.
  1109. -- @param path The path to retrieve.
  1110. -- @param options [optional] A table that lets the caller control socket timeouts, HTTP headers, and other parameters. For full documentation, see the module documentation (above).
  1111. -- @return A response table, see module documentation for description.
  1112. -- @see request
  1113. function generic_request(host, port, method, path, options)
  1114. if(not(validate_options(options))) then
  1115. return http_error("Options failed to validate.")
  1116. end
  1117. local digest_auth = options and options.auth and options.auth.digest
  1118. if digest_auth and not have_ssl then
  1119. stdnse.print_debug("http: digest auth requires openssl.")
  1120. end
  1121. if digest_auth and have_ssl then
  1122. -- If we want to do digest authentication, we have to make an initial
  1123. -- request to get realm, nonce and other fields.
  1124. local options_with_auth_removed = tcopy(options)
  1125. options_with_auth_removed["auth"] = nil
  1126. local r = generic_request(host, port, method, path, options_with_auth_removed)
  1127. local h = r.header['www-authenticate']
  1128. if not r.status or (h and not string.find(h:lower(), "digest.-realm")) then
  1129. stdnse.print_debug("http: the target doesn't support digest auth or there was an error during request.")
  1130. return http_error("The target doesn't support digest auth or there was an error during request.")
  1131. end
  1132. -- Compute the response hash
  1133. local dmd5 = sasl.DigestMD5:new(h, options.auth.username, options.auth.password, method, path)
  1134. local _, digest_table = dmd5:calcDigest()
  1135. options.digestauth = digest_table
  1136. end
  1137. return request(host, port, build_request(host, port, method, path, options), options)
  1138. end
  1139. ---Uploads a file using the PUT method and returns a result table. This is a simple wrapper
  1140. -- around <code>generic_request</code>
  1141. --
  1142. -- @param host The host to connect to.
  1143. -- @param port The port to connect to.
  1144. -- @param path The path to retrieve.
  1145. -- @param options [optional] A table that lets the caller control socket timeouts, HTTP headers, and other parameters. For full documentation, see the module documentation (above).
  1146. -- @param putdata The contents of the file to upload
  1147. -- @return A response table, see module documentation for description.
  1148. -- @see http.generic_request
  1149. function put(host, port, path, options, putdata)
  1150. if(not(validate_options(options))) then
  1151. return http_error("Options failed to validate.")
  1152. end
  1153. if ( not(putdata) ) then
  1154. return http_error("No file to PUT.")
  1155. end
  1156. local mod_options = {
  1157. content = putdata,
  1158. }
  1159. table_augment(mod_options, options or {})
  1160. return generic_request(host, port, "PUT", path, mod_options)
  1161. end
  1162. -- Check if the given URL is okay to redirect to. Return a table with keys
  1163. -- "host", "port", and "path" if okay, nil otherwise.
  1164. -- @param url table as returned by url.parse
  1165. -- @param host table as received by the action function
  1166. -- @param port table as received by the action function
  1167. -- @return loc table containing the new location
  1168. function redirect_ok(host, port)
  1169. -- A battery of tests a URL is subjected to in order to decide if it may be
  1170. -- redirected to. They incrementally fill in loc.host, loc.port, and loc.path.
  1171. local rules = {
  1172. -- Check if there's any credentials in the url
  1173. function (url, host, port)
  1174. -- bail if userinfo is present
  1175. return ( url.userinfo and false ) or true
  1176. end,
  1177. -- Check if the location is within the domain or host
  1178. function (url, host, port)
  1179. local hostname = stdnse.get_hostname(host)
  1180. if ( hostname == host.ip and host.ip == url.host.ip ) then
  1181. return true
  1182. end
  1183. local domain = hostname:match("^[^%.]-%.(.*)") or hostname
  1184. local match = ("^.*%s$"):format(domain)
  1185. if ( url.host:match(match) ) then
  1186. return true
  1187. end
  1188. return false
  1189. end,
  1190. -- Check whether the new location has the same port number
  1191. function (url, host, port)
  1192. -- port fixup, adds default ports 80 and 443 in case no url.port was
  1193. -- defined, we do this based on the url scheme
  1194. local url_port = url.port
  1195. if ( not(url_port) ) then
  1196. if ( url.scheme == "http" ) then
  1197. url_port = 80
  1198. elseif( url.scheme == "https" ) then
  1199. url_port = 443
  1200. end
  1201. end
  1202. if (not url_port) or tonumber(url_port) == port.number then
  1203. return true
  1204. end
  1205. return false
  1206. end,
  1207. -- Check whether the url.scheme matches the port.service
  1208. function (url, host, port)
  1209. -- if url.scheme is present then it must match the scanned port
  1210. if url.scheme and url.port then return true end
  1211. if url.scheme and url.scheme ~= port.service then return false end
  1212. return true
  1213. end,
  1214. -- make sure we're actually being redirected somewhere and not to the same url
  1215. function (url, host, port)
  1216. -- path cannot be unchanged unless host has changed
  1217. -- loc.path must be set if returning true
  1218. if ( not url.path or url.path == "/" ) and url.host == ( host.targetname or host.ip) then return false end
  1219. if not url.path then return true end
  1220. return true
  1221. end,
  1222. }
  1223. local counter = MAX_REDIRECT_COUNT
  1224. -- convert a numeric port to a table
  1225. if ( "number" == type(port) ) then
  1226. port = { number = port }
  1227. end
  1228. return function(url)
  1229. if ( counter == 0 ) then return false

Large files files are truncated, but you can click here to view the full file