class Dnsruby::RR

Superclass for all Dnsruby resource records.

Represents a DNS RR (resource record) [RFC1035, section 3.2]

Use ::create to create a new RR record.

mx = Dnsruby::RR.create("example.com. 7200 MX 10 mailhost.example.com.")

rr = Dnsruby::RR.create({:name => "example.com", :type => "MX", :ttl => 7200,
                               :preference => 10, :exchange => "mailhost.example.com"})

s = rr.to_s # Get a String representation of the RR (in zone file format)
rr_again = Dnsruby::RR.create(s)

Attributes

klass[R]

The Resource class

name[R]

The Resource's domain name

rdata[RW]

The Resource data section

rr_type[R]

The Resource type

ttl[RW]

The Resource Time-To-Live

type[R]

The Resource type

Public Class Methods

create(*args) click to toggle source

Create a new RR from the arguments, which can be either a String or a Hash. See ::new_from_string and ::new_from_hash for details

a     = Dnsruby::RR.create("foo.example.com. 86400 A 10.1.2.3")
mx    = Dnsruby::RR.create("example.com. 7200 MX 10 mailhost.example.com.")
cname = Dnsruby::RR.create("www.example.com 300 IN CNAME www1.example.com")
txt   = Dnsruby::RR.create('baz.example.com 3600 HS TXT "text record"')

rr = Dnsruby::RR.create({:name => "example.com"})
rr = Dnsruby::RR.create({:name => "example.com", :type => "MX", :ttl => 10,
                               :preference => 5, :exchange => "mx1.example.com"})
# File lib/Dnsruby/resource/resource.rb, line 650
def RR.create(*args)
  if (args.length == 1) && (args[0].class == String)
    return new_from_string(args[0])
  elsif (args.length == 1) && (args[0].class == Hash)
    return new_from_hash(args[0])
  else
    return new_from_data(args)
  end
end
get_num(bytes) click to toggle source
# File lib/Dnsruby/resource/resource.rb, line 660
def self.get_num(bytes)
  ret = 0
  shift = (bytes.length-1) * 8
  bytes.each_byte {|byte|
    ret += byte.to_i << shift
    shift -= 8
  }
  return ret
end
implemented_rrs() click to toggle source

Return an array of all the currently implemented RR types

# File lib/Dnsruby/resource/resource.rb, line 505
def RR.implemented_rrs
  if (!@@implemented_rr_map)
    @@implemented_rr_map = ClassHash.keys.map {|k| Dnsruby::Types.to_string(k[0])}
  end
  return @@implemented_rr_map
end
new_from_hash(inhash) click to toggle source

Create a new RR from the hash. The name is required; all other fields are optional. Type defaults to ANY and the Class defaults to IN. The TTL defaults to 0.

If the type is specified, then it is necessary to provide ALL of the resource record fields which are specific to that record; i.e. for an MX record, you would need to specify the exchange and the preference

require 'Dnsruby'
rr = Dnsruby::RR.new_from_hash({:name => "example.com"})
rr = Dnsruby::RR.new_from_hash({:name => "example.com", :type => Types.MX, :ttl => 10, :preference => 5, :exchange => "mx1.example.com"})
# File lib/Dnsruby/resource/resource.rb, line 350
def RR.new_from_hash(inhash)
  hash = inhash.clone
  type = hash[:type] || Types::ANY
  klass = hash[:klass] || Classes::IN
  ttl = hash[:ttl] || 0
  recordclass = get_class(type, klass)
  record = recordclass.new
  record.name=hash[:name]
  if !(record.name.kind_of?Name)
    record.name = Name.create(record.name)
  end
  record.ttl=ttl
  record.type = type
  record.klass = klass
  hash.delete(:name)
  hash.delete(:type)
  hash.delete(:ttl)
  hash.delete(:klass)
  record.from_hash(hash)
  return record
end
new_from_string(rrstring) click to toggle source

Returns a Dnsruby::RR object of the appropriate type and initialized from the string passed by the user. The format of the string is that used in zone files, and is compatible with the string returned by Net::DNS::RR.inspect

