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(=> ‘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, 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, #answersize, #authority, #header, #question, #tsigerror, #tsigstart, #tsigstate

Instance Method Summary collapse

Methods inherited from Message

#==, #add_additional, #add_answer, #add_authority, #add_question, decode, #each_additional, #each_answer, #each_authority, #each_question, #each_resource, #encode, #set_tsig, #sign!, #signed?, #to_s, #tsig, #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
# 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)
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.


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

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)


203
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
# File 'lib/Dnsruby/update.rb', line 203

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 = RR.create("#{name} #{ttl} #{zoneclass} #{type} #{rdata}")
    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)


242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/Dnsruby/update.rb', line 242

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
    klass = Classes.NONE
    resource = RR.create("#{args[0]} #{ttl} #{klass} #{args[1]} #{args[2]}")
    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)


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

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 = 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#absent")
  end
end