PageRenderTime 51ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/dns/zonefile.rb

https://github.com/zarqman/dns-zonefile
Ruby | 315 lines | 259 code | 53 blank | 3 comment | 13 complexity | 88dd67d4780a25e868c48e62d684d51f MD5 | raw file
Possible License(s): WTFPL
  1. require 'dns/zonefile_parser'
  2. module DNS
  3. class ParsingError < RuntimeError ; end
  4. class UnknownRecordType < RuntimeError ; end
  5. class Zonefile
  6. VERSION = "0.5.0"
  7. attr_reader :origin, :soa
  8. class << self
  9. def parse(zone_string)
  10. parser = DNS::ZonefileParser.new
  11. if result = parser.parse(zone_string)
  12. result
  13. else
  14. raise ParsingError, parser.failure_reason
  15. end
  16. end
  17. def load(zone_string, alternate_origin=nil)
  18. Zone.new(parse(zone_string).entries, alternate_origin)
  19. end
  20. end
  21. end
  22. class Zone
  23. attr :records
  24. def initialize(entries, alternate_origin=nil)
  25. alternate_origin ||= '.'
  26. @records = []
  27. @vars = {'origin'=>alternate_origin, :last_host=>'.'}
  28. entries.each do |e|
  29. case e.parse_type
  30. when :variable
  31. case key = e.name.text_value.downcase
  32. when 'ttl'
  33. @vars[key] = e.value.text_value.to_i
  34. else
  35. @vars[key] = e.value.text_value
  36. end
  37. when :soa
  38. @records << SOA.new(@vars, e)
  39. when :record
  40. case e.record_type
  41. when 'A' : @records << A.new(@vars, e)
  42. when 'AAAA' : @records << AAAA.new(@vars, e)
  43. when 'CNAME' : @records << CNAME.new(@vars, e)
  44. when 'MX' : @records << MX.new(@vars, e)
  45. when 'NAPTR' : @records << NAPTR.new(@vars, e)
  46. when 'NS' : @records << NS.new(@vars, e)
  47. when 'PTR' : @records << PTR.new(@vars, e)
  48. when 'SRV' : @records << SRV.new(@vars, e)
  49. when 'SPF' : @records << SPF.new(@vars, e)
  50. when 'TXT' : @records << TXT.new(@vars, e)
  51. else
  52. raise UnknownRecordType, "Unknown record type: #{e.record_type}"
  53. end
  54. end
  55. end
  56. end
  57. def soa
  58. records_of(SOA).first
  59. end
  60. def records_of(kl)
  61. @records.select{|r| r.instance_of? kl}
  62. end
  63. end
  64. class Record
  65. # assign, with handling for '@'
  66. def self.writer_for_at(*attribs)
  67. attribs.each do |attrib|
  68. c = <<-MTH
  69. def #{attrib}=(val)
  70. @#{attrib} = val.gsub('@', @vars['origin'])
  71. end
  72. MTH
  73. class_eval c, __FILE__, __LINE__
  74. end
  75. end
  76. # assign, with handling for '@', with inheritance
  77. def self.inheriting_writer_for_at(*attribs)
  78. attribs.each do |attrib|
  79. c = <<-MTH
  80. def #{attrib}=(val)
  81. if val.strip.empty?
  82. @#{attrib} = @vars[:last_host]
  83. else
  84. @#{attrib} = val.gsub('@', @vars['origin'])
  85. end
  86. end
  87. MTH
  88. class_eval c, __FILE__, __LINE__
  89. end
  90. end
  91. # assign, with handling for global TTL
  92. def self.writer_for_ttl(*attribs)
  93. attribs.each do |attrib|
  94. c = <<-MTH
  95. def #{attrib}=(val)
  96. @#{attrib} = val || @vars['ttl']
  97. end
  98. MTH
  99. class_eval c, __FILE__, __LINE__
  100. end
  101. end
  102. attr_reader :ttl
  103. attr_writer :klass
  104. writer_for_ttl :ttl
  105. def klass
  106. @klass = nil if @klass == ''
  107. @klass ||= 'IN'
  108. end
  109. end
  110. class SOA < Record
  111. attr_accessor :origin, :nameserver, :responsible_party, :serial, :refresh_time, :retry_time, :expiry_time, :nxttl
  112. writer_for_at :origin, :nameserver, :responsible_party
  113. def initialize(vars, zonefile_soa=nil)
  114. @vars = vars
  115. if zonefile_soa
  116. self.origin = zonefile_soa.origin.to_s
  117. @vars[:last_host] = self.origin
  118. self.ttl = zonefile_soa.ttl.to_i
  119. self.klass = zonefile_soa.klass.to_s
  120. self.nameserver = zonefile_soa.ns.to_s
  121. self.responsible_party = zonefile_soa.rp.to_s
  122. self.serial = zonefile_soa.serial.to_i
  123. self.refresh_time = zonefile_soa.refresh.to_i
  124. self.retry_time = zonefile_soa.reretry.to_i
  125. self.expiry_time = zonefile_soa.expiry.to_i
  126. self.nxttl = zonefile_soa.nxttl.to_i
  127. end
  128. end
  129. end
  130. class A < Record
  131. attr_accessor :host, :address
  132. inheriting_writer_for_at :host
  133. def initialize(vars, zonefile_record)
  134. @vars = vars
  135. if zonefile_record
  136. self.host = zonefile_record.host.to_s
  137. @vars[:last_host] = self.host
  138. self.ttl = zonefile_record.ttl.to_i
  139. self.klass = zonefile_record.klass.to_s
  140. self.address = zonefile_record.ip_address.to_s
  141. end
  142. end
  143. end
  144. class AAAA < A
  145. end
  146. class CNAME < Record
  147. attr_accessor :host, :domainname
  148. inheriting_writer_for_at :host
  149. writer_for_at :domainname
  150. def initialize(vars, zonefile_record)
  151. @vars = vars
  152. if zonefile_record
  153. self.host = zonefile_record.host.to_s
  154. @vars[:last_host] = self.host
  155. self.ttl = zonefile_record.ttl.to_i
  156. self.klass = zonefile_record.klass.to_s
  157. self.domainname = zonefile_record.target.to_s
  158. end
  159. end
  160. alias :target :domainname
  161. alias :alias :host
  162. end
  163. class MX < Record
  164. attr_accessor :host, :priority, :domainname
  165. inheriting_writer_for_at :host
  166. writer_for_at :domainname
  167. def initialize(vars, zonefile_record)
  168. @vars = vars
  169. if zonefile_record
  170. self.host = zonefile_record.host.to_s
  171. @vars[:last_host] = self.host
  172. self.ttl = zonefile_record.ttl.to_i
  173. self.klass = zonefile_record.klass.to_s
  174. self.priority = zonefile_record.priority.to_i
  175. self.domainname = zonefile_record.exchanger.to_s
  176. end
  177. end
  178. alias :exchange :domainname
  179. alias :exchanger :domainname
  180. end
  181. class NAPTR < Record
  182. attr_accessor :host, :data
  183. inheriting_writer_for_at :host
  184. def initialize(vars, zonefile_record)
  185. @vars = vars
  186. if zonefile_record
  187. self.host = zonefile_record.host.to_s
  188. @vars[:last_host] = self.host
  189. self.ttl = zonefile_record.ttl.to_i
  190. self.klass = zonefile_record.klass.to_s
  191. self.data = zonefile_record.data.to_s
  192. end
  193. end
  194. end
  195. class NS < Record
  196. attr_accessor :host, :domainname
  197. inheriting_writer_for_at :host
  198. writer_for_at :domainname
  199. def initialize(vars, zonefile_record)
  200. @vars = vars
  201. if zonefile_record
  202. self.host = zonefile_record.host.to_s
  203. @vars[:last_host] = self.host
  204. self.ttl = zonefile_record.ttl.to_i
  205. self.klass = zonefile_record.klass.to_s
  206. self.domainname = zonefile_record.nameserver.to_s
  207. end
  208. end
  209. alias :nameserver :domainname
  210. end
  211. class PTR < Record
  212. attr_accessor :host, :domainname
  213. inheriting_writer_for_at :host
  214. writer_for_at :domainname
  215. def initialize(vars, zonefile_record)
  216. @vars = vars
  217. if zonefile_record
  218. self.host = zonefile_record.host.to_s
  219. @vars[:last_host] = self.host
  220. self.ttl = zonefile_record.ttl.to_i
  221. self.klass = zonefile_record.klass.to_s
  222. self.domainname = zonefile_record.target.to_s
  223. end
  224. end
  225. alias :target :domainname
  226. end
  227. class SRV < Record
  228. attr_accessor :host, :priority, :weight, :port, :domainname
  229. inheriting_writer_for_at :host
  230. writer_for_at :domainname
  231. def initialize(vars, zonefile_record)
  232. @vars = vars
  233. if zonefile_record
  234. self.host = zonefile_record.host.to_s
  235. @vars[:last_host] = self.host
  236. self.ttl = zonefile_record.ttl.to_i
  237. self.klass = zonefile_record.klass.to_s
  238. self.priority = zonefile_record.priority.to_i
  239. self.weight = zonefile_record.weight.to_i
  240. self.port = zonefile_record.port.to_i
  241. self.domainname = zonefile_record.target.to_s
  242. end
  243. end
  244. alias :target :domainname
  245. end
  246. class TXT < Record
  247. attr_accessor :host, :data
  248. inheriting_writer_for_at :host
  249. def initialize(vars, zonefile_record)
  250. @vars = vars
  251. if zonefile_record
  252. self.host = zonefile_record.host.to_s
  253. @vars[:last_host] = self.host
  254. self.ttl = zonefile_record.ttl.to_i
  255. self.klass = zonefile_record.klass.to_s
  256. self.data = zonefile_record.data.to_s
  257. end
  258. end
  259. end
  260. class SPF < TXT
  261. end
  262. end