rubydns 0.6.7 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 027557f4aae547ca2ae32cc66c59909b6a6bee56
4
- data.tar.gz: f19af2749cdff025edbf9b7d8e8e6546c4911377
3
+ metadata.gz: 190faf76114f4bfe4bcbff8896f6d54ff4d75667
4
+ data.tar.gz: 76d443584858fdfb9d8223215c47b3935d22f53c
5
5
  SHA512:
6
- metadata.gz: bd783eaa39bb28ae521da7b20aaea97636e8c3dfe492864f0c299f7264d786407ecebce88d2e759c42c7e08aff448a914e1913243fafda6d9bf2bdf6489177e2
7
- data.tar.gz: 932b3c6332d87ca10684b42d34cc37b7738730ddb489afd7b08df0f54606ef24560c772e7f30c316b40652d7483d7e3f0f15312cc0f4e68df7a9ba84783d1f14
6
+ metadata.gz: 2d850649e8bb3f66638a30519898ece93a710c08925e83a8ca6ef15fce6474f80795133d71dfac0f67756f8945596771ddc6c0e98d6fd554a40e081b6ba41e61
7
+ data.tar.gz: e797f439ff7aaa0de6b2cbe15621ebf514a24a39441b200ccc09a15cc8baabc6fbfdf5ab95e69c40f31ef2925addce7f436bf5ea8598861bbbb7e072e922f2a5
data/.travis.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  language: ruby
2
2
  rvm:
3
- - "1.9.2"
4
- - "1.9.3"
5
- - "2.0"
6
- - rbx-19mode
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - 2.1.0
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup=markdown
data/README.md CHANGED
@@ -29,122 +29,128 @@ Or install it yourself as:
29
29
 
30
30
  This is copied from `test/examples/test-dns-2.rb`. It has been simplified slightly.
31
31
 
32
- ```ruby
33
- #!/usr/bin/env ruby
34
- require 'rubydns'
35
-
36
- INTERFACES = [
37
- [:udp, "0.0.0.0", 53],
38
- [:tcp, "0.0.0.0", 53]
39
- ]
40
- Name = Resolv::DNS::Name
41
- IN = Resolv::DNS::Resource::IN
42
-
43
- # Use upstream DNS for name resolution.
44
- UPSTREAM = RubyDNS::Resolver.new([[:udp, "8.8.8.8", 53], [:tcp, "8.8.8.8", 53]])
45
-
46
- def self.run
47
- # Start the RubyDNS server
48
- RubyDNS::run_server(:listen => INTERFACES) do
49
- match(/test.mydomain.org/, IN::A) do |transaction|
50
- transaction.respond!("10.0.0.80")
51
- end
52
-
53
- # Default DNS handler
54
- otherwise do |transaction|
55
- transaction.passthrough!(UPSTREAM)
56
- end
57
- end
58
- end
59
- run
60
- ```
32
+ #!/usr/bin/env ruby
33
+ require 'rubydns'
34
+
35
+ INTERFACES = [
36
+ [:udp, "0.0.0.0", 53],
37
+ [:tcp, "0.0.0.0", 53]
38
+ ]
39
+ Name = Resolv::DNS::Name
40
+ IN = Resolv::DNS::Resource::IN
41
+
42
+ # Use upstream DNS for name resolution.
43
+ UPSTREAM = RubyDNS::Resolver.new([[:udp, "8.8.8.8", 53], [:tcp, "8.8.8.8", 53]])
44
+
45
+ def self.run
46
+ # Start the RubyDNS server
47
+ RubyDNS::run_server(:listen => INTERFACES) do
48
+ match(/test.mydomain.org/, IN::A) do |transaction|
49
+ transaction.respond!("10.0.0.80")
50
+ end
51
+
52
+ # Default DNS handler
53
+ otherwise do |transaction|
54
+ transaction.passthrough!(UPSTREAM)
55
+ end
56
+ end
57
+ end
58
+ run
61
59
 
62
60
  Start the server using `rvmsudo ./test.rb`. You can then test it using dig:
63
61
 
64
- ```
65
- $ dig @localhost test1.mydomain.org
66
- $ dig @localhost dev.mydomain.org
67
- $ dig @localhost google.com
68
- ```
62
+ $ dig @localhost test1.mydomain.org
63
+ $ dig @localhost dev.mydomain.org
64
+ $ dig @localhost google.com
69
65
 
70
66
  ## Compatibility
71
67
 
