dns-zone2 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6f75671d72916d9ca1b4905cd91300b37126d716
|
4
|
+
data.tar.gz: b5a7f7f754bc0c3145efd379c29812dcee7f365f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7b05d6fcc4b0209db6c000e7febc9cec4c55fa6d3d5caae968a34540f8ece38546f04ca4bf130fdebbbd4c9008fe7f636b554d53002966124e062304656a9b8e
|
7
|
+
data.tar.gz: 3f3f32885b598a05e9bdc64d34264c85e4fe55a173038380e7f8292e20a332d479d34a302212917faeaf04272e0c11a9c7a5bc36ec449dbc90dc70de185bec26
|
data/Gemfile
ADDED
data/HISTORY.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
## HEAD
|
2
|
+
|
3
|
+
## 0.3.1 (2015-12-23)
|
4
|
+
|
5
|
+
* Fix edge case when zone file has multiple `ORIGIN` directives.
|
6
|
+
|
7
|
+
## 0.3.0 (2015-12-23)
|
8
|
+
|
9
|
+
* Requires Ruby version >= 2.0
|
10
|
+
* Ability to parse zone file with multiple `ORIGIN` directives.
|
11
|
+
|
12
|
+
## 0.2.0 (2015-10-20)
|
13
|
+
|
14
|
+
Development sponsored by Peter J. Philipp [centroid.eu](http://centroid.eu)
|
15
|
+
|
16
|
+
* Add support for DNSSEC focused RR Types:
|
17
|
+
- RFC 3403: NAPTR
|
18
|
+
- RFC 4255: SSHFP
|
19
|
+
- RFC 4034: DNSKEY, DS, RRSIG, NSEC
|
20
|
+
- RFC 7344: CDNSKEY, CDS
|
21
|
+
- RFC 4431: DLV
|
22
|
+
- RFC 5155: NSEC3, NSEC3PARAM
|
23
|
+
* Allow unqualified `domain-name` labels.
|
24
|
+
* Allow `ORIGIN` to be specified as an optional parameter when loading a zone, e.g. `zone = DNS::Zone.load(zone_as_string, 'example.com.')`
|
25
|
+
|
26
|
+
# 0.1.4 (no gem release)
|
27
|
+
|
28
|
+
* Add helper method to quickly access (or create) SOA.
|
29
|
+
* Add `dump_pretty` method to `DNS::Zone`.
|
30
|
+
|
31
|
+
## 0.1.3 (2014-10-21)
|
32
|
+
|
33
|
+
* Fix TXT record parsing bug, when quote enclosed RDATA contained semicolons.
|
34
|
+
|
35
|
+
## 0.1.1 (2014-03-30)
|
36
|
+
|
37
|
+
* Remove `required_ruby_version` from gemspec.
|
38
|
+
|
39
|
+
## 0.1.0 (2014-03-30)
|
40
|
+
|
41
|
+
* Initial non-alpha release with support for common resource records.
|
42
|
+
|
43
|
+
## 0.0.0 (2014-02-16)
|
44
|
+
|
45
|
+
* Initial development/hacking initiated.
|
data/README.md
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
dns-zone
|
2
|
+
========
|
3
|
+
|
4
|
+
[![Build Status](https://secure.travis-ci.org/lantins/dns-zone.png?branch=master)](http://travis-ci.org/lantins/dns-zone)
|
5
|
+
[![Gem Version](https://badge.fury.io/rb/dns-zone.png)](http://badge.fury.io/rb/dns-zone)
|
6
|
+
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/lantins/dns-zone/blob/master/LICENSE)
|
7
|
+
[![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/github/lantins/dns-zone/master/frames)
|
8
|
+
|
9
|
+
A Ruby library for building, parsing and manipulating DNS zone files.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your Gemfile:
|
14
|
+
|
15
|
+
gem 'dns-zone'
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
bundle install
|
20
|
+
|
21
|
+
Require the gem in your code:
|
22
|
+
|
23
|
+
require 'dns/zone'
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
### Loading a zone file
|
28
|
+
|
29
|
+
zone = DNS::Zone.load(zone_as_string)
|
30
|
+
|
31
|
+
### Loading a zone file, without an `$ORIGIN` directive
|
32
|
+
|
33
|
+
zone = DNS::Zone.load(zone_as_string, "example.com.")
|
34
|
+
|
35
|
+
### Creating a new zone programmatically
|
36
|
+
|
37
|
+
zone = DNS::Zone.new
|
38
|
+
zone.origin = 'example.com.'
|
39
|
+
zone.ttl = '1d'
|
40
|
+
|
41
|
+
# quick access to SOA RR
|
42
|
+
zone.soa.nameserver = 'ns0.lividpenguin.com.'
|
43
|
+
zone.soa.email = 'hostmaster.lividpenguin.com.'
|
44
|
+
|
45
|
+
# add an A RR
|
46
|
+
rec = DNS::Zone::RR::A.new
|
47
|
+
rec.address = '127.0.0.1'
|
48
|
+
zone.records << rec
|
49
|
+
|
50
|
+
# output using dns zone file format
|
51
|
+
zone.dump
|
52
|
+
|
53
|
+
# Development
|
54
|
+
|
55
|
+
## Development Commands
|
56
|
+
|
57
|
+
# install external gem dependencies first
|
58
|
+
bundle install
|
59
|
+
|
60
|
+
# run all tests and build code coverage
|
61
|
+
bundle exec rake test
|
62
|
+
|
63
|
+
# hints where to improve docs
|
64
|
+
bundle exec inch
|
65
|
+
|
66
|
+
# watch for changes and run development commands (tests, documentation, etc)
|
67
|
+
bundle exec guard
|
68
|
+
|
69
|
+
# Acknowledgement
|
70
|
+
|
71
|
+
Special thanks to Peter J. Philipp [centroid.eu](http://centroid.eu) for sponsoring the 0.2.0 release of dns-zone.
|
72
|
+
|
73
|
+
---
|
74
|
+
|
75
|
+
# TODO
|
76
|
+
|
77
|
+
## Must have
|
78
|
+
|
79
|
+
[x] Ability to load a zone made of multiple RR's
|
80
|
+
[x] Add support for RR Type: SOA
|
81
|
+
[x] Add support for RR Type: NS
|
82
|
+
[x] Add support for RR Type: MX
|
83
|
+
[x] Add support for RR Type: AAAA
|
84
|
+
[x] Add support for RR Type: A
|
85
|
+
[x] Add support for RR Type: CNAME
|
86
|
+
[x] Add support for RR Type: TXT
|
87
|
+
[x] Add support for RR Type: SRV
|
88
|
+
[x] Add support for RR Type: PTR
|
89
|
+
[x] Add support for RR Type: SPF
|
90
|
+
[x] Add support for RR Type: HINFO
|
91
|
+
[x] Support loading zone where some records have an empty label
|
92
|
+
|
93
|
+
[x] Add support for RR Type: NAPTR (RFC 3403)
|
94
|
+
[x] Add support for RR Type: SSHFP (RFC 4255)
|
95
|
+
|
96
|
+
[ ] Add test using real bind zone file, with DNSSEC RR's.
|
97
|
+
[ ] Add support for DNSSEC (RFC 4034) RR Types:
|
98
|
+
[x] DNSKEY
|
99
|
+
[ ] Algorithm may be integer or mnemonic.
|
100
|
+
[x] RRSIG
|
101
|
+
[ ] Algorithm may be integer or mnemonic.
|
102
|
+
[x] NSEC
|
103
|
+
[ ] Handle "Type Bit Maps" better, much better...
|
104
|
+
[x] DS
|
105
|
+
[ ] Add support for DNSSEC (RFC 5155) RR Types:
|
106
|
+
[x] NSEC3
|
107
|
+
[x] NSEC3PARAM
|
108
|
+
[ ] Correctly handle "Presentation Format" as defined in RFC.
|
109
|
+
|
110
|
+
[x] Add support for DNSSEC (RFC 4431 & RFC 7344) RR Types:
|
111
|
+
[x] CDNSKEY (identical to DNSKEY)
|
112
|
+
[x] CDS (identical to DS)
|
113
|
+
[x] DLV (identical to DS)
|
114
|
+
|
115
|
+
[ ] Look at newly added DNSSEC RR's and rename fields to be more appropriate, where required.
|
116
|
+
|
117
|
+
## Would be nice
|
118
|
+
|
119
|
+
[ ] Basic validation, error checking:
|
120
|
+
[ ] Only one SOA per zone.
|
121
|
+
[ ] CNAMEs can't use a label of `@`.
|
122
|
+
[ ] PTR zones have some extra conditions:
|
123
|
+
[ ] labels cant be repeated
|
124
|
+
[ ] names should end in a dot, otherwise they are invalid after expansion
|
125
|
+
[ ] IPv4 and IPv6 cant be mixed
|
126
|
+
|
127
|
+
[ ] Ability to 'include' defaults/records into a zone.
|
128
|
+
This may or may not mean supporting the `$INCLUDE` directive.
|
129
|
+
|
130
|
+
## At some point; low priority
|
131
|
+
|
132
|
+
[ ] Configuration options:
|
133
|
+
[ ] spaces/tabs used between RR params in zone file output
|
134
|
+
[ ] time format used in output (should parse both formats, seconds or bind time format (e.g. 1d))
|
135
|
+
[ ] add comments to explain TTL's that are in seconds
|
136
|
+
[ ] Ability to add comment to RR (n.b. currently we strip comments when parsing)
|
137
|
+
[ ] Add support for RR Type: LOC (RFC 1876)
|
138
|
+
[ ] Add support for RR Type: DNAME (RFC 2672)
|
139
|
+
[ ] Add support for RR Type: KEY
|
140
|
+
[ ] Add support for RR Type: RP
|
141
|
+
[ ] Add support for RR Type: RT
|
142
|
+
|
143
|
+
# Misc. Development Notes
|
144
|
+
|
145
|
+
- RR Format: `[<TTL>] [<class>] <type> <RDATA>`
|
146
|
+
- A DNS zone is built from RR's and a couple of other special directives.
|
147
|
+
- If zone file does not include $ORIGIN, it will be inferred by the `zone "<zone-name>" {}` clause from bind.conf
|
148
|
+
In general we should always explicitly define an $ORIGIN directive unless there is a very good reason not to.
|
149
|
+
- [RFC 1035 - Domain Names - Implementation and Specification](http://www.ietf.org/rfc/rfc1035.txt)
|
150
|
+
- [RFC 2308 - Negative Caching of DNS Queries (DNS NCACHE)](http://www.ietf.org/rfc/rfc2308.txt)
|
151
|
+
- [RFC 3596 - DNS Extensions to Support IP Version 6](http://www.ietf.org/rfc/rfc3596.txt)
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rubygems' unless defined?(Gem)
|
2
|
+
require 'bundler'
|
3
|
+
require 'rake'
|
4
|
+
require 'rake/testtask'
|
5
|
+
|
6
|
+
# by default run unit tests.
|
7
|
+
task :default => 'test'
|
8
|
+
|
9
|
+
desc 'Run full test suite and generate code coverage -- COVERAGE=false to disable code coverage'
|
10
|
+
Rake::TestTask.new(:test) do |task|
|
11
|
+
ENV['COVERAGE'] ||= 'yes'
|
12
|
+
task.libs << 'test'
|
13
|
+
task.pattern = 'test/**/*_test.rb'
|
14
|
+
task.verbose = true
|
15
|
+
end
|
data/dns-zone2.gemspec
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require './lib/dns/zone/version'
|
2
|
+
|
3
|
+
spec = Gem::Specification.new do |s|
|
4
|
+
# gem information/details
|
5
|
+
s.name = 'dns-zone2'
|
6
|
+
s.version = DNS::Zone::Version
|
7
|
+
s.date = Time.now.strftime('%Y-%m-%d')
|
8
|
+
s.summary = 'A Ruby library for building and parsing DNS zone files.'
|
9
|
+
s.license = 'MIT'
|
10
|
+
s.homepage = 'https://github.com/hetznerZA/dns-zone2'
|
11
|
+
s.authors = ['Hetzner']
|
12
|
+
s.email = ['seals@hetzner.co.za ']
|
13
|
+
|
14
|
+
# gem settings for what files to include.
|
15
|
+
s.files = %w(Rakefile README.md HISTORY.md Gemfile dns-zone2.gemspec)
|
16
|
+
s.files += Dir.glob('{test/**/*,lib/**/*}')
|
17
|
+
s.require_paths = ['lib']
|
18
|
+
#s.executables = ['dns-zone']
|
19
|
+
#s.default_executable = 'dns-zone'
|
20
|
+
|
21
|
+
# min ruby version
|
22
|
+
s.required_ruby_version = ::Gem::Requirement.new(">= 2.0")
|
23
|
+
|
24
|
+
# cross platform gem dependencies
|
25
|
+
#s.add_dependency('gli')
|
26
|
+
#s.add_dependency('paint')
|
27
|
+
s.add_development_dependency('bundler', '~> 1.0')
|
28
|
+
s.add_development_dependency('rake', '>= 9.0')
|
29
|
+
s.add_development_dependency('minitest', '~> 5.0')
|
30
|
+
s.add_development_dependency('simplecov', '~> 0.7.1')
|
31
|
+
s.add_development_dependency('yard', '~> 0.8')
|
32
|
+
s.add_development_dependency('inch', '~> 0.6')
|
33
|
+
s.add_development_dependency('guard-minitest', '~> 2.0')
|
34
|
+
s.add_development_dependency('guard-bundler', '~> 2.0')
|
35
|
+
|
36
|
+
# long description.
|
37
|
+
s.description = <<-EOL
|
38
|
+
A Ruby library for building and parsing DNS zone files for use with
|
39
|
+
Bind and PowerDNS (with Bind backend) DNS servers.
|
40
|
+
EOL
|
41
|
+
end
|
data/lib/dns/zone.rb
ADDED
@@ -0,0 +1,207 @@
|
|
1
|
+
require 'dns/zone/rr'
|
2
|
+
require 'dns/zone/version'
|
3
|
+
|
4
|
+
# :nodoc:
|
5
|
+
module DNS
|
6
|
+
|
7
|
+
# Represents a 'whole' zone of many resource records (RRs).
|
8
|
+
#
|
9
|
+
# This is also the primary namespace for the `dns-zone` gem.
|
10
|
+
class Zone
|
11
|
+
|
12
|
+
# The default $TTL (directive) of the zone.
|
13
|
+
attr_accessor :ttl
|
14
|
+
# The primary $ORIGIN (directive) of the zone.
|
15
|
+
attr_accessor :origin
|
16
|
+
# Array of all the zones RRs (including the SOA).
|
17
|
+
attr_accessor :records
|
18
|
+
|
19
|
+
# Create an empty instance of a DNS zone that you can drive programmatically.
|
20
|
+
#
|
21
|
+
# @api public
|
22
|
+
def initialize
|
23
|
+
@records = []
|
24
|
+
soa = DNS::Zone::RR::SOA.new
|
25
|
+
# set a couple of defaults on the SOA
|
26
|
+
soa.serial = Time.now.utc.strftime("%Y%m%d01")
|
27
|
+
soa.refresh_ttl = '3h'
|
28
|
+
soa.retry_ttl = '15m'
|
29
|
+
soa.expiry_ttl = '4w'
|
30
|
+
soa.minimum_ttl = '30m'
|
31
|
+
end
|
32
|
+
|
33
|
+
# Helper method to access the zones SOA RR.
|
34
|
+
#
|
35
|
+
# @api public
|
36
|
+
def soa
|
37
|
+
# return the first SOA we find in the records array.
|
38
|
+
rr = @records.find { |rr| rr.type == "SOA" }
|
39
|
+
return rr if rr
|
40
|
+
# otherwise create a new SOA
|
41
|
+
rr = DNS::Zone::RR::SOA.new
|
42
|
+
rr.serial = Time.now.utc.strftime("%Y%m%d01")
|
43
|
+
rr.refresh_ttl = '3h'
|
44
|
+
rr.retry_ttl = '15m'
|
45
|
+
rr.expiry_ttl = '4w'
|
46
|
+
rr.minimum_ttl = '30m'
|
47
|
+
# store and return new SOA
|
48
|
+
@records << rr
|
49
|
+
return rr
|
50
|
+
end
|
51
|
+
|
52
|
+
# Generates output of the zone and its records.
|
53
|
+
#
|
54
|
+
# @api public
|
55
|
+
def dump
|
56
|
+
content = []
|
57
|
+
|
58
|
+
@records.each do |rr|
|
59
|
+
content << rr.dump
|
60
|
+
end
|
61
|
+
|
62
|
+
content.join("\n") << "\n"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Generates pretty output of the zone and its records.
|
66
|
+
#
|
67
|
+
# @api public
|
68
|
+
def dump_pretty
|
69
|
+
content = []
|
70
|
+
|
71
|
+
last_type = "SOA"
|
72
|
+
sorted_records.each do |rr|
|
73
|
+
content << '' if last_type != rr.type
|
74
|
+
content << rr.dump
|
75
|
+
last_type = rr.type
|
76
|
+
end
|
77
|
+
|
78
|
+
content.join("\n") << "\n"
|
79
|
+
end
|
80
|
+
|
81
|
+
# Load the provided zone file data into a new DNS::Zone object.
|
82
|
+
#
|
83
|
+
# @api public
|
84
|
+
def self.load(string, default_origin = "")
|
85
|
+
# get entries
|
86
|
+
entries = self.extract_entries(string)
|
87
|
+
|
88
|
+
instance = self.new
|
89
|
+
|
90
|
+
options = {}
|
91
|
+
entries.each do |entry|
|
92
|
+
# read in special statments like $TTL and $ORIGIN
|
93
|
+
if entry =~ /\$(ORIGIN|TTL)\s+(.+)/
|
94
|
+
instance.ttl = $2 if $1 == 'TTL'
|
95
|
+
if $1 == 'ORIGIN'
|
96
|
+
instance.origin ||= $2
|
97
|
+
options[:origin] ||= $2
|
98
|
+
options[:last_origin] = $2
|
99
|
+
end
|
100
|
+
next
|
101
|
+
end
|
102
|
+
|
103
|
+
# parse each RR and create a Ruby object for it
|
104
|
+
if entry =~ DNS::Zone::RR::REGEX_RR
|
105
|
+
rec = DNS::Zone::RR.load(entry, options)
|
106
|
+
next unless rec
|
107
|
+
instance.records << rec
|
108
|
+
options[:last_label] = rec.label
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# use default_origin if we didn't see a ORIGIN directive in the zone
|
113
|
+
if instance.origin.to_s.empty? && !default_origin.empty?
|
114
|
+
instance.origin = default_origin
|
115
|
+
end
|
116
|
+
|
117
|
+
return instance
|
118
|
+
end
|
119
|
+
|
120
|
+
# Extract entries from a zone file that will be later parsed as RRs.
|
121
|
+
#
|
122
|
+
# @api private
|
123
|
+
def self.extract_entries(string)
|
124
|
+
# FROM RFC:
|
125
|
+
# The format of these files is a sequence of entries. Entries are
|
126
|
+
# predominantly line-oriented, though parentheses can be used to continue
|
127
|
+
# a list of items across a line boundary, and text literals can contain
|
128
|
+
# CRLF within the text. Any combination of tabs and spaces act as a
|
129
|
+
# delimiter between the separate items that make up an entry. The end of
|
130
|
+
# any line in the master file can end with a comment. The comment starts
|
131
|
+
# with a ";" (semicolon).
|
132
|
+
|
133
|
+
entries = []
|
134
|
+
mode = :line
|
135
|
+
entry = ''
|
136
|
+
|
137
|
+
parentheses_ref_count = 0
|
138
|
+
|
139
|
+
string.lines.each do |line|
|
140
|
+
# strip comments unless escaped
|
141
|
+
# strip comments, unless its escaped.
|
142
|
+
# skip semicolons within "quote segments" (TXT records)
|
143
|
+
line = line.gsub(/((?<!\\);)(?=(?:[^"]|"[^"]*")*$).*/o, "").chomp
|
144
|
+
|
145
|
+
next if line.gsub(/\s+/, '').empty?
|
146
|
+
|
147
|
+
# append to entry line
|
148
|
+
entry << line
|
149
|
+
|
150
|
+
quotes = entry.count('"')
|
151
|
+
has_quotes = quotes > 0
|
152
|
+
|
153
|
+
parentheses = entry.count('()')
|
154
|
+
has_parentheses = parentheses > 0
|
155
|
+
|
156
|
+
if has_quotes
|
157
|
+
character_strings = entry.scan(/("(?:[^"\\]+|\\.)*")/).join(' ')
|
158
|
+
without = entry.gsub(/"((?:[^"\\]+|\\.)*)"/, '')
|
159
|
+
parentheses_ref_count = without.count('(') - without.count(')')
|
160
|
+
else
|
161
|
+
parentheses_ref_count = entry.count('(') - entry.count(')')
|
162
|
+
end
|
163
|
+
|
164
|
+
# are parentheses balanced?
|
165
|
+
if parentheses_ref_count == 0
|
166
|
+
if has_quotes
|
167
|
+
without.gsub!(/[()]/, '')
|
168
|
+
without.gsub!(/[ ]{2,}/, ' ')
|
169
|
+
#entries << (without + character_strings)
|
170
|
+
entry = (without + character_strings)
|
171
|
+
else
|
172
|
+
entry.gsub!(/[()]/, '')
|
173
|
+
entry.gsub!(/[ ]{2,}/, ' ')
|
174
|
+
entry.gsub!(/[ ]+$/, '')
|
175
|
+
#entries << entry
|
176
|
+
end
|
177
|
+
entries << entry
|
178
|
+
entry = ''
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
return entries
|
184
|
+
end
|
185
|
+
|
186
|
+
private
|
187
|
+
|
188
|
+
# Records sorted with more important types being at the top.
|
189
|
+
#
|
190
|
+
# @api private
|
191
|
+
def sorted_records
|
192
|
+
# pull out RRs we want to stick near the top
|
193
|
+
top_rrs = {}
|
194
|
+
top = %w{SOA NS MX SPF TXT}
|
195
|
+
top.each { |t| top_rrs[t] = @records.select { |rr| rr.type == t } }
|
196
|
+
|
197
|
+
remaining = @records.reject { |rr| top.include?(rr.type) }
|
198
|
+
|
199
|
+
# sort remaining RRs by type, alphabeticly
|
200
|
+
remaining.sort! { |a,b| a.type <=> b.type }
|
201
|
+
|
202
|
+
top_rrs.values.flatten + remaining
|
203
|
+
end
|
204
|
+
|
205
|
+
|
206
|
+
end
|
207
|
+
end
|