vagrant-autodns 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +3 -0
- data/LICENSE +202 -0
- data/NOTICE +34 -0
- data/README.md +124 -0
- data/Rakefile +1 -0
- data/lib/vagrant-autodns.rb +22 -0
- data/lib/vagrant-autodns/action.rb +38 -0
- data/lib/vagrant-autodns/actions/add.rb +29 -0
- data/lib/vagrant-autodns/actions/delete.rb +27 -0
- data/lib/vagrant-autodns/actions/redirect_dns.rb +25 -0
- data/lib/vagrant-autodns/actions/start.rb +25 -0
- data/lib/vagrant-autodns/actions/teardown.rb +25 -0
- data/lib/vagrant-autodns/autodnsdb.rb +86 -0
- data/lib/vagrant-autodns/cap/common.rb +42 -0
- data/lib/vagrant-autodns/cap/get_ip.rb +30 -0
- data/lib/vagrant-autodns/cap/install_iptables.rb +37 -0
- data/lib/vagrant-autodns/cap/redirect_dns.rb +78 -0
- data/lib/vagrant-autodns/command.rb +111 -0
- data/lib/vagrant-autodns/commands/add.rb +37 -0
- data/lib/vagrant-autodns/commands/clear.rb +34 -0
- data/lib/vagrant-autodns/commands/delete.rb +34 -0
- data/lib/vagrant-autodns/commands/list.rb +36 -0
- data/lib/vagrant-autodns/commands/reload_all.rb +28 -0
- data/lib/vagrant-autodns/commands/restart.rb +28 -0
- data/lib/vagrant-autodns/commands/status.rb +28 -0
- data/lib/vagrant-autodns/commands/stop.rb +28 -0
- data/lib/vagrant-autodns/config.rb +110 -0
- data/lib/vagrant-autodns/daemon.rb +172 -0
- data/lib/vagrant-autodns/plugin.rb +95 -0
- data/lib/vagrant-autodns/version.rb +12 -0
- data/test/example/Vagrantfile +18 -0
- data/test/example/install_plugin.sh +9 -0
- data/vagrant-autodns.gemspec +38 -0
- metadata +169 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
#© 2014 LinkedIn Corp. All rights reserved.
|
2
|
+
#Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
3
|
+
#use this file except in compliance with the License. You may obtain a copy of
|
4
|
+
#the License at http://www.apache.org/licenses/LICENSE-2.0
|
5
|
+
|
6
|
+
#Unless required by applicable law or agreed to in writing, software
|
7
|
+
#distributed under the License is distributed on an "AS IS" BASIS,
|
8
|
+
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
9
|
+
|
10
|
+
module VagrantAutoDNS
|
11
|
+
class Command
|
12
|
+
class Add < Vagrant.plugin("2", :command)
|
13
|
+
|
14
|
+
def execute
|
15
|
+
require_relative '../autodnsdb'
|
16
|
+
|
17
|
+
opts = OptionParser.new do |optp|
|
18
|
+
optp.banner = "Usage: vagrant autodns add <hostname> <ip> [vagrant_id]"
|
19
|
+
end
|
20
|
+
argv = parse_options(opts) || return
|
21
|
+
#vagrant_id is an option parameter
|
22
|
+
raise Vagrant::Errors::CLIInvalidUsage, :help => opts.help.chomp if (argv.length < 2 || argv.length > 3)
|
23
|
+
|
24
|
+
hostname, ip, vagrant_id = argv
|
25
|
+
|
26
|
+
if VagrantAutoDNS.autodnsdb.update_record(hostname, ip, vagrant_id)
|
27
|
+
@env.ui.info("Entry #{ip} added for host #{hostname}")
|
28
|
+
0
|
29
|
+
else
|
30
|
+
@env.ui.error("Entry #{ip} not added for host #{hostname}")
|
31
|
+
1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#© 2014 LinkedIn Corp. All rights reserved.
|
2
|
+
#Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
3
|
+
#use this file except in compliance with the License. You may obtain a copy of
|
4
|
+
#the License at http://www.apache.org/licenses/LICENSE-2.0
|
5
|
+
|
6
|
+
#Unless required by applicable law or agreed to in writing, software
|
7
|
+
#distributed under the License is distributed on an "AS IS" BASIS,
|
8
|
+
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
9
|
+
|
10
|
+
module VagrantAutoDNS
|
11
|
+
class Command
|
12
|
+
class Clear < Vagrant.plugin("2", :command)
|
13
|
+
|
14
|
+
def execute
|
15
|
+
require_relative '../autodnsdb'
|
16
|
+
|
17
|
+
opts = OptionParser.new do |optp|
|
18
|
+
optp.banner = "Usage: vagrant autodns clear"
|
19
|
+
end
|
20
|
+
argv = parse_options(opts) || return
|
21
|
+
#Takes no arguments
|
22
|
+
raise Vagrant::Errors::CLIInvalidUsage, :help => opts.help.chomp if (argv.length != 0)
|
23
|
+
|
24
|
+
if VagrantAutoDNS.autodnsdb.delete_all_records
|
25
|
+
@env.ui.info("DNS cleared")
|
26
|
+
0
|
27
|
+
else
|
28
|
+
@env.ui.error("Something went wrong")
|
29
|
+
1
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#© 2014 LinkedIn Corp. All rights reserved.
|
2
|
+
#Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
3
|
+
#use this file except in compliance with the License. You may obtain a copy of
|
4
|
+
#the License at http://www.apache.org/licenses/LICENSE-2.0
|
5
|
+
|
6
|
+
#Unless required by applicable law or agreed to in writing, software
|
7
|
+
#distributed under the License is distributed on an "AS IS" BASIS,
|
8
|
+
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
9
|
+
|
10
|
+
module VagrantAutoDNS
|
11
|
+
class Command
|
12
|
+
class Delete < Vagrant.plugin("2", :command)
|
13
|
+
def execute
|
14
|
+
require_relative '../autodnsdb'
|
15
|
+
|
16
|
+
opts = OptionParser.new do |optp|
|
17
|
+
optp.banner = "Usage: vagrant autodns delete <hostname>"
|
18
|
+
end
|
19
|
+
argv = parse_options(opts) || return
|
20
|
+
raise Vagrant::Errors::CLIInvalidUsage, :help => opts.help.chomp if (argv.length != 1)
|
21
|
+
|
22
|
+
db = VagrantAutoDNS.autodnsdb
|
23
|
+
hostname = argv[0]
|
24
|
+
if db.delete_record(hostname)
|
25
|
+
@env.ui.info("Host #{hostname} deleted")
|
26
|
+
0
|
27
|
+
else
|
28
|
+
@env.ui.error("Host #{hostname} not deleted")
|
29
|
+
1
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#© 2014 LinkedIn Corp. All rights reserved.
|
2
|
+
#Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
3
|
+
#use this file except in compliance with the License. You may obtain a copy of
|
4
|
+
#the License at http://www.apache.org/licenses/LICENSE-2.0
|
5
|
+
|
6
|
+
#Unless required by applicable law or agreed to in writing, software
|
7
|
+
#distributed under the License is distributed on an "AS IS" BASIS,
|
8
|
+
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
9
|
+
|
10
|
+
module VagrantAutoDNS
|
11
|
+
class Command
|
12
|
+
class List < Vagrant.plugin("2", :command)
|
13
|
+
|
14
|
+
def execute
|
15
|
+
require_relative '../autodnsdb'
|
16
|
+
|
17
|
+
opts = OptionParser.new do |optp|
|
18
|
+
optp.banner = "Usage: vagrant autodns list"
|
19
|
+
end
|
20
|
+
argv = parse_options(opts) || return
|
21
|
+
#Takes no arguments
|
22
|
+
raise Vagrant::Errors::CLIInvalidUsage, :help => opts.help.chomp if (argv.length != 0)
|
23
|
+
|
24
|
+
records = VagrantAutoDNS.autodnsdb.list_all_records
|
25
|
+
if records.empty?
|
26
|
+
@env.ui.error("No records found")
|
27
|
+
else
|
28
|
+
records.each do |record|
|
29
|
+
@env.ui.success("Host #{record["hostname"]} has IP #{record["ip"]}")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
0
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#© 2014 LinkedIn Corp. All rights reserved.
|
2
|
+
#Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
3
|
+
#use this file except in compliance with the License. You may obtain a copy of
|
4
|
+
#the License at http://www.apache.org/licenses/LICENSE-2.0
|
5
|
+
|
6
|
+
#Unless required by applicable law or agreed to in writing, software
|
7
|
+
#distributed under the License is distributed on an "AS IS" BASIS,
|
8
|
+
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
9
|
+
|
10
|
+
module VagrantAutoDNS
|
11
|
+
class Command
|
12
|
+
class Reload < Vagrant.plugin("2", :command)
|
13
|
+
def execute
|
14
|
+
require_relative '../daemon'
|
15
|
+
|
16
|
+
opts = OptionParser.new do |optp|
|
17
|
+
optp.banner = "Usage: vagrant autodns [re]start"
|
18
|
+
end
|
19
|
+
argv = parse_options(opts) || return
|
20
|
+
#Takes no arguments
|
21
|
+
raise Vagrant::Errors::CLIInvalidUsage, :help => opts.help.chomp if (argv.length != 0)
|
22
|
+
|
23
|
+
#TODO: Fixme
|
24
|
+
0
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#© 2014 LinkedIn Corp. All rights reserved.
|
2
|
+
#Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
3
|
+
#use this file except in compliance with the License. You may obtain a copy of
|
4
|
+
#the License at http://www.apache.org/licenses/LICENSE-2.0
|
5
|
+
|
6
|
+
#Unless required by applicable law or agreed to in writing, software
|
7
|
+
#distributed under the License is distributed on an "AS IS" BASIS,
|
8
|
+
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
9
|
+
|
10
|
+
module VagrantAutoDNS
|
11
|
+
class Command
|
12
|
+
class Restart < Vagrant.plugin("2", :command)
|
13
|
+
def execute
|
14
|
+
require_relative '../daemon'
|
15
|
+
|
16
|
+
opts = OptionParser.new do |optp|
|
17
|
+
optp.banner = "Usage: vagrant autodns [re]start"
|
18
|
+
end
|
19
|
+
argv = parse_options(opts) || return
|
20
|
+
#Takes no arguments
|
21
|
+
raise Vagrant::Errors::CLIInvalidUsage, :help => opts.help.chomp if (argv.length != 0)
|
22
|
+
|
23
|
+
VagrantAutoDNS::Daemon.restart
|
24
|
+
0
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#© 2014 LinkedIn Corp. All rights reserved.
|
2
|
+
#Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
3
|
+
#use this file except in compliance with the License. You may obtain a copy of
|
4
|
+
#the License at http://www.apache.org/licenses/LICENSE-2.0
|
5
|
+
|
6
|
+
#Unless required by applicable law or agreed to in writing, software
|
7
|
+
#distributed under the License is distributed on an "AS IS" BASIS,
|
8
|
+
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
9
|
+
|
10
|
+
module VagrantAutoDNS
|
11
|
+
class Command
|
12
|
+
class Status < Vagrant.plugin("2", :command)
|
13
|
+
def execute
|
14
|
+
require_relative '../daemon'
|
15
|
+
|
16
|
+
opts = OptionParser.new do |optp|
|
17
|
+
optp.banner = "Usage: vagrant autodns [re]start"
|
18
|
+
end
|
19
|
+
argv = parse_options(opts) || return
|
20
|
+
#Takes no arguments
|
21
|
+
raise Vagrant::Errors::CLIInvalidUsage, :help => opts.help.chomp if (argv.length != 0)
|
22
|
+
|
23
|
+
@env.ui.success("Daemon status is #{VagrantAutoDNS::Daemon.daemon_status}")
|
24
|
+
0
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#© 2014 LinkedIn Corp. All rights reserved.
|
2
|
+
#Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
3
|
+
#use this file except in compliance with the License. You may obtain a copy of
|
4
|
+
#the License at http://www.apache.org/licenses/LICENSE-2.0
|
5
|
+
|
6
|
+
#Unless required by applicable law or agreed to in writing, software
|
7
|
+
#distributed under the License is distributed on an "AS IS" BASIS,
|
8
|
+
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
9
|
+
|
10
|
+
module VagrantAutoDNS
|
11
|
+
class Command
|
12
|
+
class Stop < Vagrant.plugin("2", :command)
|
13
|
+
def execute
|
14
|
+
require_relative '../daemon'
|
15
|
+
|
16
|
+
opts = OptionParser.new do |optp|
|
17
|
+
optp.banner = "Usage: vagrant autodns [re]start"
|
18
|
+
end
|
19
|
+
argv = parse_options(opts) || return
|
20
|
+
#Takes no arguments
|
21
|
+
raise Vagrant::Errors::CLIInvalidUsage, :help => opts.help.chomp if (argv.length != 0)
|
22
|
+
|
23
|
+
VagrantAutoDNS::Daemon.stop
|
24
|
+
0
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
#© 2014 LinkedIn Corp. All rights reserved.
|
2
|
+
#Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
3
|
+
#use this file except in compliance with the License. You may obtain a copy of
|
4
|
+
#the License at http://www.apache.org/licenses/LICENSE-2.0
|
5
|
+
|
6
|
+
#Unless required by applicable law or agreed to in writing, software
|
7
|
+
#distributed under the License is distributed on an "AS IS" BASIS,
|
8
|
+
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
9
|
+
|
10
|
+
require_relative 'daemon'
|
11
|
+
|
12
|
+
module VagrantAutoDNS
|
13
|
+
class Config < Vagrant.plugin('2', :config)
|
14
|
+
|
15
|
+
# @return [Boolean]
|
16
|
+
attr_accessor :enabled
|
17
|
+
|
18
|
+
# @return [String, Array] (default System resolver)
|
19
|
+
attr_accessor :resolver
|
20
|
+
|
21
|
+
# @return [String] Valid IPV4 address (default 127.0.0.1)
|
22
|
+
attr_accessor :listen_ip
|
23
|
+
|
24
|
+
# @return [Fixnum] Port number (default 15353)
|
25
|
+
attr_accessor :listen_port
|
26
|
+
|
27
|
+
# @return [String] IPv6 address
|
28
|
+
attr_accessor :listen_ipv6
|
29
|
+
|
30
|
+
# @return [Boolean] Enable ipv6
|
31
|
+
attr_accessor :enable_ipv6
|
32
|
+
|
33
|
+
# @return [String] Directory to store data and state
|
34
|
+
attr_accessor :working_directory
|
35
|
+
|
36
|
+
# @return [String] DB File name
|
37
|
+
attr_accessor :db_file
|
38
|
+
|
39
|
+
DAEMON_DEFAULT_OPTS = {
|
40
|
+
:working_directory => '.vagrant/autodns',
|
41
|
+
:listen_ip => '127.0.0.1',
|
42
|
+
:listen_port => 15353,
|
43
|
+
:resolver => :system, #Deamon defaults to system
|
44
|
+
:db_file => 'autodns.db',
|
45
|
+
:enable_ipv6 => true,
|
46
|
+
}
|
47
|
+
|
48
|
+
CLIENT_DEFAULT_OPTS = {
|
49
|
+
:aliases => []
|
50
|
+
}
|
51
|
+
|
52
|
+
DEFAULT_VALUES = {
|
53
|
+
:enabled => false
|
54
|
+
}.merge(DAEMON_DEFAULT_OPTS).merge(CLIENT_DEFAULT_OPTS)
|
55
|
+
|
56
|
+
def initialize
|
57
|
+
super
|
58
|
+
DEFAULT_VALUES.keys.each do |default_key|
|
59
|
+
instance_key = instance_var(default_key)
|
60
|
+
instance_variable_set(instance_key, UNSET_VALUE)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def alias(*aliases)
|
65
|
+
@aliases.concat(aliases)
|
66
|
+
end
|
67
|
+
|
68
|
+
def enable
|
69
|
+
@enabled = true
|
70
|
+
end
|
71
|
+
|
72
|
+
def disable
|
73
|
+
@enabled = false
|
74
|
+
end
|
75
|
+
|
76
|
+
def enabled?
|
77
|
+
#Coerce to boolean
|
78
|
+
!!@enabled
|
79
|
+
end
|
80
|
+
|
81
|
+
def finalize!
|
82
|
+
#special handling for working_directory
|
83
|
+
expand_working_directory
|
84
|
+
|
85
|
+
DEFAULT_VALUES.each do |default_key, default_value|
|
86
|
+
instance_key = instance_var(default_key)
|
87
|
+
if instance_variable_get(instance_key) == UNSET_VALUE
|
88
|
+
instance_variable_set(instance_key, default_value)
|
89
|
+
end
|
90
|
+
next unless DAEMON_DEFAULT_OPTS.has_key?(default_key)
|
91
|
+
Daemon.send(:instance_variable_set, instance_key, instance_variable_get(instance_key))
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def expand_working_directory
|
98
|
+
case @working_directory
|
99
|
+
when UNSET_VALUE
|
100
|
+
@working_directory = File.expand_path DAEMON_DEFAULT_OPTS[:working_directory]
|
101
|
+
else
|
102
|
+
@working_directory = File.expand_path working_directory
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def instance_var(key)
|
107
|
+
'@' + key.to_s
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
#© 2014 LinkedIn Corp. All rights reserved.
|
2
|
+
#Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
3
|
+
#use this file except in compliance with the License. You may obtain a copy of
|
4
|
+
#the License at http://www.apache.org/licenses/LICENSE-2.0
|
5
|
+
|
6
|
+
#Unless required by applicable law or agreed to in writing, software
|
7
|
+
#distributed under the License is distributed on an "AS IS" BASIS,
|
8
|
+
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
9
|
+
|
10
|
+
require 'rexec'
|
11
|
+
require 'rexec/daemon'
|
12
|
+
require 'rubydns'
|
13
|
+
require 'rubydns/resolver'
|
14
|
+
require 'rubydns/system'
|
15
|
+
require 'rainbow/ext/string'
|
16
|
+
require_relative 'autodnsdb'
|
17
|
+
|
18
|
+
module VagrantAutoDNS
|
19
|
+
class Daemon < RExec::Daemon::Base
|
20
|
+
|
21
|
+
@@base_directory = nil
|
22
|
+
|
23
|
+
ProcessFile = RExec::Daemon::ProcessFile
|
24
|
+
A_RECORD = Resolv::DNS::Resource::IN::A
|
25
|
+
AAAA_RECORD = Resolv::DNS::Resource::IN::AAAA
|
26
|
+
|
27
|
+
class << self
|
28
|
+
attr_accessor :working_directory, :resolver, :db_file
|
29
|
+
attr_accessor :listen_ip, :listen_port, :enable_ipv6
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.run
|
33
|
+
upstream = upstream_resolver
|
34
|
+
db_lib = AutoDNSDB
|
35
|
+
db_absolute_path = autodnsdb_path
|
36
|
+
allow_ipv6 = ipv6_enabled?
|
37
|
+
RubyDNS::run_server(:listen => listen_interface) do
|
38
|
+
db = db_lib.new(db_absolute_path)
|
39
|
+
match(//, A_RECORD) do |transaction|
|
40
|
+
domain = transaction.name.to_s.encode('US-ASCII')
|
41
|
+
record = db.find_record(domain)
|
42
|
+
if record
|
43
|
+
transaction.respond!(record['ip'])
|
44
|
+
else
|
45
|
+
transaction.passthrough!(upstream)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
match(//, AAAA_RECORD) do |transaction|
|
50
|
+
if allow_ipv6
|
51
|
+
transaction.passthrough!(upstream)
|
52
|
+
else
|
53
|
+
transaction.fail!(:NXDomain)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Default DNS handler
|
58
|
+
otherwise do |transaction|
|
59
|
+
transaction.passthrough!(upstream)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.restart
|
65
|
+
stop unless stopped?
|
66
|
+
start
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.ensure_running
|
70
|
+
restart unless running?
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.daemon_status
|
74
|
+
ProcessFile.status(self)
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.pid
|
78
|
+
ProcessFile.recall(self)
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.running?
|
82
|
+
daemon_status == :running
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.stopped?
|
86
|
+
daemon_status == :stopped
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.ipv6_enabled?
|
90
|
+
@enable_ipv6.nil? || @enable_ipv6
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.autodnsdb
|
94
|
+
return @autodnsdb if @autodnsdb.is_a?(AutoDNSDB)
|
95
|
+
@autodnsdb = AutoDNSDB.new(autodnsdb_path)
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.autodnsdb_path
|
99
|
+
@autodnsdb_path ||= File.expand_path(File.join(working_directory, db_file))
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.working_directory=(dir)
|
103
|
+
@working_directory = File.expand_path(dir)
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
# RubyDNS upstream resolver
|
109
|
+
def self.upstream_resolver
|
110
|
+
#Bail out if already set
|
111
|
+
return @resolver if @resolver.is_a?(RubyDNS::Resolver)
|
112
|
+
#Case statment must set new_resolver to a valid interface
|
113
|
+
case @resolver
|
114
|
+
when String
|
115
|
+
# IP or IP/PORT combo
|
116
|
+
new_resolver = to_interface(@resolver)
|
117
|
+
when Array
|
118
|
+
#If 2 strings are provided assume they are IPs
|
119
|
+
if @resolver.length == 2 && @resolver.all?{|v| v.is_a? String}
|
120
|
+
new_resolver = @resolver.map{|ip| to_interface(ip)}.flatten(1)
|
121
|
+
#Else expect array formated in interface form
|
122
|
+
else
|
123
|
+
new_resolver = @resolver
|
124
|
+
end
|
125
|
+
when Symbol
|
126
|
+
#Use the predefined custom_resolvers
|
127
|
+
new_resolver = custom_resolver(@resolver)
|
128
|
+
when NilClass
|
129
|
+
#Default to system_resolver
|
130
|
+
new_resolver = system_resolver
|
131
|
+
end
|
132
|
+
@resolver = RubyDNS::Resolver.new(new_resolver)
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.listen_interface
|
136
|
+
to_interface(listen_ip, listen_port)
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.custom_resolver(resolver = :random)
|
140
|
+
return system_resolver if resolver == :system
|
141
|
+
#TODO: move to config file somewhere
|
142
|
+
hosted_resolvers = {
|
143
|
+
:level3 => ['209.244.0.3', '209.244.0.4'],
|
144
|
+
:google => ['8.8.8.8', '8.8.4.4'],
|
145
|
+
:securly => ['184.169.143.224', '184.169.161.155'],
|
146
|
+
:comodo => ['8.26.56.26', '8.20.247.20'],
|
147
|
+
:opendns => ['208.67.222.222', '208.67.220.220'],
|
148
|
+
:norton => ['198.153.192.40', '198.153.194.40'],
|
149
|
+
:opennic => ['216.87.84.211', '23.90.4.6']
|
150
|
+
}
|
151
|
+
resolver = hosted_resolvers.keys.sample if resolver == :random
|
152
|
+
resolver_ip = hosted_resolvers[resolver]
|
153
|
+
resolver_ip.map{|ip| to_interface(ip)}.flatten(1)
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.system_resolver
|
157
|
+
RubyDNS::System::nameservers
|
158
|
+
end
|
159
|
+
|
160
|
+
IPV4_6_PORT_REGEX =
|
161
|
+
/^(?:[0-9.]+|(?:\[[0-9a-fA-F:]+\]))(:[0-9]+)?$/
|
162
|
+
|
163
|
+
def self.to_interface(ip, port = 53)
|
164
|
+
#Try to extract IP and PORT from IP
|
165
|
+
ip_r, port_r = ip.match(IPV4_6_PORT_REGEX).to_a
|
166
|
+
#If regex found port, set it accordingly
|
167
|
+
# remove preceding semi-colon
|
168
|
+
port = port_r[1..-1].to_i if port_r
|
169
|
+
[[:udp, ip_r, port], [:tcp, ip_r, port]]
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|