72
- ### Migrating from RubyDNS 0.5.x to 0.6.x ###
68
+ ### Migrating from RubyDNS 0.6.x to 0.7.x
69
+
70
+ The asynchronous deferred processing became the default and only method for processing requests in `0.7.0`. This simplifies the API but there were a few changes, notably the removal of `defer!` and the addition of `defer`. The reason for this was due to issues relating to deferred processing and the flow of control, which were confusing and introduced bugs in specific situations. Now, you can assume flow control through the entire block even with non-blocking functions.
71
+
72
+ RubyDNS::run_server(:listen => SERVER_PORTS) do
73
+ match(/\.*.com/, IN::A) do |transaction|
74
+ # Won't block and won't continue until handle.resume is called.
75
+ defer do |fiber|
76
+ # No domain exists, after 5 seconds:
77
+ EventMachine::Timer.new(5) do
78
+ transaction.fail!(:NXDomain)
79
+
80
+ fiber.resume
81
+ end
82
+ end
83
+ end
84
+
85
+ otherwise do
86
+ transaction.fail!(:NXDomain)
87
+ end
88
+ end
89
+
90
+ You can see a complete example in `test/test_slow_server.rb`.
91
+
92
+ #### Server structure changes
93
+
94
+ When integrating RubyDNS into another project, the rule based DSL is often a hurdle rather than a feature. Thus, the rule-based DSL component of `RubyDNS::Server` class has been separated into a derived `RubyDNS::RuleBasedServer` class. `RubyDNS::Server` can be derived and the `RubyDNS::Server#process` method can be overridden to provide a single entry point for DNS processing.
95
+
96
+ In addition, `RubyDNS::Server#run` can now start the server, provided you are within an `EventMachine#run` context. The existing entry point, `RubyDNS::run_server` provides the same rule-based DSL as previous versions.
97
+
98
+ #### Method name changes
99
+
100
+ Some method names have changed to improve consistency.
101
+
102
+ - `failure!` became `fail!`
103
+ - `append` became `add`
104
+ - `append_query!` became `append!`
105
+
106
+ ### Migrating from RubyDNS 0.5.x to 0.6.x
73
107
 
74
108
  The order of arguments to pattern based rules has changed. For regular expression based rules, the arguments are now ordered `|transaction, match_data|`. The main reason for this change was that in many cases match_data is not important and can thus be ignored, e.g. `|transaction|`.
75
109
 
76
110
  Going forward, Ruby 1.8.x is no longer supported.
77
111
 
78
- ### Migrating from RubyDNS 0.3.x to 0.4.x ###
79
-
80
- Due to changes in `resolv.rb`, superficial parts of RubyDNS have changed. Rather than using `:A` to specify A-records, one must now use the class name.
81
- ```ruby
82
- match(..., :A)
83
- ```
84
- becomes
85
- ```ruby
86
- IN = Resolv::DNS::Resource::IN
87
- match(..., IN::A)
88
- ```
89
- ### Migrating from RubyDNS 0.4.x to 0.5.x ###
112
+ ### Migrating from RubyDNS 0.4.x to 0.5.x
90
113
 
91
114
  The system standard resolver was synchronous, and this could stall the server when making upstream requests to other DNS servers. A new resolver `RubyDNS::Resolver` now provides an asynchronous interface and the `Transaction::passthrough` makes exclusive use of this to provide high performance asynchonous resolution.
92
115
 
93
116
  Here is a basic example of how to use the new resolver in full. It is important to provide both `:udp` and `:tcp` connection specifications, so that large requests will be handled correctly:
94
- ```ruby
95
- resolver = RubyDNS::Resolver.new([[:udp, "8.8.8.8", 53], [:tcp, "8.8.8.8", 53]])
96
-
97
- EventMachine::run do
98
- resolver.query('google.com', IN::A) do |response|
99
- case response
100
- when RubyDNS::Message
101
- puts "Got response: #{response.answers.first}"
102
- else
103
- # Response is of class RubyDNS::ResolutionFailure
104
- puts "Failed: #{response.message}"
105
- end
106
117
 
107
- EventMachine::stop
118
+ resolver = RubyDNS::Resolver.new([[:udp, "8.8.8.8", 53], [:tcp, "8.8.8.8", 53]])
119
+
120
+ EventMachine::run do
121
+ resolver.query('google.com', IN::A) do |response|
122
+ case response
123
+ when RubyDNS::Message
124
+ puts "Got response: #{response.answers.first}"
125
+ else
126
+ # Response is of class RubyDNS::ResolutionFailure
127
+ puts "Failed: #{response.message}"
128
+ end
129
+
130
+ EventMachine::stop
131
+ end
108
132
  end
109
- end
110
- ```
133
+
111
134
  Existing code that uses `Resolv::DNS` as a resolver will need to be updated:
