Project

General

Profile

Actions

Feature #3835

closed

Resolv::DNS: Retry via TCP on truncated UDP response

Added by julian.mehnle (Julian Mehnle) over 13 years ago. Updated almost 13 years ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:32407]

Description

=begin
Resolv::DNS has code implementing DNS queries via TCP, but it is not currently used at all. Furthermore, any truncated responses received via UDP are parsed and intact RRs are used, silently discarding any truncated RRs. E.g.:

 $ dig amazon.com TXT
 ;; Truncated, retrying in TCP mode.

 ; <<>> DiG 9.6.1-P3 <<>> amazon.com TXT
 ;; global options: +cmd
 ;; Got answer:
 ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1197
 ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

 ;; QUESTION SECTION:
 ;amazon.com.                    IN      TXT

 ;; ANSWER SECTION:
 amazon.com.             3592    IN      TXT     "spf2.0/pra ip4:207.171.160.0/19 ip4:87.238.80.0/21 ip4:72.21.193.0/24
                                                 ip4:72.21.196.0/22 ip4:72.21.208.0/24 ip4:72.21.205.0/24
                                                 ip4:72.21.209.0/24 ip4:194.154.193.200/28 ip4:194.7.41.152/28
                                                 ip4:212.123.28.40/32 ip4:203.81.17.0/24 ~all"
 amazon.com.             3592    IN      TXT     "v=spf1 ip4:207.171.160.0/19 ip4:87.238.80.0/21 ip4:72.21.193.0/24
                                                 ip4:72.21.196.0/22 ip4:72.21.208.0/24 ip4:72.21.205.0/24
                                                 ip4:72.21.209.0/24 ip4:194.154.193.200/28 ip4:194.7.41.152/28
                                                 ip4:212.123.28.40/32 ip4:203.81.17.0/24 ~all"

 ;; Query time: 0 msec
 ;; SERVER: 127.0.0.1#53(127.0.0.1)
 ;; WHEN: Wed Sep 15 20:21:49 2010
 ;; MSG SIZE  rcvd: 516

With an unpatched 1.9.2 Resolv::DNS:

 >> pp Resolv::DNS.new.getresources('amazon.com', Resolv::DNS::Resource::IN::TXT); nil
 [#<Resolv::DNS::Resource::IN::TXT:0x0000000143b0b0
   @strings=
    ["spf2.0/pra ip4:207.171.160.0/19 ip4:87.238.80.0/21 ip4:72.21.193.0/24 ip4:72.21.196.0/22
     ip4:72.21.208.0/24 ip4:72.21.205.0/24 ip4:72.21.209.0/24 ip4:194.154.193.200/28 ip4:194.7.41.152/28
     ip4:212.123.28.40/32 ip4:203.81.17.0/24 ~all"],
   @ttl=2185>]
 => nil

The attached patch changes Resolv::DNS#each_resource to check UDP responses for truncation and retries via TCP, which is the proper behavior per RFC 1123, section 6.1.3.2 http://tools.ietf.org/html/rfc1123#page-75 and implemented by most resolver libraries.

Effect:

 >> pp Resolv::DNS.new.getresources('amazon.com', Resolv::DNS::Resource::IN::TXT); nil
 [#<Resolv::DNS::Resource::IN::TXT:0x0000000214adf0
   @strings=
    ["spf2.0/pra ip4:207.171.160.0/19 ip4:87.238.80.0/21 ip4:72.21.193.0/24 ip4:72.21.196.0/22
     ip4:72.21.208.0/24 ip4:72.21.205.0/24 ip4:72.21.209.0/24 ip4:194.154.193.200/28 ip4:194.7.41.152/28
     ip4:212.123.28.40/32 ip4:203.81.17.0/24 ~all"],
   @ttl=2237>,
  #<Resolv::DNS::Resource::IN::TXT:0x0000000214a580
   @strings=
    ["v=spf1 ip4:207.171.160.0/19 ip4:87.238.80.0/21 ip4:72.21.193.0/24 ip4:72.21.196.0/22
     ip4:72.21.208.0/24 ip4:72.21.205.0/24 ip4:72.21.209.0/24 ip4:194.154.193.200/28 ip4:194.7.41.152/28
     ip4:212.123.28.40/32 ip4:203.81.17.0/24 ~all"],
   @ttl=2237>]
 => nil

I'm also attaching a patch for 1.8.7 in the hope that it will be merged into 1.8.7, too.

Of course it would be nice to also support EDNS0, but that's beyond what I can deliver right now.
=end


Files

resolv-1.9.2-tcp-fallback.diff (1.84 KB) resolv-1.9.2-tcp-fallback.diff TCP fallback for Ruby 1.9.2's Resolv::DNS julian.mehnle (Julian Mehnle), 09/16/2010 05:48 AM
resolv-1.8.7-tcp-fallback.diff (1.83 KB) resolv-1.8.7-tcp-fallback.diff TCP fallback for Ruby 1.8.7's Resolv::DNS julian.mehnle (Julian Mehnle), 09/16/2010 05:48 AM
resolv-1.9.2-tcp-fallback2.diff (1.87 KB) resolv-1.9.2-tcp-fallback2.diff TCP fallback for Ruby 1.9.2's Resolv::DNS (revision 2) julian.mehnle (Julian Mehnle), 09/19/2010 05:51 AM
resolv-1.8.7-tcp-fallback2.diff (1.87 KB) resolv-1.8.7-tcp-fallback2.diff TCP fallback for Ruby 1.8.7's Resolv::DNS (revision 2) julian.mehnle (Julian Mehnle), 09/19/2010 05:51 AM

Updated by julian.mehnle (Julian Mehnle) over 13 years ago

=begin
I've discovered a bug in my patch: Resolv::DNS::Message#tc returns a numerical value (0 or 1), not a boolean. Also, let's play it safe and #close the UDP requester before replacing it with the TCP requester.

I've successfully tested these revised patches in a heavy-load production environment that does hundreds of thousands of DNS lookups every day.
=end

Actions #2

Updated by akr (Akira Tanaka) over 13 years ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100

=begin
This issue was solved with changeset r29631.
Julian, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.

=end

Actions #3

Updated by julian.mehnle (Julian Mehnle) over 13 years ago

=begin
Oh, thanks for reminding me! I recently discovered another issue with my patch. It fails if the system has more than one resolver configured in /etc/resolv.conf:

$ cat /etc/resolv.conf

192.168.0.123 does not exist, 127.0.0.1 does:

nameserver 192.168.0.123
nameserver 127.0.0.1
search mehnle.net

$ irb

require 'resolv'
=> true
require 'patch/resolv'
=> true
dns = Resolv::DNS.new
=> #<Resolv::DNS:0x7fa2e9fe01a8 @config=#<Resolv::DNS::Config:0x7fa2e9fe0130 @initialized=nil, @config_info=nil, @mutex=#Mutex:0x7fa2e9fe00b8>, @initialized=nil, @mutex=#Mutex:0x7fa2e9fe0158>
dns.getresources('amazon.com', Resolv::DNS::Resource::IN::TXT)
Errno::EHOSTUNREACH: No route to host - connect(2)
from /usr/lib/ruby/1.8/resolv.rb:762:in initialize' from /usr/lib/ruby/1.8/resolv.rb:762:in new'
from /usr/lib/ruby/1.8/resolv.rb:762:in initialize' from patch/resolv.rb:61:in new'
from patch/resolv.rb:61:in make_tcp_requester' from patch/resolv.rb:29:in each_resource'
from patch/resolv.rb:131:in resolv' from patch/resolv.rb:129:in each'
from patch/resolv.rb:129:in resolv' from patch/resolv.rb:128:in each'
from patch/resolv.rb:128:in resolv' from patch/resolv.rb:126:in each'
from patch/resolv.rb:126:in resolv' from patch/resolv.rb:15:in each_resource'
from /usr/lib/ruby/1.8/resolv.rb:468:in `getresources'
from (irb):2

We worked around this by reducing our resolv.conf files to a single nameserver, but obviously this is not a generally acceptable solution.

I'll try to come up with a fix today.

=end

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0