Subject: Re: [DNSOP] draft-song-dns-wireformat-http

From: Shane Kerr <[email-masked]>
Date: Fri, 29 Apr 2016 15:57:14 +0200

Julian,

Thanks for the feedback! Comments below...

On 2016-04-28 20:12:52+0200 (Thursday)
Julian Reschke <[email-masked]> wrote:

> below some feedback...
>
> >    One of alternative way of DNS described in that document is to  
> 
> s/of//  

Thanks, rephrased slightly.

> >    transport DNS binary data inside HTTP, with the goal of improving DNS
> >    service availability.  The DNS traffic is simply sent as web traffic
> >    using port 80/443 over HTTP.  It can bypass badly behaving middle
> >    boxes like firewalls, proxies or traffic shaping devices on path
> >    which might interfere with normal DNS traffic [RFC5625] [DOTSE]
> >    [SAC035].  
>   
> > 3.  DNS-over-HTTP Message Format
> >
> >    Although this document simply proposes that HTTP be used for DNS
> >    massage exchange, it is informative to explore the context with HTTP-  
> 
> s/massage/message/ :-)  

Oops! Fixed.

> >    specific semantics, such as the HTTP request method, specific
> >    request-target, HTTP-version, and HTTP header field, all of which
> >    have impact on interoperability as well as performance.
> >
> >    In HTTP 1.1 specification section 3 in RFC 7230 [RFC7230], an HTTP
> >    message consists of three parts: start-line, header fields, and
> >    message body with an empty line between header fields and message
> >    body.  The DNS over HTTP message also contains these parts.  
> 
> Otherwise, it wouldn't be HTTP/1.1, right. FWIW, if you make this 
> requirement here, you wouldn't be able to use HTTP/2.  

Of all your observations, this one is the trickiest. :(

Right now the protocol is clearly based on HTTP/1.1, although we have
an implementation that works fine with HTTP/2 since the Go HTTP library
supports it (basically) transparently.

Let me talk with my co-authors and see what they think!

> > 3.1.  Start-line
> >
> >    By definition the HTTP start-line is either a request-line (for
> >    requests) or a status-line (for responses).  A request-line consists
> >    of the request method, request-target, and HTTP-version with a CRLF
> >    in the end.
> >
> >    For a DNS query over HTTP, the request is always POST [section 4.3.3
> >    in RFC 7230 [RFC7230]].  If a GET is sent to the server, it  
> 
> s/7230/7231/  

Good catch, thanks!
 
> >    optionally returns a human-readable page showing its web server
> >    environment.
> >
> >    - Note that choosing POST (not GET) as the request method for DNS
> >    wire-format over HTTP is mainly based on two reasons.  One is that
> >    the protocol is designed using HTTP as a tunnel-like technology
> >    carrying data from one side to another, not a web service with
> >    RESTful framework.  Another is that from the view of implementation
> >    some servers may ignore undefined entity-body if using GET; and HTTP
> >    libs vary on supporting GET with payload.  
> 
> GET with payload would indeed be a bad idea. However you could use the 
> request URI for the payload; was this discussed?  

So you mean encoding the entire DNS query packet as a long URL?

That was *not* discussed, and is actually quite a clever idea. :-D

A typical DNS query is less than 100 bytes, which means even
hex-encoded would be only a 200-byte URI. That would have the nice
effect of giving a URL that can be cut & paste for debugging and so on.
(We could also use base64 or base32, but I find that hex-encoding is
relatively easy to work with for humans should that ever be necessary.)

Anyway, it *is* more bytes, but I'm not sure it would result in more
packets which is probably more important. (This depends on HTTP
pipelining and the like.)

Let me discuss it with my co-authors and/or the dnsop working group and
we'll see what we think.

> >    Usually the target URI is provides explicitly by the services  
> 
> s/provides/provided/  

Thanks, fixed.
 
> >    provider.  Derived from the target URI, the request-target in
> >    request-line identifies the target resource upon which to apply the
> >    request.  To avoid URI conflicts and enhance interoperability, a
> >    well-known URI is necessary to allow interoperability.  As defined in  
> 
> (language)  

Reworked the language a bit.
 
> >    RFC 5785 [RFC5785], it begins with the characters "/.well-known/" and
> >    the name "dns-wireformat".  So the request-target for DNS wire-format
> >    over HTTP SHOULD be '/.well-known/dns-wireformat'.  
> 
> No reason for a "SHOULD" here. Just define the well-known URI.  

I'm not sure how this works. Clearly developers and operators don't
need to use the well-known port, but we think that they should unless
they have a good reason not to. Is this not the use case for the
"SHOULD" key word?

> >    DNS transaction over HTTP has no specific requirement for transport
> >    protocol; developers can use any version of HTTP to accomplish the
> >    transaction.  But developers should be aware that HTTP/1.1 RFC 7230
> >    [RFC7230] and HTTP/2 RFC 7540 [RFC7540] do have differences in  
> 
> s/RFC 7230//  

Right, removed.
 
> >    performance regarding multiplexing.  HTTP/2 is fully multiplexed,
> >    instead of ordered and blocking.  Because there is a general desire
> >    to achieve similar performance with DNS over UDP, the modern HTTP/2
> >    is preferred for DNS over HTTP implementation.  Note that there
> >    should be no problem for advanced HTTP protocol in the future
> >    deployed for DNS over HTTP.
> >
> >    As an example, given HTTP-version is "HTTP/1.1", the request-line is
> >    :j
> >
> >    POST /.well-known/dns-wireformat HTTP/1.1
> >
> >    The status-line returns the status-code [Section 6 of RFC 7231
> >    [RFC7231]], which only reflects status of HTTP connection.  If the  
> 
> s/RFC 7231//  

Right.

> >    request has succeeded, the status-line is:
> >
> >    HTTP/1.1 200 OK
> >
> >    If the request fails, the proxy server will supply an appropriate
> >    error code, typically 4xx (client error) if the client has provided a
> >    query that the server cannot understand for some reasons, or 5xx
> >    (server error) if some server-side problem prevented a query from
> >    succeeding.
> >
> > 3.2.  Header Fields
> >
> >    By definition header fields are key:value pairs that can be used to
> >    communicate data about the message, its payload, the target resource,
> >    or the connection (for example control data).
> >
> >    The Content-Type: header should be set to "application/dns-
> >    wireformat".  
> 
> s/header/header field/  

Right.

> >    We add one a new header field:
> >
> >    Proxy-DNS-Transport: xyz
> >
> >    Where xyz is either UDP or TCP, which is the client's indication of
> >    how it received the underlying DNS query, and which the server will
> >    use when sending the query to the far-end DNS server.  This means if
> >    a stub DNS client asks for TCP, then that's what the far-end DNS
> >    server will see, and likewise for UDP.  This header field is used for
> >    both request and response, for all DNS over HTTP message.
> >
> >    Exposing the transport protocol of the query allows the HTTP server
> >    proxy to send DNS queries to the recursive resolver that look like
> >    those that the DNS client is sending to the client proxy.  If the
> >    stub resolver sent a UDP packet, then this allows the recursive
> >    resolver to implement the logic of truncating the packet properly,
> >    instead of requiring that the HTTP client proxy somehow manage that
> >    functionality.
> >
> >    For a stub resolver that connect directly via HTTP to the HTTP server
> >    proxy then this flag should be set to TCP, as the entire response can
> >    always be delivered so truncation is never required.
> >
> >    The client MUST include this option.  If it is missing then it is an
> >    error and the server should respond with HTTP code 400 (bad request).  
> 
> I'm not sure why it's needed, but if it's needed it would be simpler to 
> just define two well-known URIs.  

It's needed because acting in proxy mode the client needs to be able to
have the proxy transparently carry through the DNS protocol. If we
didn't have this then the proxy would need non-trivial logic to handle
DNS truncation.

But your idea is interesting of using two well-known URIs is
interesting. It also dovetails quite nicely with the idea of using a
URI to encode the query data - by using both of these techniques then
we end up with nice REST-style URI. :)
 
