Class: DNS::DomainName

Inherits:
Object
  • Object
show all
Defined in:
lib/faildns/domainname.rb

Overview

– Domain names in messages are expressed in terms of a sequence of labels. Each label is represented as a one octet length field followed by that number of octets. Since every domain name ends with the null label of the root, a domain name is terminated by a length byte of zero. The high order two bits of every length octet must be zero, and the remaining six bits of the length field limit the label to 63 octets or less.

To simplify implementations, the total length of a domain name (i.e., label octets and label length octets) is restricted to 255 octets or less.

Although labels can contain any 8 bit values in octets that make up a label, it is strongly recommended that labels follow the preferred syntax described elsewhere in this memo, which is compatible with existing host naming conventions. Name servers and resolvers must compare labels in a case-insensitive manner (i.e., A=a), assuming ASCII with zero parity. Non-alphabetic codes must match exactly.

In order to reduce the size of messages, the domain system utilizes a compression scheme which eliminates the repetition of domain names in a message. In this scheme, an entire domain name or a list of labels at the end of a domain name is replaced with a pointer to a prior occurance of the same name.

The pointer takes the form of a two octet sequence:

+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| 1  1|                OFFSET                   |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

The first two bits are ones. This allows a pointer to be distinguished from a label, since the label must begin with two zero bits because labels are restricted to 63 octets or less. (The 10 and 01 combinations are reserved for future use.) The OFFSET field specifies an offset from the start of the message (i.e., the first octet of the ID field in the domain header). A zero offset specifies the first byte of the ID field, etc.

The compression scheme allows a domain name in a message to be represented as either:

- a sequence of labels ending in a zero octet

- a pointer

- a sequence of labels ending with a pointer

Pointers can only be used for occurances of a domain name where the format is not class specific. If this were not the case, a name server or resolver would be required to know the format of all RRs it handled. As yet, there are no such cases, but they may occur in future RDATA formats.

If a domain name is contained in a part of the message subject to a length field (such as the RDATA section of an RR), and compression is used, the length of the compressed name is used in the length calculation, rather than the length of the expanded name.

Programs are free to avoid using pointers in messages they generate, although this will reduce datagram capacity, and may cause truncation. However all programs are required to understand arriving messages that contain pointers.

For example, a datagram might need to use the domain names F.ISI.ARPA, FOO.F.ISI.ARPA, ARPA, and the root. Ignoring the other fields of the message, these domain names might be represented as:

   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
20 |           1           |           F           |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
22 |           3           |           I           |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
24 |           S           |           I           |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
26 |           4           |           A           |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
28 |           R           |           P           |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
30 |           A           |           0           |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
40 |           3           |           F           |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
42 |           O           |           O           |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
44 | 1  1|                20                       |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
64 | 1  1|                26                       |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
92 |           0           |                       |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

The domain name for F.ISI.ARPA is shown at offset 20. The domain name FOO.F.ISI.ARPA is shown at offset 40; this definition uses a pointer to concatenate a label for FOO to the previously defined F.ISI.ARPA. The domain name ARPA is defined at offset 64 using a pointer to the ARPA component of the name F.ISI.ARPA at 20; note that this pointer relies on ARPA being the last label in the string at 20. The root domain name is defined by a single octet of zeros at 92; the root domain name has no labels. ++

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(domain) ⇒ DomainName

Returns a new instance of DomainName.



194
195
196
197
198
199
200
201
202
203
204
# File 'lib/faildns/domainname.rb', line 194

def initialize (domain)
  if domain.is_a? DomainName
    domain = domain.domain
  end

  if !domain.is_a? String
    raise ArgumentError.new 'The passed value is not a string.'
  end

  @domain = domain
end

Instance Attribute Details

#domainObject

Returns the value of attribute domain.



192
193
194
# File 'lib/faildns/domainname.rb', line 192

def domain
  @domain
end

Class Method Details

.length(string) ⇒ Object



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/faildns/domainname.rb', line 168

def self.length (string)
  string.force_encoding 'BINARY'

  string = string.clone
  result = 0

  if string.unpack('c').first & 0xC0 == 0xC0
    return 2
  else
    while (length = string.unpack('c').first) != 0 && (length & 0xC0) == 0
      result                += 1 + length
      string[0, length + 1]  = ''
    end

    if length & 0xC0 == 0xC0
      result += 2
    else
      result += 1
    end
  end

  return result
end

.parse(string, whole) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/faildns/domainname.rb', line 138

def self.parse (string, whole)
  string.force_encoding 'BINARY'

  result = ''

  case string.unpack('c').first & 0xC0
    when 0xC0
      result       += DomainName.parse(DomainName.pointer(whole, string), whole)
      string[0, 2]  = ''

    when 0x00
      while (length = string.unpack('c').first) != 0 && (length & 0xC0) == 0
        result                += '.' + string[1, length]
        string[0, length + 1]  = ''
      end

      if length & 0xC0 == 0xC0
        result += '.' + DomainName.parse(string, whole)

        string[0, 2] = ''
      else
        string[0, 1] = ''
      end

      result[0, 1] = ''
  end

  DomainName.new result
end

.pointer(string, offset) ⇒ Object



132
133
134
135
136
# File 'lib/faildns/domainname.rb', line 132

def self.pointer (string, offset)
  string.force_encoding 'BINARY'

  return string[offset.unpack('n').first & 0x3FFF, 512]
end

Instance Method Details

#pack(options = {}) ⇒ Object



212
213
214
215
216
217
218
219
220
# File 'lib/faildns/domainname.rb', line 212

def pack (options={})
  result = ''

  @domain.split('.').each {|part|
    result += [part.length].pack('c') + part
  }

  result += [0].pack('c')
end

#to_sObject Also known as: to_str



206
207
208
# File 'lib/faildns/domainname.rb', line 206

def to_s
  @domain
end