dns-zonefile 0.0.1 → 1.0.0

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.
@@ -0,0 +1,5 @@
1
+ module DNS
2
+ module Zonefile
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
@@ -8,12 +8,8 @@ describe "DNS::Zonefile" do
8
8
  }.should_not raise_error
9
9
  end
10
10
 
11
- it "should be version 0.0.1" do
12
- DNS::Zonefile::VERSION.should eql("0.0.1")
13
- end
14
-
15
- it "should have an origin" do
16
- DNS::Zonefile.new.should respond_to(:origin)
11
+ it "should be version 1.0.0" do
12
+ DNS::Zonefile::VERSION.should eql("1.0.0")
17
13
  end
18
14
 
19
15
  it "should provide a way of parsing a string" do
@@ -26,33 +22,78 @@ describe "DNS::Zonefile" do
26
22
  ; Hi! I'm an example zonefile.
27
23
  $ORIGIN example.com.
28
24
  $TTL 86400; expire in 1 day.
25
+ $OTHER abc
26
+ ; line above has spaces at the end, but no comment
29
27
  @ IN SOA ns.example.com. hostmaster.example.com. (
30
28
  2007120710 ; serial number of this zone file
31
29
  1d ; slave refresh (1 day)
32
30
  1d ; slave retry time in case of a problem (1 day)
33
- 4w ; slave expiration time (4 weeks)
34
- 1h ; minimum caching time in case of failed lookups (1 hour)
31
+ 4W ; slave expiration time (4 weeks)
32
+ 3600 ; minimum caching time in case of failed lookups (1 hour)
35
33
  )
36
34
  ; That's the SOA part done.
37
35
 
36
+ ; Next comment line has nothing after the semi-colon.
37
+ ;
38
+
38
39
  ; Let's start the resource records.
39
40
  example.com. NS ns ; ns.example.com is the nameserver for example.com
40
- example.com. NS ns.somewhere.com. ; ns.somewhere.com is a backup nameserver for example.co
41
- example.com. A 10.0.0.1 ; ip address for "example.com"
41
+ example.com. NS ns.somewhere.com. ; ns.somewhere.com is a backup nameserver for example.com
42
+ example.com. A 10.0.0.1 ; ip address for "example.com". next line has spaces after the IP, but no actual comment.
43
+ @ A 10.0.0.11
44
+ A 10.0.0.12 ; tertiary ip for "example.com"
42
45
  ns A 10.0.0.2 ; ip address for "ns.example.com"
46
+ 60 A 10.0.0.21 ; secondary ip for "ns.example.com" with TTL
47
+ * A 10.0.0.100 ; wildcard
48
+ *.sub A 10.0.0.101 ; subdomain wildcard
49
+ with-class IN A 10.0.0.3 ; record that includes the class type of IN
50
+ with-ttl 60 A 10.0.0.5 ; with a specified TTL
51
+ ttl-class 60 IN A 10.0.0.6 ; with TTL and class type
43
52
  www CNAME ns ; "www.example.com" is an alias for "ns.example.com"
44
53
  wwwtest CNAME www ; "wwwtest.example.com" is another alias for "www.example.com"
54
+ www2 CNAME ns.example.com. ; yet another alias, with FQDN target
45
55
 
46
56
  ; Email... that'll be fun then
47
57
  example.com. MX 10 mail.example.com. ; mail.example.com is the mailserver for example.com
48
58
  @ MX 20 mail2.example.com. ; Similar to above line, but using "@" to say "use $ORIGIN"
49
59
  @ MX 50 mail3 ; Similar to above line, but using a host within this domain
