dns_one 0.5.5 → 0.5.6

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
  SHA1:
3
- metadata.gz: d78210ea5e09411a507c872baf45cdd2e6d9b645
4
- data.tar.gz: 0f3dddc89fb102922fae3506003577cc3fd1f781
3
+ metadata.gz: 1712bca4a25d8e72f60b38c83c121087245f583b
4
+ data.tar.gz: 6f6d4c432b13d708273643c7abed58b2c7b8da04
5
5
  SHA512:
6
- metadata.gz: f99f8cea22ad191fdc6c99fb791192ce53988d982c31b1a50f24b2dd4e792a26b2f83ae98e8c68dd38f36dac1d4a60d7e850aa753981b268fb2fde3c44ae69c2
7
- data.tar.gz: 791b7d95188a5a95da729de2d089b28cc168324ee910d90279aeb8169182f53d0e94fdf60e0d261a2a12400e5a22ce659415955e6dcc285130435aa1e39ddb9a
6
+ metadata.gz: 54a23b46cfba3138ad0c76084f71705a5f8194a1d4c5134a0c623117d52a729bfdb404ec73477014fb5deec93c21893a98b7e4bcee810075c52baa40d6ce9a56
7
+ data.tar.gz: 55a248615c9999cd3a63aa04288af1b32514867971ade91ac2cd555d49053c7d5c8b5049bfa0dab889967973d5ba6bb8b2914253ce41b1c6d61090a738f5d285
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency "rspec", "~> 3.0"
27
27
 
28
28
  spec.add_runtime_dependency "thor", '~> 0.19'
29
- spec.add_runtime_dependency "rubydns", '~> 1.0'
29
+ spec.add_runtime_dependency "rubydns", '~> 2.0.1'
30
30
  spec.add_runtime_dependency "rexec", '~> 1.6'
31
31
  spec.add_runtime_dependency "pg", '~> 0.21'
32
32
  spec.add_runtime_dependency "activerecord", '~> 5.0'
@@ -1,6 +1,4 @@
1
1
  # Core
2
- require 'syslog'
3
- require 'syslog/logger'
4
2
  require 'ostruct'
5
3
  require 'singleton'
6
4
  require 'fileutils'
@@ -20,76 +18,63 @@ require "dns_one/core_ext/string"
20
18
  require "dns_one/core_ext/blank"
21
19
  require "dns_one/core_ext/hash"
22
20
 
23
- require "dns_one/log"
21
+ require "dns_one/global"
24
22
  require "dns_one/util"
25
23
  require "dns_one/server"
26
- require "dns_one/stat"
24
+ require "dns_one/req_log/db"
27
25
 
28
26
  module DnsOne; class DnsOne
29
27
 
30
- DEFAULT_CONF_FILE = '/etc/dns_one/conf.yml'
31
- WORK_DIR = "/var/local/dns_one"
32
- CONF_DIR = "/etc/dns_one"
33
-
34
- def initialize conf_file: nil, work_dir: nil
35
- Log.setup
36
-
37
- conf_file ||= DEFAULT_CONF_FILE
38
- @conf_all = parse_conf conf_file
39
- @conf = @conf_all.main
40
-
41
- work_dir ||= WORK_DIR
42
-
43
- begin
44
- Dir.chdir work_dir
45
- rescue => e
46
- Log.w "Cannot change working dir to #{WORK_DIR}. Will continue in #{Dir.pwd}."
47
- end
28
+ DEFAULTS = {
29
+ conf_file: "/etc/dns_one.yml",
30
+ work_dir: "/var/local/dns_one",
31
+ log_file: "/var/log/dns_one/dns_one.log",
32
+ rubydns_log_file: "/var/log/dns_one/dns_one_rubydns.log",
33
+ run_as: "dnsone",
34
+ interfaces: [ [:udp, "0.0.0.0", 53],
35
+ [:tcp, "0.0.0.0", 53],
36
+ [:udp, "::", 5300],
37
+ [:tcp, "::", 5300]
38
+ ],
39
+ log_req_socket_file: '/tmp/dns_one_log_result.sock'
40
+ }
41
+
42
+ def initialize conf_file: nil
43
+ @conf = Global.conf = load_conf(conf_file || DEFAULTS[:conf_file])
48
44
  end
49
-
45
+
50
46
  def start
51
- Server.new(@conf_all.server, @conf_all.zone_search).run
47
+ init_loggers
48
+ chdir
49
+ Server.new.run
52
50
  end
53
51
 
54
52
  private
55
-
56
- def parse_conf conf_file
57
- check_conf_file conf_file
58
53
 
59
- conf = YAML.load_file conf_file
60
- conf = conf.symbolize_keys
54
+ def load_conf conf_file
55
+ conf = DEFAULTS.clone
56
+ conf.merge! YAML.load_file(conf_file).symbolize_keys
57
+ Util.hash_to_ostruct_deep conf
61
58
 
