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.
Files changed (37) hide show
  1. data/bin/failnamed +203 -0
  2. data/bin/failresolve +37 -0
  3. data/lib/faildns.rb +20 -0
  4. data/lib/faildns/class.rb +96 -0
  5. data/lib/faildns/client.rb +114 -0
  6. data/lib/faildns/common.rb +52 -0
  7. data/lib/faildns/domainname.rb +223 -0
  8. data/lib/faildns/header.rb +254 -0
  9. data/lib/faildns/header/opcode.rb +95 -0
  10. data/lib/faildns/header/status.rb +123 -0
  11. data/lib/faildns/header/type.rb +72 -0
  12. data/lib/faildns/ip.rb +57 -0
  13. data/lib/faildns/message.rb +100 -0
  14. data/lib/faildns/qclass.rb +51 -0
  15. data/lib/faildns/qtype.rb +60 -0
  16. data/lib/faildns/question.rb +101 -0
  17. data/lib/faildns/resourcerecord.rb +140 -0
  18. data/lib/faildns/resourcerecord/IN.rb +29 -0
  19. data/lib/faildns/resourcerecord/IN/A.rb +75 -0
  20. data/lib/faildns/resourcerecord/IN/AAAA.rb +77 -0
  21. data/lib/faildns/resourcerecord/IN/CNAME.rb +70 -0
  22. data/lib/faildns/resourcerecord/IN/HINFO.rb +79 -0
  23. data/lib/faildns/resourcerecord/IN/MX.rb +75 -0
  24. data/lib/faildns/resourcerecord/IN/NS.rb +77 -0
  25. data/lib/faildns/resourcerecord/IN/NULL.rb +66 -0
  26. data/lib/faildns/resourcerecord/IN/PTR.rb +69 -0
  27. data/lib/faildns/resourcerecord/IN/SOA.rb +128 -0
  28. data/lib/faildns/resourcerecord/IN/TXT.rb +63 -0
  29. data/lib/faildns/resourcerecord/data.rb +41 -0
  30. data/lib/faildns/server.rb +71 -0
  31. data/lib/faildns/server/dispatcher.rb +181 -0
  32. data/lib/faildns/server/dispatcher/connectiondispatcher.rb +93 -0
  33. data/lib/faildns/server/dispatcher/event.rb +47 -0
  34. data/lib/faildns/server/dispatcher/eventdispatcher.rb +73 -0
  35. data/lib/faildns/server/dispatcher/socket.rb +93 -0
  36. data/lib/faildns/type.rb +186 -0
  37. 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
@@ -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