112
- ```ruby
113
- # 1/ Add this at the top of your file; Host specific system information:
114
- require 'rubydns/system'
135
+
136
+ # 1/ Add this at the top of your file; Host specific system information:
137
+ require 'rubydns/system'
115
138
 
116
- # 2/ Change from R = Resolv::DNS.new to:
117
- R = RubyDNS::Resolver.new(RubyDNS::System::nameservers)
118
- ```
119
- Everything else in the server can remain the same. You can see a complete example in `test/test_resolver.rb`.
139
+ # 2/ Change from R = Resolv::DNS.new to:
140
+ R = RubyDNS::Resolver.new(RubyDNS::System::nameservers)
120
141
 
121
- #### Deferred Transactions ####
142
+ Everything else in the server can remain the same. You can see a complete example in `test/test_resolver.rb`.
122
143
 
123
- The implementation of the above depends on a new feature which was added in 0.5.0:
144
+ ### Migrating from RubyDNS 0.3.x to 0.4.x
124
145
 
125
- ```ruby
126
- transaction.defer!
127
- ```
146
+ Due to changes in `resolv.rb`, superficial parts of RubyDNS have changed. Rather than using `:A` to specify A-records, one must now use the class name.
128
147
 
129
- Once you call this, the transaction won't complete until you call either `transaction.succeed` or `transaction.fail`.
130
- ```ruby
131
- RubyDNS::run_server(:listen => SERVER_PORTS) do
132
- match(/\.*.com/, IN::A) do |transaction|
133
- transaction.defer!
134
-
135
- # No domain exists, after 5 seconds:
136
- EventMachine::Timer.new(5) do
137
- transaction.failure!(:NXDomain)
138
- end
139
- end
148
+ match(..., :A)
140
149
 
141
- otherwise do
142
- transaction.failure!(:NXDomain)
143
- end
144
- end
145
- ```
150
+ becomes
146
151
 
147
- You can see a complete example in `test/test_slow_server.rb`.
152
+ IN = Resolv::DNS::Resource::IN
153
+ match(..., IN::A)
148
154
 
149
155
  ## Contributing
150
156
 
@@ -163,7 +169,7 @@ You can see a complete example in `test/test_slow_server.rb`.
163
169
 
164
170
  Released under the MIT license.
165
171
 
166
- Copyright, 2009, 2012, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
172
+ Copyright, 2009, 2012, 2014, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
167
173
 
168
174
  Permission is hereby granted, free of charge, to any person obtaining a copy
169
175
  of this software and associated documentation files (the "Software"), to deal
data/lib/rubydns.rb CHANGED
@@ -20,14 +20,6 @@
20
20
 
21
21
  require 'rubydns/version'
22
22
 
23
- if RUBY_VERSION < "1.9"
24
- require 'rubydns/extensions/string-1.8'
25
- elsif RUBY_VERSION < "1.9.3"
26
- require 'rubydns/extensions/string-1.9.2'
27
- else
28
- require 'rubydns/extensions/string-1.9.3'
29
- end
30
-
31
23
  require 'rubydns/message'
32
24
  require 'rubydns/server'
33
25
  require 'rubydns/resolver'
@@ -42,50 +34,16 @@ require 'rubydns/handler'
42
34
 
43
35
  module RubyDNS
44
36
 
45
- # Run a server with the given rules. A number of options can be supplied:
46
- #
47
- # <tt>:interfaces</tt>:: A set of sockets or addresses as defined below.
48
- #
49
- # One important feature of DNS is the port it runs on. The <tt>options[:listen]</tt>
50
- # allows you to specify a set of network interfaces and ports to run the server on. This
51
- # must be a list of <tt>[protocol, interface address, port]</tt>.
52
- #
53
- # INTERFACES = [[:udp, "0.0.0.0", 5300]]
54
- # RubyDNS::run_server(:listen => INTERFACES) do
55
- # ...
56
- # end
57
- #
58
- # You can specify already connected sockets if need be:
59
- #
60
- # socket = UDPSocket.new; socket.bind("0.0.0.0", 53)
61
- # Process::Sys.setuid(server_uid)
62
- # INTERFACES = [socket]
63
- #
64
- # The default interface is <tt>[[:udp, "0.0.0.0", 53]]</tt>. The server typically needs
65
- # to run as root for this to work, since port 53 is privileged.
66
- #
37
+ # Run a server with the given rules.
67
38
  def self.run_server (options = {}, &block)
68
- server = RubyDNS::Server.new(&block)
69
- server.logger.info "Starting RubyDNS server (v#{RubyDNS::VERSION})..."
70
-
71
- options[:listen] ||= [[:udp, "0.0.0.0", 53], [:tcp, "0.0.0.0", 53]]
39
+ server = RubyDNS::RuleBasedServer.new(&block)
72
40
 
73
41
  EventMachine.run do
74
- server.fire(:setup)
75
-
76
- # Setup server sockets
77
- options[:listen].each do |spec|
78
- server.logger.info "Listening on #{spec.join(':')}"
79
- if spec[0] == :udp
80
- EventMachine.open_datagram_socket(spec[1], spec[2], UDPHandler, server)
81
- elsif spec[0] == :tcp
82
- EventMachine.start_server(spec[1], spec[2], TCPHandler, server)
83
- end
84
- end
85
-
86
- server.fire(:start)
42
+ server.run(options)
87
43
  end