62
- OpenStruct.new(
63
- main: {
64
- work_dir: conf[:config][:work_dir]
65
- },
66
- server: {
67
- run_as: conf[:config][:run_as],
68
- save_stats: conf[:config][:save_stats],
69
- log_result_file: conf[:config][:log_result_file],
70
- log_result_socket: conf[:config][:log_result_socket],
71
- log_result_socket_file: conf[:config][:log_result_socket_file],
72
- },
73
- zone_search: {
74
- ignore_subdomains: conf[:config][:ignore_subdomains],
75
- cache_max: conf[:config][:cache_max],
76
- record_sets: conf[:record_sets],
77
- backend: conf[:backend]
78
- }
79
- )
59
+ rescue => e
60
+ $stderr.puts e.desc
61
+ $stderr.puts "Error opening conf file #{conf_file}. Aborting."
62
+ exit 1
80
63
  end
81
64
 
82
- def check_conf_file conf_file
83
- unless File.readable? conf_file
84
- Util.die "Conf file #{conf_file} not found or unreadable. Aborting."
85
- end
65
+ def init_loggers
66
+ Global.logger = Util.init_logger @conf.log_file , Logger::INFO
67
+ Global.ruby_dns_logger = Util.init_logger @conf.ruby_dns_logger, Logger::WARN
68
+ end
86
69
 
87
- conf_stat = File.stat conf_file
70
+ def chdir
71
+ d = @conf.work_dir
72
+ FileUtils.mkdir_p d
73
+ Dir.chdir d
88
74
 
89
- unless conf_stat.mode.to_s(8) =~ /0600$/
90
- Util.die "Conf file #{conf_file} must have mode 0600. Aborting."
91
- end
75
+ rescue => e
76
+ Global.logger.error e.desc
77
+ Global.logger.error "Cannot chdir to #{@conf.work_dir}. Will continue in #{Dir.pwd}"
92
78
  end
93
79
 
94
80
  end; end
95
-
@@ -31,12 +31,12 @@ module DnsOne; module Backend; class DB < Base
31
31
  record_values&.first
32
32
 
33
33
  rescue ActiveRecord::StatementInvalid => e
34
- Log.e "SQL query error. Trying to reconnect #{tries}. Details:\n#{e.desc}"
34
+ Global.logger.error "SQL query error. Trying to reconnect #{tries}. Details:\n#{e.desc}"
35
35
  # http://geoff.evason.name/2015/01/18/postgres-ssl-connection-has-been-closed-unexpectedly
36
36
  ActiveRecord::Base.connection.reconnect!
37
37
  find sql, (tries+1)
38
38
  rescue => e
39
- Log.e "SQL query error. Details:\n#{e.desc}"
39
+ Global.logger.error "SQL query error. Details:\n#{e.desc}"
40
40
  end
41
41
 
42
42
  def build_query dom_name
@@ -46,7 +46,7 @@ module DnsOne; module Backend; class DB < Base
46
46
 
47
47
  def setup_db
48
48
  #require_deps
49
- ActiveRecord::Base.logger = Log.logger
49
+ ActiveRecord::Base.logger = Global.logger
50
50
  ActiveRecord::Base.establish_connection @conf
51
51
  end
52
52
 
@@ -24,7 +24,7 @@ module DnsOne; module Backend; class File < Base
24
24
  if domain_name and not domain_name.empty?
25
25
  @domain_map[domain_name.strip.downcase] = rec_set_name&.strip || ''
26
26
  else
27
- Log.w "Ignoring #{file} line: #{line}"
27
+ Global.logger.warn "Ignoring #{file} line: #{line}"
28
28
  end
29
29
  end
30
30
  end
