class Dnsruby::Update

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)

Public Class Methods

new(zone=nil, klass=nil) click to toggle source

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')
Calls superclass method Dnsruby::Message::new
# 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

Public Instance Methods

absent(*args) click to toggle source

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.
# 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) click to toggle source

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)
# 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) click to toggle source

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)
# 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) click to toggle source

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)
# 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