60
+
61
+ @ AAAA 2001:db8:a::1 ; IPv6, lowercase
62
+ ns AAAA 2001:DB8:B::1 ; IPv6, uppercase
63
+ mail AAAA 2001:db8:c::10.0.0.4 ; IPv6, with trailing IPv4-type address
64
+
65
+ sip NAPTR 100 10 "U" "E2U+sip" "!^.*$!sip:cs@example.com!i" . ; NAPTR record
66
+ sip2 NAPTR 100 10 "" "" "/urn:cid:.+@([^\\.]+\\.)(.*)$/\\2/i" . ; another one
67
+
68
+ _xmpp-server._tcp SRV 5 0 5269 xmpp-server.l.google.com. ; SRV record
69
+
70
+ ; TXT record, with embedded semicolons
71
+ _domainkey TXT "v=DKIM1\\;g=*\\;k=rsa\\; p=4tkw1bbkfa0ahfjgnbewr2ttkvahvfmfizowl9s4g0h28io76ndow25snl9iumpcv0jwxr2k"
72
+
73
+ @ TXT "some other \\"message\\" goes here" ; embedded quotes
74
+ long TXT "a multi-segment TXT record" "usually used for really long TXT records" "since each segment can only span 255 chars"
75
+ unquoted TXT some text data
76
+ @ SPF "v=spf1 a a:other.domain.com ~all"
77
+
78
+ 45 IN PTR @
79
+
80
+ $ORIGIN test.example.com.
81
+ $TTL 3600; expire in 1 day.
82
+ @ A 10.1.0.1 ; Test with alternate origin
83
+ MX 10 mail.example.com.
84
+ www A 10.1.0.2 ; www.test.example.com.
85
+
50
86
  ZONE
51
87
  end
52
88
 
53
89
  it "should set the origin correctly" do
54
90
  zone = DNS::Zonefile.parse(@zonefile)
55
- zone.origin.should eql('example.com.')
91
+ zone.origin.should eql('@')
92
+ end
93
+
94
+ it "should interpret the origin correctly" do
95
+ zone = DNS::Zonefile.load(@zonefile)
96
+ zone.soa.origin.should eql('example.com.')
56
97
  end
57
98
 
58
99
  it "should set the zone variables correctly" do
@@ -61,81 +102,240 @@ ZONE
61
102
  zone.variables['ORIGIN'].should eql('example.com.')
62
103
  end
63
104
 
64
- it "should set the SOA correctly" do
65
- zone = DNS::Zonefile.parse(@zonefile)
105
+ it "should interpret the SOA correctly" do
106
+ zone = DNS::Zonefile.load(@zonefile)
66
107
  soa = zone.soa
67
- soa.ns.to_s.should eql('ns.example.com.')
68
- soa.rp.to_s.should eql('hostmaster.example.com.')
69
- soa.serial.to_i.should eql(2007120710)
70
- soa.refresh.to_i.should eql(86400)
71
- soa.retry.to_i.should eql(86400)
72
- soa.expiry.to_i.should eql(2419200)
73
- soa.ttl.to_i.should eql(3600)
108
+ soa.klass.should eql('IN')
109
+ soa.ttl.should eql(86400)
110
+ soa.nameserver.should eql('ns.example.com.')
111
+ soa.responsible_party.should eql('hostmaster.example.com.')
112
+ soa.serial.should eql(2007120710)
113
+ soa.refresh_time.should eql(86400)
114
+ soa.retry_time.should eql(86400)
115
+ soa.expiry_time.should eql(2419200)
116
+ soa.nxttl.should eql(3600)
74
117
  end
75
118
 
76
119
  it "should build the correct number of resource records" do
77
120
  zone = DNS::Zonefile.parse(@zonefile)
78
- zone.rr.size.should be(9)
121
+ zone.rr.size.should be(33)
79
122
  end
80
123
 
81
124
  it "should build the correct NS records" do
82
- zone = DNS::Zonefile.parse(@zonefile)
83
- ns_records = zone.rr.select { |rr| rr.record_type == "NS" }
125
+ zone = DNS::Zonefile.load(@zonefile)
126
+ ns_records = zone.records_of DNS::Zonefile::NS
84
127
  ns_records.size.should be(2)
85
128
 
