Class: Dnsruby::Update

Inherits:
Message show all
Defined in:
lib/dnsruby/update.rb

Overview

The first example below shows a complete program; subsequent examples show only the creation of the update packet.

Add a new host

require 'Dnsruby'

# Create the update packet.
update = Dnsruby::Update.new('example.com')

# Prerequisite is that no A records exist for the name.
update.absent('foo.example.com.', 'A')

# Add two A records for the name.
update.add('foo.example.com.', 'A', 86400, '192.168.1.2')
update.add('foo.example.com.', 'A', 86400, '172.16.3.4')

# Send the update to the zone's primary master.
res = Dnsruby::Resolver.new({:nameserver => 'primary-master.example.com'})

begin
    reply = res.send_message(update)
    print "Update succeeded\n"
 rescue Exception => e
    print 'Update failed: #{e}\n'
 end

Add an MX record for a name that already exists

update = Dnsruby::Update.new('example.com')
update.present('example.com')
update.add('example.com', Dnsruby::Types.MX, 86400, 10, 'mailhost.example.com')

Add a TXT record for a name that doesn’t exist

update = Dnsruby::Update.new('example.com')
update.absent('info.example.com')
update.add('info.example.com', Types.TXT, 86400, "yabba dabba doo"')

Delete all A records for a name

update = Dnsruby::Update.new('example.com')
update.present('foo.example.com', 'A')
update.delete('foo.example.com', 'A')

Delete all RRs for a name

update = Dnsruby::Update.new('example.com')
update.present('byebye.example.com')
update.delete('byebye.example.com')

Perform a signed update

key_name = 'tsig-key'
key      = 'awwLOtRfpGE+rRKF2+DEiw=='

update = Dnsruby::Update.new('example.com')
update.add('foo.example.com', 'A', 86400, '10.1.2.3'))
update.add('bar.example.com', 'A', 86400, '10.4.5.6'))
res.tsig=(key_name,key)

Instance Attribute Summary

Attributes inherited from Message

#additional, #answer, #answerfrom, #answerip, #answersize, #authority, #cached, #do_caching, #do_validation, #header, #question, #security_error, #security_level, #send_raw, #tsigerror, #tsigstart, #tsigstate

Instance Method Summary collapse

Methods inherited from Message

#==, #add_additional, #add_answer, #add_answer!, #add_authority, #add_question, #clone, decode, #each_additional, #each_answer, #each_authority, #each_question, #each_resource, #each_section, #encode, #get_exception, #get_opt, #old_to_s, #rcode, #remove_additional, #rrset, #rrsets, #section_rrsets, #set_tsig, #sign!, #signed?, #to_s, #tsig, #update_counts, #verified?

Constructor Details

#initialize(zone = nil, klass = nil) ⇒ Update

Returns a Dnsruby::Update object suitable for performing a DNS dynamic update. Specifically, it creates a message with the header opcode set to UPDATE and the zone record type to SOA (per RFC 2136, Section 2.3).

Programs must use the push method to add RRs to the prerequisite, update, and additional sections before performing the update.

Arguments are the zone name and the class. If the zone is omitted, the default domain will be taken from the resolver configuration. If the class is omitted, it defaults to IN.

packet = Dnsruby::Update.new
packet = Dnsruby::Update.new('example.com')
packet = Dnsruby::Update.new('example.com', 'HS')


98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/dnsruby/update.rb', line 98

def initialize(zone=nil, klass=nil)

  #  sort out the zone section (RFC2136, section 2.3)
  if (zone==nil)
    config = Config.new
    zone = (config.search)[0]
    return unless zone
  end

  type  = 'SOA'
  klass  ||= 'IN'

  super(zone, type, klass) || return

  @header.opcode=('UPDATE')
  @header.rd=(0)
  @do_validation = false
end

Instance Method Details

#absent(*args) ⇒ Object

Ways to create the prerequisite records (exists, notexists, inuse, etc. - RFC2136, section 2.4) Can be called with one arg :

update.absent(name)
   (5)  Name is not in use.  No RR of any type is owned by a
        specified NAME.  Note that this prerequisite IS satisfied by
        empty nonterminals.

Or with two :

update.absent(name, type)
   (3)  RRset does not exist.  No RRs with a specified NAME and TYPE
       (in the zone and class denoted by the Zone Section) can exist.


174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/dnsruby/update.rb', line 174

def absent(*args)
  ttl = 0
  rdata = ""
  klass = Classes.NONE
  if (args.length>=1) # domain (RFC2136, Section 2.4.5)
    name = args[0]
    type = Types.ANY
    if (args.length==2) # RRSET (RFC2136, Section 2.4.3)
      type = args[1]
    end
    rec = RR.create("#{name} #{ttl} #{klass} #{type} #{rdata}")
    add_pre(rec)
    return rec
  else
    raise ArgumentError.new("Wrong number of arguments (#{args.length} for 1 or 2) for Update#absent")
  end
