radd 1.4.1 → 1.5.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f979c2d87f1f25eb5c780da9d4d5ecb0543c299bee5d7e73a046825357759d1f
4
- data.tar.gz: 8f92e1c1018b4a5ea9f86e138f3a439e4bd76eaadbfe4ab78a91ecc15d12b33f
3
+ metadata.gz: 8ce6277f2c17ee82c7e873be185b142c0bf8cd4fcfe5faf7b6287360e9a5de77
4
+ data.tar.gz: 9bcb6d8caa6fd25c73dd284ad556ec3be6071b38bca02adbe4b2a0ee24edf0b2
5
5
  SHA512:
6
- metadata.gz: b7e11faf5690621e6027d2356c7ee403488fabf29caa0d5007a2e8d6b8ed8319f3b3ce8373e2f0f97905516f0eea9c263f824da406b067ab188ce0c8936d9fdf
7
- data.tar.gz: 64f91eb6deccbaf8932960b620f65b1f87807c19d7a6492e44a8fa836608cfefe226b25ffde0d3bdec69434742e38bd3e5086bd1f251f11e5c17e451aa2e449f
6
+ metadata.gz: 529ba3c5d7129dc4ba5e783c75e82617ee095578558e7dc23c54ea1aa7439e9c02a5410bf7e40257dcaeff2162e59cc0ee055c9626d11a51ce09b6557124f744
7
+ data.tar.gz: d102da674aea8d27f70cca080c197ac5646e3786327d37e2ed25ab0e216eed128b5b2d2ba9bd5b5987cffce2eae50801eeb58037be1ed8ef9dc8468a1da460d6
data/README.md CHANGED
@@ -1,3 +1,6 @@
1
+ [![Gem Version](https://badge.fury.io/rb/radd.svg)](http://badge.fury.io/rb/radd)
2
+ [![build](https://github.com/mtgrosser/radd/actions/workflows/build.yml/badge.svg)](https://github.com/mtgrosser/radd/actions/workflows/build.yml)
3
+
1
4
  # radd
2
5
 
3
6
  Minimal dynamic DNS service
@@ -13,15 +16,41 @@ gem install radd
13
16
 
14
17
  ```yaml
15
18
  # radd.yml
19
+ origin: ddns.example.com
16
20
  ip: 10.1.2.3
17
- http: 127.0.0.1:3000
18
- dns: 0.0.0.0:53
19
- domain: example.com
20
21
  mname: ns.example.com
21
22
  rname: hostmaster.example.com
23
+ ttl: 300
24
+ http: 127.0.0.1:3000
25
+ dns: 0.0.0.0:53
22
26
  db: radd.sqlite3
23
27
  ```
24
28
 
29
+ #### origin
30
+ Your domain where subdomains are the dynamic hostnames
31
+
32
+ #### ip
33
+ The nameserver's public IP
34
+
35
+ #### mname
36
+ Hostname of the nameserver, must not be a subdomain of `origin`
37
+
38
+ #### rname
39
+ Email address of the nameserver contact, default: `hostmaster.ORIGIN`
40
+
41
+ #### ttl
42
+ TTL of the dynamic A records, default: `300`
43
+
44
+ #### http
45
+ `ÌP:port` the HTTP server should listen on, default: `127.0.0.1:3003`
46
+
47
+ #### dns
48
+ `IP:port` the DNS server should listen on, default: `0.0.0.0:53`
49
+
50
+ #### db
51
+ Path to the zone db, default: `radd.sqlite3`
52
+
53
+
25
54
  ## Usage
26
55
 
27
56
  ```
@@ -37,3 +66,37 @@ delete Delete record
37
66
  list List available records
38
67
  start Run the server
39
68
  ```
69
+
70
+ ## Deployment
71
+
72
+ ### Webserver
73
+ The HTTP server should be exposed via a reverse proxy like Nginx, which provides SSL encryption.
74
+
75
+ ### Nameserver
76
+ The DNS ports (53/udp, 53/tcp) can be exposed directly when using `systemd` to run `radd`.
77
+ The provided unit file (`radd.service`) includes the necessary directives which enable an unprivileged user
78
+ to access port 53.
79
+
80
+ ### DNS configuration
81
+ You need to set your dynamic DNS server as the authoritative nameserver for the used (sub)domain:
82
+
83
+ ```
84
+ NS ddns.example.com ns.example.com. 86400
85
+ ```
86
+
87
+ ## Updating a record via HTTP
88
+
89
+ In order to update a record, an authorized request must be made to the `/update` endpoint.
90
+
91
+ The hostname is determined by the HTTP user name.
92
+ The IP address can be supplied by the `ip` parameter, otherwise, the remote IP of the request will be used:
93
+
94
+ ```
95
+ # use remote IP
96
+ curl --user "hostname:password" https://ddns.example.com/update
97
+ ```
98
+
99
+ ```
100
+ # use given IP
101
+ curl --user "hostname:password" https://ddns.example.com/update?ip=10.20.30.40
102
+ ```
data/lib/radd/cli.rb CHANGED
@@ -100,7 +100,7 @@ module Radd::Cli
100
100
 
101
101
  def start
102
102
  load_config
103
- puts "Starting Radd server for #{Radd.domain}"
103
+ puts "Starting Radd server for #{Radd.origin}"
104
104
 
105
105
  dns, http = Radd::Nameserver.new, Radd::Webserver.new
106
106
 
data/lib/radd/config.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Radd
2
2
 
3
3
  class << self
4
- attr_reader :domain, :ip, :db, :http_host, :http_port, :dns_host, :dns_port, :ttl,
4
+ attr_reader :origin, :ip, :db, :http_host, :http_port, :dns_host, :dns_port, :ttl,
5
5
  :mname, :rname
6
6
 
7
7
  def configure!(file, skip_models: false, skip_db: false)
@@ -9,8 +9,8 @@ module Radd
9
9
  file_path = Radd.root + file_path unless file_path.absolute?
10
10
  raise ConfigurationError, "could not open config file #{file_path}" unless file_path.file?
11
11
  config = YAML.load(file_path.read)
12
- raise ConfigurationError, 'domain missing' unless config['domain']
13
- @domain = config['domain']
12
+ raise ConfigurationError, 'origin missing' unless config['origin']
13
+ @origin = config['origin']
14
14
  raise ConfigurationError, 'invalid IP' unless Radd.valid_ip?(config['ip'])
15
15
  @ip = config['ip']
16
16
  uri = URI.parse("http://#{config['http']}")
@@ -22,8 +22,8 @@ module Radd
22
22
  raise ConfigurationError, 'invalid TTL' if config['ttl'] && config['ttl'] < 1
23
23
  @ttl = config['ttl'] || 300
24
24
  raise ConfigurationError, 'master name missing' unless config['mname']
25
- @mname = config['mname'].split('.').freeze
26
- @rname = encode_email(config['rname'] || "hostmaster@#{domain}").freeze
25
+ @mname = Resolv::DNS::Name.create(config['mname'])
26
+ @rname = Resolv::DNS::Name.create(config['rname'] || "hostmaster@#{origin}")
27
27
  db_path = Pathname.new(config['db'] || 'radd.sqlite3')
28
28
  db_path = Radd.root + db_path unless db_path.absolute?
29
29
  @db = db_path
@@ -39,13 +39,6 @@ module Radd
39
39
  def valid_ip?(ip)
40
40
  !!(ip && ip.match(Resolv::IPv4::Regex))
41
41
  end
42
-
43
- private
44
-
45
- def encode_email(email)
46
- addr, domain = email.split('@')
47
- [addr, *domain.split('.')]
48
- end
49
42
  end
50
43
 
51
44
  end
@@ -9,11 +9,13 @@ module Radd
9
9
  name = name.downcase
10
10
  # NOTE: do not use case..when, as resource classes are not identical
11
11
  if Resolv::DNS::Resource::IN::A == resource_class
12
- ip = Radd.domain == name ? Radd.ip : Radd.query(name)
12
+ ip = [Radd.mname, Radd.origin].include?(name) ? Radd.ip : Radd.query(name)
13
13
  return transaction.respond!(ip, ttl: Radd.ttl) if ip
14
- elsif resource_class <= Resolv::DNS::Resource::SOA && Radd.domain == name
14
+ elsif resource_class <= Resolv::DNS::Resource::SOA && Radd.origin == name
15
15
  # mname, rname, serial, refresh, retry_, expire, minimum
16
16
  return transaction.respond!(Radd.mname, Radd.rname, Radd.serial, 10800, 1800, 604800, 1800)
17
+ elsif resource_class <= Resolv::DNS::Resource::NS && Radd.origin == name
18
+ return transaction.respond!(Radd.mname)
17
19
  end
18
20
  transaction.fail!(:NXDomain)
19
21
  end
data/lib/radd/update.rb CHANGED
@@ -32,7 +32,7 @@ module Radd
32
32
  record.ip = ip
33
33
  record.save
34
34
  Radd.logger.info "Updated record #{record.name} to #{ip} from #{remote_ip}"
35
- [200, {'Content-Type' => 'text/plain'}, ["OK #{ip}"]]
35
+ [200, {'Content-Type' => 'text/plain'}, ["OK #{ip}\n"]]
36
36
  rescue RaddError => boom
37
37
  status = case boom
38
38
  when InvalidRequest, Sequel::ValidationFailed then 422
data/lib/radd/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Radd
2
- VERSION = '1.4.1'
2
+ VERSION = '1.5.2'
3
3
  end
data/lib/radd.rb CHANGED
@@ -63,7 +63,7 @@ module Radd
63
63
  end
64
64
 
65
65
  def fqdn2name(fqdn)
66
- if match = fqdn.downcase.match(/\A([a-z0-9-]{1,63})\.#{Regexp.escape(domain)}\z/)
66
+ if match = fqdn.downcase.match(/\A([a-z0-9-]{1,63})\.#{Regexp.escape(origin)}\z/)
67
67
  match.captures[0]
68
68
  end
69
69
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: radd
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.1
4
+ version: 1.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthias Grosser
@@ -177,6 +177,20 @@ dependencies:
177
177
  - - ">="
178
178
  - !ruby/object:Gem::Version
179
179
  version: '0'
180
+ - !ruby/object:Gem::Dependency
181
+ name: minitest
182
+ requirement: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - "~>"
185
+ - !ruby/object:Gem::Version
186
+ version: '5.0'
187
+ type: :development
188
+ prerelease: false
189
+ version_requirements: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - "~>"
192
+ - !ruby/object:Gem::Version
193
+ version: '5.0'
180
194
  description: Minimal dynamic DNS service
181
195
  email: mtgrosser@gmx.net
182
196
  executables: