Forum: Ruby DNS MX lookup issue: local machine returned as MX for an non-existant domain!

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Yves-Eric (Guest)
on 2009-02-23 04:30
(Received via mailing list)
Hi all,


Trying to do some email domain validation, I am facing a weird issue
when looking up an MX entry. Here is a three-liner test code:

require 'resolv'
domain = "i-dont-exist-iutjdfuyoxfugy.com"
Resolv::DNS.open { |dns| dns.getresources(domain,
Resolv::DNS::Resource::IN::MX)}

On my development machine, this returns an empty list, as expected
(the domain does not exist, it cannot have an MX record!).
However, in my production environment, the same code returns:
=> [#<Resolv::DNS::Resource::IN::MX:0xb7cde342
@exchange=#<Resolv::DNS::Name: mydomain.com.>, @preference=10>]

It returns the production machine itself as a valid MX for a domain
that does not exist!

I double-checked on the command line that "nslookup -q=mx i-dont-exist-
iutjdfuyoxfugy.com" indeed returns NXDOMAIN...

Could someone please explain to me why this may be happening, and how
to fix it? Howcome Resolv::DNS is returning an MX record for a domain
that does not exist?! As a temporary workaround, I am simply filtering
out mydomain.com from the MX list, but it really bugs me not knowing
what the root of the problem is.


Thank you,
Iñaki Baz C. (Guest)
on 2009-02-23 13:03
(Received via mailing list)
2009/2/23 Yves-Eric <removed_email_address@domain.invalid>:
>
> what the root of the problem is.
So you confirm that  "nslookup -q=mx i-dont-exist-iutjdfuyoxfugy.com"
also returns your local hostname?
If so, then it's not a bug in Ruby Resolv::DNS but in your DNS client
configuration in your server.
Brian C. (Guest)
on 2009-02-23 14:54
Yves-Eric wrote:
> require 'resolv'
> domain = "i-dont-exist-iutjdfuyoxfugy.com"
> Resolv::DNS.open { |dns| dns.getresources(domain,
> Resolv::DNS::Resource::IN::MX)}
>
> On my development machine, this returns an empty list, as expected
> (the domain does not exist, it cannot have an MX record!).
> However, in my production environment, the same code returns:
> => [#<Resolv::DNS::Resource::IN::MX:0xb7cde342
> @exchange=#<Resolv::DNS::Name: mydomain.com.>, @preference=10>]
>
> It returns the production machine itself as a valid MX for a domain
> that does not exist!
>
> I double-checked on the command line that "nslookup -q=mx i-dont-exist-
> iutjdfuyoxfugy.com" indeed returns NXDOMAIN...

Also try "dig i-dont-exist-iutjdfuyoxfugy.com mx" - dig is a bit
lower-level than nslookup.

If you still see the difference between Ruby and dig, then I suggest you
run tcpdump (on both your loopback interface and your external
interface) for udp port 53.

I suspect this will show something different in the queries, e.g. they
are being sent to different nameservers. Perhaps there is a wildcard MX
record floating around.

Regards,

Brian.
Yves-Eric (Guest)
on 2009-03-01 05:35
(Received via mailing list)
On Feb 23, 8:01 pm, Iñaki Baz C. <removed_email_address@domain.invalid> wrote:
> So you confirm that  "nslookup -q=mx i-dont-exist-iutjdfuyoxfugy.com"
> also returns your local hostname?
> If so, then it's not a bug in Ruby Resolv::DNSbut in yourDNSclient
> configuration in your server.

No, you misread my message:, "nslookup -q=mx i-dont-exist-
iutjdfuyoxfugy.com" returns **NXDOMAIN**, which means "Non-Existent
Domain". This is as expected since the given domain does not exist.
So, the DNS configuration on the server seems to be fine, and the
problem seems to be with Resolv::DNS. Note the use of "seems"... Still
no clue what the cause of the problem could be (^_^;)
Yves-Eric (Guest)
on 2009-03-01 06:25
(Received via mailing list)
On Feb 23, 9:53 pm, Brian C. <removed_email_address@domain.invalid> wrote:
> Also try "dig i-dont-exist-iutjdfuyoxfugy.com mx" - dig is a bit
> lower-level than nslookup.
>
> If you still see the difference between Ruby and dig, then I suggest you
> run tcpdump (on both your loopback interface and your external
> interface) for udp port 53.
>
> I suspect this will show something different in the queries, e.g. they
> are being sent to different nameservers. Perhaps there is a wildcard MX
> record floating around.

I tried with dig, but I still see the difference: dig gives me a Non-
Existent
Domain (NXDOMAIN) status, while Resolv::DNS still wrongly returns my
server as valid MX.

But I have gather some interesting data, thanks to your suggestion of
using tcpdump. Indeed, I can see a difference in activity (see dump
pasted below), but I am not quite sure what to make of it... It looks
like
Resolv::DNS does proceed properly at first, sending an MX query and
getting an NXDOMAIN response. But apparently, it is not satisfied by
that NXDOMAIN reply, and from there, Resolv::DNS continues with 3
other queries: PTR, [|domain], and another PTR.

Have we stumbled upon a bug in Resolv::DNS? I can feel we are getting
a little closer to the answer, but I am still quite puzzled by this
strange
behaviour...

Please find below the tcpdump of both the dig and Resolv::DNS
queries. Any help with interpreting these results and getting to
the root of the issue will be greatly appreciated.


--- BEGIN TCPDUMP LOG ---
[root@www ~]# tcpdump -ni any port 53
tcpdump: WARNING: Promiscuous mode not supported on the "any" device
tcpdump: verbose output suppressed, use -v or -vv for full protocol
decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 96
bytes

# dump of dig activity:
12:52:13.186912 IP 119.18.243.83.39721 > 202.45.161.161.domain:
53442+ MX? i-dont-exist-iutjdfuyoxfugy.com. (49)
12:52:13.186916 IP 119.18.243.83.39721 > 202.45.161.161.domain:
53442+ MX? i-dont-exist-iutjdfuyoxfugy.com. (49)
12:52:13.187338 IP 202.45.161.161.domain > 119.18.243.83.39721:  53442
NXDomain 0/1/0 (122)

# dump of Resolv::DNS activity:
12:51:57.398419 IP 119.18.243.83.39720 > 202.45.161.161.domain:  0+
MX? i-dont-exist-iutjdfuyoxfugy.com. (49)
12:51:57.398512 IP 119.18.243.83.39720 > 202.45.161.161.domain:  0+
MX? i-dont-exist-iutjdfuyoxfugy.com. (49)
12:51:57.399497 IP 202.45.161.161.domain > 119.18.243.83.39720:  0
NXDomain 0/1/0 (122)
12:51:57.399615 IP 119.18.243.83.39721 > 202.45.161.161.domain:
31798+ PTR? 161.161.45.202.in-addr.arpa. (45)
12:51:57.399616 IP 119.18.243.83.39721 > 202.45.161.161.domain:
31798+ PTR? 161.161.45.202.in-addr.arpa. (45)
12:51:57.400471 IP 202.45.161.161.domain > 119.18.243.83.39721:  31798
1/5/5 (253)
12:51:57.401140 IP 119.18.243.83.39720 > 202.45.161.161.domain:  1+[|
domain]
12:51:57.401142 IP 119.18.243.83.39720 > 202.45.161.161.domain:  1+[|
domain]
12:51:57.401648 IP 202.45.161.161.domain > 119.18.243.83.39720:  1[|
domain]
12:51:57.401742 IP 119.18.243.83.39721 > 202.45.161.161.domain:
32336+ PTR? 161.161.45.202.in-addr.arpa. (45)
12:51:57.401745 IP 119.18.243.83.39721 > 202.45.161.161.domain:
32336+ PTR? 161.161.45.202.in-addr.arpa. (45)
12:51:57.402261 IP 202.45.161.161.domain > 119.18.243.83.39721:  32336
1/5/5 (253)

15 packets captured
19 packets received by filter
0 packets dropped by kernel
[root@www ~]#
--- END TCPDUMP LOG ---


Best regards,
Brian C. (Guest)
on 2009-03-01 17:25
Yves-Eric wrote:
> But I have gather some interesting data, thanks to your suggestion of
> using tcpdump. Indeed, I can see a difference in activity (see dump
> pasted below), but I am not quite sure what to make of it... It looks
> like
> Resolv::DNS does proceed properly at first, sending an MX query and
> getting an NXDOMAIN response. But apparently, it is not satisfied by
> that NXDOMAIN reply, and from there, Resolv::DNS continues with 3
> other queries: PTR, [|domain], and another PTR.
>
> Have we stumbled upon a bug in Resolv::DNS?

Possibly - you have the source, so you can trace it / debug it, at
simplest just by adding STDERR.puts at interesting places.

It looks like the PTR records are just the library (or Ruby) doing
reverse DNS lookups on IP addresses of the DNS servers themselves.

There is a knob you can set which might minimise this noise, if it's
Ruby doing it:

Socket.do_not_reverse_lookup = true
Yves-Eric (Guest)
on 2009-03-02 06:10
(Received via mailing list)
Problem solved. Executive summary: it is a documentation bug. DNS
name queries need a final dot.

Do not query resources for "domain.com" as the Resolv documentation
[1] suggests. One should instead query for "domain.com.", with an
extra dot at the end. The first form, without the final dot, will
also be looked up in the local domain (for example, you could look
for just "www", and you would get the result for
"www.localdomain.com"). The problem is when you have a wildcard DNS
entry in the local domain: then any non-existent domain would match
that entry.

Because the current documentation uses "www.ruby-lang.org" as an
example, a lookup could occur for something like
"www.ruby-lang.org.localdomain.com", which is **not** what users
unfamiliar with DNS would expect. More importantly, even people
familiar with DNS could be mislead by the documentation and forget
the final dot. So, to follow the principle of least surprise, the
documentation should be updated to include the final dot in example
DNS name strings.

Where should I fill a bug report?


PS: thanks again for your suggestions Brian. While it sounded quite
daunting at first, I took the plunge into Ruby source code, and it
was really not that bad. With a few strategically placed STDERR.puts,
I could quickly get to the root of the problem. For the record, I
also learned that "[|proto]" means that the packet was truncated at
the "proto" protocol level, in our case "domain", and we needed to
capture more data. So here is a new cleaned-up dump (thanks also for
the Socket.do_not_reverse_lookup for noise reduction, it was indeed
Ruby doing the PTR queries), where the second query shows the problem
clearly:


# dump of Resolv::DNS activity:
host > dns:  0+ MX? i-dont-exist.com. (49)
dns > host:  0 NXDomain 0/1/0 (122)
host > dns:  1+ MX? i-dont-exist.com.mydomain.com. (61)
dns > host:  1 2/13/11 CNAME mydomain.com., MX mydomain.com. 10 (491)


[1] http://www.ruby-doc.org/core-1.9/classes/Resolv.html

Best regards,
Brian C. (Guest)
on 2009-03-02 10:55
Yves-Eric wrote:
> Problem solved. Executive summary: it is a documentation bug. DNS
> name queries need a final dot.

I disagree. DNS queries in normal use should *not* need a trailing dot,
and indeed in E-mail addresses the final dot is forbidden.

If your system is appending a default domain, then it should be doing so
according to an explicit configuration. In the case of nslookup / dig
(libbind), this configuration is in /etc/resolv.conf

If Resolv::DNS is making up its own default domains from some other
source, e.g. by hacking up your system hostname and guessing the domain
from that, that's a bug in my opinion.

A quick source scan suggests this is exactly what's happening, and the
offending code is here:

              hostname = Socket.gethostname
              if /\./ =~ hostname
                @search = [Label.split($')]
              else
                @search = [[]]
              end

However looking at the source also suggests you can fix this problem by
setting :search=>[] as an argument to Resolv::DNS.new

> Where should I fill a bug report?

redmine.ruby-lang.org

I'd argue it's a case of dangerous defaults - but it may be rejected on
the grounds that users (who know what they are doing) can override the
default.

> For the record, I
> also learned that "[|proto]" means that the packet was truncated at
> the "proto" protocol level

Oh yes, sorry I forgot that. My prototypical use:

  tcpdump -ieth0 -s0 -nX ...

Regards,

Brian.
This topic is locked and can not be replied to.