faildns 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/failnamed +203 -0
- data/bin/failresolve +37 -0
- data/lib/faildns.rb +20 -0
- data/lib/faildns/class.rb +96 -0
- data/lib/faildns/client.rb +114 -0
- data/lib/faildns/common.rb +52 -0
- data/lib/faildns/domainname.rb +223 -0
- data/lib/faildns/header.rb +254 -0
- data/lib/faildns/header/opcode.rb +95 -0
- data/lib/faildns/header/status.rb +123 -0
- data/lib/faildns/header/type.rb +72 -0
- data/lib/faildns/ip.rb +57 -0
- data/lib/faildns/message.rb +100 -0
- data/lib/faildns/qclass.rb +51 -0
- data/lib/faildns/qtype.rb +60 -0
- data/lib/faildns/question.rb +101 -0
- data/lib/faildns/resourcerecord.rb +140 -0
- data/lib/faildns/resourcerecord/IN.rb +29 -0
- data/lib/faildns/resourcerecord/IN/A.rb +75 -0
- data/lib/faildns/resourcerecord/IN/AAAA.rb +77 -0
- data/lib/faildns/resourcerecord/IN/CNAME.rb +70 -0
- data/lib/faildns/resourcerecord/IN/HINFO.rb +79 -0
- data/lib/faildns/resourcerecord/IN/MX.rb +75 -0
- data/lib/faildns/resourcerecord/IN/NS.rb +77 -0
- data/lib/faildns/resourcerecord/IN/NULL.rb +66 -0
- data/lib/faildns/resourcerecord/IN/PTR.rb +69 -0
- data/lib/faildns/resourcerecord/IN/SOA.rb +128 -0
- data/lib/faildns/resourcerecord/IN/TXT.rb +63 -0
- data/lib/faildns/resourcerecord/data.rb +41 -0
- data/lib/faildns/server.rb +71 -0
- data/lib/faildns/server/dispatcher.rb +181 -0
- data/lib/faildns/server/dispatcher/connectiondispatcher.rb +93 -0
- data/lib/faildns/server/dispatcher/event.rb +47 -0
- data/lib/faildns/server/dispatcher/eventdispatcher.rb +73 -0
- data/lib/faildns/server/dispatcher/socket.rb +93 -0
- data/lib/faildns/type.rb +186 -0
- metadata +100 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
#--
|
2
|
+
# Copyleft meh. [http://meh.doesntexist.org | meh@paranoici.org]
|
3
|
+
#
|
4
|
+
# This file is part of faildns.
|
5
|
+
#
|
6
|
+
# faildns is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Affero General Public License as published
|
8
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# faildns is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
17
|
+
# along with faildns. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#++
|
19
|
+
|
20
|
+
module DNS
|
21
|
+
Version = '0.0.1'
|
22
|
+
|
23
|
+
def self.debug (argument, options={})
|
24
|
+
if !ENV['DEBUG']
|
25
|
+
return
|
26
|
+
end
|
27
|
+
|
28
|
+
if ENV['DEBUG'].to_i < (options[:level] || 1)
|
29
|
+
return
|
30
|
+
end
|
31
|
+
|
32
|
+
output = "From: #{caller[0, options[:deep] || 1].join("\n")}\n"
|
33
|
+
|
34
|
+
if argument.is_a?(Exception)
|
35
|
+
output << "#{argument.class}: #{argument.message}\n"
|
36
|
+
output << argument.backtrace.collect {|stack|
|
37
|
+
stack
|
38
|
+
}.join("\n")
|
39
|
+
output << "\n\n"
|
40
|
+
elsif argument.is_a?(String)
|
41
|
+
output << "#{argument}\n"
|
42
|
+
else
|
43
|
+
output << "#{argument.inspect}\n"
|
44
|
+
end
|
45
|
+
|
46
|
+
if options[:separator]
|
47
|
+
output << options[:separator]
|
48
|
+
end
|
49
|
+
|
50
|
+
puts output
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,223 @@
|
|
1
|
+
#--
|
2
|
+
# Copyleft meh. [http://meh.doesntexist.org | meh@paranoici.org]
|
3
|
+
#
|
4
|
+
# This file is part of faildns.
|
5
|
+
#
|
6
|
+
# faildns is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Affero General Public License as published
|
8
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# faildns is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
17
|
+
# along with faildns. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#++
|
19
|
+
|
20
|
+
module DNS
|
21
|
+
|
22
|
+
#--
|
23
|
+
# Domain names in messages are expressed in terms of a sequence of labels.
|
24
|
+
# Each label is represented as a one octet length field followed by that
|
25
|
+
# number of octets. Since every domain name ends with the null label of
|
26
|
+
# the root, a domain name is terminated by a length byte of zero. The
|
27
|
+
# high order two bits of every length octet must be zero, and the
|
28
|
+
# remaining six bits of the length field limit the label to 63 octets or
|
29
|
+
# less.
|
30
|
+
#
|
31
|
+
# To simplify implementations, the total length of a domain name (i.e.,
|
32
|
+
# label octets and label length octets) is restricted to 255 octets or
|
33
|
+
# less.
|
34
|
+
#
|
35
|
+
# Although labels can contain any 8 bit values in octets that make up a
|
36
|
+
# label, it is strongly recommended that labels follow the preferred
|
37
|
+
# syntax described elsewhere in this memo, which is compatible with
|
38
|
+
# existing host naming conventions. Name servers and resolvers must
|
39
|
+
# compare labels in a case-insensitive manner (i.e., A=a), assuming ASCII
|
40
|
+
# with zero parity. Non-alphabetic codes must match exactly.
|
41
|
+
#
|
42
|
+
# In order to reduce the size of messages, the domain system utilizes a
|
43
|
+
# compression scheme which eliminates the repetition of domain names in a
|
44
|
+
# message. In this scheme, an entire domain name or a list of labels at
|
45
|
+
# the end of a domain name is replaced with a pointer to a prior occurance
|
46
|
+
# of the same name.
|
47
|
+
#
|
48
|
+
# The pointer takes the form of a two octet sequence:
|
49
|
+
#
|
50
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
51
|
+
# | 1 1| OFFSET |
|
52
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
53
|
+
#
|
54
|
+
# The first two bits are ones. This allows a pointer to be distinguished
|
55
|
+
# from a label, since the label must begin with two zero bits because
|
56
|
+
# labels are restricted to 63 octets or less. (The 10 and 01 combinations
|
57
|
+
# are reserved for future use.) The OFFSET field specifies an offset from
|
58
|
+
# the start of the message (i.e., the first octet of the ID field in the
|
59
|
+
# domain header). A zero offset specifies the first byte of the ID field,
|
60
|
+
# etc.
|
61
|
+
#
|
62
|
+
# The compression scheme allows a domain name in a message to be
|
63
|
+
# represented as either:
|
64
|
+
#
|
65
|
+
# - a sequence of labels ending in a zero octet
|
66
|
+
#
|
67
|
+
# - a pointer
|
68
|
+
#
|
69
|
+
# - a sequence of labels ending with a pointer
|
70
|
+
#
|
71
|
+
# Pointers can only be used for occurances of a domain name where the
|
72
|
+
# format is not class specific. If this were not the case, a name server
|
73
|
+
# or resolver would be required to know the format of all RRs it handled.
|
74
|
+
# As yet, there are no such cases, but they may occur in future RDATA
|
75
|
+
# formats.
|
76
|
+
#
|
77
|
+
# If a domain name is contained in a part of the message subject to a
|
78
|
+
# length field (such as the RDATA section of an RR), and compression is
|
79
|
+
# used, the length of the compressed name is used in the length
|
80
|
+
# calculation, rather than the length of the expanded name.
|
81
|
+
#
|
82
|
+
# Programs are free to avoid using pointers in messages they generate,
|
83
|
+
# although this will reduce datagram capacity, and may cause truncation.
|
84
|
+
# However all programs are required to understand arriving messages that
|
85
|
+
# contain pointers.
|
86
|
+
#
|
87
|
+
# For example, a datagram might need to use the domain names F.ISI.ARPA,
|
88
|
+
# FOO.F.ISI.ARPA, ARPA, and the root. Ignoring the other fields of the
|
89
|
+
# message, these domain names might be represented as:
|
90
|
+
#
|
91
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
92
|
+
# 20 | 1 | F |
|
93
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
94
|
+
# 22 | 3 | I |
|
95
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
96
|
+
# 24 | S | I |
|
97
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
98
|
+
# 26 | 4 | A |
|
99
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
100
|
+
# 28 | R | P |
|
101
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
102
|
+
# 30 | A | 0 |
|
103
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
104
|
+
#
|
105
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
106
|
+
# 40 | 3 | F |
|
107
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
108
|
+
# 42 | O | O |
|
109
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
110
|
+
# 44 | 1 1| 20 |
|
111
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
112
|
+
#
|
113
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
114
|
+
# 64 | 1 1| 26 |
|
115
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
116
|
+
#
|
117
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
118
|
+
# 92 | 0 | |
|
119
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
120
|
+
#
|
121
|
+
# The domain name for F.ISI.ARPA is shown at offset 20. The domain name
|
122
|
+
# FOO.F.ISI.ARPA is shown at offset 40; this definition uses a pointer to
|
123
|
+
# concatenate a label for FOO to the previously defined F.ISI.ARPA. The
|
124
|
+
# domain name ARPA is defined at offset 64 using a pointer to the ARPA
|
125
|
+
# component of the name F.ISI.ARPA at 20; note that this pointer relies on
|
126
|
+
# ARPA being the last label in the string at 20. The root domain name is
|
127
|
+
# defined by a single octet of zeros at 92; the root domain name has no
|
128
|
+
# labels.
|
129
|
+
#++
|
130
|
+
|
131
|
+
class DomainName
|
132
|
+
def self.pointer (string, offset)
|
133
|
+
string.force_encoding 'BINARY'
|
134
|
+
|
135
|
+
return string[offset.unpack('n').first & 0x3FFF, 512]
|
136
|
+
end
|
137
|
+
|
138
|
+
def self.parse (string, whole)
|
139
|
+
string.force_encoding 'BINARY'
|
140
|
+
|
141
|
+
result = ''
|
142
|
+
|
143
|
+
case string.unpack('c').first & 0xC0
|
144
|
+
when 0xC0
|
145
|
+
result += DomainName.parse(DomainName.pointer(whole, string), whole)
|
146
|
+
string[0, 2] = ''
|
147
|
+
|
148
|
+
when 0x00
|
149
|
+
while (length = string.unpack('c').first) != 0 && (length & 0xC0) == 0
|
150
|
+
result += '.' + string[1, length]
|
151
|
+
string[0, length + 1] = ''
|
152
|
+
end
|
153
|
+
|
154
|
+
if length & 0xC0 == 0xC0
|
155
|
+
result += '.' + DomainName.parse(string, whole)
|
156
|
+
|
157
|
+
string[0, 2] = ''
|
158
|
+
else
|
159
|
+
string[0, 1] = ''
|
160
|
+
end
|
161
|
+
|
162
|
+
result[0, 1] = ''
|
163
|
+
end
|
164
|
+
|
165
|
+
DomainName.new result
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.length (string)
|
169
|
+
string.force_encoding 'BINARY'
|
170
|
+
|
171
|
+
string = string.clone
|
172
|
+
result = 0
|
173
|
+
|
174
|
+
if string.unpack('c').first & 0xC0 == 0xC0
|
175
|
+
return 2
|
176
|
+
else
|
177
|
+
while (length = string.unpack('c').first) != 0 && (length & 0xC0) == 0
|
178
|
+
result += 1 + length
|
179
|
+
string[0, length + 1] = ''
|
180
|
+
end
|
181
|
+
|
182
|
+
if length & 0xC0 == 0xC0
|
183
|
+
result += 2
|
184
|
+
else
|
185
|
+
result += 1
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
return result
|
190
|
+
end
|
191
|
+
|
192
|
+
attr_accessor :domain
|
193
|
+
|
194
|
+
def initialize (domain)
|
195
|
+
if domain.is_a? DomainName
|
196
|
+
domain = domain.domain
|
197
|
+
end
|
198
|
+
|
199
|
+
if !domain.is_a? String
|
200
|
+
raise ArgumentError.new 'The passed value is not a string.'
|
201
|
+
end
|
202
|
+
|
203
|
+
@domain = domain
|
204
|
+
end
|
205
|
+
|
206
|
+
def to_s
|
207
|
+
@domain
|
208
|
+
end
|
209
|
+
|
210
|
+
alias to_str to_s
|
211
|
+
|
212
|
+
def pack (options={})
|
213
|
+
result = ''
|
214
|
+
|
215
|
+
@domain.split('.').each {|part|
|
216
|
+
result += [part.length].pack('c') + part
|
217
|
+
}
|
218
|
+
|
219
|
+
result += [0].pack('c')
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
@@ -0,0 +1,254 @@
|
|
1
|
+
#--
|
2
|
+
# Copyleft meh. [http://meh.doesntexist.org | meh@paranoici.org]
|
3
|
+
#
|
4
|
+
# This file is part of faildns.
|
5
|
+
#
|
6
|
+
# faildns is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Affero General Public License as published
|
8
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# faildns is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
17
|
+
# along with faildns. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#++
|
19
|
+
|
20
|
+
require 'faildns/header/type'
|
21
|
+
require 'faildns/header/opcode'
|
22
|
+
require 'faildns/header/status'
|
23
|
+
|
24
|
+
module DNS
|
25
|
+
|
26
|
+
#--
|
27
|
+
# The header contains the following fields:
|
28
|
+
#
|
29
|
+
# 1 1 1 1 1 1
|
30
|
+
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
31
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
32
|
+
# | ID |
|
33
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
34
|
+
# |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
|
35
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
36
|
+
# | QDCOUNT |
|
37
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
38
|
+
# | ANCOUNT |
|
39
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
40
|
+
# | NSCOUNT |
|
41
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
42
|
+
# | ARCOUNT |
|
43
|
+
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
44
|
+
#
|
45
|
+
# where:
|
46
|
+
#
|
47
|
+
# ID A 16 bit identifier assigned by the program that
|
48
|
+
# generates any kind of query. This identifier is copied
|
49
|
+
# the corresponding reply and can be used by the requester
|
50
|
+
# to match up replies to outstanding queries.
|
51
|
+
#
|
52
|
+
# QR A one bit field that specifies whether this message is a
|
53
|
+
# query (0), or a response (1).
|
54
|
+
#
|
55
|
+
# OPCODE A four bit field that specifies kind of query in this
|
56
|
+
# message. This value is set by the originator of a query
|
57
|
+
# and copied into the response. The values are:
|
58
|
+
#
|
59
|
+
# 0 a standard query (QUERY)
|
60
|
+
#
|
61
|
+
# 1 an inverse query (IQUERY)
|
62
|
+
#
|
63
|
+
# 2 a server status request (STATUS)
|
64
|
+
#
|
65
|
+
# 3-15 reserved for future use
|
66
|
+
#
|
67
|
+
# AA Authoritative Answer - this bit is valid in responses,
|
68
|
+
# and specifies that the responding name server is an
|
69
|
+
# authority for the domain name in question section.
|
70
|
+
#
|
71
|
+
# Note that the contents of the answer section may have
|
72
|
+
# multiple owner names because of aliases. The AA bit
|
73
|
+
# corresponds to the name which matches the query name, or
|
74
|
+
# the first owner name in the answer section.
|
75
|
+
#
|
76
|
+
# TC TrunCation - specifies that this message was truncated
|
77
|
+
# due to length greater than that permitted on the
|
78
|
+
# transmission channel.
|
79
|
+
#
|
80
|
+
# RD Recursion Desired - this bit may be set in a query and
|
81
|
+
# is copied into the response. If RD is set, it directs
|
82
|
+
# the name server to pursue the query recursively.
|
83
|
+
# Recursive query support is optional.
|
84
|
+
#
|
85
|
+
# RA Recursion Available - this be is set or cleared in a
|
86
|
+
# response, and denotes whether recursive query support is
|
87
|
+
# available in the name server.
|
88
|
+
#
|
89
|
+
# Z Reserved for future use. Must be zero in all queries
|
90
|
+
# and responses.
|
91
|
+
#
|
92
|
+
# RCODE Response code - this 4 bit field is set as part of
|
93
|
+
# responses. The values have the following
|
94
|
+
# interpretation:
|
95
|
+
#
|
96
|
+
# 0 No error condition
|
97
|
+
#
|
98
|
+
# 1 Format error - The name server was
|
99
|
+
# unable to interpret the query.
|
100
|
+
#
|
101
|
+
# 2 Server failure - The name server was
|
102
|
+
# unable to process this query due to a
|
103
|
+
# problem with the name server.
|
104
|
+
#
|
105
|
+
# 3 Name Error - Meaningful only for
|
106
|
+
# responses from an authoritative name
|
107
|
+
# server, this code signifies that the
|
108
|
+
# domain name referenced in the query does
|
109
|
+
# not exist.
|
110
|
+
#
|
111
|
+
# 4 Not Implemented - The name server does
|
112
|
+
# not support the requested kind of query.
|
113
|
+
#
|
114
|
+
# 5 Refused - The name server refuses to
|
115
|
+
# perform the specified operation for
|
116
|
+
# policy reasons. For example, a name
|
117
|
+
# server may not wish to provide the
|
118
|
+
# information to the particular requester,
|
119
|
+
# or a name server may not wish to perform
|
120
|
+
# a particular operation (e.g., zone
|
121
|
+
# transfer) for particular data.
|
122
|
+
#
|
123
|
+
# 6-15 Reserved for future use.
|
124
|
+
#
|
125
|
+
# QDCOUNT an unsigned 16 bit integer specifying the number of
|
126
|
+
# entries in the question section.
|
127
|
+
#
|
128
|
+
# ANCOUNT an unsigned 16 bit integer specifying the number of
|
129
|
+
# resource records in the answer section.
|
130
|
+
#
|
131
|
+
# NSCOUNT an unsigned 16 bit integer specifying the number of name
|
132
|
+
# server resource records in the authority records
|
133
|
+
# section.
|
134
|
+
#
|
135
|
+
# ARCOUNT an unsigned 16 bit integer specifying the number of
|
136
|
+
# resource records in the additional records section.
|
137
|
+
#++
|
138
|
+
|
139
|
+
class Header
|
140
|
+
@@default = {
|
141
|
+
:AA => false, :TC => false, :RD => false, :RA => false, :AD => false, :CD => true,
|
142
|
+
|
143
|
+
:RCODE => Status.new(:NOERROR),
|
144
|
+
|
145
|
+
:QDCOUNT => 0,
|
146
|
+
:ANCOUNT => 0,
|
147
|
+
:NSCOUNT => 0,
|
148
|
+
:ARCOUNT => 0
|
149
|
+
}
|
150
|
+
|
151
|
+
def self.parse (string)
|
152
|
+
data = string.unpack('nnnnnn')
|
153
|
+
|
154
|
+
string[0, Header.length] = ''
|
155
|
+
|
156
|
+
return Header.new(
|
157
|
+
:ID => data[0],
|
158
|
+
|
159
|
+
:QR => Type.new((data[1] & 0x8000) >> 15),
|
160
|
+
|
161
|
+
:OPCODE => Opcode.new((data[1] & 0x7800) >> 11),
|
162
|
+
|
163
|
+
:AA => (data[1] & 0x400 != 0),
|
164
|
+
:TC => (data[1] & 0x200 != 0),
|
165
|
+
:RD => (data[1] & 0x100 != 0),
|
166
|
+
:RA => (data[1] & 0x80 != 0),
|
167
|
+
:AD => (data[1] & 0x40 != 0),
|
168
|
+
:CD => (data[1] & 0x20 != 0),
|
169
|
+
|
170
|
+
:RCODE => Status.new(data[1] & 0xf),
|
171
|
+
|
172
|
+
:QDCOUNT => data[2],
|
173
|
+
|
174
|
+
:ANCOUNT => data[3],
|
175
|
+
|
176
|
+
:NSCOUNT => data[4],
|
177
|
+
|
178
|
+
:ARCOUNT => data[5]
|
179
|
+
)
|
180
|
+
end
|
181
|
+
|
182
|
+
def self.length (string=nil)
|
183
|
+
12
|
184
|
+
end
|
185
|
+
|
186
|
+
def initialize (what={})
|
187
|
+
if !what.is_a? Hash
|
188
|
+
raise ArgumentError.new('You have to pass a Hash.')
|
189
|
+
end
|
190
|
+
|
191
|
+
@data = @@default.merge(what)
|
192
|
+
|
193
|
+
if block_given?
|
194
|
+
yield self
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def id; @data[:ID] end
|
199
|
+
def type; @data[:QR] end
|
200
|
+
def class; @data[:OPCODE] end
|
201
|
+
def authoritative?; @data[:AA] end
|
202
|
+
def truncated?; @data[:TC] end
|
203
|
+
def recursive?; @data[:RD] end
|
204
|
+
def recursivable?; @data[:RA] end
|
205
|
+
def authentic?; @data[:AD] end
|
206
|
+
def checking?; @data[:CD] end
|
207
|
+
def status; @data[:RCODE] end
|
208
|
+
def questions; @data[:QDCOUNT] end
|
209
|
+
def answers; @data[:ANCOUNT] end
|
210
|
+
def authorities; @data[:NSCOUNT] end
|
211
|
+
def additionals; @data[:ARCOUNT] end
|
212
|
+
|
213
|
+
def id= (val); @data[:ID] = val end
|
214
|
+
def type= (val); @data[:QR] = Type.new(val) end
|
215
|
+
def class= (val); @data[:OPCODE] = Opcode.new(val) end
|
216
|
+
def authoritative!; @data[:AA] = true end
|
217
|
+
def truncated!; @data[:TC] = true end
|
218
|
+
def recursive!; @data[:RD] = true end
|
219
|
+
def recursivable!; @data[:RA] = true end
|
220
|
+
def authentic!; @data[:AD] = true end
|
221
|
+
def checking!; @data[:CD] = true end
|
222
|
+
def not_authoritative!; @data[:AA] = false end
|
223
|
+
def not_truncated!; @data[:TC] = false end
|
224
|
+
def not_recursive!; @data[:RD] = false end
|
225
|
+
def not_recursivable!; @data[:RA] = false end
|
226
|
+
def not_authentic!; @data[:AD] = false end
|
227
|
+
def not_checking!; @data[:CD] = false end
|
228
|
+
def status= (val); @data[:RCODE] = Status.new(val) end
|
229
|
+
def questions= (val); @data[:QDCOUNT] = val end
|
230
|
+
def answers= (val); @data[:ANCOUNT] = val end
|
231
|
+
def authorities= (val); @data[:NSCOUNT] = val end
|
232
|
+
def additionals= (val); @data[:ARCOUNT] = val end
|
233
|
+
|
234
|
+
def pack
|
235
|
+
[
|
236
|
+
self.id,
|
237
|
+
|
238
|
+
( (self.type.value << 15) \
|
239
|
+
| (self.class.value << 14) \
|
240
|
+
| ((self.authoritative?) ? (1 << 10) : 0) \
|
241
|
+
| ((self.truncated?) ? (1 << 9) : 0) \
|
242
|
+
| ((self.recursive?) ? (1 << 8) : 0) \
|
243
|
+
| ((self.recursivable?) ? (1 << 7) : 0) \
|
244
|
+
| (self.status.value)),
|
245
|
+
|
246
|
+
self.questions,
|
247
|
+
self.answers,
|
248
|
+
self.authorities,
|
249
|
+
self.additionals
|
250
|
+
].pack('nnnnnn')
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|