> Note that defining new header fields does not come free (see RFC 7231).  

Hm... people keep telling me that obtaining such identifiers is easy in
the IETF. :-/

> > 3.3.  Message Body
> >
> >    As mentioned, the message body is DNS wire-format data.  It is worth
> >    mentioning that DNS messages sent over TCP connections is prefixed
> >    with a two-byte length field which gives the message length[section  
> 
> s/length/length /  

Thanks, fixed.
 
> >    4.2.2 in RFC 1035 [RFC1035]], excluding the two-byte length field.
> >    This length field allows the low-level processing to assemble a
> >    complete message before beginning to parse it.  In the context of
> >    HTTP, there is content-length header field [section 3.3.2 in RFC 7230  
> 
> s/RFC 7230 //  

Okay.
 
> (where does this funny reference format come from?)  

xml2rfc? (Proving once again that anything with "xml" in it is the
devil's work.)

> >    [RFC7230]]in which the field-value is the same with two bytes length
> >    field in DNS over TCP.
> >
> >    Since this two-byte length field is redundant, when the client proxy
> >    receives a DNS message over TCP, it MUST NOT include the length field
> >    in the message sent to the server.  The length in the content-length
> >    header is only the size of the DNS message itself, and MUST NOT
> >    include this two-byte length header.
>  > ...  

Thank you SO MUCH for your detailed input and interesting suggestions.

Please do let me know if you are willing to have this discussed on the
dnsop mailing list.

Cheers,

--
Shane

---

From: Bob Harold <[email-masked]>
Date: Fri, 29 Apr 2016 12:20:19 -0400

> Let me discuss it with my co-authors and/or the dnsop working group and

I had to search to be sure that the GET URL is encrypted, and found that
there might be additional concerns if the user is using this with https for
privacy.
The web page at
https://blog.httpwatch.com/2009/02/20/how-secure-are-query-strings-over-https/
listed three concerns:
1. The URL would get logged in the web server logs.  Including the DNS
query.
2. If using a browser, the URL is saved in the browser history
3. If used in a web page, URLs are passed in Referrer headers
I don't think #2 and #3 apply to DNS over HTTPS, but #1 might be a
concern.  However, the server is already getting the DNS query and might be
logging queries at the DNS level, so maybe this is just an issue to mention
to the server admin.

-- 
Bob Harold