86
129
  ns_records.detect { |ns|
87
- ns.host.to_s == "example.com." && ns.nameserver.to_s == "ns.example.com."
130
+ ns.host == "example.com." && ns.nameserver == "ns.example.com."
88
131
  }.should_not be_nil
89
132
 
90
133
  ns_records.detect { |ns|
91
- ns.host.to_s == "example.com." && ns.nameserver.to_s == "ns.somewhere.com."
134
+ ns.host == "example.com." && ns.nameserver == "ns.somewhere.com." && ns.ttl == 86400
92
135
  }.should_not be_nil
93
136
  end
94
137
 
95
138
  it "should build the correct A records" do
96
- zone = DNS::Zonefile.parse(@zonefile)
97
- a_records = zone.rr.select { |rr| rr.record_type == "A" }
98
- a_records.size.should be(2)
139
+ zone = DNS::Zonefile.load(@zonefile)
140
+ a_records = zone.records_of DNS::Zonefile::A
141
+ a_records.size.should be(12)
142
+
143
+ a_records.detect { |a|
144
+ a.host == "example.com." && a.address == "10.0.0.1"
145
+ }.should_not be_nil
146
+
147
+ a_records.detect { |a|
148
+ a.host == "example.com." && a.address == "10.0.0.11"
149
+ }.should_not be_nil
150
+
151
+ a_records.detect { |a|
152
+ a.host == "example.com." && a.address == "10.0.0.12"
153
+ }.should_not be_nil
99
154
 
100
155
  a_records.detect { |a|
101
- a.host.to_s == "example.com." && a.ip_address.to_s == "10.0.0.1"
156
+ a.host == "ns.example.com." && a.address == "10.0.0.2" && a.ttl == 86400
102
157
  }.should_not be_nil
103
158
 
104
159
  a_records.detect { |a|
105
- a.host.to_s == "ns.example.com." && a.ip_address.to_s == "10.0.0.2"
160
+ a.host == "ns.example.com." && a.address == "10.0.0.21" && a.ttl == 60
161
+ }.should_not be_nil
162
+
163
+ a_records.detect { |a|
164
+ a.host == "*.example.com." && a.address == "10.0.0.100"
165
+ }.should_not be_nil
166
+
167
+ a_records.detect { |a|
168
+ a.host == "*.sub.example.com." && a.address == "10.0.0.101"
169
+ }.should_not be_nil
170
+
171
+ a_records.detect { |a|
172
+ a.host == "with-class.example.com." && a.address == "10.0.0.3" && a.ttl == 86400
173
+ }.should_not be_nil
174
+
175
+ a_records.detect { |a|
176
+ a.host == "with-ttl.example.com." && a.address == "10.0.0.5" && a.ttl == 60
177
+ }.should_not be_nil
178
+
179
+ a_records.detect { |a|
180
+ a.host == "ttl-class.example.com." && a.address == "10.0.0.6" && a.ttl == 60
181
+ }.should_not be_nil
182
+
183
+ a_records.detect { |a|
184
+ a.host == "test.example.com." && a.address == "10.1.0.1" && a.ttl == 3600
185
+ }.should_not be_nil
186
+
187
+ a_records.detect { |a|
188
+ a.host == "www.test.example.com." && a.address == "10.1.0.2" && a.ttl == 3600
106
189
  }.should_not be_nil
107
190
  end
108
191
 
109
192
  it "should build the correct CNAME records" do
110
- zone = DNS::Zonefile.parse(@zonefile)
111
- cname_records = zone.rr.select { |rr| rr.record_type == "CNAME" }
112
- cname_records.size.should be(2)
193
+ zone = DNS::Zonefile.load(@zonefile)
194
+ cname_records = zone.records_of DNS::Zonefile::CNAME
195
+ cname_records.size.should be(3)
196
+
197
+ cname_records.detect { |cname|
198
+ cname.host == "www.example.com." && cname.target == "ns.example.com."
199
+ }.should_not be_nil
113
200
 
