]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
doh: GET support, breaks on large payloads
authorPetr Špaček <petr.spacek@nic.cz>
Mon, 1 Apr 2019 17:05:57 +0000 (19:05 +0200)
committerPetr Špaček <petr.spacek@nic.cz>
Thu, 11 Apr 2019 07:12:48 +0000 (09:12 +0200)
This seems to be a limitation in cqueues but we have to confirm this.

modules/http/http_doh.lua
modules/http/http_doh.test.lua

index ae1367dc55a3ce8e4df45df4cea5caa7076ef9ba..9b0f6a35c73c06797550af207045b1acc2747f0c 100644 (file)
@@ -1,3 +1,4 @@
+local basexx = require('basexx')
 local ffi = require('ffi')
 local condition = require('cqueues.condition')
 
@@ -35,10 +36,32 @@ end
 
 -- Trace execution of DNS queries
 local function serve_doh(h, stream)
+       local input
        local method = h:get(':method')
-       if method ~= 'POST' then
-               return 405, 'only HTTP post is supported'
+       if method == 'POST' then
+               input = stream:get_body_chars(65536, 10)  -- FIXME: timeout
+       elseif method == 'GET' then
+               local input_b64 = string.match(h:get(':path'), '^/doh%?dns=([a-zA-Z0-9_-]+)$')
+               if not input_b64 then
+                       return 400, 'base64url query not found'
+               end
+               if #input_b64 > 87380 then  -- base64url encode 65535
+                       return 414, 'query parameter in URI too long'
+               end
+               input = basexx.from_url64(input_b64)
+               if not input then
+                       return 400, 'invalid base64url'
+               end
+       else
+               return 405, 'only HTTP POST and GET are supported'
        end
+
+       if #input < 12 then
+               return 400, 'input too short'
+       elseif #input > 65535 then
+               return 413, 'input too long'
+       end
+
        local content_type = h:get('content-type') or 'application/dns-message'
        if content_type ~= 'application/dns-message' then
                return 415, 'only Content-Type: application/dns-message is supported'
@@ -49,12 +72,6 @@ local function serve_doh(h, stream)
 --             return 406, 'only Accept: application/dns-message is supported'
 --     end
 
-       local input = stream:get_body_chars(65536, 10)  -- FIXME: timeout
-       if #input < 12 then
-               return 400, 'bad request: input too short'
-       elseif #input > 65535 then
-               return 413, 'bad request: input too long'
-       end
        -- Output buffer
        local output = ''
 
@@ -65,7 +82,7 @@ local function serve_doh(h, stream)
        local cond = condition.new()
        local waiting, done = false, false
        local finish_cb = function (answer, req)
-               print(tostring(answer))
+               print(tostring(answer))  -- FIXME
 
                print('TTL: ', get_http_ttl(answer))
 
index f3691246d997b6298ea14704fcf8ce608d21d1ad..148e66014cddc9a4e03833f1b0afd700209417f7 100644 (file)
@@ -1,3 +1,4 @@
+local basexx = require('basexx')
 local ffi = require('ffi')
 
 function parse_pkt(input)
@@ -49,10 +50,13 @@ else
        end
 
        local function check_err(req, exp_status, desc)
-               local headers = req:go(5)  -- randomly chosen timeout
+               local headers, errmsg, errno = req:go(5)  -- TODO: randomly chosen timeout
+               if errno then
+                       nok(errmsg, desc .. ': ' .. errmsg)
+                       return
+               end
                local got_status = headers:get(':status')
                same(got_status, exp_status, desc)
-               print(got_status)  -- TODO
        end
 
        -- test whether http interface responds and binds
@@ -85,6 +89,13 @@ else
                check_err(req, '413', 'too long POST finishes with 413')
        end
 
+       local function test_get_long_input()
+               local req = assert(req_templ:clone())
+               req.headers:upsert(':method', 'GET')
+               req.headers:upsert(':path', '/doh?dns=' .. basexx.to_url64(string.rep('s', 65536)))
+               check_err(req, '414', 'too long GET finishes with 414')
+       end
+
        local function test_post_unparseable_input()
                local req = assert(req_templ:clone())
                req.headers:upsert(':method', 'POST')
@@ -115,6 +126,7 @@ else
                -- test_doh_post,
                test_post_short_input,
                test_post_long_input,
+               test_get_long_input,
                test_post_unparseable_input,
                test_post_unsupp_type
        }