stubby 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|