Class: Bind9mgr::Zone

Inherits:
Object
  • Object
show all
Defined in:
lib/zone.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(zone_name = nil, zone_db_file = nil, options = { }) ⇒ Zone

Returns a new instance of Zone.



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/zone.rb', line 7

def initialize( zone_name = nil, zone_db_file = nil, options = { } )
  self.origin = zone_name
  @file = zone_db_file
  @options = options

  @default_ttl ||= 86400
  @options[:serial] ||= 109
  @options[:refresh] ||= 3600
  @options[:retry] ||= 3600
  @options[:expiry] ||= 604800
  @options[:default_ttl] ||= 86400
  
  clear_records

  self
end

Instance Attribute Details

#default_ttlObject

Returns the value of attribute default_ttl.



3
4
5
# File 'lib/zone.rb', line 3

def default_ttl
  @default_ttl
end

#fileObject

Returns the value of attribute file.



4
5
6
# File 'lib/zone.rb', line 4

def file
  @file
end

#optionsObject

Returns the value of attribute options.



4
5
6
# File 'lib/zone.rb', line 4

def options
  @options
end

#recordsObject (readonly)

Returns the value of attribute records.



5
6
7
# File 'lib/zone.rb', line 5

def records
  @records
end

Class Method Details

.domain_name_syntax_valid(string) ⇒ Object



164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/zone.rb', line 164

def self.domain_name_syntax_valid( string )
  # ! string.match(/^([\w\d\-]{2,}\.)+(\w{2,})\.?$/).nil?
  # ! string.match(/^(((xn--)?[a-z0-9](-?[a-z0-9]+)*\.)+((xn--[a-z0-9](-?[a-z0-9]+)*)|([a-z]{2,})))?$/).nil?
  # ! string.match(/^(([^\W_]+\.)*xn--)?[^\W_]+([-.][^\W_]+)*\.[a-z]{2,6}\.?$/).nil?

  # TODO Постараться выразить в одном регулярном выражении
  if string.match(/^xn--/)
    ! string.match(/^xn--([a-z0-9](-?[a-z0-9]+)){2,}*\.((xn--[a-z0-9](-?[a-z0-9]+)*)|([a-z]{2,}))?\.?$/).nil?
  elsif string.match(/(com|net|org|biz|me|pro)$/)
    ! string.match(/^([\w\d\-]+\.)+(\w{2,})\.?$/).nil?
  else
    ! string.match(/^([\w\d\-]{2,}\.)+(\w{2,})\.?$/).nil?
  end
end

.validete_rrs_uniqueness(rrs_array) ⇒ Object

rrs_array is a array like: [[owner, ttl, klass, type, rdata], …]



47
48
49
50
51
52
53
# File 'lib/zone.rb', line 47

def self.validete_rrs_uniqueness( rrs_array )
  array = []
  rrs_array.each do |owner, ttl, klass, type, rdata|
    raise( ArgumentError, "owner, type and rdata have to be unique" ) if array.include? [owner,type,rdata]
    array.push [owner,type,rdata]
  end
end

Instance Method Details

#add_default_rrsObject

Raises:

  • (ArgumentError)


101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/zone.rb', line 101

def add_default_rrs
  raise ArgumentError, "Main ns not specified" unless @options[:main_ns]
  # TODO main server ip should be renamed to default server ip (or what?)
  raise ArgumentError, "Main server ip not specified" unless @options[:main_server_ip]

  ensure_soa_rr( default_soa )
  ensure_rr( ResourceRecord.new('@', nil, 'IN', 'A', @options[:main_server_ip]) )
  ensure_rr( ResourceRecord.new('@', nil, 'IN', 'NS', @options[:main_ns]) )
  ensure_rr( ResourceRecord.new('@', nil, 'IN', 'NS', @options[:secondary_ns]) ) if @options[:secondary_ns]
  # ensure_rr( ResourceRecord.new('@', nil, 'IN', 'MX', ['90', @options[:mail_server_ip]]) )
  ensure_rr( ResourceRecord.new('www', nil, nil, 'CNAME', '@') )
end

#add_rr(owner, ttl, klass, type, rdata) ⇒ Object



114
115
116
117
# File 'lib/zone.rb', line 114

def add_rr( owner, ttl, klass, type, rdata )
  initialized?
  @records.push ResourceRecord.new(owner, ttl, klass, type, rdata)
end

#clear_recordsObject



143
144
145
# File 'lib/zone.rb', line 143

def clear_records
  @records = []
end

#ensure_rr(record) ⇒ Object

Raises:

  • (ArgumentError)


156
157
158
159
160
161
162
# File 'lib/zone.rb', line 156

