Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/net/dns/rr.rb
Views: 11778
# -*- coding: binary -*-1#2# $Id: RR.rb,v 1.19 2006/07/28 07:33:36 bluemonk Exp $3#45require 'net/dns/names/names'6require 'net/dns/rr/types'7require 'net/dns/rr/classes'8910%w[a ns mx cname txt hinfo soa ptr aaaa mr srv].each do |file|11require "net/dns/rr/#{file}"12end1314module Net # :nodoc:15module DNS1617# =Name18#19# Net::DNS::RR - DNS Resource Record class20#21# =Synopsis22#23# require 'net/dns/rr'24#25# =Description26#27# The Net::DNS::RR is the base class for DNS Resource28# Record (RR) objects. A RR is a pack of data that represents29# resources for a DNS zone. The form in which this data is30# shows can be drawn as follow:31#32# "name ttl class type data"33#34# The +name+ is the name of the resource, like an canonical35# name for an +A+ record (internet ip address). The +ttl+ is the36# time to live, expressed in seconds. +type+ and +class+ are37# respectively the type of resource (+A+ for ip addresses, +NS+38# for nameservers, and so on) and the class, which is almost39# always +IN+, the Internet class. At the end, +data+ is the40# value associated to the name for that particular type of41# resource record. An example:42#43# # A record for IP address44# "www.example.com 86400 IN A 172.16.100.1"45#46# # NS record for name server47# "www.example.com 86400 IN NS ns.example.com"48#49# A new RR object can be created in 2 ways: passing a string50# such the ones above, or specifying each field as the pair51# of an hash. See the Net::DNS::RR.new method for details.52#53# =Error classes54#55# Some error classes has been defined for the Net::DNS::RR class,56# which are listed here to keep a light and browsable main documentation.57# We have:58#59# * RRArgumentError: Generic argument error for class Net::DNS::RR60# * RRDataError: Error in parsing binary data, maybe from a malformed packet61#62# =Copyright63#64# Copyright (c) 2006 Marco Ceresa65#66# All rights reserved. This program is free software; you may redistribute67# it and/or modify it under the same terms as Ruby itself.68#69class RR70include Net::DNS::Names7172# Regexp matching an RR string73RR_REGEXP = Regexp.new("^\\s*(\\S+)\\s*(\\d+)?\\s+(" +74Net::DNS::RR::Classes.regexp +75"|CLASS\\d+)?\\s*(" +76Net::DNS::RR::Types.regexp +77"|TYPE\\d+)?\\s*(.*)$", Regexp::IGNORECASE | Regexp::NOENCODING)7879# Dimension of the sum of class, type, TTL and rdlength fields in a80# RR portion of the packet, in bytes81RRFIXEDSZ = 108283# Name of the RR84attr_reader :name85# TTL time (in seconds) of the RR86attr_reader :ttl87# Data belonging to that appropriate class,88# not to be used (use real accessors instead)89attr_reader :rdata9091# Create a new instance of Net::DNS::RR class, or an instance of92# any of the subclass of the appropriate type.93#94# Argument can be a string or an hash. With a string, we can pass95# a RR resource record in the canonical format:96#97# a = Net::DNS::RR.new("foo.example.com. 86400 A 10.1.2.3")98# mx = Net::DNS::RR.new("example.com. 7200 MX 10 mailhost.example.com.")99# cname = Net::DNS::RR.new("www.example.com 300 IN CNAME www1.example.com")100# txt = Net::DNS::RR.new('baz.example.com 3600 HS TXT "text record"')101#102# Incidentally, +a+, +mx+, +cname+ and +txt+ objects will be instances of103# respectively Net::DNS::RR::A, Net::DNS::RR::MX, Net::DNS::RR::CNAME and104# Net::DNS::RR::TXT classes.105#106# The name and RR data are required; all other information are optional.107# If omitted, the +TTL+ defaults to 10800, +type+ default to +A+ and the RR class108# defaults to +IN+. Omitting the optional fields is useful for creating the109# empty RDATA sections required for certain dynamic update operations.110# All names must be fully qualified. The trailing dot (.) is optional.111#112# The preferred method is however passing an hash with keys and values:113#114# rr = Net::DNS::RR.new(115# :name => "foo.example.com",116# :ttl => 86400,117# :cls => "IN",118# :type => "A",119# :address => "10.1.2.3"120# )121#122# rr = Net::DNS::RR.new(123# :name => "foo.example.com",124# :rdata => "10.1.2.3"125# )126#127# Name and data are required; all the others fields are optionals like128# we've seen before. The data field can be specified either with the129# right name of the resource (+:address+ in the example above) or with130# the generic key +:rdata+. Consult documentation to find the exact name131# for the resource in each subclass.132#133def initialize(arg)134case arg135when String136instance = new_from_string(arg)137when Hash138instance = new_from_hash(arg)139else140raise RRArgumentError, "Invalid argument, must be a RR string or an hash of values"141end142143if @type.to_s == "ANY"144@cls = Net::DNS::RR::Classes.new("IN")145end146147build_pack148set_type149150instance151end152153# Return a new RR object of the correct type (like Net::DNS::RR::A154# if the type is A) from a binary string, usually obtained from155# network stream.156#157# This method is used when parsing a binary packet by the Packet158# class.159#160def RR.parse(data)161o = allocate162obj,offset = o.send(:new_from_binary, data, 0)163return obj164end165166# Same as RR.parse, but takes an entire packet binary data to167# perform name expansion. Default when analyzing a packet168# just received from a network stream.169#170# Return an instance of appropriate class and the offset171# pointing at the end of the data parsed.172#173def RR.parse_packet(data,offset)174o = allocate175o.send(:new_from_binary,data,offset)176end177178# Return the RR object in binary data format, suitable179# for using in network streams, with names compressed.180# Must pass as arguments the offset inside the packet181# and an hash of compressed names.182#183# This method is to be used in other classes and is184# not intended for user space programs.185#186# TO FIX in one of the future releases187#188def comp_data(offset,compnames)189type,cls = @type.to_i, @cls.to_i190str,offset,names = dn_comp(@name,offset,compnames)191str += [type,cls,@ttl,@rdlength].pack("n2 N n")192offset += Net::DNS::RRFIXEDSZ193return str,offset,names194end195196# Return the RR object in binary data format, suitable197# for using in network streams.198#199# raw_data = rr.data200# puts "RR is #{raw_data.size} bytes long"201#202def data203type,cls = @type.to_i, @cls.to_i204str = pack_name(@name)205return str + [type,cls,@ttl,@rdlength].pack("n2 N n") + get_data206end207208# Canonical inspect method209#210# mx = Net::DNS::RR.new("example.com. 7200 MX 10 mailhost.example.com.")211# #=> example.com. 7200 IN MX 10 mailhost.example.com.212#213def inspect214data = get_inspect215# Returns the preformatted string216if @name.size < 24217[@name, @ttl.to_s, @cls.to_s, @type.to_s,218data].pack("A24 A8 A8 A8 A*")219else220to_a.join(" ")221end222end223224# Returns the RR in a string format.225#226# mx = Net::DNS::RR.new("example.com. 7200 MX 10 mailhost.example.com.")227# mx.to_s228# #=> "example.com. 7200 IN MX 10 mailhost.example.com."229#230def to_s231"#{self.inspect}"232end233234# Returns an array with all the fields for the RR record.235#236# mx = Net::DNS::RR.new("example.com. 7200 MX 10 mailhost.example.com.")237# mx.to_a238# #=> ["example.com.",7200,"IN","MX","10 mailhost.example.com."]239#240def to_a241[@name,@ttl,@cls.to_s,@type.to_s,get_inspect]242end243244# Type accessor245def type246@type.to_s247end248249# Class accessor250def cls251@cls.to_s252end253254private255256#---257# New RR with argument in string form258#---259def new_from_string(rrstring)260261unless rrstring =~ RR_REGEXP262raise RRArgumentError,263"Format error for RR string (maybe CLASS and TYPE not valid?)"264end265266# Name of RR - mandatory267begin268@name = $1.downcase269rescue NoMethodError270raise RRArgumentError, "Missing name field in RR string #{rrstring}"271end272273# Time to live for RR, default 3 hours274@ttl = $2 ? $2.to_i : 10800275276# RR class, default to IN277@cls = Net::DNS::RR::Classes.new $3278279# RR type, default to A280@type = Net::DNS::RR::Types.new $4281282# All the rest is data283@rdata = $5 ? $5.strip : ""284285if self.class == Net::DNS::RR286(eval "Net::DNS::RR::#@type").new(rrstring)287else288subclass_new_from_string(@rdata)289self.class290end291end292293def new_from_hash(args)294295# Name field is mandatory296unless args.has_key? :name297raise RRArgumentError, "RR argument error: need at least RR name"298end299300@name = args[:name].downcase301@ttl = args[:ttl] ? args[:ttl].to_i : 10800 # Default 3 hours302@type = Net::DNS::RR::Types.new args[:type]303@cls = Net::DNS::RR::Classes.new args[:cls]304305@rdata = args[:rdata] ? args[:rdata].strip : ""306@rdlength = args[:rdlength] || @rdata.size307308if self.class == Net::DNS::RR309(eval "Net::DNS::RR::#@type").new(args)310else311hash = args - [:name,:ttl,:type,:cls]312if hash.has_key? :rdata313subclass_new_from_string(hash[:rdata])314else315subclass_new_from_hash(hash)316end317self.class318end319end # new_from_hash320321def new_from_binary(data,offset)322if self.class == Net::DNS::RR323temp = dn_expand(data,offset)[1]324type = Net::DNS::RR::Types.new data.unpack("@#{temp} n")[0]325return unless Net::DNS::RR.const_defined?(type.to_s)326(eval "Net::DNS::RR::#{type}").parse_packet(data,offset)327else328@name,offset = dn_expand(data,offset)329rrtype,cls,@ttl,@rdlength = data.unpack("@#{offset} n2 N n")330@type = Net::DNS::RR::Types.new rrtype331@cls = Net::DNS::RR::Classes.new cls332offset += RRFIXEDSZ333offset = subclass_new_from_binary(data,offset)334build_pack335set_type336return [self,offset]337end338# rescue StandardError => err339# raise RRDataError, "Caught exception, maybe packet malformed: #{err}"340end341342# Methods to be overridden by subclasses343def subclass_new_from_array(arr)344end345def subclass_new_from_string(str)346end347def subclass_new_from_hash(hash)348end349def subclass_new_from_binary(data,offset)350end351def build_pack352end353def set_type354end355def get_inspect356@rdata357end358def get_data359@rdata360end361362# NEW new method :)363def self.new(*args)364o = allocate365obj = o.send(:initialize,*args)366if self == Net::DNS::RR367return obj368else369return o370end371end372373end # class RR374375end # module DNS376end # module Net377378class RRArgumentError < ArgumentError # :nodoc:379end380class RRDataError < StandardError # :nodoc:381end382383module ExtendHash # :nodoc:384385# Performs a sort of group difference386# operation on hashes or arrays387#388# a = {:a=>1,:b=>2,:c=>3}389# b = {:a=>1,:b=>2}390# c = [:a,:c]391# a-b #=> {:c=>3}392# a-c #=> {:b=>2}393#394def -(oth)395case oth396when Hash397delete_if {|k,v| oth.has_key? k}398when Array399delete_if {|k,v| oth.include? k}400end401end402end403404class Hash # :nodoc:405include ExtendHash406end407408409