114
201
  cname_records.detect { |cname|
115
- cname.alias.to_s == "www.example.com." && cname.host.to_s == "ns.example.com."
202
+ cname.host == "wwwtest.example.com." && cname.domainname == "www.example.com."
116
203
  }.should_not be_nil
117
204
 
118
205
  cname_records.detect { |cname|
119
- cname.alias.to_s == "wwwtest.example.com." && cname.host.to_s == "www.example.com."
206
+ cname.host == "www2.example.com." && cname.domainname == "ns.example.com." && cname.ttl == 86400
120
207
  }.should_not be_nil
121
208
  end
122
209
 
123
210
  it "should build the correct MX records" do
124
- zone = DNS::Zonefile.parse(@zonefile)
125
- mx_records = zone.rr.select { |rr| rr.record_type == "MX" }
126
- mx_records.size.should be(3)
211
+ zone = DNS::Zonefile.load(@zonefile)
212
+ mx_records = zone.records_of DNS::Zonefile::MX
213
+ mx_records.size.should be(4)
214
+
215
+ mx_records.detect { |mx|
216
+ mx.host == "example.com." && mx.priority == 10 && mx.exchanger == 'mail.example.com.'
217
+ }.should_not be_nil
127
218
 
128
219
  mx_records.detect { |mx|
129
- mx.host.to_s == "example.com." && mx.priority.to_i == 10 && mx.exchanger.to_s == 'mail.example.com.'
220
+ mx.host == "example.com." && mx.priority == 20 && mx.exchange == 'mail2.example.com.'
130
221
  }.should_not be_nil
131
222
 
132
223
  mx_records.detect { |mx|
133
- mx.host.to_s == "example.com." && mx.priority.to_i == 20 && mx.exchanger.to_s == 'mail2.example.com.'
224
+ mx.host == "example.com." && mx.priority == 50 && mx.domainname == 'mail3.example.com.' && mx.ttl == 86400
134
225
  }.should_not be_nil
135
226
 
136
227
  mx_records.detect { |mx|
137
- mx.host.to_s == "example.com." && mx.priority.to_i == 50 && mx.exchanger.to_s == 'mail3.example.com.'
228
+ mx.host == "test.example.com." && mx.priority == 10 && mx.domainname == 'mail.example.com.' && mx.ttl == 3600
229
+ }.should_not be_nil
230
+ end
231
+
232
+ it "should build the correct AAAA records" do
233
+ zone = DNS::Zonefile.load(@zonefile)
234
+ aaaa_records = zone.records_of DNS::Zonefile::AAAA
235
+ aaaa_records.size.should be(3)
236
+
237
+ aaaa_records.detect { |a|
238
+ a.host == "example.com." && a.address == "2001:db8:a::1"
239
+ }.should_not be_nil
240
+
241
+ aaaa_records.detect { |a|
242
+ a.host == "ns.example.com." && a.address == "2001:db8:b::1"
243
+ }.should_not be_nil
244
+
245
+ aaaa_records.detect { |a|
246
+ a.host == "mail.example.com." && a.address == "2001:db8:c::10.0.0.4" && a.ttl == 86400
247
+ }.should_not be_nil
248
+ end
249
+
250
+ it "should build the correct NAPTR records" do
251
+ zone = DNS::Zonefile.load(@zonefile)
252
+ naptr_records = zone.records_of DNS::Zonefile::NAPTR
253
+ naptr_records.size.should be(2)
254
+
255
+ naptr_records.detect { |r|
256
+ r.host == "sip.example.com." && r.data == '100 10 "U" "E2U+sip" "!^.*$!sip:cs@example.com!i" .'
257
+ }.should_not be_nil
258
+
259
+ naptr_records.detect { |r|
260
+ r.host == "sip2.example.com." && r.data == %q{100 10 "" "" "/urn:cid:.+@([^\\.]+\\.)(.*)$/\\2/i" .} && r.ttl == 86400
261
+ }.should_not be_nil
262
+ end
263
+
264
+ it "should build the correct SRV records" do
265
+ zone = DNS::Zonefile.load(@zonefile)
266
+ srv_records = zone.records_of DNS::Zonefile::SRV
267
+ srv_records.size.should be(1)
268
+
269
+ srv_records.detect { |r|
270
+ r.host == "_xmpp-server._tcp.example.com." && r.priority == 5 && r.weight == 0 && r.port == 5269 && r.target == 'xmpp-server.l.google.com.' && r.ttl == 86400
271
+ }.should_not be_nil
272
+ end
273
+
274
+ it "should build the correct TXT records" do
275
+ zone = DNS::Zonefile.load(@zonefile)
276
+ txt_records = zone.records_of DNS::Zonefile::TXT
277
+ txt_records.size.should be(4)
278
+
279
+ txt_records.detect { |r|
280
+ r.host == "_domainkey.example.com." && r.data == '"v=DKIM1\;g=*\;k=rsa\; p=4tkw1bbkfa0ahfjgnbewr2ttkvahvfmfizowl9s4g0h28io76ndow25snl9iumpcv0jwxr2k"'
281
+ }.should_not be_nil
282
+
283
+ txt_records.detect { |r|
284
+ r.host == "example.com." && r.data == '"some other \"message\" goes here"' && r.ttl == 86400
285
+ }.should_not be_nil
286
+
287
+ txt_records.detect { |r|
288
+ r.host == "long.example.com." && r.data == '"a multi-segment TXT record" "usually used for really long TXT records" "since each segment can only span 255 chars"'
289
+ }.should_not be_nil
290
+
291
+ txt_records.detect { |r|
292
+ r.host == "unquoted.example.com." && r.data == 'some text data'
138
293
  }.should_not be_nil
