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,93 @@
|
|
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 'thread'
|
21
|
+
require 'socket'
|
22
|
+
|
23
|
+
require 'faildns/server/dispatcher/socket'
|
24
|
+
require 'faildns/message'
|
25
|
+
|
26
|
+
module DNS
|
27
|
+
|
28
|
+
class Server
|
29
|
+
|
30
|
+
class Dispatcher
|
31
|
+
|
32
|
+
class ConnectionDispatcher
|
33
|
+
attr_reader :server, :dispatcher, :listening
|
34
|
+
|
35
|
+
def initialize (dispatcher)
|
36
|
+
@server = dispatcher.server
|
37
|
+
@dispatcher = dispatcher
|
38
|
+
|
39
|
+
@host = @server.options[:host] || '0.0.0.0'
|
40
|
+
@port = @server.options[:port] || 53
|
41
|
+
|
42
|
+
@sockets = []
|
43
|
+
end
|
44
|
+
|
45
|
+
def start
|
46
|
+
@listening = {
|
47
|
+
:TCP => TCPServer.new(@host, @port),
|
48
|
+
:UDP => UDPSocket.new
|
49
|
+
}
|
50
|
+
|
51
|
+
@listening[:UDP].bind(@host, @port)
|
52
|
+
end
|
53
|
+
|
54
|
+
def read
|
55
|
+
reading, = IO::select @sockets.concat([@listening[:UDP], @listening[:TCP]])
|
56
|
+
|
57
|
+
if !reading
|
58
|
+
return
|
59
|
+
end
|
60
|
+
|
61
|
+
reading.each {|socket|
|
62
|
+
if socket.is_a? TCPServer
|
63
|
+
@sockets.push @listening[:TCP].accept_nonblock
|
64
|
+
elsif socket.is_a? TCPSocket
|
65
|
+
self.handle socket.recv_nonblock(65535), socket
|
66
|
+
@sockets.delete(socket)
|
67
|
+
else
|
68
|
+
begin
|
69
|
+
self.handle *@listening[:UDP].recvfrom_nonblock(512)
|
70
|
+
rescue Errno::EAGAIN
|
71
|
+
end
|
72
|
+
end
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
def handle (string, socket)
|
77
|
+
DNS.debug "#{socket.inspect}: #{string.inspect}", { :level => 9 }
|
78
|
+
|
79
|
+
Thread.new(string) {|input|
|
80
|
+
begin
|
81
|
+
@dispatcher.dispatch :input, Socket.new(@dispatcher, socket), Message.parse(string)
|
82
|
+
rescue Exception => e
|
83
|
+
DNS.debug e
|
84
|
+
end
|
85
|
+
}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,47 @@
|
|
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
|
+
|
21
|
+
module DNS
|
22
|
+
|
23
|
+
class Server
|
24
|
+
|
25
|
+
class Dispatcher
|
26
|
+
|
27
|
+
class Event
|
28
|
+
class Callback
|
29
|
+
attr_reader :method
|
30
|
+
attr_accessor :priority
|
31
|
+
|
32
|
+
def initialize (method, priority=0)
|
33
|
+
@method = method
|
34
|
+
@priority = priority
|
35
|
+
end
|
36
|
+
|
37
|
+
def call (*args)
|
38
|
+
return @method.call(*args)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,73 @@
|
|
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/server/dispatcher/event'
|
21
|
+
|
22
|
+
module DNS
|
23
|
+
|
24
|
+
class Server
|
25
|
+
|
26
|
+
class Dispatcher
|
27
|
+
|
28
|
+
class EventDispatcher
|
29
|
+
attr_reader :server, :dispatcher
|
30
|
+
|
31
|
+
def initialize (dispatcher)
|
32
|
+
@server = dispatcher.server
|
33
|
+
@dispatcher = dispatcher
|
34
|
+
|
35
|
+
@chains = {
|
36
|
+
:input => [],
|
37
|
+
:output => [],
|
38
|
+
|
39
|
+
:custom => {}
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def dispatch (chain, socket, message)
|
44
|
+
@chains[chain].each {|callback|
|
45
|
+
callback.call(socket, message)
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
def fire (event, *args)
|
50
|
+
(@chain[:custom][event] || []).each {|callback|
|
51
|
+
begin
|
52
|
+
if callback.call(*args) == false
|
53
|
+
return false
|
54
|
+
end
|
55
|
+
rescue Exception => e
|
56
|
+
end
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
def observe (event, callback, priority=0)
|
61
|
+
@chains[:custom][event].push((callback.is_a?(Event::Callback)) ? callback : Event::Callback.new(callback, priority))
|
62
|
+
end
|
63
|
+
|
64
|
+
def register (chain, callback, priority=0)
|
65
|
+
@chains[chain].push((callback.is_a?(Event::Callback)) ? callback : Event::Callback.new(callback, priority))
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,93 @@
|
|
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
|
+
class Server
|
23
|
+
|
24
|
+
class Dispatcher
|
25
|
+
|
26
|
+
class ConnectionDispatcher
|
27
|
+
|
28
|
+
class Socket
|
29
|
+
attr_reader :ip, :port, :type
|
30
|
+
|
31
|
+
def initialize (dispatcher, what)
|
32
|
+
@dispatcher = dispatcher
|
33
|
+
|
34
|
+
if what.is_a? TCPSocket
|
35
|
+
@type = :TCP
|
36
|
+
@ip = what.peeraddr[3]
|
37
|
+
@port = what.addr[1]
|
38
|
+
|
39
|
+
@socket = what
|
40
|
+
else
|
41
|
+
@type = :UDP
|
42
|
+
@ip = what[3]
|
43
|
+
@port = what[1]
|
44
|
+
|
45
|
+
@socket = dispatcher.connection.listening[:UDP]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def send (message, close=true)
|
50
|
+
@dispatcher.dispatch :output, self, message
|
51
|
+
|
52
|
+
if @type == :UDP && message.pack.length > 512
|
53
|
+
[message.additionals, message.authorities, message.answers, message.questions].each {|rr|
|
54
|
+
while (tmp = message.pack).length > 512 && r.pop; end
|
55
|
+
|
56
|
+
if tmp.length <= 512
|
57
|
+
break
|
58
|
+
end
|
59
|
+
}
|
60
|
+
|
61
|
+
message.header.questions = message.questions.length
|
62
|
+
message.header.answers = message.answers.length
|
63
|
+
message.header.authorities = message.authorities.length
|
64
|
+
message.header.additionals = message.additionals.length
|
65
|
+
|
66
|
+
message.header.truncated!
|
67
|
+
end
|
68
|
+
|
69
|
+
if @socket.is_a? TCPSocket
|
70
|
+
@socket.send_nonblock(message.pack)
|
71
|
+
|
72
|
+
if close
|
73
|
+
@socket.close
|
74
|
+
end
|
75
|
+
else
|
76
|
+
@socket.send(message.pack, 0, ::Socket.pack_sockaddr_in(@port, @ip))
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def close
|
81
|
+
if @socket.is_a? TCPSocket
|
82
|
+
@socket.close
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
data/lib/faildns/type.rb
ADDED
@@ -0,0 +1,186 @@
|
|
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
|
+
# TYPE fields are used in resource records. Note that these types are a
|
24
|
+
# subset of QTYPEs.
|
25
|
+
#
|
26
|
+
# TYPE value and meaning
|
27
|
+
#
|
28
|
+
# A 1 a host address
|
29
|
+
#
|
30
|
+
# NS 2 an authoritative name server
|
31
|
+
#
|
32
|
+
# MD 3 a mail destination (Obsolete - use MX)
|
33
|
+
#
|
34
|
+
# MF 4 a mail forwarder (Obsolete - use MX)
|
35
|
+
#
|
36
|
+
# CNAME 5 the canonical name for an alias
|
37
|
+
#
|
38
|
+
# SOA 6 marks the start of a zone of authority
|
39
|
+
#
|
40
|
+
# MB 7 a mailbox domain name (EXPERIMENTAL)
|
41
|
+
#
|
42
|
+
# MG 8 a mail group member (EXPERIMENTAL)
|
43
|
+
#
|
44
|
+
# MR 9 a mail rename domain name (EXPERIMENTAL)
|
45
|
+
#
|
46
|
+
# NULL 10 a null RR (EXPERIMENTAL)
|
47
|
+
#
|
48
|
+
# WKS 11 a well known service description
|
49
|
+
#
|
50
|
+
# PTR 12 a domain name pointer
|
51
|
+
#
|
52
|
+
# HINFO 13 host information
|
53
|
+
#
|
54
|
+
# MINFO 14 mailbox or mail list information
|
55
|
+
#
|
56
|
+
# MX 15 mail exchange
|
57
|
+
#
|
58
|
+
# TXT 16 text strings
|
59
|
+
#++
|
60
|
+
|
61
|
+
class Type
|
62
|
+
Values = {
|
63
|
+
1 => :A,
|
64
|
+
2 => :NS,
|
65
|
+
3 => :MD,
|
66
|
+
4 => :MF,
|
67
|
+
5 => :CNAME,
|
68
|
+
6 => :SOA,
|
69
|
+
7 => :MB,
|
70
|
+
8 => :MG,
|
71
|
+
9 => :MR,
|
72
|
+
10 => :NULL,
|
73
|
+
11 => :WKS,
|
74
|
+
12 => :PTR,
|
75
|
+
13 => :HINFO,
|
76
|
+
14 => :MINFO,
|
77
|
+
15 => :MX,
|
78
|
+
16 => :TXT,
|
79
|
+
17 => :RP,
|
80
|
+
18 => :AFSDB,
|
81
|
+
19 => :X25,
|
82
|
+
20 => :ISDN,
|
83
|
+
21 => :RT,
|
84
|
+
22 => :NSAP,
|
85
|
+
23 => :NSAP_PTR,
|
86
|
+
24 => :SIG,
|
87
|
+
25 => :KEY,
|
88
|
+
26 => :PX,
|
89
|
+
27 => :GPOS,
|
90
|
+
28 => :AAAA,
|
91
|
+
29 => :LOC,
|
92
|
+
30 => :NXT,
|
93
|
+
31 => :EID,
|
94
|
+
32 => :NIMLOC,
|
95
|
+
33 => :SRV,
|
96
|
+
34 => :ATMA,
|
97
|
+
35 => :NAPTR,
|
98
|
+
36 => :KX,
|
99
|
+
37 => :CERT,
|
100
|
+
38 => :A6,
|
101
|
+
39 => :DNAME,
|
102
|
+
40 => :SINK,
|
103
|
+
41 => :OPT,
|
104
|
+
42 => :APL,
|
105
|
+
43 => :DS,
|
106
|
+
44 => :SSHFP,
|
107
|
+
45 => :IPSECKEY,
|
108
|
+
46 => :RRSIG,
|
109
|
+
47 => :NSEC,
|
110
|
+
48 => :DNSKEY,
|
111
|
+
49 => :DHCID,
|
112
|
+
50 => :NSEC3,
|
113
|
+
51 => :NSEC3PARAM,
|
114
|
+
|
115
|
+
55 => :HIP,
|
116
|
+
56 => :NINFO,
|
117
|
+
57 => :RKEY,
|
118
|
+
58 => :TALINK,
|
119
|
+
|
120
|
+
99 => :SPF,
|
121
|
+
100 => :UINFO,
|
122
|
+
101 => :UID,
|
123
|
+
102 => :GID,
|
124
|
+
103 => :UNSPEC,
|
125
|
+
|
126
|
+
249 => :TKEY,
|
127
|
+
250 => :TSIG,
|
128
|
+
251 => :IXFR,
|
129
|
+
|
130
|
+
32768 => :TA,
|
131
|
+
32769 => :DLV
|
132
|
+
}
|
133
|
+
|
134
|
+
def self.parse (string)
|
135
|
+
string.force_encoding 'BINARY'
|
136
|
+
|
137
|
+
result = self.new(string.unpack('n').first)
|
138
|
+
string[0, self.length] = ''
|
139
|
+
|
140
|
+
return result
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.length (string=nil)
|
144
|
+
2
|
145
|
+
end
|
146
|
+
|
147
|
+
attr_reader :value
|
148
|
+
|
149
|
+
def initialize (value)
|
150
|
+
if value.is_a? Symbol
|
151
|
+
@value = Values.find {|key, val| val == value}.first rescue nil
|
152
|
+
elsif value.is_a? Integer
|
153
|
+
@value = value
|
154
|
+
else
|
155
|
+
@value = value.value rescue nil
|
156
|
+
end
|
157
|
+
|
158
|
+
if !self.to_sym
|
159
|
+
raise ArgumentError.new('The passed value is not a suitable type.')
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def pack
|
164
|
+
[@value].pack('n')
|
165
|
+
end
|
166
|
+
|
167
|
+
def == (what)
|
168
|
+
if what.is_a? Symbol
|
169
|
+
self.to_sym == what
|
170
|
+
elsif value.is_a? Integer
|
171
|
+
@value == what
|
172
|
+
else
|
173
|
+
@value == what.value rescue false
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def to_sym
|
178
|
+
Values[@value]
|
179
|
+
end
|
180
|
+
|
181
|
+
def to_s
|
182
|
+
Values[@value].to_s
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|