diff --git a/ChangeLog b/ChangeLog index e53fc4746f..825483d0fe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Sun Jan 3 01:29:18 2010 Tanaka Akira + + * lib/resolv.rb (Resolv::DNS::Message::MessageDecoder#inspect): + implemented. + Sat Jan 2 15:57:54 2010 Tanaka Akira * lib/resolv.rb (Resolv::DNS#initialize): new option :nameserver_port. diff --git a/lib/resolv.rb b/lib/resolv.rb index 560f1dfe95..4ac24f3b36 100644 --- a/lib/resolv.rb +++ b/lib/resolv.rb @@ -1385,6 +1385,10 @@ class Resolv yield self end + def inspect + "\#<#{self.class}: #{@data[0, @index].inspect} #{@data[@index..-1].inspect}>" + end + def get_length16 len, = self.get_unpack('n') save_limit = @limit @@ -2097,8 +2101,11 @@ class Resolv end def initialize(address) # :nodoc: - unless address.kind_of?(String) && address.length == 4 - raise ArgumentError.new('IPv4 address must be 4 bytes') + unless address.kind_of?(String) + raise ArgumentError, 'IPv4 address must be a string' + end + unless address.length == 4 + raise ArgumentError, "IPv4 address expects 4 bytes but #{address.length} bytes" end @address = address end diff --git a/test/resolv/test_dns.rb b/test/resolv/test_dns.rb new file mode 100644 index 0000000000..0ab59665a3 --- /dev/null +++ b/test/resolv/test_dns.rb @@ -0,0 +1,107 @@ +require 'test/unit' +require 'resolv' +require 'socket' + +class TestResolvDNS < Test::Unit::TestCase + def setup + @save_do_not_reverse_lookup = BasicSocket.do_not_reverse_lookup + BasicSocket.do_not_reverse_lookup = true + end + + def teardown + BasicSocket.do_not_reverse_lookup = @save_do_not_reverse_lookup + end + + def with_udp(host, port) + u = UDPSocket.new + begin + u.bind(host, port) + yield u + ensure + u.close + end + end + + def test_query_ipv4_address + with_udp('127.0.0.1', 0) {|u| + _, server_port, _, server_address = u.addr + begin + th = Thread.new { + Resolv::DNS.open(:nameserver_port => [[server_address, server_port]]) {|dns| + dns.getresources("foo.example.org", Resolv::DNS::Resource::IN::A) + } + } + msg, (af, client_port, _, client_address) = u.recvfrom(4096) + id, word2, qdcount, ancount, nscount, arcount = msg.unpack("nnnnnn") + qr = (word2 & 0x8000) >> 15 + opcode = (word2 & 0x7800) >> 11 + aa = (word2 & 0x0400) >> 10 + tc = (word2 & 0x0200) >> 9 + rd = (word2 & 0x0100) >> 8 + ra = (word2 & 0x0080) >> 7 + z = (word2 & 0x0070) >> 4 + rcode = word2 & 0x000f + rest = msg[12..-1] + assert_equal(0, qr) # 0:query 1:response + assert_equal(0, opcode) # 0:QUERY 1:IQUERY 2:STATUS + assert_equal(0, aa) # Authoritative Answer + assert_equal(0, tc) # TrunCation + assert_equal(1, rd) # Recursion Desired + assert_equal(0, ra) # Recursion Available + assert_equal(0, z) # Reserved for future use + assert_equal(0, rcode) # 0:No-error 1:Format-error 2:Server-failure 3:Name-Error 4:Not-Implemented 5:Refused + assert_equal(1, qdcount) # number of entries in the question section. + assert_equal(0, ancount) # number of entries in the answer section. + assert_equal(0, nscount) # number of entries in the authority records section. + assert_equal(0, arcount) # number of entries in the additional records section. + name = [3, "foo", 7, "example", 3, "org", 0].pack("Ca*Ca*Ca*C") + assert_operator(rest, :start_with?, name) + rest = rest[name.length..-1] + assert_equal(4, rest.length) + qtype, qclass = rest.unpack("nn") + assert_equal(1, qtype) # A + assert_equal(1, qtype) # IN + id = id + qr = 1 + opcode = opcode + aa = 0 + tc = 0 + rd = rd + ra = 1 + z = 0 + rcode = 0 + qdcount = 0 + ancount = 1 + nscount = 0 + arcount = 0 + word2 = (qr << 15) | + (opcode << 11) | + (aa << 10) | + (tc << 9) | + (rd << 8) | + (ra << 7) | + (z << 4) | + rcode + msg = [id, word2, qdcount, ancount, nscount, arcount].pack("nnnnnn") + type = 1 + klass = 1 + ttl = 3600 + rdlength = 4 + rdata = [192,0,2,1].pack("CCCC") # 192.0.2.1 (TEST-NET address) RFC 3330 + rr = [name, type, klass, ttl, rdlength, rdata].pack("a*nnNna*") + msg << rr + u.send(msg, 0, client_address, client_port) + result = th.value + assert_instance_of(Array, result) + assert_equal(1, result.length) + rr = result[0] + assert_instance_of(Resolv::DNS::Resource::IN::A, rr) + assert_instance_of(Resolv::IPv4, rr.address) + assert_equal("192.0.2.1", rr.address.to_s) + assert_equal(3600, rr.ttl) + ensure + th.join + end + } + end +end