139
294
  end
295
+
296
+ it "should build the correct SPF records" do
297
+ zone = DNS::Zonefile.load(@zonefile)
298
+ spf_records = zone.records_of DNS::Zonefile::SPF
299
+ spf_records.size.should be(1)
300
+
301
+ spf_records.detect { |r|
302
+ r.host == "example.com." && r.data == '"v=spf1 a a:other.domain.com ~all"' && r.ttl == 86400
303
+ }.should_not be_nil
304
+ end
305
+
306
+ it "should build the correct PTR records" do
307
+ zone = DNS::Zonefile.load(@zonefile)
308
+ ptr_records = zone.records_of DNS::Zonefile::PTR
309
+ ptr_records.size.should be(1)
310
+
311
+ ptr_records.detect { |r|
312
+ r.host == "45.example.com." && r.target == 'example.com.' && r.ttl == 86400
313
+ }.should_not be_nil
314
+ end
315
+ end
316
+
317
+ describe "parsing an SOA without parens" do
318
+ before(:each) do
319
+ @zonefile =<<-ZONE
320
+ example.com. 86400 IN SOA ns0.example.com. hostmaster.example.com. 2006010558 43200 3600 1209600 180
321
+ example.com. 3600 IN A 1.2.3.4
322
+ example.com. 86400 IN SOA ns0.example.com. hostmaster.example.com. 2006010558 43200 3600 1209600 180
323
+
324
+ ZONE
325
+ end
326
+
327
+ it "should parse the SOA record correctly" do
328
+ zone = DNS::Zonefile.load(@zonefile)
329
+ soa = zone.soa
330
+ soa.klass.should eql('IN')
331
+ soa.ttl.should eql(86400)
332
+ soa.nameserver.should eql('ns0.example.com.')
333
+ soa.responsible_party.should eql('hostmaster.example.com.')
334
+ soa.serial.should eql(2006010558)
335
+ soa.refresh_time.should eql(43200)
336
+ soa.retry_time.should eql(3600)
337
+ soa.expiry_time.should eql(1209600)
338
+ soa.nxttl.should eql(180)
339
+ end
140
340
  end
141
341
  end
@@ -1,2 +1,2 @@
1
- require 'spec'
2
- require 'dns/zonefile'
1
+ require 'rspec'
2
+ require 'dns/zonefile'
metadata CHANGED
@@ -1,72 +1,101 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: dns-zonefile
3
- version: !ruby/object:Gem::Version
4
- version: 0.0.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
5
6
  platform: ruby
