radd 1.2.0 → 1.3.0
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.
- checksums.yaml +4 -4
- data/bin/radd +1 -1
- data/lib/radd/app.rb +2 -0
- data/lib/radd/cli.rb +77 -4
- data/lib/radd/config.rb +23 -33
- data/lib/radd/ip.rb +2 -2
- data/lib/radd/middleware.rb +12 -0
- data/lib/radd/nameserver.rb +2 -2
- data/lib/radd/schema.rb +17 -0
- data/lib/radd/tasks.rb +39 -0
- data/lib/radd/update.rb +11 -1
- data/lib/radd/version.rb +1 -1
- data/lib/radd/webserver.rb +4 -1
- data/lib/radd.rb +12 -3
- metadata +28 -12
- data/CHANGELOG +0 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aff371d343007b06413d5aeffa546a25824130d0ef8052b1ae7d300f97b665c7
|
|
4
|
+
data.tar.gz: cb860484d7cb6ad5531be423bffbdabecd96bdc5e9544fe97489cd747a6237f5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3eef89dbaad0dfc736443237743a9123452df584cb3c60f1f09a8fe83efe13ba70de21bd1c4ee7fd0e9043477250ed03d08e2a3652cbf4db39f47ac9202b0a36
|
|
7
|
+
data.tar.gz: 5c822bafd10f4fde3714a7eea8051bce9e34197f261ed6eeb8d452ec1a87c0688cd4b6a48ddf1fffdecfc1e71f5976ef850f699bbd7a064d98df07fdd939be53
|
data/bin/radd
CHANGED
data/lib/radd/app.rb
CHANGED
data/lib/radd/cli.rb
CHANGED
|
@@ -2,19 +2,93 @@ require 'optparse'
|
|
|
2
2
|
|
|
3
3
|
module Radd::Cli
|
|
4
4
|
|
|
5
|
+
COMMANDS = %w[help setup add delete list start].freeze
|
|
6
|
+
|
|
5
7
|
class << self
|
|
6
8
|
|
|
7
|
-
def load_config
|
|
9
|
+
def load_config(**opts)
|
|
8
10
|
config = {}
|
|
9
11
|
parser = OptionParser.new
|
|
10
|
-
parser.banner = 'Usage: radd --config
|
|
12
|
+
parser.banner = 'Usage: radd COMMAND [--config FILE]'
|
|
11
13
|
parser.on('--config FILE', 'Config file') do |file|
|
|
12
14
|
config['file'] = file
|
|
13
15
|
end
|
|
14
16
|
|
|
15
17
|
parser.parse!
|
|
16
18
|
|
|
17
|
-
Radd.configure!(config['file'])
|
|
19
|
+
Radd.configure!(config['file'], **opts)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def run
|
|
23
|
+
command = ARGV.shift
|
|
24
|
+
unless COMMANDS.include?(command)
|
|
25
|
+
puts "Unknown command #{command}"
|
|
26
|
+
exit(1)
|
|
27
|
+
end
|
|
28
|
+
send(command)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def help
|
|
32
|
+
puts <<~EOS
|
|
33
|
+
Usage:
|
|
34
|
+
radd COMMAND [--config FILE]
|
|
35
|
+
|
|
36
|
+
You must specify one of the following commands:
|
|
37
|
+
|
|
38
|
+
setup Create the database
|
|
39
|
+
add Add new record
|
|
40
|
+
list List available records
|
|
41
|
+
start Run the server
|
|
42
|
+
|
|
43
|
+
EOS
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def setup
|
|
47
|
+
require_relative 'schema'
|
|
48
|
+
load_config(skip_db: true, skip_models: true)
|
|
49
|
+
Radd::Schema.create
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def add
|
|
53
|
+
load_config
|
|
54
|
+
print "Enter name: "
|
|
55
|
+
name = STDIN.gets.chomp
|
|
56
|
+
print "Password: "
|
|
57
|
+
password = STDIN.gets.chomp
|
|
58
|
+
print "Re-type password: "
|
|
59
|
+
password_confirmation = STDIN.gets.chomp
|
|
60
|
+
raise "Password mismatch!" unless password == password_confirmation
|
|
61
|
+
record = Radd::Record.new(password: password)
|
|
62
|
+
record.name = name
|
|
63
|
+
record.save
|
|
64
|
+
puts "Added record '#{name}'\n"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def delete
|
|
68
|
+
load_config
|
|
69
|
+
print "Enter name: "
|
|
70
|
+
name = STDIN.gets.chomp
|
|
71
|
+
if record = Radd::Record.where(name: name).first
|
|
72
|
+
print "Do you really want to delete #{name} (y/N)?"
|
|
73
|
+
confirm = STDIN.gets.chomp
|
|
74
|
+
if 'y' == confirm
|
|
75
|
+
record.delete
|
|
76
|
+
puts "Record #{name} deleted"
|
|
77
|
+
end
|
|
78
|
+
else
|
|
79
|
+
puts "Record #{name} not found"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def list
|
|
84
|
+
load_config
|
|
85
|
+
puts
|
|
86
|
+
records = Radd::Record.all
|
|
87
|
+
tab = [records.map(&:name).map(&:size).max, 24].compact.max
|
|
88
|
+
records.each do |record|
|
|
89
|
+
puts "#{record.name.ljust(tab)} #{record.ip.to_s.ljust(15)} #{record.updated_at || 'never updated'}\n"
|
|
90
|
+
end
|
|
91
|
+
puts
|
|
18
92
|
end
|
|
19
93
|
|
|
20
94
|
def start
|
|
@@ -25,7 +99,6 @@ module Radd::Cli
|
|
|
25
99
|
|
|
26
100
|
Async do
|
|
27
101
|
dns_task, http_task = dns.run, http.run
|
|
28
|
-
|
|
29
102
|
watchdog = Async do
|
|
30
103
|
sleep(1) while !http_task.failed? && !dns_task.failed?
|
|
31
104
|
puts "Task failed!"
|
data/lib/radd/config.rb
CHANGED
|
@@ -1,44 +1,34 @@
|
|
|
1
1
|
module Radd
|
|
2
2
|
|
|
3
3
|
class << self
|
|
4
|
-
|
|
4
|
+
attr_reader :domain, :ip, :db, :http_host, :http_port, :dns_host, :dns_port, :ttl
|
|
5
|
+
|
|
6
|
+
def configure!(file, skip_models: false, skip_db: false)
|
|
5
7
|
file_path = Pathname.new(file || 'radd.yml')
|
|
6
8
|
file_path = Radd.root + file_path unless file_path.absolute?
|
|
7
|
-
raise
|
|
8
|
-
|
|
9
|
-
raise
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
raise ConfigurationError, "could not open config file #{file_path}" unless file_path.file?
|
|
10
|
+
config = YAML.load(file_path.read)
|
|
11
|
+
raise ConfigurationError, 'domain missing' unless config['domain']
|
|
12
|
+
@domain = config['domain']
|
|
13
|
+
raise ConfigurationError, 'invalid IP' unless Radd.valid_ip?(config['ip'])
|
|
14
|
+
@ip = config['ip']
|
|
15
|
+
uri = URI.parse("http://#{config['http']}")
|
|
16
|
+
@http_host = uri.host || '127.0.0.1'
|
|
17
|
+
@http_port = uri.port || 3003
|
|
18
|
+
uri = URI.parse("dns://#{config['dns']}")
|
|
19
|
+
@dns_host = uri.host || '0.0.0.0'
|
|
20
|
+
@dns_port = uri.port || 53
|
|
21
|
+
raise ConfigurationError, 'invalid TTL' if config['ttl'] && config['ttl'] < 1
|
|
22
|
+
@ttl = config['ttl'] || 300
|
|
23
|
+
db_path = Pathname.new(config['db'] || 'radd.sqlite3')
|
|
12
24
|
db_path = Radd.root + db_path unless db_path.absolute?
|
|
13
|
-
@
|
|
14
|
-
raise
|
|
25
|
+
@db = db_path
|
|
26
|
+
raise ConfigurationError, 'invalid database' if !skip_db && !Radd.db.file?
|
|
27
|
+
#
|
|
15
28
|
# Late loading required by Sequel architecture
|
|
29
|
+
#
|
|
16
30
|
require_relative 'db'
|
|
17
|
-
require_relative 'record'
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def domain
|
|
21
|
-
@config['domain']
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def ip
|
|
25
|
-
@config['ip']
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def db
|
|
29
|
-
@config['db']
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def host
|
|
33
|
-
@config['host'] || '127.0.0.1'
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def dns_port
|
|
37
|
-
@config['dns_port'] || 5300
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def http_port
|
|
41
|
-
@config['http_port'] || 3000
|
|
31
|
+
require_relative 'record' unless skip_models
|
|
42
32
|
end
|
|
43
33
|
|
|
44
34
|
# Check whether +ip+ is a valid IP address string
|
data/lib/radd/ip.rb
CHANGED
data/lib/radd/nameserver.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
class Radd::Nameserver < Async::DNS::Server
|
|
2
2
|
def initialize
|
|
3
|
-
super(Async::DNS::Endpoint.for(Radd.
|
|
3
|
+
super(Async::DNS::Endpoint.for(Radd.dns_host, port: Radd.dns_port))
|
|
4
4
|
end
|
|
5
5
|
|
|
6
6
|
def process(name, resource_class, transaction)
|
|
@@ -12,7 +12,7 @@ class Radd::Nameserver < Async::DNS::Server
|
|
|
12
12
|
ip = Radd.query(name)
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
|
-
return transaction.respond!(ip, ttl:
|
|
15
|
+
return transaction.respond!(ip, ttl: Radd.ttl) if ip
|
|
16
16
|
transaction.fail!(:NXDomain)
|
|
17
17
|
end
|
|
18
18
|
end
|
data/lib/radd/schema.rb
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Radd
|
|
2
|
+
module Schema
|
|
3
|
+
def self.create
|
|
4
|
+
if DB.table_exists?(:records)
|
|
5
|
+
puts "Database #{Radd.db} exists"
|
|
6
|
+
exit(1)
|
|
7
|
+
end
|
|
8
|
+
DB.create_table?(:records) do
|
|
9
|
+
String :name, primary_key: true
|
|
10
|
+
String :password_hash
|
|
11
|
+
String :ip
|
|
12
|
+
DateTime :updated_at
|
|
13
|
+
end
|
|
14
|
+
puts "Created database #{Radd.db}"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
data/lib/radd/tasks.rb
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
namespace :radd do
|
|
2
|
+
task :config do
|
|
3
|
+
Radd::Cli.load_config
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
namespace :db do
|
|
7
|
+
desc 'Create database'
|
|
8
|
+
task create: :config do
|
|
9
|
+
load './db/schema.rb'
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
desc 'Add record'
|
|
14
|
+
task add: :config do
|
|
15
|
+
print "Enter name: "
|
|
16
|
+
name = STDIN.gets.chomp
|
|
17
|
+
print "Password: "
|
|
18
|
+
password = STDIN.gets.chomp
|
|
19
|
+
print "Re-type password: "
|
|
20
|
+
password_confirmation = STDIN.gets.chomp
|
|
21
|
+
raise "Password mismatch!" unless password == password_confirmation
|
|
22
|
+
record = Radd::Record.new(password: password)
|
|
23
|
+
record.name = name
|
|
24
|
+
record.save
|
|
25
|
+
puts "Added record '#{name}'\n"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
desc 'List all records'
|
|
29
|
+
task list: :config do
|
|
30
|
+
puts
|
|
31
|
+
records = Radd::Record.all
|
|
32
|
+
tab = [records.map(&:name).map(&:size).max, 24].compact.max
|
|
33
|
+
records.each do |record|
|
|
34
|
+
puts "#{record.name.ljust(tab)} #{record.ip.to_s.ljust(15)} #{record.updated_at || 'never updated'}\n"
|
|
35
|
+
end
|
|
36
|
+
puts
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
data/lib/radd/update.rb
CHANGED
|
@@ -15,7 +15,14 @@ module Radd
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def ip
|
|
18
|
-
|
|
18
|
+
@ip ||= begin
|
|
19
|
+
addr = env['rack.request'].params['ip'] || remote_ip
|
|
20
|
+
addr && Radd.valid_ip?(addr) && addr
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def remote_ip
|
|
25
|
+
addr = env['rack.request'].ip
|
|
19
26
|
addr && Radd.valid_ip?(addr) && addr
|
|
20
27
|
end
|
|
21
28
|
|
|
@@ -24,6 +31,7 @@ module Radd
|
|
|
24
31
|
raise InvalidRequest.new('Invalid IP address') unless ip
|
|
25
32
|
record.ip = ip
|
|
26
33
|
record.save
|
|
34
|
+
Radd.logger.info "Updated record #{record.name} to #{ip} from #{remote_ip}"
|
|
27
35
|
[200, {'Content-Type' => 'text/plain'}, ["OK #{ip}"]]
|
|
28
36
|
rescue RaddError => boom
|
|
29
37
|
status = case boom
|
|
@@ -32,8 +40,10 @@ module Radd
|
|
|
32
40
|
else
|
|
33
41
|
500
|
|
34
42
|
end
|
|
43
|
+
Radd.logger.error boom
|
|
35
44
|
respond status, "ERROR #{boom.message}"
|
|
36
45
|
rescue Exception => e
|
|
46
|
+
Radd.logger.error e
|
|
37
47
|
respond 500, "ERROR"
|
|
38
48
|
end
|
|
39
49
|
|
data/lib/radd/version.rb
CHANGED
data/lib/radd/webserver.rb
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
class Radd::Webserver < Async::HTTP::Server
|
|
2
2
|
def initialize
|
|
3
|
-
endpoint = Async::HTTP::Endpoint.parse("http://#{Radd.
|
|
3
|
+
endpoint = Async::HTTP::Endpoint.parse("http://#{Radd.http_host}:#{Radd.http_port}")
|
|
4
|
+
# TODO: support UNIX endpoints
|
|
5
|
+
# endpoint = Async::HTTP::Endpoint.parse("http://127.0.0.1")
|
|
6
|
+
# endpoint.endpoint = IO::Endpoint.unix("/tmp/radd1.sock")
|
|
4
7
|
middleware = Protocol::Rack::Adapter.new(Radd::App)
|
|
5
8
|
super(middleware, endpoint)
|
|
6
9
|
end
|
data/lib/radd.rb
CHANGED
|
@@ -2,6 +2,7 @@ require 'yaml'
|
|
|
2
2
|
require 'sequel'
|
|
3
3
|
require 'resolv'
|
|
4
4
|
require 'bcrypt'
|
|
5
|
+
require 'logger'
|
|
5
6
|
|
|
6
7
|
require 'async'
|
|
7
8
|
require 'async/dns'
|
|
@@ -9,11 +10,15 @@ require 'async/http/server'
|
|
|
9
10
|
require 'async/http/endpoint'
|
|
10
11
|
require 'protocol/rack/adapter'
|
|
11
12
|
|
|
13
|
+
# require 'io/endpoint'
|
|
14
|
+
# require 'io/endpoint/unix_endpoint'
|
|
15
|
+
|
|
12
16
|
require_relative 'radd/version'
|
|
13
17
|
require_relative 'radd/errors'
|
|
14
18
|
require_relative 'radd/config'
|
|
15
19
|
require_relative 'radd/ip'
|
|
16
20
|
require_relative 'radd/update'
|
|
21
|
+
require_relative 'radd/middleware'
|
|
17
22
|
require_relative 'radd/nameserver'
|
|
18
23
|
require_relative 'radd/webserver'
|
|
19
24
|
require_relative 'radd/app'
|
|
@@ -24,11 +29,15 @@ module Radd
|
|
|
24
29
|
def root=(path)
|
|
25
30
|
@root = Pathname.new(path)
|
|
26
31
|
end
|
|
27
|
-
|
|
32
|
+
|
|
28
33
|
def root
|
|
29
34
|
@root ||= Pathname.new(Dir.pwd)
|
|
30
35
|
end
|
|
31
|
-
|
|
36
|
+
|
|
37
|
+
def logger
|
|
38
|
+
@logger = Logger.new(STDOUT)
|
|
39
|
+
end
|
|
40
|
+
|
|
32
41
|
# Check whether +name+ is authorized with +password+
|
|
33
42
|
def authorized?(name, password)
|
|
34
43
|
return false unless record = Record.where(name: name).first
|
|
@@ -42,7 +51,7 @@ module Radd
|
|
|
42
51
|
return unless record = Record.active.where(name: name).first
|
|
43
52
|
record.ip
|
|
44
53
|
end
|
|
45
|
-
|
|
54
|
+
|
|
46
55
|
private
|
|
47
56
|
|
|
48
57
|
def config
|
metadata
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: radd
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Matthias Grosser
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-04-
|
|
10
|
+
date: 2026-04-29 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
|
-
name:
|
|
13
|
+
name: yaml
|
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
@@ -24,7 +24,7 @@ dependencies:
|
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '0'
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
|
-
name:
|
|
27
|
+
name: logger
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
29
29
|
requirements:
|
|
30
30
|
- - ">="
|
|
@@ -94,13 +94,13 @@ dependencies:
|
|
|
94
94
|
- !ruby/object:Gem::Version
|
|
95
95
|
version: '0'
|
|
96
96
|
- !ruby/object:Gem::Dependency
|
|
97
|
-
name:
|
|
97
|
+
name: rack
|
|
98
98
|
requirement: !ruby/object:Gem::Requirement
|
|
99
99
|
requirements:
|
|
100
100
|
- - ">="
|
|
101
101
|
- !ruby/object:Gem::Version
|
|
102
102
|
version: '0'
|
|
103
|
-
type: :
|
|
103
|
+
type: :runtime
|
|
104
104
|
prerelease: false
|
|
105
105
|
version_requirements: !ruby/object:Gem::Requirement
|
|
106
106
|
requirements:
|
|
@@ -108,7 +108,7 @@ dependencies:
|
|
|
108
108
|
- !ruby/object:Gem::Version
|
|
109
109
|
version: '0'
|
|
110
110
|
- !ruby/object:Gem::Dependency
|
|
111
|
-
name:
|
|
111
|
+
name: sequel
|
|
112
112
|
requirement: !ruby/object:Gem::Requirement
|
|
113
113
|
requirements:
|
|
114
114
|
- - ">="
|
|
@@ -122,7 +122,7 @@ dependencies:
|
|
|
122
122
|
- !ruby/object:Gem::Version
|
|
123
123
|
version: '0'
|
|
124
124
|
- !ruby/object:Gem::Dependency
|
|
125
|
-
name:
|
|
125
|
+
name: sqlite3
|
|
126
126
|
requirement: !ruby/object:Gem::Requirement
|
|
127
127
|
requirements:
|
|
128
128
|
- - ">="
|
|
@@ -136,7 +136,7 @@ dependencies:
|
|
|
136
136
|
- !ruby/object:Gem::Version
|
|
137
137
|
version: '0'
|
|
138
138
|
- !ruby/object:Gem::Dependency
|
|
139
|
-
name:
|
|
139
|
+
name: bcrypt
|
|
140
140
|
requirement: !ruby/object:Gem::Requirement
|
|
141
141
|
requirements:
|
|
142
142
|
- - ">="
|
|
@@ -150,13 +150,27 @@ dependencies:
|
|
|
150
150
|
- !ruby/object:Gem::Version
|
|
151
151
|
version: '0'
|
|
152
152
|
- !ruby/object:Gem::Dependency
|
|
153
|
-
name:
|
|
153
|
+
name: rake
|
|
154
154
|
requirement: !ruby/object:Gem::Requirement
|
|
155
155
|
requirements:
|
|
156
156
|
- - ">="
|
|
157
157
|
- !ruby/object:Gem::Version
|
|
158
158
|
version: '0'
|
|
159
|
-
type: :
|
|
159
|
+
type: :development
|
|
160
|
+
prerelease: false
|
|
161
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
162
|
+
requirements:
|
|
163
|
+
- - ">="
|
|
164
|
+
- !ruby/object:Gem::Version
|
|
165
|
+
version: '0'
|
|
166
|
+
- !ruby/object:Gem::Dependency
|
|
167
|
+
name: irb
|
|
168
|
+
requirement: !ruby/object:Gem::Requirement
|
|
169
|
+
requirements:
|
|
170
|
+
- - ">="
|
|
171
|
+
- !ruby/object:Gem::Version
|
|
172
|
+
version: '0'
|
|
173
|
+
type: :development
|
|
160
174
|
prerelease: false
|
|
161
175
|
version_requirements: !ruby/object:Gem::Requirement
|
|
162
176
|
requirements:
|
|
@@ -170,7 +184,6 @@ executables:
|
|
|
170
184
|
extensions: []
|
|
171
185
|
extra_rdoc_files: []
|
|
172
186
|
files:
|
|
173
|
-
- CHANGELOG
|
|
174
187
|
- LICENSE
|
|
175
188
|
- README.md
|
|
176
189
|
- bin/radd
|
|
@@ -185,8 +198,11 @@ files:
|
|
|
185
198
|
- lib/radd/http.rb
|
|
186
199
|
- lib/radd/http_service.rb
|
|
187
200
|
- lib/radd/ip.rb
|
|
201
|
+
- lib/radd/middleware.rb
|
|
188
202
|
- lib/radd/nameserver.rb
|
|
189
203
|
- lib/radd/record.rb
|
|
204
|
+
- lib/radd/schema.rb
|
|
205
|
+
- lib/radd/tasks.rb
|
|
190
206
|
- lib/radd/update.rb
|
|
191
207
|
- lib/radd/version.rb
|
|
192
208
|
- lib/radd/webserver.rb
|