dyndnsd 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -3,6 +3,7 @@ language: ruby
3
3
  rvm:
4
4
  - 2.0.0
5
5
  - 1.9.3
6
+ - 1.8.7
6
7
 
7
8
  gemfile:
8
9
  - Gemfile
data/README.md CHANGED
@@ -4,6 +4,117 @@
4
4
 
5
5
  A small, lightweight and extensible DynDNS server written with Ruby and Rack.
6
6
 
7
+ ## Description
8
+
9
+ dyndnsd.rb is aimed to implement a small [DynDNS-compliant](http://dyn.com/support/developers/api/) server in Ruby. It has an integrated user and hostname database in it's configuration file that is used for authentication and authorization. Besides talking the DynDNS protocol it is able to invoke an so-called *updater*, a small Ruby module that takes care of supplying the current host => ip mapping to a DNS server.
10
+
11
+ The is currently one updater shipped with dyndnsd.rb `command_with_bind_zone` that writes out a zone file in BIND syntax onto the current system and invokes a user-supplied command afterwards that is assumed to trigger the DNS server (not necessarily BIND since it's zone files are read by other DNS servers too) to reload it's zone configuration.
12
+
13
+ ## General Usage
14
+
15
+ Install the gem:
16
+
17
+ gem install dyndnsd
18
+
19
+ Create a configuration file in YAML format somewhere:
20
+
21
+ ```yaml
22
+ # listen address and port
23
+ host: "0.0.0.0"
24
+ port: "80"
25
+ # logfile is optional, logs to STDOUT else
26
+ logfile: "dyndnsd.log"
27
+ # interal database file
28
+ db: "db.json"
29
+ # all hostnames are required to be cool-name.example.org
30
+ domain: "example.org"
31
+ # configure the updater, here we use command_with_bind_zone, params are updater-specific
32
+ updater:
33
+ name: "command_with_bind_zone"
34
+ params:
35
+ zone_file: "dyn.zone"
36
+ command: "echo 'Hello'"
37
+ ttl: "5m"
38
+ dns: "dns.example.org."
39
+ email_addr: "admin.example.org."
40
+ # user database with hostnames a user is allowed to update
41
+ users:
42
+ # 'foo' is username, 'secret' the password
43
+ foo:
44
+ password: "secret"
45
+ hosts:
46
+ - foo.example.org
47
+ - bar.example.org
48
+ test:
49
+ password: "ihavenohosts"
50
+ ```
51
+
52
+ Run dyndnsd.rb by:
53
+
54
+ dyndnsd /path/to/config.yaml
55
+
56
+ ## Using dyndnsd.rb with [NSD](https://www.nlnetlabs.nl/nsd/)
57
+
58
+ NSD is a nice opensource, authoritative-only, low-memory DNS server that reads BIND-style zone files (and converts them into it's own database) and has a simple config file.
59
+
60
+ A feature NSD is lacking is the [Dynamic DNS update](https://tools.ietf.org/html/rfc2136) functionality BIND offers but one can fake it using the following dyndnsd.rb config:
61
+
62
+ ```yaml
63
+ host: "0.0.0.0"
64
+ port: "8245" # the DynDNS.com alternative HTTP port
65
+ db: "/opt/dyndnsd/db.json"
66
+ domain: "dyn.example.org"
67
+ updater:
68
+ name: "command_with_bind_zone"
69
+ params:
70
+ # make sure to register zone file in your nsd.conf
71
+ zone_file: "/etc/nsd3/dyn.example.org.zone"
72
+ # fake DNS update (discards NSD stats)
73
+ command: "nsdc rebuild; nsdc reload"
74
+ ttl: "5m"
75
+ dns: "dns.example.org."
76
+ email_addr: "admin.example.org."
77
+ # specify additional raw BIND-style zone content
78
+ # here: an A record for dyn.example.org itself
79
+ additional_zone_content: "@ IN A 1.2.3.4"
80
+ users:
81
+ foo:
82
+ password: "secret"
83
+ hosts:
84
+ - foo.example.org
85
+ ```
86
+
87
+ Start dyndnsd.rb before NSD to make sure the zone file exists else NSD complains.
88
+
89
+ ## Using dyndnsd.rb with X
90
+
91
+ Please provide ideas if you are using dyndnsd.rb with other DNS servers :)
92
+
93
+ ## Advanced topics
94
+
95
+ ### Update URL
96
+
97
+ The update URL you want to tell your clients (humans or scripts ^^) consists of the following
98
+
99
+ http[s]://[USER]:[PASSWORD]@[DOMAIN]:[PORT]/nic/update?hostname=[HOSTNAMES]&myip=[MYIP]
100
+
101
+ where:
102
+
103
+ * the protocol depends on your (webserver/proxy) settings
104
+ * USER and PASSWORD are needed for HTTP Basic Auth and valid combinations are defined in your config.yaml
105
+ * DOMAIN should match what you defined in your config.yaml as domain but may be anything else when using a webserver as proxy
106
+ * PORT depends on your (webserver/proxy) settings
107
+ * HOSTNAMES is a required list of comma separated FQDNs (they all have to end with your config.yaml domain) the user wants to update
108
+ * MYIP is optional and the HTTP client's address will be used if missing
109
+
110
+ ### SSL, multiple listen ports
111
+
112
+ Use a webserver as a proxy to handle SSL and/or multiple listen addresses and ports. DynDNS.com provides HTTP on port 80 and 8245 and HTTPS on port 443.
113
+
114
+ ### Init scripts
115
+
116
+ Coming soon for Debian 6.
117
+
7
118
  ## License
8
119
 
9
120
  dyndnsd.rb is licensed under the Apache License, Version 2.0. See LICENSE for more information.
data/dyndnsd.gemspec CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |s|
21
21
  s.executables = ['dyndnsd']
22
22
 
23
23
  s.add_runtime_dependency 'rack'
24
+ s.add_runtime_dependency('json') if RUBY_VERSION < '1.9'
24
25
 
25
26
  s.add_development_dependency 'bundler', '~> 1.3'
26
27
  s.add_development_dependency 'rake'
@@ -1,4 +1,4 @@
1
1
 
2
2
  module Dyndnsd
3
- VERSION = "0.0.3"
3
+ VERSION = "0.0.4"
4
4
  end
data/lib/dyndnsd.rb CHANGED
@@ -89,6 +89,8 @@ module Dyndnsd
89
89
 
90
90
  myip = params["myip"]
91
91
 
92
+ Dyndnsd.logger.info "Request to update #{hostnames} to #{myip} for user #{user}"
93
+
92
94
  changes = []
93
95
  hostnames.each do |hostname|
94
96
  if (not @db['hosts'].include? hostname) or (@db['hosts'][hostname] != myip)
@@ -101,6 +103,7 @@ module Dyndnsd
101
103
 
102
104
  if @db.changed?
103
105
  @db['serial'] += 1
106
+ Dyndnsd.logger.info "Committing update ##{@db['serial']}"
104
107
  @db.save
105
108
  update
106
109
  end
@@ -109,9 +112,6 @@ module Dyndnsd
109
112
  end
110
113
 
111
114
  def self.run!
112
- Dyndnsd.logger = Logger.new(STDOUT)
113
- Dyndnsd.logger.formatter = LogFormatter.new
114
-
115
115
  if ARGV.length != 1
116
116
  puts "Usage: dyndnsd config_file"
117
117
  exit 1
@@ -120,14 +120,25 @@ module Dyndnsd
120
120
  config_file = ARGV[0]
121
121
 
122
122
  if not File.file?(config_file)
123
- Dyndnsd.logger.fatal "Config file not found!"
123
+ puts "Config file not found!"
124
124
  exit 1
125
125
  end
126
-
127
- Dyndnsd.logger.info "DynDNSd version #{Dyndnsd::VERSION}"
128
- Dyndnsd.logger.info "Using config file #{config_file}"
126
+
127
+ puts "DynDNSd version #{Dyndnsd::VERSION}"
128
+ puts "Using config file #{config_file}"
129
129
 
130
130
  config = YAML::load(File.open(config_file, 'r') { |f| f.read })
131
+
132
+ if config['logfile']
133
+ Dyndnsd.logger = Logger.new(config['logfile'])
134
+ else
135
+ Dyndnsd.logger = Logger.new(STDOUT)
136
+ end
137
+
138
+ Dyndnsd.logger.progname = "dyndnsd"
139
+ Dyndnsd.logger.formatter = LogFormatter.new
140
+
141
+ Dyndnsd.logger.info "Starting..."
131
142
 
132
143
  db = Database.new(config['db'])
133
144
  updater = Updater::CommandWithBindZone.new(config['domain'], config['updater']['params']) if config['updater']['name'] == 'command_with_bind_zone'
@@ -135,10 +146,13 @@ module Dyndnsd
135
146
 
136
147
  app = Daemon.new(config, db, updater, responder)
137
148
  app = Rack::Auth::Basic.new(app, "DynDNS") do |user,pass|
138
- (config['users'].has_key? user) and (config['users'][user]['password'] == pass)
149
+ allow = (config['users'].has_key? user) and (config['users'][user]['password'] == pass)
150
+ Dyndnsd.logger.warn "Login failed for #{user}" if not allow
151
+ allow
139
152
  end
140
153
 
141
154
  Signal.trap('INT') do
155
+ Dyndnsd.logger.info "Quitting..."
142
156
  Rack::Handler::WEBrick.shutdown
143
157
  end
144
158
 
data/spec/daemon_spec.rb CHANGED
@@ -4,6 +4,9 @@ describe Dyndnsd::Daemon do
4
4
  include Rack::Test::Methods
5
5
 
6
6
  def app
7
+ Dyndnsd.logger = Logger.new(STDOUT)
8
+ Dyndnsd.logger.level = Logger::UNKNOWN
9
+
7
10
  config = {
8
11
  'domain' => 'example.org',
9
12
  'users' => {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dyndnsd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2013-04-27 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
16
- requirement: &70238649740540 !ruby/object:Gem::Requirement
16
+ requirement: &73791630 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70238649740540
24
+ version_requirements: *73791630
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: bundler
27
- requirement: &70238649740040 !ruby/object:Gem::Requirement
27
+ requirement: &73791370 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '1.3'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70238649740040
35
+ version_requirements: *73791370
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rake
38
- requirement: &70238649739620 !ruby/object:Gem::Requirement
38
+ requirement: &73791160 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70238649739620
46
+ version_requirements: *73791160
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rspec
49
- requirement: &70238649739160 !ruby/object:Gem::Requirement
49
+ requirement: &73790930 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70238649739160
57
+ version_requirements: *73790930
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rack-test
60
- requirement: &70238649738740 !ruby/object:Gem::Requirement
60
+ requirement: &73790720 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,7 +65,7 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70238649738740
68
+ version_requirements: *73790720
69
69
  description: A small, lightweight and extensible DynDNS server written with Ruby and
70
70
  Rack.
71
71
  email: chrnicolai@gmail.com