6
- authors:
7
+ authors:
7
8
  - Craig R Webster
8
- autorequire: dns/zonefile
9
+ autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
-
12
- date: 2010-01-13 00:00:00 +00:00
13
- default_executable:
14
- dependencies: []
15
-
16
- description: Parse and manipulate with DNS zonefiles. Great for working with BIND.
17
- email: craig@barkingiguana.com
12
+ date: 2011-10-26 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &70265569399900 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - =
20
+ - !ruby/object:Gem::Version
21
+ version: '2.6'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70265569399900
25
+ - !ruby/object:Gem::Dependency
26
+ name: treetop
27
+ requirement: &70265569399480 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70265569399480
36
+ - !ruby/object:Gem::Dependency
37
+ name: polyglot
38
+ requirement: &70265569399020 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70265569399020
47
+ description: ! "The format of a DNS Zonefile is defined in RFC 1035 section 5 and
48
+ RFC\n1034 section 3.6.1. To anyone who's using BIND they'll look very \nfamiliar.\n\nThis
49
+ is an attempt to use Ruby parse them into an object graph which can \nbe investigated
50
+ programatically, manipulated, validated or printed into \nsome canonical form."
51
+ email:
52
+ - craig@barkingiguana.com
18
53
  executables: []
19
-
20
54
  extensions: []
21
-
22
- extra_rdoc_files:
23
- - Rakefile
55
+ extra_rdoc_files: []
56
+ files:
57
+ - .gitignore
58
+ - Gemfile
59
+ - Gemfile.lock
60
+ - LICENCE
24
61
  - README
62
+ - Rakefile
25
63
  - TODO
64
+ - dns-zonefile.gemspec
65
+ - doc/example.com.zone
26
66
  - doc/example2.com.zone
27
67
  - doc/example3.com.zone
28
68
  - doc/zonefile.example
29
69
  - doc/zonefile.treetop
30
- files:
31
70
  - lib/dns/zonefile.rb
32
- - lib/dns/zonefile_parser.rb
71
+ - lib/dns/zonefile/parser.rb
72
+ - lib/dns/zonefile/version.rb
33
73
  - spec/dns/zonefile_spec.rb
34
74
  - spec/spec_helper.rb
35
- - Rakefile
36
- - README
37
- - TODO
38
- - doc/example2.com.zone
39
- - doc/example3.com.zone
40
- - doc/zonefile.example
41
- - doc/zonefile.treetop
42
- has_rdoc: true
43
- homepage: http://barkingiguana.com/
75
+ homepage: ''
44
76
  licenses: []
45
-
46
77
  post_install_message:
47
- rdoc_options:
48
- - --title
49
- - DNS::Zonefile -- Work with zonefiles
50
- require_paths:
78
+ rdoc_options: []
79
+ require_paths:
51
80
  - lib
52
- required_ruby_version: !ruby/object:Gem::Requirement
53
- requirements:
54
- - - ">="
55
- - !ruby/object:Gem::Version
56
- version: "0"
57
- version:
58
- required_rubygems_version: !ruby/object:Gem::Requirement
59
- requirements:
60
- - - ">="
61
- - !ruby/object:Gem::Version
62
- version: "0"
63
- version:
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
64
93
  requirements: []
65
-
66
- rubyforge_project:
67
- rubygems_version: 1.3.5
94
+ rubyforge_project: dns-zonefile
95
+ rubygems_version: 1.8.10
68
96
  signing_key:
69
97
  specification_version: 3
70
- summary: Parse and manipulate with DNS zonefiles.
71
- test_files: []
72
-
98
+ summary: Work with zonefiles (RFC 1035 section 5 and RFC 1034 section 3.6.1)
99
+ test_files:
100
+ - spec/dns/zonefile_spec.rb
101
+ - spec/spec_helper.rb