net-dns 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +10 -0
- data/INSTALL +0 -0
- data/README +55 -0
- data/Rakefile +65 -0
- data/THANKS +0 -0
- data/demo/check_soa.rb +120 -0
- data/demo/threads.rb +21 -0
- data/gemspec +16 -0
- data/lib/net/dns/dns.rb +117 -0
- data/lib/net/dns/header.rb +692 -0
- data/lib/net/dns/names/names.rb +109 -0
- data/lib/net/dns/packet.rb +549 -0
- data/lib/net/dns/question.rb +195 -0
- data/lib/net/dns/resolver.rb +1199 -0
- data/lib/net/dns/resolver/socks.rb +154 -0
- data/lib/net/dns/resolver/timeouts.rb +73 -0
- data/lib/net/dns/rr.rb +386 -0
- data/lib/net/dns/rr/a.rb +121 -0
- data/lib/net/dns/rr/aaaa.rb +92 -0
- data/lib/net/dns/rr/classes.rb +148 -0
- data/lib/net/dns/rr/cname.rb +69 -0
- data/lib/net/dns/rr/hinfo.rb +74 -0
- data/lib/net/dns/rr/mr.rb +68 -0
- data/lib/net/dns/rr/mx.rb +74 -0
- data/lib/net/dns/rr/ns.rb +70 -0
- data/lib/net/dns/rr/null.rb +61 -0
- data/lib/net/dns/rr/ptr.rb +71 -0
- data/lib/net/dns/rr/soa.rb +85 -0
- data/lib/net/dns/rr/txt.rb +72 -0
- data/lib/net/dns/rr/types.rb +200 -0
- data/setup.rb +1360 -0
- data/test/net/dns/resolver/test_timeouts.rb +59 -0
- data/test/net/dns/rr/test_a.rb +72 -0
- data/test/net/dns/rr/test_classes.rb +73 -0
- data/test/net/dns/rr/test_ns.rb +66 -0
- data/test/net/dns/rr/test_types.rb +127 -0
- data/test/net/dns/test_header.rb +170 -0
- data/test/net/dns/test_packet.rb +42 -0
- data/test/net/dns/test_question.rb +54 -0
- data/test/net/dns/test_rr.rb +128 -0
- metadata +97 -0
data/lib/net/dns/rr/a.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
##
|
2
|
+
#
|
3
|
+
# Net::DNS::RR::A
|
4
|
+
#
|
5
|
+
# $id$
|
6
|
+
#
|
7
|
+
##
|
8
|
+
|
9
|
+
require 'ipaddr'
|
10
|
+
|
11
|
+
module Net # :nodoc:
|
12
|
+
module DNS
|
13
|
+
|
14
|
+
class RR
|
15
|
+
|
16
|
+
# =Name
|
17
|
+
#
|
18
|
+
# Net::DNS::RR::A DNS A resource record
|
19
|
+
#
|
20
|
+
# =Synopsis
|
21
|
+
#
|
22
|
+
# require "net/dns/rr"
|
23
|
+
#
|
24
|
+
# =Description
|
25
|
+
#
|
26
|
+
# Net::DNS::RR::A is the class to handle resource records of type A, the
|
27
|
+
# most common in a DNS query. Its resource data is an IPv4 (i.e. 32 bit
|
28
|
+
# long) address, hold in the instance variable +address+.
|
29
|
+
# a = Net::DNS::RR::A.new("localhost.movie.edu. 360 IN A 127.0.0.1")
|
30
|
+
#
|
31
|
+
# a = Net::DNS::RR::A.new(:name => "localhost.movie.edu.",
|
32
|
+
# :ttl => 360,
|
33
|
+
# :cls => Net::DNS::IN,
|
34
|
+
# :type => Net::DNS::A,
|
35
|
+
# :address => "127.0.0.1")
|
36
|
+
#
|
37
|
+
# When computing binary data to trasmit the RR, the RDATA section is an
|
38
|
+
# Internet address expressed as four decimal numbers separated by dots
|
39
|
+
# without any imbedded spaces (e.g.,"10.2.0.52" or "192.0.5.6").
|
40
|
+
#
|
41
|
+
class A < RR
|
42
|
+
attr_reader :address
|
43
|
+
|
44
|
+
# Assign to the RR::A object a new IPv4 address, which can be in the
|
45
|
+
# form of a string or an IPAddr object
|
46
|
+
#
|
47
|
+
# a.address = "192.168.0.1"
|
48
|
+
# a.address = IPAddr.new("10.0.0.1")
|
49
|
+
#
|
50
|
+
def address=(addr)
|
51
|
+
@address = check_address addr
|
52
|
+
build_pack
|
53
|
+
end # address=
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def check_address(addr)
|
58
|
+
address = ""
|
59
|
+
case addr
|
60
|
+
when String
|
61
|
+
address = IPAddr.new addr
|
62
|
+
when Integer # Address in numeric form
|
63
|
+
tempAddr = [(addr>>24),(addr>>16)&0xFF,(addr>>8)&0xFF,addr&0xFF]
|
64
|
+
tempAddr = tempAddr.collect {|x| x.to_s}.join(".")
|
65
|
+
address = IPAddr.new tempAddr
|
66
|
+
when IPAddr
|
67
|
+
address = addr
|
68
|
+
else
|
69
|
+
raise RRArgumentError, "Unknown address type: #{addr}"
|
70
|
+
end
|
71
|
+
raise RRArgumentError, "Must specify an IPv4 address" unless address.ipv4?
|
72
|
+
address
|
73
|
+
rescue ArgumentError
|
74
|
+
raise RRArgumentError, "Invalid address #{addr}"
|
75
|
+
end
|
76
|
+
|
77
|
+
def build_pack
|
78
|
+
@address_pack = @address.hton
|
79
|
+
@rdlength = @address_pack.size
|
80
|
+
end
|
81
|
+
|
82
|
+
def set_type
|
83
|
+
@type = Net::DNS::RR::Types.new("A")
|
84
|
+
end
|
85
|
+
|
86
|
+
def get_data
|
87
|
+
@address_pack
|
88
|
+
end
|
89
|
+
|
90
|
+
def get_inspect
|
91
|
+
"#@address"
|
92
|
+
end
|
93
|
+
|
94
|
+
def subclass_new_from_hash(args)
|
95
|
+
if args.has_key? :address
|
96
|
+
@address = check_address args[:address]
|
97
|
+
elsif args.has_key? :rdata
|
98
|
+
@address = check_address args[:rdata]
|
99
|
+
else
|
100
|
+
# Address field is mandatory
|
101
|
+
raise RRArgumentError, ":address field is mandatory but missing"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def subclass_new_from_string(str)
|
106
|
+
@address = check_address(str)
|
107
|
+
end
|
108
|
+
|
109
|
+
def subclass_new_from_binary(data,offset)
|
110
|
+
a,b,c,d = data.unpack("@#{offset} CCCC")
|
111
|
+
@address = IPAddr.new "#{a}.#{b}.#{c}.#{d}"
|
112
|
+
return offset + 4
|
113
|
+
end
|
114
|
+
|
115
|
+
end # class A
|
116
|
+
|
117
|
+
end # class RR
|
118
|
+
end # module DNS
|
119
|
+
end # module Net
|
120
|
+
|
121
|
+
|
@@ -0,0 +1,92 @@
|
|
1
|
+
##
|
2
|
+
#
|
3
|
+
# Net::DNS::RR::AAAA
|
4
|
+
#
|
5
|
+
# $id$
|
6
|
+
#
|
7
|
+
##
|
8
|
+
|
9
|
+
require 'ipaddr'
|
10
|
+
|
11
|
+
module Net
|
12
|
+
module DNS
|
13
|
+
|
14
|
+
class RR
|
15
|
+
|
16
|
+
#
|
17
|
+
# RR type AAAA
|
18
|
+
#
|
19
|
+
class AAAA < RR
|
20
|
+
attr_reader :address
|
21
|
+
|
22
|
+
# Assign to the RR::AAAA object a new IPv6 address, which can be in the
|
23
|
+
# form of a string or an IPAddr object
|
24
|
+
#
|
25
|
+
# a.address = "::1"
|
26
|
+
# a.address = IPAddr.new("::1")
|
27
|
+
#
|
28
|
+
def address=(addr)
|
29
|
+
@address = check_address addr
|
30
|
+
build_pack
|
31
|
+
end # address=
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def check_address(addr)
|
36
|
+
address = ""
|
37
|
+
case addr
|
38
|
+
when String
|
39
|
+
address = IPAddr.new addr
|
40
|
+
when IPAddr
|
41
|
+
address = addr
|
42
|
+
else
|
43
|
+
raise RRArgumentError, "Unknown address type: #{addr.inspect}"
|
44
|
+
end
|
45
|
+
raise RRArgumentError, "Must specify an IPv6 address" unless address.ipv6?
|
46
|
+
address
|
47
|
+
rescue ArgumentError
|
48
|
+
raise RRArgumentError, "Invalid address #{addr.inspect}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def build_pack
|
52
|
+
@address_pack = @address.hton
|
53
|
+
@rdlength = @address_pack.size
|
54
|
+
end
|
55
|
+
|
56
|
+
def set_type
|
57
|
+
@type = Net::DNS::RR::Types.new("AAAA")
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_data
|
61
|
+
@address_pack
|
62
|
+
end
|
63
|
+
|
64
|
+
def get_inspect
|
65
|
+
"#@address"
|
66
|
+
end
|
67
|
+
|
68
|
+
def subclass_new_from_hash(args)
|
69
|
+
if args.has_key? :address
|
70
|
+
@address = check_address args[:address]
|
71
|
+
else
|
72
|
+
raise RRArgumentError, ":address field is mandatory but missing"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def subclass_new_from_string(str)
|
77
|
+
@address = check_address(str)
|
78
|
+
end
|
79
|
+
|
80
|
+
def subclass_new_from_binary(data,offset)
|
81
|
+
arr = data.unpack("@#{offset} n8")
|
82
|
+
@address = IPAddr.new sprintf("%x:%x:%x:%x:%x:%x:%x:%x",*arr)
|
83
|
+
return offset + 16
|
84
|
+
end
|
85
|
+
|
86
|
+
end # class AAAA
|
87
|
+
|
88
|
+
end # class RR
|
89
|
+
end # module DNS
|
90
|
+
end # module Net
|
91
|
+
|
92
|
+
|
@@ -0,0 +1,148 @@
|
|
1
|
+
module Net # :nodoc:
|
2
|
+
module DNS
|
3
|
+
|
4
|
+
class RR
|
5
|
+
|
6
|
+
#
|
7
|
+
# This is an auxiliary class to hadle RR class field in a DNS packet.
|
8
|
+
#
|
9
|
+
class Classes
|
10
|
+
|
11
|
+
# An hash with the values of each RR class stored with the
|
12
|
+
# respective id number
|
13
|
+
Classes = {
|
14
|
+
'IN' => 1, # RFC 1035
|
15
|
+
'CH' => 3, # RFC 1035
|
16
|
+
'HS' => 4, # RFC 1035
|
17
|
+
'NONE' => 254, # RFC 2136
|
18
|
+
'ANY' => 255, # RFC 1035
|
19
|
+
}
|
20
|
+
|
21
|
+
# The default value when class is nil in Resource Records
|
22
|
+
@@default = Classes["IN"]
|
23
|
+
|
24
|
+
# Be able to control the default class to assign when
|
25
|
+
# cls argument is +nil+. Default to +IN+
|
26
|
+
def self.default=(str)
|
27
|
+
if Classes.has_key? str
|
28
|
+
@@default = Classes[str]
|
29
|
+
else
|
30
|
+
raise ClassArgumentError, "Unknown class #{str}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Checks whether +cls+ is a valid RR class.
|
35
|
+
def self.valid?(cls)
|
36
|
+
case cls
|
37
|
+
when String
|
38
|
+
return Classes.has_key?(cls)
|
39
|
+
when Fixnum
|
40
|
+
return Classes.invert.has_key?(cls)
|
41
|
+
else
|
42
|
+
raise ClassArgumentError, "Wrong cls class: #{cls.class}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns the class in string format, as "IN" or "CH",
|
47
|
+
# given the numeric value
|
48
|
+
def self.to_str(cls)
|
49
|
+
case cls
|
50
|
+
when Fixnum
|
51
|
+
if Classes.invert.has_key? cls
|
52
|
+
return Classes.invert[cls]
|
53
|
+
else
|
54
|
+
raise ClassArgumentError, "Unknown class number #{cls}"
|
55
|
+
end
|
56
|
+
else
|
57
|
+
raise ClassArgumentError, "Wrong cls class: #{cls.class}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Gives in output the keys from the +Classes+ hash
|
62
|
+
# in a format suited for regexps
|
63
|
+
def self.regexp
|
64
|
+
Classes.keys.join("|")
|
65
|
+
end
|
66
|
+
|
67
|
+
# Creates a new object representing an RR class. Performs some
|
68
|
+
# checks on the argument validity too. Il +cls+ is +nil+, the
|
69
|
+
# default value is +ANY+ or the one set with Classes.default=
|
70
|
+
def initialize(cls)
|
71
|
+
case cls
|
72
|
+
when String
|
73
|
+
# type in the form "A" or "NS"
|
74
|
+
new_from_string(cls.upcase)
|
75
|
+
when Fixnum
|
76
|
+
# type in numeric form
|
77
|
+
new_from_num(cls)
|
78
|
+
when nil
|
79
|
+
# default type, control with Classes.default=
|
80
|
+
@str = Classes.invert[@@default]
|
81
|
+
@num = @@default
|
82
|
+
else
|
83
|
+
raise ClassArgumentError, "Wrong cls class: #{cls.class}"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Constructor for string data class,
|
88
|
+
# *PRIVATE* method
|
89
|
+
def new_from_string(cls)
|
90
|
+
case cls
|
91
|
+
when /^CLASS\\d+/
|
92
|
+
# TODO!!!
|
93
|
+
else
|
94
|
+
# String with name of class
|
95
|
+
if Classes.has_key? cls
|
96
|
+
@str = cls
|
97
|
+
@num = Classes[cls]
|
98
|
+
else
|
99
|
+
raise ClassesArgumentError, "Unknown cls #{cls}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Contructor for numeric data class
|
105
|
+
# *PRIVATE* method
|
106
|
+
def new_from_num(cls)
|
107
|
+
if Classes.invert.has_key? cls
|
108
|
+
@num = cls
|
109
|
+
@str = Classes.invert[cls]
|
110
|
+
else
|
111
|
+
raise ClassesArgumentError, "Unkown cls number #{cls}"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Returns the class in number format
|
116
|
+
# (default for normal use)
|
117
|
+
def inspect
|
118
|
+
@num
|
119
|
+
end
|
120
|
+
|
121
|
+
# Returns the class in string format,
|
122
|
+
# i.d. "IN" or "CH" or such a string.
|
123
|
+
def to_s
|
124
|
+
@str
|
125
|
+
end
|
126
|
+
|
127
|
+
# Returns the class in numeric format,
|
128
|
+
# usable by the pack methods for data transfers
|
129
|
+
def to_i
|
130
|
+
@num.to_i
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
# Should be used only for testing purpouses
|
135
|
+
def to_str
|
136
|
+
@num.to_s
|
137
|
+
end
|
138
|
+
|
139
|
+
private :new_from_num, :new_from_string
|
140
|
+
|
141
|
+
end # class Classes
|
142
|
+
|
143
|
+
end # class RR
|
144
|
+
end # module DNS
|
145
|
+
end # module Net
|
146
|
+
|
147
|
+
class ClassArgumentError < ArgumentError # :nodoc:
|
148
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
##
|
2
|
+
#
|
3
|
+
# Net::DNS::RR::CNAME
|
4
|
+
#
|
5
|
+
# $Id: CNAME.rb,v 1.7 2006/07/28 07:33:36 bluemonk Exp $
|
6
|
+
#
|
7
|
+
##
|
8
|
+
|
9
|
+
module Net
|
10
|
+
module DNS
|
11
|
+
|
12
|
+
class RR
|
13
|
+
|
14
|
+
#------------------------------------------------------------
|
15
|
+
# RR type CNAME
|
16
|
+
#------------------------------------------------------------
|
17
|
+
class CNAME < RR
|
18
|
+
attr_reader :cname
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def check_name(name)
|
23
|
+
unless name =~ /(\w\.?)+\s*$/ and name =~ /[a-zA-Z]/
|
24
|
+
raise RRArgumentError, "Canonical Name not valid: #{name}"
|
25
|
+
end
|
26
|
+
name
|
27
|
+
end
|
28
|
+
|
29
|
+
def build_pack
|
30
|
+
@cname_pack = pack_name(@cname)
|
31
|
+
@rdlength = @cname_pack.size
|
32
|
+
end
|
33
|
+
|
34
|
+
def set_type
|
35
|
+
@type = Net::DNS::RR::Types.new("CNAME")
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_data
|
39
|
+
@cname_pack
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_inspect
|
43
|
+
"#@cname"
|
44
|
+
end
|
45
|
+
|
46
|
+
def subclass_new_from_hash(args)
|
47
|
+
if args.has_key? :cname
|
48
|
+
@cname = check_name args[:cname]
|
49
|
+
else
|
50
|
+
raise RRArgumentError, ":cname field is mandatory but missing"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def subclass_new_from_string(str)
|
55
|
+
@cname = check_name(str)
|
56
|
+
end
|
57
|
+
|
58
|
+
def subclass_new_from_binary(data,offset)
|
59
|
+
@cname,offset = dn_expand(data,offset)
|
60
|
+
return offset
|
61
|
+
end
|
62
|
+
|
63
|
+
end # class CNAME
|
64
|
+
|
65
|
+
end # class RR
|
66
|
+
end # module DNS
|
67
|
+
end # module Net
|
68
|
+
|
69
|
+
|
@@ -0,0 +1,74 @@
|
|
1
|
+
##
|
2
|
+
#
|
3
|
+
# Net::DNS::RR::HINFO
|
4
|
+
#
|
5
|
+
# $Id: HINFO.rb,v 1.4 2006/07/28 07:33:36 bluemonk Exp $
|
6
|
+
#
|
7
|
+
##
|
8
|
+
|
9
|
+
module Net
|
10
|
+
module DNS
|
11
|
+
class RR
|
12
|
+
|
13
|
+
#------------------------------------------------------------
|
14
|
+
# RR type HINFO
|
15
|
+
#------------------------------------------------------------
|
16
|
+
class HINFO < RR
|
17
|
+
attr_reader :cpu, :os
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def check_hinfo(str)
|
22
|
+
if str.strip =~ /^["'](.*?)["']\s+["'](.*?)["']$/
|
23
|
+
return $1,$2
|
24
|
+
else
|
25
|
+
raise RRArgumentError, "HINFO section not valid: #{str.inspect}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def build_pack
|
30
|
+
@hinfo_pack = [@cpu.size].pack("C") + @cpu
|
31
|
+
@hinfo_pack += [@os.size].pack("C") + @os
|
32
|
+
@rdlength = @hinfo_pack.size
|
33
|
+
end
|
34
|
+
|
35
|
+
def set_type
|
36
|
+
@type = Net::DNS::RR::Types.new("HINFO")
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_data
|
40
|
+
@hinfo_pack
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_inspect
|
44
|
+
"#@cpu #@os"
|
45
|
+
end
|
46
|
+
|
47
|
+
def subclass_new_from_hash(args)
|
48
|
+
if args.has_key? :cpu and args.has_key? :os
|
49
|
+
@cpu = args[:cpu]
|
50
|
+
@os = args[:os]
|
51
|
+
else
|
52
|
+
raise RRArgumentError, ":cpu and :os fields are mandatory but missing"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def subclass_new_from_string(str)
|
57
|
+
@cpu,@os = check_hinfo(str)
|
58
|
+
end
|
59
|
+
|
60
|
+
def subclass_new_from_binary(data,offset)
|
61
|
+
len = data.unpack("@#{offset} C")[0]
|
62
|
+
@cpu = data[offset+1..offset+1+len]
|
63
|
+
offset += len+1
|
64
|
+
len = @data.unpack("@#{offset} C")[0]
|
65
|
+
@os = data[offset+1..offset+1+len]
|
66
|
+
return offset += len+1
|
67
|
+
end
|
68
|
+
|
69
|
+
end # class HINFO
|
70
|
+
|
71
|
+
end # class RR
|
72
|
+
end # module DNS
|
73
|
+
end # module Net
|
74
|
+
|