88
44
 
89
45
  server.fire(:stop)
90
46
  end
47
+
48
+
91
49
  end
@@ -1,3 +1,4 @@
1
+
1
2
  # Copyright, 2009, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
3
  #
3
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -21,6 +22,7 @@
21
22
  require 'stringio'
22
23
 
23
24
  module RubyDNS
25
+ # A helper class for processing incoming network data.
24
26
  class BinaryStringIO < StringIO
25
27
  def initialize
26
28
  super
@@ -19,7 +19,7 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module RubyDNS
22
- # Logs an exception nicely.
22
+ # Logs an exception nicely to a standard `Logger`.
23
23
  def self.log_exception(logger, exception)
24
24
  logger.error "#{exception.class}: #{exception.message}"
25
25
  if exception.backtrace
@@ -23,11 +23,7 @@ require 'resolv'
23
23
  class Resolv
24
24
  class DNS
25
25
  class Message
26
- # Merge the given message with this message. A number of heuristics are
27
- # applied in order to ensure that the result makes sense. For example,
28
- # If the current message is not recursive but is being merged with a
29
- # message that was recursive, this bit is maintained. If either message
30
- # is authoritive, then the result is also authoritive.
26
+ # Merge the given message with this message. A number of heuristics are applied in order to ensure that the result makes sense. For example, If the current message is not recursive but is being merged with a message that was recursive, this bit is maintained. If either message is authoritive, then the result is also authoritive.
31
27
  #
32
28
  # Modifies the current message in place.
33
29
  def merge! (other)
@@ -21,6 +21,7 @@
21
21
  require 'rubydns/chunked'
22
22
 
23
23
  class String
24
+ # Chunk a string which is required for the TEXT `resource_class`.
24
25
  def chunked(chunk_size = 255)
25
26
  RubyDNS::chunked(self)
26
27
  end
@@ -19,18 +19,21 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  require 'rubydns/message'
22
+ require 'rubydns/binary_string'
22
23
 
23
24
  module RubyDNS
24
-
25
+ # @returns the [port, ip address] of the given connection.
25
26
  def self.get_peer_details(connection)
26
27
  Socket.unpack_sockaddr_in(connection.get_peername)
27
28
  end
28
29
 
30
+ # Handling incoming UDP requests, which are single data packets, and pass them on to the given server.
29
31
  module UDPHandler
30
32
  def initialize(server)
31
33
  @server = server
32
34
  end
33
-
35
+
36
+ # Process a packet of data with the given server. If an exception is thrown, a failure message will be sent back.
34
37
  def self.process(server, data, options = {}, &block)
35
38
  server.logger.debug "Receiving incoming query (#{data.bytesize} bytes)..."
36
39
  query = nil
@@ -98,6 +101,7 @@ module RubyDNS
98
101
  @processed = 0
99
102
  end
100
103
 
104
+ # Receive the data via a TCP connection, process messages when we receive the indicated amount of data.
101
105
  def receive_data(data)
102
106
  # We buffer data until we've received the entire packet:
103
107
  @buffer.write(data)
@@ -132,6 +136,7 @@ module RubyDNS
132
136
  end
133
137
  end
134
138
 
139
+ # Check that all data received was processed.
135
140
  def unbind
136
141
  if @processed != @buffer.size
137
142
  raise LengthError.new("Unprocessed data remaining (#{@buffer.size - @processed} bytes unprocessed)")
@@ -46,18 +46,31 @@ module RubyDNS
46
46
  RubyDNS.log_exception(bad_messages_log, error)
47
47
  end
48
48
  end
49
-
49
+
50
+ # Decodes binary data into a {Message}.
50
51
  def self.decode_message(data)
52
+ # Otherwise the decode process might fail with non-binary data.
51
53
  if data.respond_to? :force_encoding
52
54
  data.force_encoding("BINARY")
53
55
  end
54
56
 
55
- Message.decode(data)
57
+ begin
58
+ return Message.decode(data)
59
+ rescue DecodeError
60
+ raise
61
+ rescue StandardError => error
62
+ new_error = DecodeError.new(error.message)
63
+ new_error.set_backtrace(error.backtrace)
64
+
65
+ raise new_error
66
+ end
67
+
56
68
  rescue => error
69
+ # Log the bad messsage if required:
57
70
  if @dump_bad_message
58
- @dump_bad_message.call(StandardError.new("foo"), data)
71
+ @dump_bad_message.call(error, data)
59
72
  end
60
73
 
61
74
  raise
62
75
  end
63
- end
76
+ end