def ensure_rr record
  raise ArgumentError, "record expected to be Bind9mgr::ResourceRecord" unless record.kind_of? ResourceRecord
  current_record = @records.find{ |rr| (rr.owner == record.owner) && (rr.type == record.type) && (rr.rdata == record.rdata) }
  return false if current_record
  @records.push record
  true
end

#ensure_soa_rr(record) ⇒ Object

Raises:

  • (ArgumentError)


147
148
149
150
151
152
153
154
# File 'lib/zone.rb', line 147

def ensure_soa_rr record
  raise ArgumentError, "record expected to be Bind9mgr::ResourceRecord" unless record.kind_of? ResourceRecord
  cnt = @records.select{ |r| r.type == 'SOA' }.count
  raise RuntimeError, "Multiple SOA detected. zone:#{@origin}" if cnt > 1
  return false if cnt == 1
  @records.unshift record
  true
end

#gen_db_contentObject

Raises:

  • (ArgumentError)


72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/zone.rb', line 72

def gen_db_content
  initialized?
  raise ArgumentError, "default_ttl not secified" unless @default_ttl
  
  add_default_rrs

  rrhash = @records.inject({}){|s, v| s[v.type] ||= []; s[v.type] << v; s}

  cont = "; File is under automatic control. Edit with caution.\n"
  cont << ";;; Zone #{@origin} ;;;\n" << "\n"
  cont << "$ORIGIN #{@origin}" << "\n" if @origin
  cont << "$TTL #{@default_ttl}" << "\n" if @default_ttl

  rrhash.keys.each do |rr_type|
    cont << ";;; #{rr_type} ;;;\n"
    cont << rrhash[rr_type].map{ |r| r.gen_rr_string }.join("\n")
    cont << "\n"
  end

  cont
end

#gen_zone_entryObject



129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/zone.rb', line 129

def gen_zone_entry
  initialized?

  cont = ''
  cont << %Q|
zone "#{name}" {
  type master;
  file "#{@file}";
  allow-update { none; };
  allow-query { any; };
};
|
end

#loadObject

Raises:

  • (ArgumentError)


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/zone.rb', line 55

def load
  raise ArgumentError, "file not specified" unless @file
  
  # TODO what should we do if there is no db file?
  # raise ArgumentError, "File: #{file} not found." unless File.exists?( @file )
  # just emulate parsing of empty file
  return 0 unless File.exists?( @file )
  
  p = Parser.new
  p.result = self
  begin
    p.parse File.read( @file )
  rescue 
    raise ParserError, "Parser error. File: #{@file.inspect}.\nError: #{$!.to_s}\n#{$!.backtrace.join("\n")}"
  end
end

#nameObject



38
39
40
# File 'lib/zone.rb', line 38

def name
  @origin.sub(/\.$/, '')
end

#name=(str) ⇒ Object



42
43
44
# File 'lib/zone.rb', line 42

def name= str
  @origin = str + '.'
end

#originObject



24
25
26
# File 'lib/zone.rb', line 24

def origin
  @origin
end

#origin=(zone_origin) ⇒ Object



28
29
30
31
32
33
34
35
36
# File 'lib/zone.rb', line 28

def origin= zone_origin
  if zone_origin.kind_of?( String ) && zone_origin.length > 0
    @origin = zone_origin.clone
    @origin << '.' unless @origin[-1] == '.'
  else
    @origin = zone_origin 
  end
  @origin
end

#remove_rr(owner, type) ⇒ Object

removes all resourse record with specified owner and type

Raises:

  • (ArgumentError)


120
121
122
123
124
125
126
127
# File 'lib/zone.rb', line 120

def remove_rr( owner, type )
  raise( ArgumentError, "wrong owner" ) if     owner.nil?
  raise( ArgumentError, "wrong type" )  unless ALLOWED_TYPES.include? type

  initialized?

  @records.delete_if { |rr| (rr.owner == owner) && (rr.type == type) }
end

#valid?Boolean

Returns:

  • (Boolean)


179
180
181
182
183
# File 'lib/zone.rb', line 179

def valid?
  return false if @records.size < 1
  return false unless Bind9mgr::Zone.domain_name_syntax_valid( self.origin )
  @records.select{ |z| !z.valid? }.size == 0
end

#write_db_fileObject

Raises:

  • (ArgumentError)


94
95
96
97
98
99
# File 'lib/zone.rb', line 94

def write_db_file
  raise ArgumentError, "File not specified" if @file.nil? || @file.length < 1
  db_dir = File.dirname( @file )
  raise( Errno::ENOENT, "No such dir: #{db_dir}" ) unless File.exists? db_dir
  File.open( @file, 'w' ){|f| f.write( gen_db_content )}
end