MockDnsServer
A mock DNS server that can be instructed to perform actions based on
user-provided conditions, and queried for its history of inputs and outputs.
This server listens and responds on both UDP and TCP ports.
An admin interface is provided, currently in the form of Ruby methods that
can be called. In the future we will probably add an HTTP interface
to these methods. The admin methods:
- instructing the server how to respond given the characteristics of the request
- query the server for its history of inputs and outputs
- request shutdown
Implementation
Threads
server.start
launches its own thread in which it runs. This thread is terminated when server.close
is called.
Admin requests (configuration, analysis, etc.) will occur on the caller's thread.
Starting a Server
The simplest way to run a server is to call the convenience method Server#with_new_server
:
Server.with_new_server(options) do |server|
server.start
end
Options currently consist of:
Option Name | Default Value | Description |
---|
port | 53 | port on which to listen (UDP and TCP) |
timeout | 0.25 sec | timeout for IO.select call |
verbose | false | Whether or not to output diagnostic messages |
The code above will result in the creation of a new thread in which the server will listen
and respond indefinitely. Terminating the server is accomplished by calling server.close
in the caller's thread.
Locking
A single mutex will be used to protect access to the rules and history objects.
All mutex handling will be done by code in this gem, so the caller does not
need to know or care that it is being done.
Message Read Loop
The server will have the following flow of execution:
loop do
read a packet
attempt to parse it into a Dnsruby::Message object; if not, the message will be a string
mutex.synchronize do
action = look up rule
action.call # (perform appropriate action -- send or don't send response, etc.)
add input and output to history
end
end
The above loop is wrapped in an IO.select timeout loop, although currently nothing
is done at timeout time. (Closing the server is accomplished by calling server.close
on the caller's thread.)
For TCP, since the application layer requires that the transmission begin with a 2-byte
message length field (which is packed/unpacked with 'n'), this field is read first,
and the server continues reading until the entire transmission is read.
Conditional Actions
The server can be set up with conditional actions that will control how it responds to
incoming requests. Basically, a ConditionalAction consists of a proc (usually a lambda)
that will be called to determine whether or not the action should be executed,
and another proc (also usually a lambda) defining the action that should be performed.
Only one conditional action will be performed per incoming request.
The conditions in the conditional actions are evaluated in the order with which
they were added to the server. When a condition returns true, the corresponding
action will be performed, and the message loop iteration will end.
For more information about how conditional actions are created, see the ConditionalAction,
PredicateFactory, ActionFactory, and ConditionalActionFactory classes. For how
the conditional actions are searched and performed, see the ConditionalActions class.
History
To get a history of the server's events, call server.history_copy
.
Installation
Add this line to your application's Gemfile:
gem 'mock_dns_server'
And then execute:
$ bundle
Or install it yourself as:
$ gem install mock_dns_server
Usage
TODO: Write usage instructions here
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request