end

#add(*args) ⇒ Object

Ways to create the update records (add, delete, RFC2136, section 2.5)

" 2.5.1 - Add To An RRset

 RRs are added to the Update Section whose NAME, TYPE, TTL, RDLENGTH
 and RDATA are those being added, and CLASS is the same as the zone
 class.  Any duplicate RRs will be silently ignored by the primary
 master."

 update.add(rr)
 update.add([rr1, rr2])
 update.add(name, type, ttl, rdata)


204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/dnsruby/update.rb', line 204

def add(*args)
  zoneclass=zone()[0].zclass
  case args[0]
  when Array
    args[0].each do |resource|
      add(resource)
    end
  when RR
    #  Make sure that the Class is the same as the zone
    resource = args[0]
    if (resource.klass != zoneclass)
      raise ArgumentError.new("Wrong class #{resource.klass} for update (should be #{zoneclass})!")
    end
    add_update(resource)
    return resource
  else
    name=args[0]
    type=args[1]
    ttl=args[2]
    rdata=args[3]
    resource = nil
    if (Types.new(type) == Types.TXT)
      instring = "#{name} #{ttl} #{zoneclass} #{type} ";
      if (String === rdata)
        instring += " '#{rdata}'"
      elsif (Array === rdata)
        rdata.length.times {|rcounter|
        instring += " '#{rdata[rcounter]}' "
        }
      else
        instring += rdata
      end
      resource = RR.create(instring)
    else
      resource = RR.create("#{name} #{ttl} #{zoneclass} #{type} #{rdata}")
    end
    add_update(resource)
    return resource
  end
  #  @TODO@ Should be able to take RRSet!
end

#delete(*args) ⇒ Object

Ways to create the update records (add, delete, RFC2136, section 2.5)

2.5.2 - Delete An RRset

update.delete(name, type)

2.5.3 - Delete All RRsets From A Name

update.delete(name)

2.5.4 - Delete An RR From An RRset

update.delete(name, type, rdata)


258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
# File 'lib/dnsruby/update.rb', line 258

def delete(*args)
  ttl = 0
  klass = Classes.ANY
  rdata=""
  resource = nil
  case args.length
  when 1 # name
    resource = RR.create("#{args[0]} #{ttl} #{klass} #{Types.ANY} #{rdata}")
    add_update(resource)
  when 2 # name, type
    resource = RR.create("#{args[0]} #{ttl} #{klass} #{args[1]} #{rdata}")
    add_update(resource)
  when 3 # name, type, rdata
    name = args[0]
    type = args[1]
    rdata = args[2]
    if (Types.new(type) == Types.TXT)
      instring = "#{name} #{ttl} IN #{type} ";
      if (String === rdata)
        instring += " '#{rdata}'"
      elsif (Array === rdata)
        rdata.length.times {|rcounter|
        instring += " '#{rdata[rcounter]}' "
        }
      else
        instring += rdata
      end
      resource = RR.create(instring)
    else
      resource = RR.create("#{name} #{ttl} IN #{type} #{rdata}")
    end
    resource.klass = Classes.NONE
    add_update(resource)
  end
  return resource
end

#present(*args) ⇒ Object

Ways to create the prerequisite records (exists, notexists, inuse, etc. - RFC2136, section 2.4)

(1)  RRset exists (value independent).  At least one RR with a
     specified NAME and TYPE (in the zone and class specified by
     the Zone Section) must exist.

     update.present(name, type)

(2)  RRset exists (value dependent).  A set of RRs with a
     specified NAME and TYPE exists and has the same members
     with the same RDATAs as the RRset specified here in this
     Section.

     update.present(name, type, rdata)

(4)  Name is in use.  At least one RR with a specified NAME (in
     the zone and class specified by the Zone Section) must exist.
     Note that this prerequisite is NOT satisfied by empty
     nonterminals.

     update.present(name)


138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/dnsruby/update.rb', line 138

def present(*args)
  ttl = 0
  rdata = ""
  klass = Classes.ANY
  if (args.length>=1) # domain (RFC2136, Section 2.4.4)
    name = args[0]
    type = Types.ANY
    if (args.length>=2) # RRSET (RFC2136, Section 2.4.1)
      type = args[1]
    end
    if (args.length > 2) # RRSET (RFC2136, Section 2.4.2)
      klass = Classes.new(zone()[0].zclass)
      rdata=args[2]
    end
    rec = RR.create("#{name} #{ttl} #{klass} #{type} #{rdata}")
    add_pre(rec)
    return rec
  else
    raise ArgumentError.new("Wrong number of arguments (#{args.length} for 1 or 2) for Update#present")
  end
end