@@ -52,7 +52,7 @@ module DnsOne; module Backend; class HTTPBell < Base
52
52
  .map{ |r|
53
53
  id, domain = r.strip.split /\s+/
54
54
  if id !~ /^\d+$/ || domain !~ Util::DOM_REGEX
55
- Log.w "invalid line '#{r}'"
55
+ Global.logger.warn "invalid line '#{r}'"
56
56
  nil
57
57
  else
58
58
  [id.to_i, domain.downcase]
@@ -66,17 +66,17 @@ module DnsOne; module Backend; class HTTPBell < Base
66
66
  case point
67
67
  when :start
68
68
  @log_update_t0 = Time.now
69
- Log.i "update`ing..."
69
+ Global.logger.info "update`ing..."
70
70
  when :end
71
71
  dt = '%.2f' % (Time.now - @log_update_t0)
72
72
  dots = '...' if recs.size > LOG_DOM_NUM
73
73
  zones = recs[0, LOG_DOM_NUM].map(&:last).join(', ')
74
- Log.i "#{recs.size} zone(s) added in #{dt}s: #{zones}#{dots}"
74
+ Global.logger.info "#{recs.size} zone(s) added in #{dt}s: #{zones}#{dots}"
75
75
  else
76
- Log.e "Wrong param #{point} for log_update"
76
+ Global.logger.error e.desc "Wrong param #{point} for log_update"
77
77
  end
78
78
  rescue => e
79
- Log.exc e
79
+ Global.logger.error e.desc
80
80
  end
81
81
 
82
82
  def listen_updater_bell
@@ -86,19 +86,19 @@ module DnsOne; module Backend; class HTTPBell < Base
86
86
  require "socket"
87
87
  dts = TCPServer.new '0.0.0.0', @conf[:http_bell_port]
88
88
  allow_ips = @conf[:http_bell_allow_ips]
89
- Log.i 'Starting bell listener...'
89
+ Global.logger.info 'Starting bell listener...'
90
90
  Thread.new do
91
91
  loop do
92
92
  Thread.start(dts.accept) do |client|
93
- Log.i 'accepted'
93
+ Global.logger.info 'accepted'
94
94
  numeric_address = client.peeraddr[3]
95
95
  if !allow_ips || allow_ips.include?(numeric_address)
96
- Log.i 'will update'
96
+ Global.logger.info 'will update'
97
97
  update
98
98
  else
99
- Log.w "Ignoring bell ring from #{numeric_address}."
99
+ Global.logger.warn "Ignoring bell ring from #{numeric_address}."
100
100
  end
101
- Log.i 'closing connection'
101
+ Global.logger.info 'closing connection'
102
102
  client.close
103
103
  end
104
104
  end
@@ -12,11 +12,9 @@ class DnsOne::CLI < Thor
12
12
 
13
13
  desc "run", "run server"
14
14
  option :conf
15
- option :work_dir
16
15
  def run_srv
17
16
  DnsOne::DnsOne.new(
18
- conf_file: options[:conf],
19
- work_dir: options[:work_dir]
17
+ conf_file: options[:conf]
20
18
  ).start
21
19
  end
22
20
 
@@ -0,0 +1,3 @@
1
+ module DnsOne
2
+ Global = OpenStruct.new
3
+ end
@@ -0,0 +1,85 @@
1
+ module DnsOne; module Backend; class Account
2
+
3
+ def initialize
4
+ @conf = Global.conf
5
+ @stat = {}
6
+ @last_stat = nil
7
+ @mutex = Mutex.new
8
+ open_socket
9
+ reap
10
+ end
11
+
12
+ def on_response ip_address, domain_name, res_class, rcode, resp_log, from_cache
13
+ @mutex.synchronize {
14
+ @stat[:requests] ||= 0
15
+ @stat[:requests] += 1
16
+
17
+ @stat[:cache] ||= 0
18
+ @stat[:cache] += 1 if from_cache
19
+
20
+ rcode_uc = Util.const_underscore rcode
21
+ @stat[:rcode] ||= {}
22
+ @stat[:rcode][rcode_uc] ||= 0
23
+ @stat[:rcode][rcode_uc] += 1
24
+
25
+ req_resource = Util.last_mod(res_class).downcase
26
+ @stat[:req_resource] ||= {}
27
+ @stat[:req_resource][req_resource] ||= 0
28
+ @stat[:req_resource][req_resource] += 1
29
+ }
30
+ end
31
+
32
+ def reap
33
+ Thread.new do
34
+ loop do
35
+ sleep (300 - Time.now.to_f % 300)
36
+ @mutex.synchronize {
37
+ @last_stat = @stat.deep_dup
38
+ reset @stat
39
+ }
40
+ end
41
+ end
42
+ end
43
+
44
+ def open_socket
45
+ conf = @conf
46
+ mutex = @mutex
47
+ stat = @stat
48
+ sock = Thread.new do
49
+ sleep 1
50
+ begin
51
+ Socket.unix_server_loop(Global.conf.log_req_socket_file) do |sock, addr|
52
+ Thread.new do
53
+ loop do
54
+ begin
55
+ mutex.synchronize {
56
+ sock.write "#{ last_stat.to_json }\n"
57
+ }
58
+ rescue Errno::EPIPE => e
59
+ break
60
+ rescue => e
61
+ Global.logger.error e.desc
62
+ break
63
+ end
64
+ Thread.pass
65
+ sleep 0.1
66
+ end
67
+ end
68
+ end
69
+ rescue => e
70
+ Global.logger.error e.desc
71
+ end
72
+ end
73
+ end
74
+
75
+ def reset hash
76
+ hash.each_key do |k|
77
+ if hash[k].is_a? Hash
78
+ reset hash[k]
79
+ else
80
+ hash[k] = 0
81
+ end
82
+ end
83
+ end
84
+
85
+ end
@@ -1,4 +1,5 @@
1
- module DnsOne; class Stat
1
+ module DnsOne; module Backend; class DB
2
+
2
3
  DB_FNAME = "stat.db"
3
4
  META_STAT_ON = false
4
5
  META_STAT_FILE = '/tmp/dnsone_sql_prof.log'
@@ -12,19 +13,19 @@ module DnsOne; class Stat
12
13
  ensure_db
13
14
  end
14
15
 
15
- def save rcode, req_resource, cache
16
- Log.d "saving stat (user: #{ `id -un #{Process.uid}`.strip })"
16
+ def on_response ip_address, domain_name, res_class, rcode, resp_log, from_cache
17
+ Global.logger.debug "saving stat (user: #{ `id -un #{Process.uid}`.strip })"
17
18
  rsql(
18
19
  "INSERT INTO responses (time, rcode, req_resource, cache) VALUES (?, ?, ?, ?)",
19
20
  [
20
21
  Time.now.to_i,
21
22
  Resolv::DNS::RCode.const_get(rcode),
22
- req_resource::TypeValue,
23
- (cache ? 1 : 0)
23
+ res_class::TypeValue,
24
+ (from_cache ? 1 : 0)
24
25
  ]
25
26
  )
26
27
  rescue => e
27
- Log.e e
28
+ Global.logger.error e.desc
28
29
  end
29
30
 
30
31
  # select rcode, count(*) from responses where time > strftime('%s', 'now') - 300 group by rcode
@@ -120,7 +121,7 @@ module DnsOne; class Stat
120
121
  opts = {}
121
122
  opts[:readonly] = true if @conf[:readonly]
122
123
 
123
- # Log.i "Opening stat db #{db_file} (cwd: #{Dir.pwd})."
124
+ # Global.logger.info "Opening stat db #{db_file} (cwd: #{Dir.pwd})."
124
125
  @db = SQLite3::Database.new db_file, opts
125
126
 
126
127
  if new_db
@@ -165,5 +166,5 @@ module DnsOne; class Stat
165
166
  @meta_stats_log.info "#{time} #{dur} #{sql}"
166
167
  end
167
168
 
168
- end; end
169
+ end; end; end
169
170
 
@@ -0,0 +1,28 @@
1
+ module DnsOne; module Backend; class File
2
+ if @conf.req_log_file
3
+ path = @conf.req_log_file.is_a?(String) ? @conf.req_log_file :
4
+ l = Logger.new @conf.ruby_dns_logger, 10, (10 * 2**20)
5
+ l.level = Logger::WARN
6
+ Global.ruby_dns_logger = l
7
+ end
8
+
9
+ def self.log_result ip_address, domain_name, res_class, rcode, resp_log, from_cache
10
+ fields = []
11
+
12
+ fields << domain_name
13
+ fields << Util.last_mod(res_class)
14
+ fields << rcode
15
+ fields << resp_log.map{ |rec|
16
+ Util.last_mod(rec.res_class) +
17
+ ':' +
18
+ [rec.val].flatten.join(',')
19
+ }.join(';')
20
+ fields << ip_address
21
+ fields << (from_cache ? '1' : '0')
22
+
23
+ fields.map!{|v| v.blank? ? '-' : v}
24
+
25
+ Global.logger.info "result: #{ fields.join ' ' }"
26
+ end
27
+ end
28
+
@@ -0,0 +1,25 @@
1
+ module DnsOne; module ReqLog; class ReqLog
2
+
3
+ def initialize
4
+ @conf = Global.conf
5
+ end
6
+
7
+ def on_response *args
8
+ if @conf.log_req_db
9
+ @db ||= Db.new
10
+ @db.on_response *args
11
+ end
12
+
13
+ if @conf.log_req_file
14
+ @file = File.new
15
+ @file.on_response *args
16
+ end
17
+
18
+ if @conf.log_req_account
19
+ @account ||= Account.new
20
+ @account.on_response *args
21
+ end
22
+ end
23
+
24
+ end; end; end
25
+
@@ -1,141 +1,69 @@
1
1
 
2
2
  require "dns_one/zone_search"
3
+ require "dns_one/req_log/req_log"
3
4
  require 'socket'
4
5
  require 'json'
5
6
 
6
7
  module DnsOne; class Server
7
-
8
- DEFAULT_RUN_AS = "dnsone"
9
- DEFAULT_LOG_RESULT_SOCKET_FILE = '/tmp/dns_one_log_result.sock'
10
-
11
- DNS_DAEMON_INTERFACES = [
12
- [:udp, "0.0.0.0", 53],
13
- [:tcp, "0.0.0.0", 53],
14
- [:udp, "::", 5300],
15
- [:tcp, "::", 5300]
16
- ]
17
-
18
- def initialize conf, conf_zone_search
19
- @conf = conf
20
- @zone_search = ZoneSearch.instance.setup conf_zone_search
21
- if conf[:log_result_socket]
22
- @log_result = {}
23
- @log_result_mutex = Mutex.new
24
- end
8
+ def initialize
9
+ @zone_search = ZoneSearch.instance.setup
10
+ @req_log = nil
25
11
  end
26
12
 
27
- def run
28
- zone_search = @zone_search
29
- conf = @conf
30
- stat = nil
31
- if conf[:log_result_socket]
32
- log_result = @log_result
33
- log_result_mutex = @log_result_mutex
34
- launch_log_result_socket
35
- log_result_last_reset = 0
13
+ def start
14
+ if RExec.current_user == 'root'
15
+ RExec.change_user Global.conf.run_as
36
16
  end
17
+ @req_log ||= ReqLog::ReqLog.new
18
+ Global.logger.info "Running as #{RExec.current_user}"
19
+ end
37
20
 
38
- RubyDNS::run_server(listen: dns_daemon_interfaces, logger: Log.ruby_dns_logger) do
39
- on(:start) do
40
- if RExec.current_user == 'root'
41
- run_as = conf[:run_as] || DEFAULT_RUN_AS
42
- stat = Stat.new user: run_as if !stat
43
- RExec.change_user run_as
44
- else
45
- stat = Stat.new if !stat
46
- end
47
- Log.i "Running as #{RExec.current_user}"
48
- end
49
-
50
- match(/(.+)/) do |t| # transaction
51
- rcode = :NoError
52
- resp_log = []
53
-
54
- begin
55
- domain_name = t.question.to_s
56
- ip_address = t.options[:peer] rescue nil
57
-
58
- records, from_cache = zone_search.query domain_name, t.resource_class, ip_address
59
-
60
- if records
61
- if records.empty?
62
- t.fail! :NoError
63
- else
64
- records.each do |rec|
65
- resp_log << rec
66
- t.respond! *[rec.val].flatten, {resource_class: rec.res_class, section: rec.section}
67
- end
68
- end
69
- else
70
- rcode = :NXDomain
71
- t.fail! :NXDomain
72
- end
73
- rescue => e
74
- rcode = :ServFail
75
- end
76
-
77
- begin
78
- if conf[:save_stats]
79
- stat.save rcode, t.resource_class, from_cache
80
- end
21
+ def resolve transaction
22
+ rcode = :NoError
23
+ resp_log = []
81
24
 
82
- if conf[:log_result]
83
- Util.log_result ip_address, domain_name, t.resource_class, rcode, resp_log, from_cache
84
- end
25
+ begin
26
+ domain_name = transaction.question.to_s
27
+ ip_address = transaction.options[:peer] rescue nil
85
28
 
86
- if conf[:log_result_socket]
87
- log_result_mutex.synchronize {
88
- # Reset log_result every 5 min
89
- if Time.now.to_i / 300 > log_result_last_reset / 300
90
- log_result_last_reset = Time.now.to_i
91
- log_result.each_key do |k|
92
- if log_result[k].is_a? Hash
93
- log_result[k].each_key do |k2|
94
- log_result[k][k2] = 0
95
- end
96
- else
97
- log_result[k] = 0
98
- end
99
- end
100
- end
29
+ records, from_cache = @zone_search.query domain_name, transaction.resource_class, ip_address
101
30
 
102
- log_result[:requests] ||= 0
103
- log_result[:requests] += 1
104
-
105
- log_result[:cache] ||= 0
106
- log_result[:cache] += 1 if from_cache
107
-
108
- rcode_uc = Util.const_underscore rcode
109
- log_result[:rcode] ||= {}
110
- log_result[:rcode][rcode_uc] ||= 0
111
- log_result[:rcode][rcode_uc] += 1
112
-
113
- req_resource = Util.last_mod(t.resource_class).downcase
114
- log_result[:req_resource] ||= {}
115
- log_result[:req_resource][req_resource] ||= 0
116
- log_result[:req_resource][req_resource] += 1
117
- }
31
+ if records
32
+ if records.empty?
33
+ transaction.fail! :NoError
34
+ else
35
+ records.each do |rec|
36
+ resp_log << rec
37
+ transaction.respond! *[rec.val].flatten, {resource_class: rec.res_class, section: rec.section}
118
38
  end
119
- rescue => e
120
- Log.exc e
121
39
  end
122
-
123
- raise e if e
124
- end
125
-
126
- otherwise do |t|
127
- t.fail! :NXDomain
40
+ else
41
+ rcode = :NXDomain
42
+ transaction.fail! :NXDomain
128
43
  end
44
+ rescue => e
45
+ rcode = :ServFail
129
46
  end
47
+
48
+ @req_log.on_response *[
49
+ ip_address,
50
+ domain_name,
51
+ transaction.resource_class,
52
+ rcode,
53
+ resp_log,
54
+ from_cache
55
+ ]
56
+
57
+ raise e if e
130
58
  end
131
59
 
132
60
  def dns_daemon_interfaces
133
61
  if RExec.current_user == 'root'
134
- DNS_DAEMON_INTERFACES
62
+ Global.conf.interfaces
135
63
  else
136
- ports = DNS_DAEMON_INTERFACES.map do |port|
64
+ ports = Global.conf.interfaces.map do |port|
137
65
  if port[2] <= 1024
138
- Log.w "Changing listening port #{port[2]} to #{port[2] + 10000} for non-root process."
66
+ Global.logger.warn "Changing listening port #{port.join ':'} to #{port[2] + 10000} for non-root process."
139
67
  port[2] += 10000
140
68
  end
141
69
  port
@@ -144,34 +72,20 @@ module DnsOne; class Server
144
72
  end
145
73
  end
146
74
 
147
- def launch_log_result_socket
148
- log_result = @log_result
149
- log_result_mutex = @log_result_mutex
150
- conf = @conf
75
+ def run
76
+ srv = self
151
77
 
152
- sock = Thread.new do
153
- sleep 1
154
- begin
155
- Socket.unix_server_loop(conf[:log_result_socket_file] || DEFAULT_LOG_RESULT_SOCKET_FILE) do |sock, addr|
156
- Thread.new do
157
- loop do
158
- begin
159
- log_result_mutex.synchronize {
160
- sock.write "#{ log_result.to_json }\n"
161
- }
162
- rescue Errno::EPIPE => e
163
- break
164
- rescue => e
165
- Log.exc e
166
- break
167
- end
168
- Thread.pass
169
- sleep 0.1
170
- end
171
- end
172
- end
173
- rescue => e
174
- Log.exc e
78
+ RubyDNS::run_server(dns_daemon_interfaces) do
79
+ on(:start) do
80
+ srv.start
81
+ end
82
+
83
+ match(/(.+)/) do |transaction|
84
+ srv.resolve transaction
85
+ end
86
+
87
+ otherwise do |transaction|
88
+ transaction.fail! :NXDomain
175
89
  end
176
90
  end
177
91
  end
@@ -4,7 +4,7 @@ module DnsOne; class Util
4
4
 
5
5
  class << self
6
6
  def die msg
7
- Log.f msg
7
+ Global.logger.fatal msg
8
8
  exit 1
9
9
  end
10
10
 
@@ -33,25 +33,6 @@ module DnsOne; class Util
33
33
  constant.to_s.split('::').last
34
34
  end
35
35
 
36
- def log_result ip_address, domain_name, res_class, rcode, resp_log, from_cache
37
- fields = []
38
-
39
- fields << domain_name
40
- fields << Util.last_mod(res_class)
41
- fields << rcode
42
- fields << resp_log.map{ |rec|
43
- Util.last_mod(rec.res_class) +
44
- ':' +
45
- [rec.val].flatten.join(',')
46
- }.join(';')
47
- fields << ip_address
48
- fields << (from_cache ? '1' : '0')
49
-
50
- fields.map!{|v| v.blank? ? '-' : v}
51
-
52
- Log.i "result: #{ fields.join ' ' }"
53
- end
54
-
55
36
  def const_underscore name
56
37
  name = name.to_s.dup
57
38
  name.gsub!('::', '/')
@@ -62,6 +43,33 @@ module DnsOne; class Util
62
43
  name
63
44
  end
64
45
 
46
+ def hash_to_ostruct_deep hash
47
+ os = OpenStruct.new
48
+ hash.each_pair{ |k, v|
49
+ if v.is_a? Hash
50
+ os[k] = hash_to_ostruct_deep v
51
+ else
52
+ os[k] = v
53
+ end
54
+ }
55
+ os
56
+ end
57
+
58
+ def init_logger logdev, level = Logger::WARN, shift_age = 10, shift_size = 2**20
59
+ if logdev.is_a? String
60
+ begin
61
+ FileUtils.mkdir_p File.dirname(logdev)
62
+ File.write logdev, ''
63
+ rescue => e
64
+ $stderr.puts "#{e.desc}\nCannot open log file #{logdev}. Will use STDOUT."
65
+ logdev = $stdout
66
+ end
67
+ end
68
+ l = Logger.new logdev, shift_age, shift_size
69
+ l.level = level
70
+ l
71
+ end
72
+
65
73
  end
66
74
 
67
75
  end; end
@@ -1,3 +1,3 @@
1
1
  module DnsOne
2
- VERSION = "0.5.5"
2
+ VERSION = "0.5.6"
3
3
  end
@@ -11,11 +11,11 @@ module DnsOne; class ZoneSearch
11
11
  Name = Resolv::DNS::Name
12
12
  IN = Resolv::DNS::Resource::IN
13
13
 
14
- def setup conf
15
- @conf = conf
14
+ def setup
15
+ @conf = Global.conf
16
16
  check_record_sets
17
17
  @backend = set_backend
18
- @cache = Cache.new @conf[:cache_max]
18
+ @cache = Cache.new Global.conf.cache_max
19
19
  @ignore_subdomains_re = build_ignore_subdomains_re
20
20
 
21
21
  if @backend.preload_dummy?
@@ -30,25 +30,25 @@ module DnsOne; class ZoneSearch
30
30
 
31
31
  dom_name = dom_name.dup
32
32
  res_class_short = Util.last_mod res_class # :A, :NS, found in conf.yml:record_sets items
33
- Log.d "request #{ dom_name }/#{res_class_short} from #{ip_address}..."
33
+ Global.logger.debug "request #{ dom_name }/#{res_class_short} from #{ip_address}..."
34
34
 
35
35
  records = []
36
36
 
37
37
  rec_set_name, from_cache = find_record_set dom_name
38
- Log.d "domain #{ rec_set_name ? "found, rec_set_name = '#{rec_set_name}'" : 'not found' }"
38
+ Global.logger.debug "domain #{ rec_set_name ? "found, rec_set_name = '#{rec_set_name}'" : 'not found' }"
39
39
  return unless rec_set_name
40
40
 
41
41
  # use first record set if rec_set_name == ''
42
- rec_set_name = @conf[:record_sets].keys.first if rec_set_name == ''
42
+ rec_set_name = @conf.record_sets.to_h.keys.first if rec_set_name == ''
43
43
 
44
- rec_set = @conf[:record_sets][rec_set_name.to_sym]
45
- Log.d "record set #{ rec_set ? 'found' : 'not found' }"
44
+ rec_set = @conf.record_sets[rec_set_name]
45
+ Global.logger.debug "record set #{ rec_set ? 'found' : 'not found' }"
46
46
  return records unless rec_set
47
47
 
48
48
  # TODO: move parsing logic to own class
49
49
 
50
50
  recs = rec_set[res_class_short.to_sym]
51
- Log.d "record(s) #{ recs ? 'found' : 'not found' }"
51
+ Global.logger.debug "record(s) #{ recs ? 'found' : 'not found' }"
52
52
 
53
53
  # Loop over 1 or more
54
54
  recs = [recs]
@@ -72,25 +72,25 @@ module DnsOne; class ZoneSearch
72
72
  private
73
73
 
74
74
  def build_ignore_subdomains_re
75
- if i = @conf[:ignore_subdomains].presence
75
+ if i = @conf.ignore_subdomains.presence
76
76
  s = i.strip.split(/\s+/).map(&:downcase).join '|'
77
77
  /^(#{ s })\./i
78
78
  end
79
79
  end
80
80
 
81
81
  def set_backend
82
- if file = @conf[:backend][:file]
82
+ if file = @conf.backend.file
83
83
  unless ::File.exists? file
84
- Util.die "Domain list file #{file} not found."
84
+ Util.die "Domain list file #{file} not found (pwd = #{Dir.pwd})."
85
85
  end
86
86
  Backend::File.new file
87
- elsif @conf[:backend][:http_bell_url]
88
- unless @conf[:backend][:http_bell_record_set]
87
+ elsif @conf.backend.http_bell_url
88
+ unless @conf.backend.http_bell_record_set
89
89
  Util.die "backend.http_bell_record_set not set."
90
90
  end
91
- Backend::HTTPBell.new @conf[:backend]
91
+ Backend::HTTPBell.new @conf.backend
92
92
  else
93
- Backend::DB.new @conf[:backend]
93
+ Backend::DB.new @conf.backend
94
94
  end
95
95
  end
96
96
 
@@ -101,7 +101,7 @@ module DnsOne; class ZoneSearch
101
101
  enabled_cache = use_cache && @backend.allow_cache
102
102
 
103
103
  if enabled_cache and rec_set = @cache.find(dom_name)
104
- Log.d "found in cache (#{@cache.stat})"
104
+ Global.logger.debug "found in cache (#{@cache.stat})"
105
105
  [rec_set, true]
106
106
  else
107
107
  if rec_set = @backend.find(dom_name)
@@ -130,11 +130,11 @@ module DnsOne; class ZoneSearch
130
130
  end
131
131
 
132
132
  def check_record_sets
133
- if @conf[:record_sets].blank?
133
+ if @conf.record_sets.blank?
134
134
  Util.die "Record sets cannot be empty. Check file."
135
135
  end
136
136
 
137
- @conf[:record_sets].each_pair do |rec_set_name, records|
137
+ @conf.record_sets.each_pair do |rec_set_name, records|
138
138
  unless records[:NS] and records[:NS].length >= 1
139
139
  Util.die "Record set #{rec_set_name} is invalid. It must have at least 1 NS record."
140
140
  end
@@ -6,8 +6,4 @@ Description=dns_one supervisor
6
6
  User=root
7
7
  Group=root
8
8
  Restart=on-failure
9
- WorkingDirectory=/var/local/dns_one
10
9
  ExecStart=/bin/bash -lc '/root/.rbenv/shims/dns_one'
11
- StandardOutput=syslog
12
- StandardError=syslog
13
- SyslogIdentifier=dns_one
@@ -1,13 +1,12 @@
1
1
 
2
- config:
3
- run_as: dnsserver # optional, but highly recommended! adduser --system dnsserver
4
- ignore_subdomains: www en it es pt ru fr at # optional, defaults to an empty list
5
- # cache_max: 100000 # optional, defaults to 10000
6
- # log_file: /var/log/dns_one.log # optional, defaults to /var/log/dns_one.log
7
- save_stats: false
8
- log_result_file: false
9
- log_result_socket: true
10
- # log_result_socket_file: /tmp/dns_one_log_result.sock
2
+ run_as: dnsserver # optional, but highly recommended! adduser --system dnsserver
3
+ ignore_subdomains: www en it es pt ru fr at # optional, defaults to an empty list
4
+ # cache_max: 100000 # optional, defaults to 10000
5
+ # log_file: /var/log/dns_one.log # optional, defaults to /var/log/dns_one.log
6
+ log_req_db: false
7
+ log_req_file: false
8
+ log_req_account: true
9
+ # log_req_socket_file: /tmp/socket.socket
11
10
 
12
11
  backend:
13
12
  ##############
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dns_one
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.5
4
+ version: 0.5.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Lobato
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-05-19 00:00:00.000000000 Z
11
+ date: 2018-05-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '1.0'
75
+ version: 2.0.1
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '1.0'
82
+ version: 2.0.1
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rexec
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -170,10 +170,13 @@ files:
170
170
  - lib/dns_one/core_ext/exception.rb
171
171
  - lib/dns_one/core_ext/hash.rb
172
172
  - lib/dns_one/core_ext/string.rb
173
- - lib/dns_one/log.rb
173
+ - lib/dns_one/global.rb
174
+ - lib/dns_one/req_log/account.rb
175
+ - lib/dns_one/req_log/db.rb
176
+ - lib/dns_one/req_log/file.rb
177
+ - lib/dns_one/req_log/req_log.rb
174
178
  - lib/dns_one/server.rb
175
179
  - lib/dns_one/setup.rb
176
- - lib/dns_one/stat.rb
177
180
  - lib/dns_one/util.rb
178
181
  - lib/dns_one/version.rb
179
182
  - lib/dns_one/zone_search.rb
@@ -200,7 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
200
203
  version: '0'
201
204
  requirements: []
202
205
  rubyforge_project:
203
- rubygems_version: 2.6.13
206
+ rubygems_version: 2.5.1
204
207
  signing_key:
205
208
  specification_version: 4
206
209
  summary: DNS server for many zones sharing only one or few records, written in Ruby.
@@ -1,72 +0,0 @@
1
-
2
- class Log < Logger
3
- SYSLOG_MIN_SEVERITY = Logger::WARN
4
-
5
- class << self
6
-
7
- # 'def [d|i|w|e|f] msg' for DEBUG INFO WARN ERROR FATAL
8
- Logger::Severity::constants.each do |severity|
9
- method_name = severity.to_s[0].downcase
10
- define_method(method_name) do |msg|
11
- log severity, msg
12
- end
13
- end
14
-
15
- def setup
16
- @syslog = Syslog::Logger.new "dns_one"
17
- @log_file = setfile "/var/log/dns_one.log"
18
- @logger = Logger.new @log_file
19
- @logger.level = Logger::INFO
20
- end
21
-
22
- def ruby_dns_logger
23
- l = Logger.new setfile("/var/log/dns_one_rubydns.log")
24
- l.level = Logger::WARN
25
- l
26
- end
27
-
28
- def exc exception
29
- e exception.desc
30
- end
31
-
32
- def logger
33
- @logger
34
- end
35
-
36
- def log_file_desc
37
- case @log_file
38
- when STDOUT
39
- 'STDOUT'
40
- when STDERR
41
- 'STDERR'
42
- else
43
- @log_file
44
- end
45
- end
46
-
47
- private
48
-
49
- def setfile file
50
- if File.writable?(file) or File.writable?(File.dirname(file))
51
- file
52
- else
53
- STDERR
54
- end
55
- end
56
-
57
- def log severity, msg
58
- met_name = severity.downcase
59
-
60
- @logger.send met_name, msg
61
-
62
- if sev_num(severity) >= SYSLOG_MIN_SEVERITY
63
- @syslog.send met_name, msg
64
- end
65
- end
66
-
67
- def sev_num sev
68
- Object.const_get "Logger::#{sev}"
69
- end
70
- end
71
- end
72
-