dns-zone2 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +2 -0
- data/HISTORY.md +45 -0
- data/README.md +151 -0
- data/Rakefile +15 -0
- data/dns-zone2.gemspec +41 -0
- data/lib/dns/zone.rb +207 -0
- data/lib/dns/zone/rr.rb +87 -0
- data/lib/dns/zone/rr/a.rb +21 -0
- data/lib/dns/zone/rr/aaaa.rb +5 -0
- data/lib/dns/zone/rr/cdnskey.rb +5 -0
- data/lib/dns/zone/rr/cds.rb +5 -0
- data/lib/dns/zone/rr/cname.rb +21 -0
- data/lib/dns/zone/rr/dlv.rb +5 -0
- data/lib/dns/zone/rr/dnskey.rb +38 -0
- data/lib/dns/zone/rr/ds.rb +38 -0
- data/lib/dns/zone/rr/hinfo.rb +31 -0
- data/lib/dns/zone/rr/mx.rb +33 -0
- data/lib/dns/zone/rr/naptr.rb +44 -0
- data/lib/dns/zone/rr/ns.rb +21 -0
- data/lib/dns/zone/rr/nsec.rb +32 -0
- data/lib/dns/zone/rr/nsec3.rb +45 -0
- data/lib/dns/zone/rr/nsec3param.rb +38 -0
- data/lib/dns/zone/rr/ptr.rb +21 -0
- data/lib/dns/zone/rr/record.rb +88 -0
- data/lib/dns/zone/rr/rrsig.rb +54 -0
- data/lib/dns/zone/rr/soa.rb +51 -0
- data/lib/dns/zone/rr/spf.rb +5 -0
- data/lib/dns/zone/rr/srv.rb +38 -0
- data/lib/dns/zone/rr/sshfp.rb +35 -0
- data/lib/dns/zone/rr/txt.rb +24 -0
- data/lib/dns/zone/test_case.rb +27 -0
- data/lib/dns/zone/version.rb +6 -0
- data/test/rr/a_test.rb +37 -0
- data/test/rr/aaaa_test.rb +27 -0
- data/test/rr/cdnskey_test.rb +31 -0
- data/test/rr/cds_test.rb +28 -0
- data/test/rr/cname_test.rb +19 -0
- data/test/rr/dlv_test.rb +28 -0
- data/test/rr/dnskey_test.rb +31 -0
- data/test/rr/ds_test.rb +28 -0
- data/test/rr/hinfo_test.rb +44 -0
- data/test/rr/mx_test.rb +26 -0
- data/test/rr/naptr_test.rb +60 -0
- data/test/rr/ns_test.rb +18 -0
- data/test/rr/nsec3_test.rb +33 -0
- data/test/rr/nsec3param_test.rb +29 -0
- data/test/rr/nsec_test.rb +24 -0
- data/test/rr/ptr_test.rb +19 -0
- data/test/rr/record_test.rb +37 -0
- data/test/rr/rrsig_test.rb +40 -0
- data/test/rr/soa_test.rb +34 -0
- data/test/rr/spf_test.rb +20 -0
- data/test/rr/srv_test.rb +24 -0
- data/test/rr/sshfp_test.rb +24 -0
- data/test/rr/txt_test.rb +44 -0
- data/test/rr_test.rb +50 -0
- data/test/version_test.rb +9 -0
- data/test/zone_test.rb +273 -0
- metadata +217 -0
data/lib/dns/zone/rr.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
module DNS
|
2
|
+
class Zone
|
3
|
+
|
4
|
+
# The module containes resource record types supported by this gem.
|
5
|
+
# The #{load} method will convert RR string data into a Ruby class.
|
6
|
+
module RR
|
7
|
+
|
8
|
+
REGEX_TTL = /\d+[wdmhs]?/i
|
9
|
+
REGEX_KLASS = /(?<klass>IN)?/i
|
10
|
+
REGEX_TYPE = /(?<type>A|AAAA|CDNSKEY|CDS|CNAME|DLV|DNSKEY|DS|HINFO|MX|NAPTR|NS|NSEC|NSEC3|NSEC3PARAM|RRSIG|SOA|SPF|SRV|SSHFP|TXT|PTR)\s{1}/i
|
11
|
+
REGEX_RR = /^(?<label>\S+|\s{1})\s*(?<ttl>#{REGEX_TTL})?\s*#{REGEX_KLASS}\s*#{REGEX_TYPE}\s*(?<rdata>[\s\S]*)$/i
|
12
|
+
REGEX_DOMAINNAME = /\S+\.?/i
|
13
|
+
REGEX_STRING = /((?:[^"\\]+|\\.)*)/
|
14
|
+
REGEX_CHARACTER_STRING = %r{
|
15
|
+
"#{DNS::Zone::RR::REGEX_STRING}"|#{DNS::Zone::RR::REGEX_STRING}
|
16
|
+
}mx
|
17
|
+
|
18
|
+
# Load RR string data and return an instance representing the RR.
|
19
|
+
#
|
20
|
+
# @param string [String] RR ASCII string data
|
21
|
+
# @param options [Hash] additional data required to correctly parse a 'whole' zone
|
22
|
+
# @option options [String] :last_label The last label used by the previous RR
|
23
|
+
# @return [Object]
|
24
|
+
def self.load(string, options = {})
|
25
|
+
# strip comments, unless its escaped.
|
26
|
+
# skip semicolons within "quote segments" (TXT records)
|
27
|
+
string.gsub!(/((?<!\\);)(?=(?:[^"]|"[^"]*")*$).*/o, "")
|
28
|
+
|
29
|
+
captures = string.match(REGEX_RR)
|
30
|
+
return nil unless captures
|
31
|
+
|
32
|
+
case captures[:type]
|
33
|
+
when 'A' then A.new.load(string, options)
|
34
|
+
when 'AAAA' then AAAA.new.load(string, options)
|
35
|
+
when 'CDNSKEY' then CDNSKEY.new.load(string, options)
|
36
|
+
when 'CDS' then CDS.new.load(string, options)
|
37
|
+
when 'CNAME' then CNAME.new.load(string, options)
|
38
|
+
when 'DLV' then DLV.new.load(string, options)
|
39
|
+
when 'DNSKEY' then DNSKEY.new.load(string, options)
|
40
|
+
when 'DS' then DS.new.load(string, options)
|
41
|
+
when 'HINFO' then HINFO.new.load(string, options)
|
42
|
+
when 'MX' then MX.new.load(string, options)
|
43
|
+
when 'NAPTR' then NAPTR.new.load(string, options)
|
44
|
+
when 'NS' then NS.new.load(string, options)
|
45
|
+
when 'NSEC' then NSEC.new.load(string, options)
|
46
|
+
when 'NSEC3' then NSEC3.new.load(string, options)
|
47
|
+
when 'NSEC3PARAM' then NSEC3PARAM.new.load(string, options)
|
48
|
+
when 'PTR' then PTR.new.load(string, options)
|
49
|
+
when 'RRSIG' then RRSIG.new.load(string, options)
|
50
|
+
when 'SOA' then SOA.new.load(string, options)
|
51
|
+
when 'SPF' then SPF.new.load(string, options)
|
52
|
+
when 'SRV' then SRV.new.load(string, options)
|
53
|
+
when 'SSHFP' then SSHFP.new.load(string, options)
|
54
|
+
when 'TXT' then TXT.new.load(string, options)
|
55
|
+
else
|
56
|
+
raise 'Unknown or unsupported RR Type'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
autoload :Record, 'dns/zone/rr/record'
|
61
|
+
|
62
|
+
autoload :A, 'dns/zone/rr/a'
|
63
|
+
autoload :AAAA, 'dns/zone/rr/aaaa'
|
64
|
+
autoload :CDNSKEY, 'dns/zone/rr/cdnskey'
|
65
|
+
autoload :CDS, 'dns/zone/rr/cds'
|
66
|
+
autoload :CNAME, 'dns/zone/rr/cname'
|
67
|
+
autoload :DLV, 'dns/zone/rr/dlv'
|
68
|
+
autoload :DNSKEY, 'dns/zone/rr/dnskey'
|
69
|
+
autoload :DS, 'dns/zone/rr/ds'
|
70
|
+
autoload :HINFO, 'dns/zone/rr/hinfo'
|
71
|
+
autoload :MX, 'dns/zone/rr/mx'
|
72
|
+
autoload :NAPTR, 'dns/zone/rr/naptr'
|
73
|
+
autoload :NS, 'dns/zone/rr/ns'
|
74
|
+
autoload :NSEC, 'dns/zone/rr/nsec'
|
75
|
+
autoload :NSEC3, 'dns/zone/rr/nsec3'
|
76
|
+
autoload :NSEC3PARAM, 'dns/zone/rr/nsec3param'
|
77
|
+
autoload :PTR, 'dns/zone/rr/ptr'
|
78
|
+
autoload :RRSIG, 'dns/zone/rr/rrsig'
|
79
|
+
autoload :SOA, 'dns/zone/rr/soa'
|
80
|
+
autoload :SPF, 'dns/zone/rr/spf'
|
81
|
+
autoload :SRV, 'dns/zone/rr/srv'
|
82
|
+
autoload :SSHFP, 'dns/zone/rr/sshfp'
|
83
|
+
autoload :TXT, 'dns/zone/rr/txt'
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# `A` resource record.
|
2
|
+
#
|
3
|
+
# RFC 1035
|
4
|
+
class DNS::Zone::RR::A < DNS::Zone::RR::Record
|
5
|
+
|
6
|
+
attr_accessor :address
|
7
|
+
|
8
|
+
def dump
|
9
|
+
parts = general_prefix
|
10
|
+
parts << address
|
11
|
+
parts.join(' ')
|
12
|
+
end
|
13
|
+
|
14
|
+
def load(string, options = {})
|
15
|
+
rdata = load_general_and_get_rdata(string, options)
|
16
|
+
return nil unless rdata
|
17
|
+
@address = rdata
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# `CNAME` resource record.
|
2
|
+
#
|
3
|
+
# RFC 1035
|
4
|
+
class DNS::Zone::RR::CNAME < DNS::Zone::RR::Record
|
5
|
+
|
6
|
+
attr_accessor :domainname
|
7
|
+
|
8
|
+
def dump
|
9
|
+
parts = general_prefix
|
10
|
+
parts << domainname
|
11
|
+
parts.join(' ')
|
12
|
+
end
|
13
|
+
|
14
|
+
def load(string, options = {})
|
15
|
+
rdata = load_general_and_get_rdata(string, options)
|
16
|
+
return nil unless rdata
|
17
|
+
@domainname = rdata
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# `DNSKEY` resource record.
|
2
|
+
#
|
3
|
+
# RFC 4034
|
4
|
+
class DNS::Zone::RR::DNSKEY < DNS::Zone::RR::Record
|
5
|
+
|
6
|
+
REGEX_DNSKEY_RDATA = %r{
|
7
|
+
(?<flags>\d+)\s*
|
8
|
+
(?<protocol>\d+)\s*
|
9
|
+
(?<algorithm>\d+)\s*
|
10
|
+
(?<key>#{DNS::Zone::RR::REGEX_STRING})\s*
|
11
|
+
}mx
|
12
|
+
|
13
|
+
attr_accessor :flags, :protocol, :algorithm, :key
|
14
|
+
|
15
|
+
def dump
|
16
|
+
parts = general_prefix
|
17
|
+
parts << flags
|
18
|
+
parts << protocol
|
19
|
+
parts << algorithm
|
20
|
+
parts << key
|
21
|
+
parts.join(' ')
|
22
|
+
end
|
23
|
+
|
24
|
+
def load(string, options = {})
|
25
|
+
rdata = load_general_and_get_rdata(string, options)
|
26
|
+
return nil unless rdata
|
27
|
+
|
28
|
+
captures = rdata.match(REGEX_DNSKEY_RDATA)
|
29
|
+
return nil unless captures
|
30
|
+
|
31
|
+
@flags = captures[:flags].to_i
|
32
|
+
@protocol = captures[:protocol].to_i
|
33
|
+
@algorithm = captures[:algorithm].to_i
|
34
|
+
@key = captures[:key].scan(/#{DNS::Zone::RR::REGEX_STRING}/).join
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# `DS` resource record.
|
2
|
+
#
|
3
|
+
# RFC 4034
|
4
|
+
class DNS::Zone::RR::DS < DNS::Zone::RR::Record
|
5
|
+
|
6
|
+
REGEX_DS_RDATA = %r{
|
7
|
+
(?<key_tag>\d+)\s*
|
8
|
+
(?<algorithm>\d+)\s*
|
9
|
+
(?<digest_type>\d+)\s*
|
10
|
+
(?<digest>#{DNS::Zone::RR::REGEX_STRING})\s*
|
11
|
+
}mx
|
12
|
+
|
13
|
+
attr_accessor :key_tag, :algorithm, :digest_type, :digest
|
14
|
+
|
15
|
+
def dump
|
16
|
+
parts = general_prefix
|
17
|
+
parts << key_tag
|
18
|
+
parts << algorithm
|
19
|
+
parts << digest_type
|
20
|
+
parts << digest
|
21
|
+
parts.join(' ')
|
22
|
+
end
|
23
|
+
|
24
|
+
def load(string, options = {})
|
25
|
+
rdata = load_general_and_get_rdata(string, options)
|
26
|
+
return nil unless rdata
|
27
|
+
|
28
|
+
captures = rdata.match(REGEX_DS_RDATA)
|
29
|
+
return nil unless captures
|
30
|
+
|
31
|
+
@key_tag = captures[:key_tag].to_i
|
32
|
+
@algorithm = captures[:algorithm].to_i
|
33
|
+
@digest_type = captures[:digest_type].to_i
|
34
|
+
@digest = captures[:digest].scan(/#{DNS::Zone::RR::REGEX_STRING}/).join
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# `HINFO` resource record.
|
2
|
+
#
|
3
|
+
# RFC 1035
|
4
|
+
class DNS::Zone::RR::HINFO < DNS::Zone::RR::Record
|
5
|
+
|
6
|
+
REGEX_HINFO_RDATA = %r{
|
7
|
+
(?<cpu>(?:#{DNS::Zone::RR::REGEX_CHARACTER_STRING})){1}\s
|
8
|
+
(?<os>(?:#{DNS::Zone::RR::REGEX_CHARACTER_STRING})){1}
|
9
|
+
}mx
|
10
|
+
attr_accessor :cpu
|
11
|
+
attr_accessor :os
|
12
|
+
|
13
|
+
def dump
|
14
|
+
parts = general_prefix
|
15
|
+
parts << %Q{"#{cpu}" "#{os}"}
|
16
|
+
parts.join(' ')
|
17
|
+
end
|
18
|
+
|
19
|
+
def load(string, options = {})
|
20
|
+
rdata = load_general_and_get_rdata(string, options)
|
21
|
+
return nil unless rdata
|
22
|
+
|
23
|
+
captures = rdata.match(REGEX_HINFO_RDATA)
|
24
|
+
return nil unless captures
|
25
|
+
|
26
|
+
@cpu = captures[:cpu].scan(/#{DNS::Zone::RR::REGEX_CHARACTER_STRING}/).join
|
27
|
+
@os = captures[:os].scan(/#{DNS::Zone::RR::REGEX_CHARACTER_STRING}/).join
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# `MX` resource record.
|
2
|
+
#
|
3
|
+
# RFC 1035
|
4
|
+
class DNS::Zone::RR::MX < DNS::Zone::RR::Record
|
5
|
+
|
6
|
+
REGEX_MX_RDATA = %r{
|
7
|
+
(?<priority>\d+)\s*
|
8
|
+
(?<exchange>#{DNS::Zone::RR::REGEX_DOMAINNAME})\s*
|
9
|
+
}mx
|
10
|
+
|
11
|
+
attr_accessor :priority
|
12
|
+
attr_accessor :exchange
|
13
|
+
|
14
|
+
def dump
|
15
|
+
parts = general_prefix
|
16
|
+
parts << priority
|
17
|
+
parts << exchange
|
18
|
+
parts.join(' ')
|
19
|
+
end
|
20
|
+
|
21
|
+
def load(string, options = {})
|
22
|
+
rdata = load_general_and_get_rdata(string, options)
|
23
|
+
return nil unless rdata
|
24
|
+
|
25
|
+
captures = rdata.match(REGEX_MX_RDATA)
|
26
|
+
return nil unless captures
|
27
|
+
|
28
|
+
@priority = captures[:priority].to_i
|
29
|
+
@exchange = captures[:exchange]
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# `NAPTR` resource record.
|
2
|
+
#
|
3
|
+
# RFC 3403
|
4
|
+
class DNS::Zone::RR::NAPTR < DNS::Zone::RR::Record
|
5
|
+
|
6
|
+
REGEX_NAPTR_RDATA = %r{
|
7
|
+
(?<order>\d+)\s*
|
8
|
+
(?<pref>\d+)\s*
|
9
|
+
(?<flags>#{DNS::Zone::RR::REGEX_CHARACTER_STRING})\s*
|
10
|
+
(?<service>#{DNS::Zone::RR::REGEX_CHARACTER_STRING})\s*
|
11
|
+
(?<regexp>#{DNS::Zone::RR::REGEX_CHARACTER_STRING})\s*
|
12
|
+
(?<replacement>#{DNS::Zone::RR::REGEX_DOMAINNAME}|\.{1})\s*
|
13
|
+
}mx
|
14
|
+
|
15
|
+
attr_accessor :order, :pref, :flags, :service, :regexp, :replacement
|
16
|
+
|
17
|
+
def dump
|
18
|
+
parts = general_prefix
|
19
|
+
parts << order
|
20
|
+
parts << pref
|
21
|
+
parts << %Q{"#{flags}"}
|
22
|
+
parts << %Q{"#{service}"}
|
23
|
+
parts << %Q{"#{regexp}"}
|
24
|
+
parts << replacement
|
25
|
+
parts.join(' ')
|
26
|
+
end
|
27
|
+
|
28
|
+
def load(string, options = {})
|
29
|
+
rdata = load_general_and_get_rdata(string, options)
|
30
|
+
return nil unless rdata
|
31
|
+
|
32
|
+
captures = rdata.match(REGEX_NAPTR_RDATA)
|
33
|
+
return nil unless captures
|
34
|
+
|
35
|
+
@order = captures[:order].to_i
|
36
|
+
@pref = captures[:pref].to_i
|
37
|
+
@flags = captures[:flags].scan(/#{DNS::Zone::RR::REGEX_CHARACTER_STRING}/).join
|
38
|
+
@service = captures[:service].scan(/#{DNS::Zone::RR::REGEX_CHARACTER_STRING}/).join
|
39
|
+
@regexp = captures[:regexp].scan(/#{DNS::Zone::RR::REGEX_CHARACTER_STRING}/).join
|
40
|
+
@replacement = captures[:replacement]
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# `NS` resource record.
|
2
|
+
#
|
3
|
+
# RFC 1035
|
4
|
+
class DNS::Zone::RR::NS < DNS::Zone::RR::Record
|
5
|
+
|
6
|
+
attr_accessor :nameserver
|
7
|
+
|
8
|
+
def dump
|
9
|
+
parts = general_prefix
|
10
|
+
parts << nameserver
|
11
|
+
parts.join(' ')
|
12
|
+
end
|
13
|
+
|
14
|
+
def load(string, options = {})
|
15
|
+
rdata = load_general_and_get_rdata(string, options)
|
16
|
+
return nil unless rdata
|
17
|
+
@nameserver = rdata
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# `NSEC` resource record.
|
2
|
+
#
|
3
|
+
# RFC 4034
|
4
|
+
class DNS::Zone::RR::NSEC < DNS::Zone::RR::Record
|
5
|
+
|
6
|
+
REGEX_NSEC_RDATA = %r{
|
7
|
+
(?<next_domain>#{DNS::Zone::RR::REGEX_DOMAINNAME})\s*
|
8
|
+
(?<rrset_types>#{DNS::Zone::RR::REGEX_STRING})\s*
|
9
|
+
}mx
|
10
|
+
|
11
|
+
attr_accessor :next_domain, :rrset_types
|
12
|
+
|
13
|
+
def dump
|
14
|
+
parts = general_prefix
|
15
|
+
parts << next_domain
|
16
|
+
parts << rrset_types
|
17
|
+
parts.join(' ')
|
18
|
+
end
|
19
|
+
|
20
|
+
def load(string, options = {})
|
21
|
+
rdata = load_general_and_get_rdata(string, options)
|
22
|
+
return nil unless rdata
|
23
|
+
|
24
|
+
captures = rdata.match(REGEX_NSEC_RDATA)
|
25
|
+
return nil unless captures
|
26
|
+
|
27
|
+
@next_domain = captures[:next_domain]
|
28
|
+
@rrset_types = captures[:rrset_types]
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# `NSEC3` resource record.
|
2
|
+
#
|
3
|
+
# RFC 5155
|
4
|
+
class DNS::Zone::RR::NSEC3 < DNS::Zone::RR::Record
|
5
|
+
|
6
|
+
REGEX_NSEC3_RDATA = %r{
|
7
|
+
(?<algorithm>\d+)\s*
|
8
|
+
(?<flags>\d+)\s*
|
9
|
+
(?<iterations>\d+)\s*
|
10
|
+
(?<salt>\S+)\s*
|
11
|
+
(?<next_hashed_owner_name>\S+)\s*
|
12
|
+
(?<rrset_types>#{DNS::Zone::RR::REGEX_STRING})\s*
|
13
|
+
}mx
|
14
|
+
|
15
|
+
attr_accessor :algorithm, :flags, :iterations, :salt,
|
16
|
+
:next_hashed_owner_name, :rrset_types
|
17
|
+
|
18
|
+
def dump
|
19
|
+
parts = general_prefix
|
20
|
+
parts << algorithm
|
21
|
+
parts << flags
|
22
|
+
parts << iterations
|
23
|
+
parts << salt
|
24
|
+
parts << next_hashed_owner_name
|
25
|
+
parts << rrset_types
|
26
|
+
parts.join(' ')
|
27
|
+
end
|
28
|
+
|
29
|
+
def load(string, options = {})
|
30
|
+
rdata = load_general_and_get_rdata(string, options)
|
31
|
+
return nil unless rdata
|
32
|
+
|
33
|
+
captures = rdata.match(REGEX_NSEC3_RDATA)
|
34
|
+
return nil unless captures
|
35
|
+
|
36
|
+
@algorithm = captures[:algorithm].to_i
|
37
|
+
@flags = captures[:flags].to_i
|
38
|
+
@iterations = captures[:iterations].to_i
|
39
|
+
@salt = captures[:salt]
|
40
|
+
@next_hashed_owner_name = captures[:next_hashed_owner_name]
|
41
|
+
@rrset_types = captures[:rrset_types]
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|