net-dns2 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.travis.yml +20 -0
- data/CHANGELOG.md +105 -0
- data/Gemfile +4 -0
- data/README.md +155 -0
- data/Rakefile +94 -0
- data/THANKS.rdoc +24 -0
- data/demo/check_soa.rb +115 -0
- data/demo/threads.rb +22 -0
- data/lib/net/dns.rb +112 -0
- data/lib/net/dns/core_ext.rb +52 -0
- data/lib/net/dns/header.rb +713 -0
- data/lib/net/dns/names.rb +118 -0
- data/lib/net/dns/packet.rb +563 -0
- data/lib/net/dns/question.rb +188 -0
- data/lib/net/dns/resolver.rb +1313 -0
- data/lib/net/dns/resolver/socks.rb +154 -0
- data/lib/net/dns/resolver/timeouts.rb +75 -0
- data/lib/net/dns/rr.rb +366 -0
- data/lib/net/dns/rr/a.rb +124 -0
- data/lib/net/dns/rr/aaaa.rb +103 -0
- data/lib/net/dns/rr/classes.rb +133 -0
- data/lib/net/dns/rr/cname.rb +82 -0
- data/lib/net/dns/rr/hinfo.rb +108 -0
- data/lib/net/dns/rr/mr.rb +79 -0
- data/lib/net/dns/rr/mx.rb +92 -0
- data/lib/net/dns/rr/ns.rb +78 -0
- data/lib/net/dns/rr/null.rb +53 -0
- data/lib/net/dns/rr/ptr.rb +83 -0
- data/lib/net/dns/rr/soa.rb +78 -0
- data/lib/net/dns/rr/srv.rb +45 -0
- data/lib/net/dns/rr/txt.rb +61 -0
- data/lib/net/dns/rr/types.rb +193 -0
- data/lib/net/dns/version.rb +16 -0
- data/net-dns.gemspec +37 -0
- data/test/header_test.rb +167 -0
- data/test/names_test.rb +21 -0
- data/test/packet_test.rb +49 -0
- data/test/question_test.rb +83 -0
- data/test/resolver_test.rb +117 -0
- data/test/rr/a_test.rb +113 -0
- data/test/rr/aaaa_test.rb +109 -0
- data/test/rr/classes_test.rb +85 -0
- data/test/rr/cname_test.rb +97 -0
- data/test/rr/hinfo_test.rb +117 -0
- data/test/rr/mr_test.rb +105 -0
- data/test/rr/mx_test.rb +112 -0
- data/test/rr/ns_test.rb +86 -0
- data/test/rr/types_test.rb +69 -0
- data/test/rr_test.rb +131 -0
- data/test/test_helper.rb +4 -0
- metadata +158 -0
data/lib/net/dns/rr/a.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
module Net
|
2
|
+
module DNS
|
3
|
+
class RR
|
4
|
+
|
5
|
+
#
|
6
|
+
# = IPv4 Address Record (A)
|
7
|
+
#
|
8
|
+
# Class for DNS IPv4 Address (A) resource records.
|
9
|
+
#
|
10
|
+
# The resource data is an IPv4 (i.e. 32 bit long) address,
|
11
|
+
# hold in the instance variable +address+.
|
12
|
+
#
|
13
|
+
# a = Net::DNS::RR::A.new("localhost.movie.edu. 360 IN A 127.0.0.1")
|
14
|
+
#
|
15
|
+
# a = Net::DNS::RR::A.new(:name => "localhost.movie.edu.",
|
16
|
+
# :ttl => 360,
|
17
|
+
# :cls => Net::DNS::IN,
|
18
|
+
# :type => Net::DNS::A,
|
19
|
+
# :address => "127.0.0.1" )
|
20
|
+
#
|
21
|
+
# When computing binary data to transmit the RR, the RDATA section is an
|
22
|
+
# Internet address expressed as four decimal numbers separated by dots
|
23
|
+
# without any embedded space (e.g. "10.2.0.52" or "192.0.5.6").
|
24
|
+
#
|
25
|
+
class A < RR
|
26
|
+
|
27
|
+
# Gets the current IPv4 address for this record.
|
28
|
+
#
|
29
|
+
# Returns an instance of IPAddr.
|
30
|
+
def address
|
31
|
+
@address
|
32
|
+
end
|
33
|
+
|
34
|
+
# Assigns a new IPv4 address to this record, which can be in the
|
35
|
+
# form of a <tt>String</tt> or an <tt>IPAddr</tt> object.
|
36
|
+
#
|
37
|
+
# Examples
|
38
|
+
#
|
39
|
+
# a.address = "192.168.0.1"
|
40
|
+
# a.address = IPAddr.new("10.0.0.1")
|
41
|
+
#
|
42
|
+
# Returns the new allocated instance of IPAddr.
|
43
|
+
def address=(string_or_ipaddr)
|
44
|
+
@address = check_address(string_or_ipaddr)
|
45
|
+
build_pack
|
46
|
+
@address
|
47
|
+
end
|
48
|
+
|
49
|
+
# Gets the standardized value for this record,
|
50
|
+
# represented by the value of <tt>address</tt>.
|
51
|
+
#
|
52
|
+
# Returns a String.
|
53
|
+
def value
|
54
|
+
address.to_s
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def subclass_new_from_hash(options)
|
61
|
+
if options.has_key?(:address)
|
62
|
+
@address = check_address(options[:address])
|
63
|
+
elsif options.has_key?(:rdata)
|
64
|
+
@address = check_address(options[:rdata])
|
65
|
+
else
|
66
|
+
raise ArgumentError, ":address or :rdata field is mandatory"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def subclass_new_from_string(str)
|
71
|
+
@address = check_address(str)
|
72
|
+
end
|
73
|
+
|
74
|
+
def subclass_new_from_binary(data, offset)
|
75
|
+
a, b, c, d = data.unpack("@#{offset} CCCC")
|
76
|
+
@address = IPAddr.new("#{a}.#{b}.#{c}.#{d}")
|
77
|
+
offset + 4
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
def set_type
|
82
|
+
@type = Net::DNS::RR::Types.new("A")
|
83
|
+
end
|
84
|
+
|
85
|
+
def get_inspect
|
86
|
+
value
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
def check_address(input)
|
91
|
+
address = case input
|
92
|
+
when IPAddr
|
93
|
+
input
|
94
|
+
when Integer # Address in numeric form
|
95
|
+
tmp = [(input >> 24), (input >> 16) & 0xFF, (input >> 8) & 0xFF, input & 0xFF]
|
96
|
+
tmp = tmp.collect { |x| x.to_s }.join(".")
|
97
|
+
IPAddr.new(tmp)
|
98
|
+
when String
|
99
|
+
IPAddr.new(input)
|
100
|
+
else
|
101
|
+
raise ArgumentError, "Invalid IP address `#{input}'"
|
102
|
+
end
|
103
|
+
|
104
|
+
if !address.ipv4?
|
105
|
+
raise(ArgumentError, "Must specify an IPv4 address")
|
106
|
+
end
|
107
|
+
|
108
|
+
address
|
109
|
+
end
|
110
|
+
|
111
|
+
def build_pack
|
112
|
+
@address_pack = @address.hton
|
113
|
+
@rdlength = @address_pack.size
|
114
|
+
end
|
115
|
+
|
116
|
+
def get_data
|
117
|
+
@address_pack
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Net
|
2
|
+
module DNS
|
3
|
+
class RR
|
4
|
+
|
5
|
+
#
|
6
|
+
# = IPv6 Address Record (AAAA)
|
7
|
+
#
|
8
|
+
# Class for DNS IPv6 Address (AAAA) resource records.
|
9
|
+
#
|
10
|
+
class AAAA < RR
|
11
|
+
|
12
|
+
# Gets the current IPv6 address for this record.
|
13
|
+
#
|
14
|
+
# Returns an instance of IPAddr.
|
15
|
+
def address
|
16
|
+
@address
|
17
|
+
end
|
18
|
+
|
19
|
+
# Assigns a new IPv6 address to this record, which can be in the
|
20
|
+
# form of a <tt>String</tt> or an <tt>IPAddr</tt> object.
|
21
|
+
#
|
22
|
+
# Examples
|
23
|
+
#
|
24
|
+
# a.address = "192.168.0.1"
|
25
|
+
# a.address = IPAddr.new("10.0.0.1")
|
26
|
+
#
|
27
|
+
# Returns the new allocated instance of IPAddr.
|
28
|
+
def address=(string_or_ipaddr)
|
29
|
+
@address = check_address(string_or_ipaddr)
|
30
|
+
build_pack
|
31
|
+
@address
|
32
|
+
end
|
33
|
+
|
34
|
+
# Gets the standardized value for this record,
|
35
|
+
# represented by the value of <tt>address</tt>.
|
36
|
+
#
|
37
|
+
# Returns a String.
|
38
|
+
def value
|
39
|
+
address.to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def subclass_new_from_hash(options)
|
46
|
+
if options.has_key?(:address)
|
47
|
+
@address = check_address(options[:address])
|
48
|
+
else
|
49
|
+
raise ArgumentError, ":address field is mandatory"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def subclass_new_from_string(str)
|
54
|
+
@address = check_address(str)
|
55
|
+
end
|
56
|
+
|
57
|
+
def subclass_new_from_binary(data, offset)
|
58
|
+
tokens = data.unpack("@#{offset} n8")
|
59
|
+
@address = IPAddr.new(sprintf("%x:%x:%x:%x:%x:%x:%x:%x", *tokens))
|
60
|
+
offset + 16
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def set_type
|
65
|
+
@type = Net::DNS::RR::Types.new("AAAA")
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_inspect
|
69
|
+
value
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
def check_address(input)
|
74
|
+
address = case input
|
75
|
+
when IPAddr
|
76
|
+
input
|
77
|
+
when String
|
78
|
+
IPAddr.new(input)
|
79
|
+
else
|
80
|
+
raise ArgumentError, "Invalid IP address `#{input}'"
|
81
|
+
end
|
82
|
+
|
83
|
+
if !address.ipv6?
|
84
|
+
raise(ArgumentError, "Must specify an IPv6 address")
|
85
|
+
end
|
86
|
+
|
87
|
+
address
|
88
|
+
end
|
89
|
+
|
90
|
+
def build_pack
|
91
|
+
@address_pack = @address.hton
|
92
|
+
@rdlength = @address_pack.size
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_data
|
96
|
+
@address_pack
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
module Net
|
2
|
+
module DNS
|
3
|
+
|
4
|
+
class RR
|
5
|
+
|
6
|
+
#
|
7
|
+
# = Net::DNS::Classes
|
8
|
+
#
|
9
|
+
# This is an auxiliary class to handle <tt>Net::DNS::RR</tt>
|
10
|
+
# class field in a DNS packet.
|
11
|
+
#
|
12
|
+
class Classes
|
13
|
+
|
14
|
+
# Hash with the values of each RR class stored with the
|
15
|
+
# respective id number.
|
16
|
+
CLASSES = {
|
17
|
+
'IN' => 1, # RFC 1035
|
18
|
+
'CH' => 3, # RFC 1035
|
19
|
+
'HS' => 4, # RFC 1035
|
20
|
+
'NONE' => 254, # RFC 2136
|
21
|
+
'ANY' => 255, # RFC 1035
|
22
|
+
}
|
23
|
+
|
24
|
+
# The default value when class is nil in Resource Records
|
25
|
+
@@default = CLASSES["IN"]
|
26
|
+
|
27
|
+
|
28
|
+
# Creates a new object representing an RR class. Performs some
|
29
|
+
# checks on the argument validity too. Il +cls+ is +nil+, the
|
30
|
+
# default value is +ANY+ or the one set with Classes.default=
|
31
|
+
def initialize(cls)
|
32
|
+
case cls
|
33
|
+
when String
|
34
|
+
initialize_from_str(cls)
|
35
|
+
when Fixnum
|
36
|
+
initialize_from_num(cls)
|
37
|
+
when nil
|
38
|
+
initialize_from_num(@@default)
|
39
|
+
end
|
40
|
+
|
41
|
+
if @str.nil? || @num.nil?
|
42
|
+
raise ArgumentError, "Unable to create a `Classes' from `#{cls}'"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns the class in number format
|
47
|
+
# (default for normal use)
|
48
|
+
#
|
49
|
+
# FIXME: inspect must return a String.
|
50
|
+
#
|
51
|
+
def inspect
|
52
|
+
@num
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns the class in string format,
|
56
|
+
# ex. "IN" or "CH" or such a string.
|
57
|
+
def to_s
|
58
|
+
@str.to_s
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns the class in numeric format,
|
62
|
+
# usable by the pack methods for data transfers.
|
63
|
+
def to_i
|
64
|
+
@num.to_i
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
# Be able to control the default class to assign when
|
70
|
+
# cls argument is +nil+. Default to +IN+
|
71
|
+
def self.default=(str)
|
72
|
+
if CLASSES[str]
|
73
|
+
@@default = CLASSES[str]
|
74
|
+
else
|
75
|
+
raise ArgumentError, "Unknown class `#{str}'"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns whether <tt>cls</tt> is a valid RR class.
|
80
|
+
#
|
81
|
+
# Net::DNS::RR::Classes.valid?("IN")
|
82
|
+
# # => true
|
83
|
+
# Net::DNS::RR::Classes.valid?(1)
|
84
|
+
# # => true
|
85
|
+
# Net::DNS::RR::Classes.valid?("Q")
|
86
|
+
# # => false
|
87
|
+
# Net::DNS::RR::Classes.valid?(256)
|
88
|
+
# # => false
|
89
|
+
# Net::DNS::RR::Classes.valid?(Hash.new)
|
90
|
+
# # => ArgumentError
|
91
|
+
#
|
92
|
+
# FIXME: valid? should never raise.
|
93
|
+
#
|
94
|
+
# ==== Raises
|
95
|
+
# ArgumentError:: if <tt>cls</tt> isn't either a String or a Fixnum
|
96
|
+
#
|
97
|
+
def self.valid?(cls)
|
98
|
+
case cls
|
99
|
+
when String
|
100
|
+
CLASSES.has_key?(cls)
|
101
|
+
when Fixnum
|
102
|
+
CLASSES.invert.has_key?(cls)
|
103
|
+
else
|
104
|
+
raise ArgumentError, "Wrong cls class: #{cls.class}"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Gives in output the keys from the +Classes+ hash
|
109
|
+
# in a format suited for regexps
|
110
|
+
def self.regexp
|
111
|
+
CLASSES.keys.sort.join("|")
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
# Initialize a new instance from a Class name.
|
118
|
+
def initialize_from_str(str)
|
119
|
+
key = str.to_s.upcase
|
120
|
+
@num, @str = CLASSES[key], key
|
121
|
+
end
|
122
|
+
|
123
|
+
# Initialize a new instance from the Class value.
|
124
|
+
def initialize_from_num(num)
|
125
|
+
key = num.to_i
|
126
|
+
@num, @str = key, CLASSES.invert[key]
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Net # :nodoc:
|
2
|
+
module DNS
|
3
|
+
class RR
|
4
|
+
|
5
|
+
#
|
6
|
+
# = Canonical Name Record (CNAME)
|
7
|
+
#
|
8
|
+
# Class for DNS CNAME resource records.
|
9
|
+
#
|
10
|
+
# A CNAME record maps an alias or nickname to the real or Canonical name
|
11
|
+
# which may lie outside the current zone.
|
12
|
+
# Canonical means expected or real name.
|
13
|
+
#
|
14
|
+
class CNAME < RR
|
15
|
+
|
16
|
+
# Gets the canonical name value.
|
17
|
+
#
|
18
|
+
# Returns a String.
|
19
|
+
def cname
|
20
|
+
@cname
|
21
|
+
end
|
22
|
+
|
23
|
+
# Gets the standardized value for this record,
|
24
|
+
# represented by the value of <tt>cname</tt>.
|
25
|
+
#
|
26
|
+
# Returns a String.
|
27
|
+
def value
|
28
|
+
cname.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def subclass_new_from_hash(options)
|
35
|
+
if options.has_key?(:cname)
|
36
|
+
@cname = check_name(options[:cname])
|
37
|
+
else
|
38
|
+
raise ArgumentError, ":cname field is mandatory"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def subclass_new_from_string(str)
|
43
|
+
@cname = check_name(str)
|
44
|
+
end
|
45
|
+
|
46
|
+
def subclass_new_from_binary(data, offset)
|
47
|
+
@cname, offset = dn_expand(data, offset)
|
48
|
+
offset
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
def set_type
|
53
|
+
@type = Net::DNS::RR::Types.new("CNAME")
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_inspect
|
57
|
+
value
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def check_name(input)
|
62
|
+
name = input.to_s
|
63
|
+
unless name =~ /(\w\.?)+\s*$/ and name =~ /[a-zA-Z]/
|
64
|
+
raise ArgumentError, "Invalid Canonical Name `#{name}'"
|
65
|
+
end
|
66
|
+
name
|
67
|
+
end
|
68
|
+
|
69
|
+
def build_pack
|
70
|
+
@cname_pack = pack_name(@cname)
|
71
|
+
@rdlength = @cname_pack.size
|
72
|
+
end
|
73
|
+
|
74
|
+
def get_data
|
75
|
+
@cname_pack
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module Net # :nodoc:
|
2
|
+
module DNS
|
3
|
+
class RR
|
4
|
+
|
5
|
+
#
|
6
|
+
# = System Information Record (HINFO)
|
7
|
+
#
|
8
|
+
# Class for DNS HINFO resource records.
|
9
|
+
#
|
10
|
+
# Allows definition of the Hardware type and Operating System (OS) in use at a host.
|
11
|
+
# For security reasons these records are rarely used on public servers.
|
12
|
+
# If a space exists in the field it must be enclosed in quotes.
|
13
|
+
# Single space between CPU and OS parameters.
|
14
|
+
#
|
15
|
+
class HINFO < RR
|
16
|
+
|
17
|
+
# Gets the CPU value.
|
18
|
+
#
|
19
|
+
# Returns a String.
|
20
|
+
def cpu
|
21
|
+
@cpu
|
22
|
+
end
|
23
|
+
|
24
|
+
# Gets the OS value.
|
25
|
+
#
|
26
|
+
# Returns a String.
|
27
|
+
def os
|
28
|
+
@os
|
29
|
+
end
|
30
|
+
|
31
|
+
# Gets the standardized value for this record,
|
32
|
+
# represented by the value of <tt>cpu</tt> and <tt>os</tt>.
|
33
|
+
#
|
34
|
+
# Returns a String.
|
35
|
+
def value
|
36
|
+
%Q{"#{cpu}" "#{os}"}
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# Gets a list of all the attributes for this record.
|
41
|
+
#
|
42
|
+
# Returns an Array of values.
|
43
|
+
def to_a
|
44
|
+
[nil, nil, cls.to_s, type.to_s, value]
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def subclass_new_from_hash(options)
|
51
|
+
if options.has_key?(:cpu) && options.has_key?(:os)
|
52
|
+
@cpu = options[:cpu]
|
53
|
+
@os = options[:os]
|
54
|
+
else
|
55
|
+
raise ArgumentError, ":cpu and :os fields are mandatory"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def subclass_new_from_string(str)
|
60
|
+
@cpu, @os = check_hinfo(str)
|
61
|
+
end
|
62
|
+
|
63
|
+
def subclass_new_from_binary(data, offset)
|
64
|
+
len = data.unpack("@#{offset} C").first
|
65
|
+
offset += 1
|
66
|
+
@cpu = data[offset..(offset + len)]
|
67
|
+
offset += len
|
68
|
+
|
69
|
+
len = data.unpack("@#{offset} C").first
|
70
|
+
offset += 1
|
71
|
+
@os = data[offset..(offset + len)]
|
72
|
+
offset += len
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
def set_type
|
77
|
+
@type = Net::DNS::RR::Types.new("HINFO")
|
78
|
+
end
|
79
|
+
|
80
|
+
def get_inspect
|
81
|
+
value
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
def check_hinfo(input)
|
86
|
+
if input.to_s.strip =~ /^(?:["']?(.*?)["']?)\s+(?:["']?(.*?)["']?)$/
|
87
|
+
[$1, $2]
|
88
|
+
else
|
89
|
+
raise ArgumentError, "Invalid HINFO Section `#{input}'"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def build_pack
|
94
|
+
@hinfo_pack = ""
|
95
|
+
@hinfo_pack += [cpu.size].pack("C") + cpu
|
96
|
+
@hinfo_pack += [os.size ].pack("C") + os
|
97
|
+
@rdlength = @hinfo_pack.size
|
98
|
+
end
|
99
|
+
|
100
|
+
def get_data
|
101
|
+
@hinfo_pack
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|