stubby 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/LICENSE +0 -0
- data/README.md +219 -0
- data/bin/stubby +8 -0
- data/lib/stubby/cli/application.rb +160 -0
- data/lib/stubby/cli.rb +3 -0
- data/lib/stubby/extensions/dns/osx.rb +58 -0
- data/lib/stubby/extensions/dns.rb +115 -0
- data/lib/stubby/extensions/http.rb +203 -0
- data/lib/stubby/extensions/reload.rb +46 -0
- data/lib/stubby/master.rb +182 -0
- data/lib/stubby/registry.rb +148 -0
- data/lib/stubby/stub.rb +56 -0
- data/lib/stubby.rb +10 -0
- metadata +251 -0
data/LICENSE
ADDED
File without changes
|
data/README.md
ADDED
@@ -0,0 +1,219 @@
|
|
1
|
+
# Stubby
|
2
|
+
|
3
|
+
A local DNS and HTTP server combo that provides a package manager
|
4
|
+
solution to configuring network systems on a development machine. This
|
5
|
+
is currently only designed to run on OS X.
|
6
|
+
|
7
|
+
Use it to:
|
8
|
+
|
9
|
+
* manage your dev domains (like pow, with lethal power)
|
10
|
+
|
11
|
+
* distribute a spec for your API so developers can run basic tests without
|
12
|
+
hitting your dev server.
|
13
|
+
|
14
|
+
* point a client to the right version of an app without editing a hosts file.
|
15
|
+
|
16
|
+
* lock down access to a dev system only to users running a stubby.json config
|
17
|
+
from your project.
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
Install the stubby gem:
|
22
|
+
|
23
|
+
> $ sudo gem install stubby
|
24
|
+
|
25
|
+
## Available Options
|
26
|
+
|
27
|
+
> $ sudo stubby -h
|
28
|
+
> Commands:
|
29
|
+
> stubby env NAME # Switch stubby environment
|
30
|
+
> stubby help [COMMAND] # Describe available commands or one specific command
|
31
|
+
> stubby search # View all available stubs
|
32
|
+
> stubby start ENVIRONMENT # Starts stubby HTTP and DNS servers, default env ENVIRONMENT
|
33
|
+
> stubby status # View current rules
|
34
|
+
|
35
|
+
## Getting Started
|
36
|
+
|
37
|
+
Stubby uses `Stubfile.json` for configuration. This file includes a mapping of
|
38
|
+
environments to a number of rules that define server configurations and stub
|
39
|
+
usage for the project.
|
40
|
+
|
41
|
+
> cd ~/MyProject
|
42
|
+
> cat Stubfile.json
|
43
|
+
> {
|
44
|
+
> "test": {
|
45
|
+
> "dependencies": {
|
46
|
+
> "example": "staging"
|
47
|
+
> },
|
48
|
+
>
|
49
|
+
> "(https?:\/\/)?example.com": "http://localhost:3000"
|
50
|
+
> },
|
51
|
+
>
|
52
|
+
> "staging": {
|
53
|
+
> "dependencies": {
|
54
|
+
> "example": "staging"
|
55
|
+
> },
|
56
|
+
>
|
57
|
+
> "example.com": "dns-cname://aws..."
|
58
|
+
> }
|
59
|
+
> }
|
60
|
+
|
61
|
+
> $ sudo stubby start
|
62
|
+
|
63
|
+
The 'test' and 'staging' modes for this project both include rules for the
|
64
|
+
'example' stub, and then define a single rule of their own. Stubby starts
|
65
|
+
by default in the 'development' environment, so with this `Stubfile.json`,
|
66
|
+
the stubby server is not yet modifying any requests. In a new terminal:
|
67
|
+
|
68
|
+
> $ sudo stubby env test
|
69
|
+
|
70
|
+
Switches stubby to test mode. Now the 'example' stub is activated, and
|
71
|
+
additionally any requests to http or https versions of example.com are
|
72
|
+
routed to http://localhost:3000. Let's take a look at the rules applied:
|
73
|
+
|
74
|
+
> $ sudo bin/stubby status
|
75
|
+
> {
|
76
|
+
> "rules":{
|
77
|
+
> "example":{
|
78
|
+
> "_comment":"All SMTP traffic (NOT YET FUNCTIONAL)",
|
79
|
+
> "admin.example.com":"10.0.1.1",
|
80
|
+
> "admin2.example.com":"dns-cname://admin.example.com",
|
81
|
+
> "(http?://)?merchant.example.com":"http://10.0.1.1",
|
82
|
+
> "(https?://)?.*.example.io":"http://10.0.1.1",
|
83
|
+
> "(https?://)?.*mail.*yahoo.*":"http://en.wikipedia.org/wiki/RTFM",
|
84
|
+
> "(https?://)?yahoo.com":"https-redirect://duckduckgo.com",
|
85
|
+
> "stubby\\..*":"file:///var/www/tmp",
|
86
|
+
> "api.example.com":"file://~/.stubby/example/files",
|
87
|
+
> "smtp://.*":"log:///var/log/out.txt"
|
88
|
+
> },
|
89
|
+
> "_":{
|
90
|
+
> "dependencies":{
|
91
|
+
> "example":"staging"
|
92
|
+
> },
|
93
|
+
> "(https?://)?example.com":"http://localhost:3000"
|
94
|
+
> }
|
95
|
+
> },
|
96
|
+
> "environment":"test"
|
97
|
+
> }
|
98
|
+
|
99
|
+
This shows us all activated rules. the "_" indicates that the rules are loaded
|
100
|
+
from the current `Stubfile.json`. We also see that requests to yahoo.com are
|
101
|
+
redirected to https://duckduckgo.com:
|
102
|
+
|
103
|
+
To revert the system back to normal, just CTRL-C from the main stubby process.
|
104
|
+
This will revert any changes made to configure DNS servers for all network
|
105
|
+
interfaces and will shut down the stubby server.
|
106
|
+
|
107
|
+
## Stubbing
|
108
|
+
|
109
|
+
A stub is a folder named with the name of the stub that contains a stubby.json file. The stubby.json file contains a hash with the available
|
110
|
+
modes. Each mode contains a set of rules that define how to route DNS and how to handle potential extension requests (redirects, file server, etc).
|
111
|
+
|
112
|
+
Installed stubs are in the ~/.stubby folder:
|
113
|
+
|
114
|
+
> $ ls ~/.stubby
|
115
|
+
> example system.json
|
116
|
+
|
117
|
+
The example folder is the `example` stub, and the system.json file contains the agent configurations. You don't need to manually edit it.
|
118
|
+
|
119
|
+
> $ find ~/.stubby/example
|
120
|
+
> ... example
|
121
|
+
> ... example/files
|
122
|
+
> ... example/hello.html
|
123
|
+
> ... example/stubby.json
|
124
|
+
|
125
|
+
The example/stubby.json file has two modes, staging, and production:
|
126
|
+
|
127
|
+
> cat ~/.stubby/example/stubby.json
|
128
|
+
{ "staging": {...}, "production": {...} }
|
129
|
+
|
130
|
+
Each environment contains a number of rules:
|
131
|
+
|
132
|
+
{ "staging": {
|
133
|
+
"MATCH_REGEXP": "INSTRUCTION"
|
134
|
+
} ... }
|
135
|
+
|
136
|
+
When a request is made, either DNS or HTTP (important), the request is
|
137
|
+
compared against the MATCH_REGEXP. If matched, the INSTRUCTION is executed. Since the same rules are consulted for DNS and HTTP, if you are
|
138
|
+
trying to overwrite a domain, you should make sure the match won't exclude
|
139
|
+
simply the host. For example, to proxy web traffic from test.example.com
|
140
|
+
to a server at 10.0.1.5:
|
141
|
+
|
142
|
+
"test.example.com": "http://10.0.1.5"
|
143
|
+
|
144
|
+
This results in
|
145
|
+
|
146
|
+
> $ dig test.example.com
|
147
|
+
...
|
148
|
+
;; ANSWER SECTION:
|
149
|
+
test.example.com. 0 IN A 172.16.123.1
|
150
|
+
|
151
|
+
172.16.123.1 is the stubby host url (TODO: configurable). All requests
|
152
|
+
to http://test.example.com are routed to the stubby web server at that
|
153
|
+
address.
|
154
|
+
|
155
|
+
> $ curl test.example.com
|
156
|
+
|
157
|
+
Issues a request handled by the stubby web server, which proxies the request to 172.16.123.1.
|
158
|
+
|
159
|
+
## Contributing a Stub
|
160
|
+
|
161
|
+
Fork this repository, update the index.json file, and submit a pull request. For
|
162
|
+
this major version, the remote registry will just be the index.json file from
|
163
|
+
this project's github.
|
164
|
+
|
165
|
+
### DNS Only
|
166
|
+
|
167
|
+
To simply override DNS for test.example.com, you can create an A record on lookup:
|
168
|
+
|
169
|
+
"test.example.com": "10.0.1.5"
|
170
|
+
|
171
|
+
Or a CNAME, if no IP is given:
|
172
|
+
|
173
|
+
"test.example.com": "test.example2.com"
|
174
|
+
|
175
|
+
But you can be explicit in the INSTRUCTION:
|
176
|
+
|
177
|
+
"test.example.com": "dns-a://10.0.1.5"
|
178
|
+
"test.example.com": "dns-cname://test.example2.com"
|
179
|
+
|
180
|
+
Using the dns-#{name} convention, you can create simple references to
|
181
|
+
any dns record type. TODO: need to allow mx record priority somehow.
|
182
|
+
|
183
|
+
### File Server
|
184
|
+
|
185
|
+
Because stubby can intercept HTTP requests, it includes a base set of functionality that allows you two serve files directly from the stub. Given a rule:
|
186
|
+
|
187
|
+
"api.example.com": "file://~/.stubby/example/files"
|
188
|
+
|
189
|
+
DNS will resolve to the stubby server:
|
190
|
+
|
191
|
+
> $ dig api.example.com
|
192
|
+
...
|
193
|
+
api.example.com. 0 IN A 172.16.123.1
|
194
|
+
|
195
|
+
And a web request to api.example.com will serve files from the ~/.stubby/example/files directory:
|
196
|
+
|
197
|
+
> $ curl http://api.example.com/hello.html
|
198
|
+
> <html><head></head><body>Hello</body></html>
|
199
|
+
|
200
|
+
This is designed to allow you to create API stubs (success responses, for instance).
|
201
|
+
|
202
|
+
|
203
|
+
### HTTP Redirects
|
204
|
+
|
205
|
+
Given a rule:
|
206
|
+
|
207
|
+
"(https?:\/\/)?yahoo.com": "http-redirect://duckduckgo.com"
|
208
|
+
|
209
|
+
DNS will resolve to the stubby server, and the web request to http://yahoo.com will redirect to http://duckduckgo.com.
|
210
|
+
|
211
|
+
### Vision
|
212
|
+
|
213
|
+
* protocol in instruction becomes a plugin system. dns-cname:, for instance,
|
214
|
+
could be handled by the dns plugin. If it didn't exist when Stubfile.json was
|
215
|
+
being installed, it would be installed.
|
216
|
+
* proxy traffic on ports and send to log systems:
|
217
|
+
":25": "log-smtp://"
|
218
|
+
":3306": "log-mysql://"
|
219
|
+
* web app front-end: show emails sent, mysql queries made, etc.
|
data/bin/stubby
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
require 'stubby/registry'
|
4
|
+
require 'stubby/extensions/dns'
|
5
|
+
require 'stubby/extensions/http'
|
6
|
+
|
7
|
+
module Stubby
|
8
|
+
module CLI
|
9
|
+
class Application < Thor
|
10
|
+
default_task :start
|
11
|
+
|
12
|
+
# TODO: filesystem watch all config directories for change
|
13
|
+
desc "start ENVIRONMENT", "Starts stubby HTTP and DNS servers"
|
14
|
+
long_desc <<-LONGDESC
|
15
|
+
> $ sudo stubby start [ENVIRONMENT='development']
|
16
|
+
|
17
|
+
Starts the stubby HTTP and DNS servers and loads the configuration
|
18
|
+
from `Stubfile.json` for the named environment. If no environment
|
19
|
+
is given, we default to 'development'
|
20
|
+
|
21
|
+
An environment need not actually match a name in `Stubfile.json`.
|
22
|
+
This allows you to use environments named in dependencies but not
|
23
|
+
in the application. If no rules match the environment, Stubby
|
24
|
+
just won't override any behaviors.
|
25
|
+
LONGDESC
|
26
|
+
|
27
|
+
def start(environment="development")
|
28
|
+
unless File.exists?("Stubfile.json")
|
29
|
+
puts "[ERROR]: Stubfile.json not found!"
|
30
|
+
return
|
31
|
+
end
|
32
|
+
|
33
|
+
unless permissions?
|
34
|
+
puts "[ERROR]: ATM I need to be run with sudo..."
|
35
|
+
return
|
36
|
+
end
|
37
|
+
|
38
|
+
if master_running?
|
39
|
+
puts "[ERROR]: Stubby's already running!"
|
40
|
+
return
|
41
|
+
end
|
42
|
+
|
43
|
+
environments = MultiJson.load(File.read("Stubfile.json"))
|
44
|
+
|
45
|
+
File.write(pidfile, Process.pid)
|
46
|
+
|
47
|
+
master = Stubby::Master.new(environments)
|
48
|
+
master.environment = environment
|
49
|
+
master.run!
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "env NAME", "Switch stubby environment"
|
53
|
+
long_desc <<-LONGDESC
|
54
|
+
> $ sudo stubby env test
|
55
|
+
> {"status":"ok"}
|
56
|
+
LONGDESC
|
57
|
+
def env(name=nil)
|
58
|
+
unless master_running?
|
59
|
+
puts "[ERROR]: Stubby must be running to run 'environment'"
|
60
|
+
return
|
61
|
+
end
|
62
|
+
|
63
|
+
puts HTTPI.post("http://#{STUBBY_MASTER}:9000/environment.json", environment: name).body
|
64
|
+
end
|
65
|
+
|
66
|
+
desc "search", "View all available stubs"
|
67
|
+
long_desc <<-LONGDESC
|
68
|
+
View all available registered stubs. These are stubs that you can use
|
69
|
+
as dependencies in Stubfile.json.
|
70
|
+
|
71
|
+
> $ sudo stubby search
|
72
|
+
> {
|
73
|
+
> "example":[
|
74
|
+
> {
|
75
|
+
> "name":"example",
|
76
|
+
> "version":"v0.0.1",
|
77
|
+
> ...
|
78
|
+
> }
|
79
|
+
> ],
|
80
|
+
> "spreedly":[
|
81
|
+
> {
|
82
|
+
> "name":"spreedly",
|
83
|
+
> "version":"v0.0.1",
|
84
|
+
> ...
|
85
|
+
> }
|
86
|
+
> ]
|
87
|
+
> }
|
88
|
+
|
89
|
+
Wildcard supported for search:
|
90
|
+
|
91
|
+
> $ sudo stubby search ex*
|
92
|
+
> {
|
93
|
+
> "example":[
|
94
|
+
> {
|
95
|
+
> "name":"example",
|
96
|
+
> "version":"v0.0.1",
|
97
|
+
> ...
|
98
|
+
> }
|
99
|
+
> ]
|
100
|
+
> }
|
101
|
+
|
102
|
+
LONGDESC
|
103
|
+
def search(name=nil)
|
104
|
+
if master_running?
|
105
|
+
available = MultiJson.load(HTTPI.get("http://#{STUBBY_MASTER}:9000/stubs/available.json").body)
|
106
|
+
else
|
107
|
+
available = Stubby::Api.registry.index
|
108
|
+
end
|
109
|
+
|
110
|
+
puts MultiJson.dump(available.select { |key, ri|
|
111
|
+
File.fnmatch(name || "*", key)
|
112
|
+
}, pretty: true)
|
113
|
+
end
|
114
|
+
|
115
|
+
desc "status", "View current rules"
|
116
|
+
long_desc <<-LONGDESC
|
117
|
+
> $ sudo bin/stubby status
|
118
|
+
> {
|
119
|
+
> "rules":{
|
120
|
+
> "example":{
|
121
|
+
> "admin.example.com":"10.0.1.1",
|
122
|
+
> ...
|
123
|
+
> },
|
124
|
+
> "_":{
|
125
|
+
> "dependencies":{
|
126
|
+
> "example":"staging"
|
127
|
+
> },
|
128
|
+
> "(https?://)?example.com":"http://localhost:3000"
|
129
|
+
> }
|
130
|
+
> },
|
131
|
+
> "environment":"test"
|
132
|
+
> }
|
133
|
+
LONGDESC
|
134
|
+
def status
|
135
|
+
if master_running?
|
136
|
+
environment = MultiJson.load(HTTPI.get("http://#{STUBBY_MASTER}:9000/environment.json").body)["environment"]
|
137
|
+
activated = MultiJson.load(HTTPI.get("http://#{STUBBY_MASTER}:9000/stubs/activated.json").body)
|
138
|
+
puts MultiJson.dump({ "rules" => activated, "environment" => environment }, pretty: true)
|
139
|
+
else
|
140
|
+
puts MultiJson.dump(status: "error", message: "Stubby currently not running")
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
def pidfile
|
146
|
+
@pidfile ||= File.expand_path("~/.stubby/pid")
|
147
|
+
end
|
148
|
+
|
149
|
+
def master_running?
|
150
|
+
Process.kill(0, File.read(pidfile).to_i)
|
151
|
+
rescue
|
152
|
+
false
|
153
|
+
end
|
154
|
+
|
155
|
+
def permissions?
|
156
|
+
`whoami`.strip == "root"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
data/lib/stubby/cli.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# This module extracts the OS level DNS configuration dependency for OSX.
|
2
|
+
module Extensions
|
3
|
+
module DNS
|
4
|
+
module OSX
|
5
|
+
private
|
6
|
+
def servers_for(interface)
|
7
|
+
servers = `networksetup -getdnsservers '#{interface}'`
|
8
|
+
|
9
|
+
if servers =~ /There aren't any DNS Servers/
|
10
|
+
return ["empty"]
|
11
|
+
else
|
12
|
+
return servers.split("\n")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def setup_reference(interface)
|
17
|
+
return if interface.include? "*"
|
18
|
+
@network_interfaces[interface] = servers_for(interface)
|
19
|
+
puts "[INFO] #{interface} configured with Stubby DNS. Will restore to #{@network_interfaces[interface]}"
|
20
|
+
`networksetup -setdnsservers '#{interface}' #{STUBBY_MASTER}`
|
21
|
+
end
|
22
|
+
|
23
|
+
def teardown_reference(interface, servers)
|
24
|
+
`networksetup -setdnsservers '#{interface}' #{servers.join(" ")}`
|
25
|
+
puts "[INFO] #{interface} original DNS settings restored #{servers.join(" ")}"
|
26
|
+
rescue => e
|
27
|
+
puts e.inspect
|
28
|
+
end
|
29
|
+
|
30
|
+
def setup_references
|
31
|
+
# TODO: if we connect to a new network, we'd like that to use us, too
|
32
|
+
return if @network_interfaces
|
33
|
+
|
34
|
+
@network_interfaces = {}
|
35
|
+
`networksetup listallnetworkservices`.split("\n").each do |interface|
|
36
|
+
next if interface.include? '*'
|
37
|
+
setup_reference(interface)
|
38
|
+
end
|
39
|
+
|
40
|
+
flush
|
41
|
+
end
|
42
|
+
|
43
|
+
def teardown_references
|
44
|
+
interfaces, @network_interfaces = @network_interfaces, nil
|
45
|
+
|
46
|
+
(interfaces || []).each do |interface, servers|
|
47
|
+
teardown_reference(interface, servers)
|
48
|
+
end
|
49
|
+
|
50
|
+
flush
|
51
|
+
end
|
52
|
+
|
53
|
+
def flush
|
54
|
+
`dscacheutil -flushcache`
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'rubydns'
|
2
|
+
require 'ipaddress'
|
3
|
+
require 'uri'
|
4
|
+
require 'pry'
|
5
|
+
|
6
|
+
module Extensions
|
7
|
+
module DNS
|
8
|
+
class UnsupportedOS < Exception; end
|
9
|
+
|
10
|
+
class Server < RubyDNS::Server
|
11
|
+
UPSTREAM = RubyDNS::Resolver.new([[:udp, "8.8.8.8", 53], [:tcp, "8.8.8.8", 53]])
|
12
|
+
IN = Resolv::DNS::Resource::IN
|
13
|
+
|
14
|
+
case RbConfig::CONFIG['host_os']
|
15
|
+
when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
16
|
+
raise UnsupportedOS, "Sorry, Windows is not currently supported"
|
17
|
+
when /darwin|mac os/
|
18
|
+
include Extensions::DNS::OSX
|
19
|
+
when /linux/
|
20
|
+
raise UnsupportedOS, "Sorry, Linux is not currently supported"
|
21
|
+
else
|
22
|
+
raise UnsupportedOS, "Sorry, #{RbConfig::CONFIG['host_os']} wasn't recognized"
|
23
|
+
end
|
24
|
+
|
25
|
+
def process(name, resource_class, transaction)
|
26
|
+
body = HTTPI.post("http://#{STUBBY_MASTER}:9000/rules/search.json", trigger: name).body
|
27
|
+
|
28
|
+
instruction = MultiJson.load(body)
|
29
|
+
|
30
|
+
if instruction.nil? or instruction == "@"
|
31
|
+
transaction.passthrough!(UPSTREAM)
|
32
|
+
return
|
33
|
+
end
|
34
|
+
|
35
|
+
url = URI.parse(instruction)
|
36
|
+
|
37
|
+
if url.scheme.to_s.empty?
|
38
|
+
url = URI.parse("dns-a://" + instruction)
|
39
|
+
elsif (url.scheme.to_s =~ /^dns-.*/).nil?
|
40
|
+
url.host = STUBBY_MASTER
|
41
|
+
end
|
42
|
+
|
43
|
+
response_resource_class = resource url.scheme.gsub('dns-', '')
|
44
|
+
|
45
|
+
if url.host.to_s.empty?
|
46
|
+
url.host = STUBBY_MASTER
|
47
|
+
end
|
48
|
+
|
49
|
+
if !IPAddress.valid?(url.host) and response_resource_class == IN::A
|
50
|
+
response_resource_class = IN::CNAME
|
51
|
+
end
|
52
|
+
|
53
|
+
response = url.host
|
54
|
+
|
55
|
+
if response_resource_class == IN::CNAME
|
56
|
+
response = Resolv::DNS::Name.create(url.host)
|
57
|
+
end
|
58
|
+
|
59
|
+
puts "DNS: #{name} => #{response}-#{resource_class.name})"
|
60
|
+
|
61
|
+
transaction.respond!(response,
|
62
|
+
:resource_class => response_resource_class,
|
63
|
+
:ttl => 0)
|
64
|
+
end
|
65
|
+
|
66
|
+
def run!(session, options)
|
67
|
+
return if options[:dns] == false
|
68
|
+
trap("INT"){ stop! }
|
69
|
+
|
70
|
+
@session = session
|
71
|
+
setup_references and run_dns_server
|
72
|
+
end
|
73
|
+
|
74
|
+
def stop!
|
75
|
+
teardown_references and stop_dns_server
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def resource(pattern)
|
82
|
+
return IN::A unless pattern.respond_to? :to_sym
|
83
|
+
|
84
|
+
{
|
85
|
+
a: IN::A,
|
86
|
+
aaaa: IN::AAAA,
|
87
|
+
srv: IN::SRV,
|
88
|
+
wks: IN::WKS,
|
89
|
+
minfo: IN::MINFO,
|
90
|
+
mx: IN::MX,
|
91
|
+
ns: IN::NS,
|
92
|
+
ptr: IN::PTR,
|
93
|
+
soa: IN::SOA,
|
94
|
+
txt: IN::TXT,
|
95
|
+
cname: IN::CNAME
|
96
|
+
}[pattern.to_sym] || IN::A
|
97
|
+
end
|
98
|
+
|
99
|
+
def run_dns_server
|
100
|
+
logger.level = Logger::INFO
|
101
|
+
|
102
|
+
EventMachine.run do
|
103
|
+
run(:listen => [[:tcp, STUBBY_MASTER, 53],
|
104
|
+
[:udp, STUBBY_MASTER, 53]])
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def stop_dns_server
|
109
|
+
fire :stop
|
110
|
+
EventMachine::stop_event_loop
|
111
|
+
rescue
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|