gitlab-net-dns 0.9.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/.gitlab-ci.yml +20 -0
- data/.rspec +1 -0
- data/.rubocop.yml +3 -0
- data/.rubocop_defaults.yml +359 -0
- data/.rubocop_todo.yml +207 -0
- data/.travis.yml +13 -0
- data/CHANGELOG.md +113 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +56 -0
- data/README.md +172 -0
- data/Rakefile +38 -0
- data/THANKS.rdoc +24 -0
- data/bin/console +14 -0
- data/demo/check_soa.rb +104 -0
- data/demo/threads.rb +18 -0
- data/gitlab-net-dns.gemspec +24 -0
- data/lib/net/dns.rb +104 -0
- data/lib/net/dns/header.rb +705 -0
- data/lib/net/dns/names.rb +120 -0
- data/lib/net/dns/packet.rb +560 -0
- data/lib/net/dns/question.rb +185 -0
- data/lib/net/dns/resolver.rb +1214 -0
- data/lib/net/dns/resolver/socks.rb +148 -0
- data/lib/net/dns/resolver/timeouts.rb +70 -0
- data/lib/net/dns/rr.rb +356 -0
- data/lib/net/dns/rr/a.rb +114 -0
- data/lib/net/dns/rr/aaaa.rb +94 -0
- data/lib/net/dns/rr/classes.rb +130 -0
- data/lib/net/dns/rr/cname.rb +74 -0
- data/lib/net/dns/rr/hinfo.rb +96 -0
- data/lib/net/dns/rr/mr.rb +70 -0
- data/lib/net/dns/rr/mx.rb +82 -0
- data/lib/net/dns/rr/ns.rb +70 -0
- data/lib/net/dns/rr/null.rb +50 -0
- data/lib/net/dns/rr/ptr.rb +77 -0
- data/lib/net/dns/rr/soa.rb +75 -0
- data/lib/net/dns/rr/srv.rb +41 -0
- data/lib/net/dns/rr/txt.rb +58 -0
- data/lib/net/dns/rr/types.rb +191 -0
- data/lib/net/dns/version.rb +8 -0
- data/spec/fixtures/resolv.conf +4 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/unit/resolver/dns_timeout_spec.rb +36 -0
- data/spec/unit/resolver/tcp_timeout_spec.rb +46 -0
- data/spec/unit/resolver/udp_timeout_spec.rb +46 -0
- data/test/test_helper.rb +13 -0
- data/test/unit/header_test.rb +164 -0
- data/test/unit/names_test.rb +21 -0
- data/test/unit/packet_test.rb +47 -0
- data/test/unit/question_test.rb +81 -0
- data/test/unit/resolver_test.rb +114 -0
- data/test/unit/rr/a_test.rb +106 -0
- data/test/unit/rr/aaaa_test.rb +102 -0
- data/test/unit/rr/classes_test.rb +83 -0
- data/test/unit/rr/cname_test.rb +90 -0
- data/test/unit/rr/hinfo_test.rb +111 -0
- data/test/unit/rr/mr_test.rb +99 -0
- data/test/unit/rr/mx_test.rb +106 -0
- data/test/unit/rr/ns_test.rb +80 -0
- data/test/unit/rr/types_test.rb +71 -0
- data/test/unit/rr_test.rb +127 -0
- metadata +172 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
module Net # :nodoc:
|
2
|
+
module DNS
|
3
|
+
class RR
|
4
|
+
#
|
5
|
+
# = Mail Rename Record (MR)
|
6
|
+
#
|
7
|
+
# Class for DNS MR resource records.
|
8
|
+
#
|
9
|
+
class MR < RR
|
10
|
+
# Gets the newname value.
|
11
|
+
#
|
12
|
+
# Returns a String.
|
13
|
+
attr_reader :newname
|
14
|
+
|
15
|
+
# Gets the standardized value for this record,
|
16
|
+
# represented by the value of <tt>newname</tt>.
|
17
|
+
#
|
18
|
+
# Returns a String.
|
19
|
+
def value
|
20
|
+
newname.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def subclass_new_from_hash(options)
|
26
|
+
if options.key?(:newname)
|
27
|
+
@newname = check_name(options[:newname])
|
28
|
+
else
|
29
|
+
raise ArgumentError, ":newname field is mandatory"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def subclass_new_from_string(str)
|
34
|
+
@newname = check_name(str)
|
35
|
+
end
|
36
|
+
|
37
|
+
def subclass_new_from_binary(data, offset)
|
38
|
+
@newname = dn_expand(data, offset)
|
39
|
+
offset
|
40
|
+
end
|
41
|
+
|
42
|
+
def set_type
|
43
|
+
@type = Net::DNS::RR::Types.new("MR")
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_inspect
|
47
|
+
value
|
48
|
+
end
|
49
|
+
|
50
|
+
def check_name(input)
|
51
|
+
name = input.to_s
|
52
|
+
unless name =~ /(\w\.?)+\s*$/
|
53
|
+
raise ArgumentError, "Invalid Domain Name `#{name}'"
|
54
|
+
end
|
55
|
+
|
56
|
+
name
|
57
|
+
end
|
58
|
+
|
59
|
+
def build_pack
|
60
|
+
@newname_pack = pack_name(@newname)
|
61
|
+
@rdlength = @newname_pack.size
|
62
|
+
end
|
63
|
+
|
64
|
+
def get_data
|
65
|
+
@newname_pack
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Net # :nodoc:
|
2
|
+
module DNS
|
3
|
+
class RR
|
4
|
+
#
|
5
|
+
# = Mail Exchange Record (MX)
|
6
|
+
#
|
7
|
+
# Class for DNS MX resource records.
|
8
|
+
#
|
9
|
+
# A MX record specifies the name and relative preference of mail servers
|
10
|
+
# (mail exchangers in the DNS jargon) for the zone.
|
11
|
+
# The MX RR is used by SMTP (Mail) Agents to route mail for the domain.
|
12
|
+
#
|
13
|
+
class MX < RR
|
14
|
+
# Gets the preference value.
|
15
|
+
#
|
16
|
+
# Returns an Integer.
|
17
|
+
attr_reader :preference
|
18
|
+
|
19
|
+
# Gets the exchange value.
|
20
|
+
#
|
21
|
+
# Returns a String.
|
22
|
+
attr_reader :exchange
|
23
|
+
|
24
|
+
# Gets the standardized value for this record,
|
25
|
+
# represented by the value of <tt>preference</tt> and <tt>exchange</tt>.
|
26
|
+
#
|
27
|
+
# Returns a String.
|
28
|
+
def value
|
29
|
+
"#{preference} #{exchange}"
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def subclass_new_from_hash(options)
|
35
|
+
if options.key?(:preference) && options.key?(:exchange)
|
36
|
+
@preference = options[:preference].to_i
|
37
|
+
@exchange = options[:exchange]
|
38
|
+
else
|
39
|
+
raise ArgumentError, ":preference and :exchange fields are mandatory"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def subclass_new_from_string(str)
|
44
|
+
@preference, @exchange = check_mx(str)
|
45
|
+
end
|
46
|
+
|
47
|
+
def subclass_new_from_binary(data, offset)
|
48
|
+
@preference = data.unpack("@#{offset} n")[0]
|
49
|
+
offset += 2
|
50
|
+
@exchange, offset = dn_expand(data, offset)
|
51
|
+
offset
|
52
|
+
end
|
53
|
+
|
54
|
+
def set_type
|
55
|
+
@type = Net::DNS::RR::Types.new("MX")
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_inspect
|
59
|
+
value
|
60
|
+
end
|
61
|
+
|
62
|
+
def check_mx(input)
|
63
|
+
str = input.to_s
|
64
|
+
unless str.strip =~ /^(\d+)\s+(\S+)$/
|
65
|
+
raise ArgumentError, "Invalid MX section `#{str}'"
|
66
|
+
end
|
67
|
+
|
68
|
+
[Regexp.last_match(1).to_i, Regexp.last_match(2)]
|
69
|
+
end
|
70
|
+
|
71
|
+
def build_pack
|
72
|
+
@mx_pack = [@preference].pack("n") + pack_name(@exchange)
|
73
|
+
@rdlength = @mx_pack.size
|
74
|
+
end
|
75
|
+
|
76
|
+
def get_data
|
77
|
+
@mx_pack
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Net # :nodoc:
|
2
|
+
module DNS
|
3
|
+
class RR
|
4
|
+
#
|
5
|
+
# = Name Server Record (NS)
|
6
|
+
#
|
7
|
+
# Class for DNS NS resource records.
|
8
|
+
#
|
9
|
+
class NS < RR
|
10
|
+
# Gets the name server value.
|
11
|
+
#
|
12
|
+
# Returns a String.
|
13
|
+
attr_reader :nsdname
|
14
|
+
|
15
|
+
# Gets the standardized value for this record,
|
16
|
+
# represented by the value of <tt>nsdname</tt>.
|
17
|
+
#
|
18
|
+
# Returns a String.
|
19
|
+
def value
|
20
|
+
nsdname.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def subclass_new_from_hash(options)
|
26
|
+
if options.key?(:nsdname)
|
27
|
+
@nsdname = check_name(options[:nsdname])
|
28
|
+
else
|
29
|
+
raise ArgumentError, ":nsdname field is mandatory"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def subclass_new_from_string(str)
|
34
|
+
@nsdname = check_name(str)
|
35
|
+
end
|
36
|
+
|
37
|
+
def subclass_new_from_binary(data, offset)
|
38
|
+
@nsdname, offset = dn_expand(data, offset)
|
39
|
+
offset
|
40
|
+
end
|
41
|
+
|
42
|
+
def set_type
|
43
|
+
@type = Net::DNS::RR::Types.new("NS")
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_inspect
|
47
|
+
value
|
48
|
+
end
|
49
|
+
|
50
|
+
def check_name(input)
|
51
|
+
name = input.to_s
|
52
|
+
unless name =~ /(\w\.?)+\s*$/ && name =~ /[a-zA-Z]/
|
53
|
+
raise ArgumentError, "Invalid Name Server `#{name}'"
|
54
|
+
end
|
55
|
+
|
56
|
+
name
|
57
|
+
end
|
58
|
+
|
59
|
+
def build_pack
|
60
|
+
@nsdname_pack = pack_name(@nsdname)
|
61
|
+
@rdlength = @nsdname_pack.size
|
62
|
+
end
|
63
|
+
|
64
|
+
def get_data
|
65
|
+
@nsdname_pack
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Net # :nodoc:
|
2
|
+
module DNS
|
3
|
+
class RR
|
4
|
+
#------------------------------------------------------------
|
5
|
+
# RR type NULL
|
6
|
+
#------------------------------------------------------------
|
7
|
+
class NULL < RR
|
8
|
+
attr_reader :null
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def build_pack
|
13
|
+
@null_pack = @null
|
14
|
+
@rdlength = @null_pack.size
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_data
|
18
|
+
@null_pack
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_inspect
|
22
|
+
@null.to_s
|
23
|
+
end
|
24
|
+
|
25
|
+
def subclass_new_from_hash(args)
|
26
|
+
if args.key? :null
|
27
|
+
@null = args[:null]
|
28
|
+
else
|
29
|
+
raise ArgumentError, ":null field is mandatory but missing"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def subclass_new_from_string(str)
|
34
|
+
@null = str.strip
|
35
|
+
end
|
36
|
+
|
37
|
+
def subclass_new_from_binary(data, offset)
|
38
|
+
@null = data[offset..offset + @rdlength]
|
39
|
+
offset + @rdlength
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def set_type
|
45
|
+
@type = Net::DNS::RR::Types.new("NULL")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Net
|
2
|
+
module DNS
|
3
|
+
class RR
|
4
|
+
#
|
5
|
+
# = Pointer Record (PTR)
|
6
|
+
#
|
7
|
+
# Class for DNS Pointer (PTR) resource records.
|
8
|
+
#
|
9
|
+
# Pointer records are the opposite of A and AAAA RRs
|
10
|
+
# and are used in Reverse Map zone files to map
|
11
|
+
# an IP address (IPv4 or IPv6) to a host name.
|
12
|
+
#
|
13
|
+
class PTR < RR
|
14
|
+
# Gets the PTR value.
|
15
|
+
#
|
16
|
+
# Returns a String.
|
17
|
+
def ptrdname
|
18
|
+
@ptrdname.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
alias ptr ptrdname
|
22
|
+
|
23
|
+
# Gets the standardized value for this record,
|
24
|
+
# represented by the value of <tt>ptrdname</tt>.
|
25
|
+
#
|
26
|
+
# Returns a String.
|
27
|
+
def value
|
28
|
+
ptrdname.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def build_pack
|
34
|
+
@ptrdname_pack = pack_name(@ptrdname)
|
35
|
+
@rdlength = @ptrdname_pack.size
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_data
|
39
|
+
@ptrdname_pack
|
40
|
+
end
|
41
|
+
|
42
|
+
def subclass_new_from_hash(args)
|
43
|
+
if args.key?(:ptrdname) || args.key?(:ptr)
|
44
|
+
@ptrdname = args[:ptrdname]
|
45
|
+
else
|
46
|
+
raise ArgumentError, ":ptrdname or :ptr field is mandatory"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def subclass_new_from_string(str)
|
51
|
+
@ptrdname = check_name(str)
|
52
|
+
end
|
53
|
+
|
54
|
+
def subclass_new_from_binary(data, offset)
|
55
|
+
@ptrdname, offset = dn_expand(data, offset)
|
56
|
+
offset
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def set_type
|
62
|
+
@type = Net::DNS::RR::Types.new("PTR")
|
63
|
+
end
|
64
|
+
|
65
|
+
def get_inspect
|
66
|
+
value
|
67
|
+
end
|
68
|
+
|
69
|
+
def check_name(input)
|
70
|
+
IPAddr.new(str)
|
71
|
+
rescue StandardError
|
72
|
+
raise ArgumentError, "Invalid PTR Section `#{input}'"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Net # :nodoc:
|
2
|
+
module DNS
|
3
|
+
class RR
|
4
|
+
#------------------------------------------------------------
|
5
|
+
# RR type SOA
|
6
|
+
#------------------------------------------------------------
|
7
|
+
class SOA < RR
|
8
|
+
attr_reader :mname, :rname, :serial, :refresh, :retry, :expire, :minimum
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def build_pack
|
13
|
+
@soa_pack = pack_name(@mname)
|
14
|
+
@soa_pack += pack_name(@rname)
|
15
|
+
@soa_pack += [@serial, @refresh, @retry, @expire, @minimum].pack("N5")
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_data
|
19
|
+
@soa_pack
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_inspect
|
23
|
+
"#{@mname} #{@rname} #{@serial} #{@refresh} #{@retry} #{@expire} #{@minimum}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def subclass_new_from_hash(args)
|
27
|
+
if args.key? :rdata
|
28
|
+
subclass_new_from_string(args[:rdata])
|
29
|
+
else
|
30
|
+
%i[mname rname serial refresh retry expire minimum].each do |key|
|
31
|
+
raise ArgumentError, "Missing field :#{key}" unless args.key? key
|
32
|
+
end
|
33
|
+
@mname = args[:mname] if valid? args[:mname]
|
34
|
+
@rname = args[:rname] if valid? args[:rname]
|
35
|
+
@serial = args[:serial] if number? args[:serial]
|
36
|
+
@refresh = args[:refresh] if number? args[:refresh]
|
37
|
+
@retry = args[:retry] if number? args[:retry]
|
38
|
+
@expire = args[:expire] if number? args[:expire]
|
39
|
+
@minimum = args[:minimum] if number? args[:minimum]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def number?(num)
|
44
|
+
if num.is_a?(Integer) && (num > 0)
|
45
|
+
true
|
46
|
+
else
|
47
|
+
raise ArgumentError, "Wrong format field: #{num} not a number or less than zero"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def subclass_new_from_string(str)
|
52
|
+
mname, rname, serial, refresh, ret, expire, minimum = str.strip.split(" ")
|
53
|
+
@mname = mname if valid? mname
|
54
|
+
@rname = rname if valid? rname
|
55
|
+
@serial, @refresh, @retry, @expire, @minimum = [serial, refresh, ret, expire, minimum].collect do |i|
|
56
|
+
i.to_i if valid? i.to_i
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def subclass_new_from_binary(data, offset)
|
61
|
+
@mname, offset = dn_expand(data, offset)
|
62
|
+
@rname, offset = dn_expand(data, offset)
|
63
|
+
@serial, @refresh, @retry, @expire, @minimum = data.unpack("@#{offset} N5")
|
64
|
+
offset + 5 * Net::DNS::INT32SZ
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def set_type
|
70
|
+
@type = Net::DNS::RR::Types.new("SOA")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Net # :nodoc:
|
2
|
+
module DNS
|
3
|
+
class RR
|
4
|
+
#------------------------------------------------------------
|
5
|
+
# RR type SRV
|
6
|
+
#------------------------------------------------------------
|
7
|
+
class SRV < RR
|
8
|
+
attr_reader :priority, :weight, :port, :host
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def build_pack
|
13
|
+
str = ""
|
14
|
+
end
|
15
|
+
|
16
|
+
def subclass_new_from_binary(data, offset)
|
17
|
+
off_end = offset + @rdlength
|
18
|
+
@priority, @weight, @port = data.unpack("@#{offset} n n n")
|
19
|
+
offset += 6
|
20
|
+
|
21
|
+
@host = []
|
22
|
+
while offset < off_end
|
23
|
+
len = data.unpack("@#{offset} C")[0]
|
24
|
+
offset += 1
|
25
|
+
str = data[offset..offset + len - 1]
|
26
|
+
offset += len
|
27
|
+
@host << str
|
28
|
+
end
|
29
|
+
@host = @host.join(".")
|
30
|
+
offset
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def set_type
|
36
|
+
@type = Net::DNS::RR::Types.new("SRV")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|