dns_one 0.5.5 → 0.5.6

Sign up to get free protection for your applications and to get access to all the features.
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
-