The name and RR type are required; all other information is optional. If omitted, the TTL defaults to 0 and the RR class defaults to IN.

All names must be fully qualified. The trailing dot (.) is optional.

a     = Dnsruby::RR.new_from_string("foo.example.com. 86400 A 10.1.2.3")
mx    = Dnsruby::RR.new_from_string("example.com. 7200 MX 10 mailhost.example.com.")
cname = Dnsruby::RR.new_from_string("www.example.com 300 IN CNAME www1.example.com")
txt   = Dnsruby::RR.new_from_string('baz.example.com 3600 HS TXT "text record"')
# File lib/Dnsruby/resource/resource.rb, line 389
def RR.new_from_string(rrstring)
  # strip out comments
  # Test for non escaped ";" by means of the look-behind assertion
  # (the backslash is escaped)
  rrstring = rrstring.gsub(/(\?<!\\);.*/o, "");
  
  if ((rrstring =~/#{@@RR_REGEX}/xo) == nil)
    raise Exception, "#{rrstring} did not match RR pat.\nPlease report this to the author!\n"
  end
  
  name    = $1;
  ttl     = $2.to_i || 0;
  rrclass = $3 || '';
  
  
  rrtype  = $4 || '';
  rdata   = $5 || '';
  
  if rdata
    rdata.gsub!(/\s+$/o, "")
  end
  
  # RFC3597 tweaks
  # This converts to known class and type if specified as TYPE###
  if rrtype  =~/^TYPE\d+/o
    rrtype  = Dnsruby::Types.typesbyval(Dnsruby::Types::typesbyname(rrtype))
  end
  if rrclass =~/^CLASS\d+/o
    rrclass = Dnsruby::Classes.classesbyval(Dnsruby::Classes::classesbyname(rrclass))
  end
  
  
  if (rrtype=='' && rrclass && rrclass == 'ANY')
    rrtype  = 'ANY';
    rrclass = 'IN';
  elsif (rrclass=='')
    rrclass = 'IN';
  end
  
  if (rrtype == '')
    rrtype = 'ANY';
  end

  if ((rrtype == "NAPTR") || (rrtype == "TXT"))
  else
    if (rdata)
      rdata.gsub!("(", "")
      rdata.gsub!(")", "")
    end
  end
  
  if (implemented_rrs.include?(rrtype) && rdata !~/^\s*\\#/o )
    subclass = _get_subclass(name, rrtype, rrclass, ttl, rdata)
    return subclass
  elsif (implemented_rrs.include?(rrtype))   # A known RR type starting with \#
    rdata =~ /\\\#\s+(\d+)\s+(.*)$/o;
    
    rdlength = $1.to_i;
    hexdump  = $2;
    hexdump.gsub!(/\s*/, "");
    
    if hexdump.length() != rdlength*2
      raise Exception, "#{rdata} is inconsistent; length does not match content"
    end
    
    rdata = [hexdump].pack('H*');
    
    return new_from_data(name, rrtype, rrclass, ttl, rdlength, rdata, 0) # rdata.length() - rdlength);
  elsif (rdata=~/\s*\\\#\s+\d+\s+/o)
    #We are now dealing with the truly unknown.
    raise Exception, 'Expected RFC3597 representation of RDATA' unless rdata =~/\\\#\s+(\d+)\s+(.*)$/o;
    
    rdlength = $1.to_i;
    hexdump  = $2;
    hexdump.gsub!(/\s*/o, "");
    
    if hexdump.length() != rdlength*2
      raise Exception, "#{rdata} is inconsistent; length does not match content" ;
    end
    
    rdata = [hexdump].pack('H*');
    
    return new_from_data(name,rrtype,rrclass,ttl,rdlength,rdata,0) # rdata.length() - rdlength);
  else
    #God knows how to handle these...
    subclass = _get_subclass(name, rrtype, rrclass, ttl, "")
    return subclass
  end
end

Public Instance Methods

<=>(other) click to toggle source
# File lib/Dnsruby/resource/resource.rb, line 220
def <=>(other)
  #      return 1 if ((!other) || !(other.name) || !(other.type))
  #      return -1 if (!@name)
  if (@name.canonical == other.name.canonical)
    if (@type.code == other.type.code)
      return (@rdata <=> other.rdata)
    else
      return @type.code <=> other.type.code
    end
  else
    return @name <=> other.name
  end
end
==(other) click to toggle source
# File lib/Dnsruby/resource/resource.rb, line 558
def ==(other)
  return false unless self.class == other.class
  ivars = self.instance_variables
  s_ivars = []
  ivars.each {|i| s_ivars << i.to_s} # Ruby 1.9
  s_ivars.delete "@ttl" # RFC 2136 section 1.1
  s_ivars.delete "@rdata"
  if (self.type == Types.DS)
    s_ivars.delete "@digest"
  end
  s_ivars.sort!
  
  ivars = other.instance_variables
  o_ivars = []
  ivars.each {|i| o_ivars << i.to_s} # Ruby 1.9
  o_ivars.delete "@ttl" # RFC 2136 section 1.1
  o_ivars.delete "@rdata"
  if (other.type == Types.DS)
    o_ivars.delete "@digest"
  end
  o_ivars.sort!
  
  return s_ivars == o_ivars &&
    s_ivars.collect {|name| self.instance_variable_get name} ==
    o_ivars.collect {|name| other.instance_variable_get name}
end
clone() click to toggle source
# File lib/Dnsruby/resource/resource.rb, line 280
def clone
  MessageDecoder.new(MessageEncoder.new {|msg|
      msg.put_rr(self, true)}.to_s) {|msg|
    r = msg.get_rr
    return r
  }

end
init_defaults() click to toggle source
# File lib/Dnsruby/resource/resource.rb, line 307
def init_defaults
  # Default to do nothing
end
klass=(klass) click to toggle source
# File lib/Dnsruby/resource/resource.rb, line 268
def klass=(klass)
  if (@type != Types::OPT)
    @klass= Classes.new(klass)
  else
    if (klass.class == Classes)
      @klass = klass
    else
      @klass = Classes.new("CLASS#{klass}")
    end
  end
end
name=(newname) click to toggle source
# File lib/Dnsruby/resource/resource.rb, line 255
def name=(newname)
  if (!(newname.kind_of?Name))
    @name=Name.create(newname)
  else
    @name = newname
  end
end
rdata_to_string() click to toggle source

Get a string representation of the data section of the RR (in zone file format)

# File lib/Dnsruby/resource/resource.rb, line 530
def rdata_to_string
  if (@rdata && @rdata.length > 0)
    return @rdata
  else
    return "no rdata"
  end
end
rdlength() click to toggle source
# File lib/Dnsruby/resource/resource.rb, line 251
def rdlength
  return rdata.length
end
sameRRset(rec) click to toggle source

Determines if two Records could be part of the same RRset. This compares the name, type, and class of the Records; the ttl and rdata are not compared.

# File lib/Dnsruby/resource/resource.rb, line 292
def sameRRset(rec)
  if (@klass != rec.klass || @name.downcase != rec.name.downcase)
    return false
  end
  if (rec.type == Types.RRSIG) && (@type == Types.RRSIG)
    return rec.type_covered == self.type_covered
  end
  [rec, self].each { |rr|
    if (rr.type == Types::RRSIG)
      return ((@type == rr.type_covered) || (rec.type == rr.type_covered))
    end
  }
  return (@type == rec.type)
end
to_s() click to toggle source

Returns a string representation of the RR in zone file format

# File lib/Dnsruby/resource/resource.rb, line 525
def to_s
  return (@name ? @name.to_s(true):"") + "\t" +(@ttl ? @ttl.to_s():"") + "\t" + (klass() ? klass.to_s():"") + "\t" + (type() ? type.to_s():"") + "\t" + rdata_to_string
end
type=(type) click to toggle source
# File lib/Dnsruby/resource/resource.rb, line 263
def type=(type)
  @type = Types.new(type)
end