dns-sniper 0.0.1.pre3 → 0.0.1.pre8

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
  SHA256:
3
- metadata.gz: eb0e330d2e7c2b4061f4c93ff5825ff09d768a55f57e732e6557f13e822c9436
4
- data.tar.gz: 6909002d1f80141a9855b917be54c0e2076c0b465f2f8aa6cf143ea93f6eba8d
3
+ metadata.gz: 512e7b14734237f57edc560759f751a748083c2639fa4adc5beac81f460222f5
4
+ data.tar.gz: f1223fae9ec10a2b42c797dd43a1a874ac916f241272cb84526994994c82d621
5
5
  SHA512:
6
- metadata.gz: bbb70cdbbf01ade47a2d6b359fe63fb97e1c577795d979746d93c858b0644313e0285415acf86a79d56a6baaaa6c0cc1b908bc01fb90b8b90d6bb86df2219125
7
- data.tar.gz: f5773fc187a174a969c4c8953ab3c24e9803a3eba481fb028f300a9886aa09391d85a9f5383c46a726d123b954489f4e6e5a1a613b6300f4cdbdae3ddb353bc2
6
+ metadata.gz: 93631146a7ae4eedf7fbe3d4275f5156a3cac90eb665f4c916c5b6e37977d23b91716bccae8074c8b5492fa0cc21607ebeafe246d9879f89627710c4bbff24d3
7
+ data.tar.gz: e7b9d0fc865c070561129f21aea1a936b21f5d357affeb8cc096946922059977640aea8d323035ddcc39737a31bef2d18d35d2aaa832fb90771fdcd3944b874e
data/Gemfile.lock CHANGED
@@ -1,26 +1,25 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sniper (0.0.1)
4
+ dns-sniper (0.0.1.pre6)
5
+ down (~> 5.1)
6
+ hosts_file (~> 1.0)
5
7
 
6
8
  GEM
7
9
  remote: https://rubygems.org/
8
10
  specs:
9
11
  addressable (2.7.0)
10
12
  public_suffix (>= 2.0.2, < 5.0)
11
- down (5.1.1)
13
+ down (5.2.2)
12
14
  addressable (~> 2.5)
13
15
  hosts_file (1.0.3)
14
- public_suffix (4.0.5)
16
+ public_suffix (4.0.6)
15
17
 
16
18
  PLATFORMS
17
19
  ruby
18
20
 
19
21
  DEPENDENCIES
20
- bundler (~> 2.1.2)
21
- down (~> 5.1)
22
- hosts_file (~> 1.0)
23
- sniper!
22
+ dns-sniper!
24
23
 
25
24
  BUNDLED WITH
26
25
  2.1.2
data/README.md CHANGED
@@ -40,26 +40,19 @@ require 'dns-sniper'
40
40
 
41
41
  hostnames = DNSSniper::Hostnames.new
42
42
 
43
- # Block domain names
44
- hostnames.add_from('https://pgl.yoyo.org/as/serverlist.php?hostformat=hosts;showintro=0;mimetype=plaintext') # From the web
45
- hostnames.add_from('https://raw.githubusercontent.com/brodyhoskins/dns-blocklists/master/tracking.list')
46
- hostnames.add_from('~/.config/dns-sniper/blocklists.list') # From filesystem
47
-
48
- # Manually add domain name
49
- hostnames.add('ads.yahoo.com')
50
- hostnames.add(['ads.doubleclick.net', 'ads.msn.com'])
51
-
52
- # Remove whitelisted domain names
53
- hostnames.remove_from('~/.config/dns-sniper/whitelisted-hostnames.list')
54
- hostnames.remove_from('https://example.com/whitelisted.hosts')
55
-
56
- # Manually remove domain name
57
- hostnames.remove('favoritewebsite.com')
58
- hostnames.remove(['favoritewebsite.com', 'otherfavoritewebsite.com'])
59
-
60
- # Convert to configuration file
61
- hostnames.to_format('dnsmasq')
62
- hostnames.to_format('unbound')
43
+ # Manually add blacklisted or whitelisted domains
44
+ hostnames.blacklist += 'ads.yahoo.com'
45
+ hostnames.whitelist += 'favoritewebsite.com'
46
+
47
+ # Use an Importer to process external lists
48
+ hostnames.blacklist += DNSSniper::DomainsImporter.new('https://raw.githubusercontent.com/brodyhoskins/dns-blocklists/master/tracking.list').hostnames
49
+ hostnames.blacklist += DNSSniper::HostsImporter.new('https://pgl.yoyo.org/as/serverlist.php?hostformat=hosts;showintro=0;mimetype=plaintext').hostnames
50
+
51
+ # Blocklist is accessible as an Array
52
+ hostnames.blocklist
53
+
54
+ # Use an Exporter to convert to other formats
55
+ UnboundExporter.new(hostnames.blocklist).data
63
56
  ```
64
57
 
65
58
  ### From CLI
@@ -71,7 +64,6 @@ Using the CLI version makes it easy to update configuration formats automaticall
71
64
  ```bash
72
65
  #!/usr/bin/env bash
73
66
 
74
- /path/to/dns-sniper -f ~/.config/dns-sniper/blacklist.list -w ~/.config/dns-sniper/whitelist.list -o unbound > /etc/unbound/unbound.conf.t/blocklist.conf
75
-
67
+ /path/to/dns-sniper --conf ~/.config/dns-sniper/dns-sniper.yml --output unbound > /etc/unbound/unbound.conf.d/blocklist.conf
76
68
  service unbound reload
77
69
  ```
data/bin/dns-sniper CHANGED
@@ -5,19 +5,16 @@ require 'optparse'
5
5
  require 'set'
6
6
  require 'dns-sniper'
7
7
 
8
- VALID_FORMATS = DNSSniper::Formatters.all.inject([]) { |arr, f| arr << f.name.to_s.sub('DNSSniper::', '').downcase }
9
- Options = Struct.new(:blacklist_urls_file, :whitelisted_hosts_file, :format)
8
+ VALID_FORMATS = DNSSniper::Exporters.all.inject([]) { |arr, f| arr << f.name.to_s.sub('DNSSniper::', '').sub('Exporter', '').downcase }
9
+ Options = Struct.new(:conf_path, :format)
10
10
 
11
11
  class Parser
12
12
  def self.parse(options)
13
13
  args = Options.new('world')
14
14
  opt_parser = OptionParser.new do |opts|
15
15
  opts.banner = "Usage: #{File.basename(__FILE__)} -f PATH -o FORMAT [options]\n#{File.basename(__FILE__)} combines online DNS blacklists and combines them into the desired configuration FORMAT.\n\n"
16
- opts.on('-f', '--blacklist=PATH', 'PATH to file with line-separated list of URL’s of blacklists') do |path|
17
- args.blacklist_urls_file = path
18
- end
19
- opts.on('-w', '--whitelist=path', 'Path to file with line-separated list of whitelisted hostnames') do |path|
20
- args.whitelisted_hosts_file = path
16
+ opts.on('-c', '--conf=PATH', 'PATH to YAML configuration file') do |path|
17
+ args.conf_path = path
21
18
  end
22
19
  opts.on('-o', '--output=FORMAT', "FORMAT to output — one of #{VALID_FORMATS.join(', ')}") do |format|
23
20
  args.format = format
@@ -34,20 +31,20 @@ end
34
31
 
35
32
  options = Parser.parse ARGV
36
33
 
37
- unless VALID_FORMATS.include?(options[:format])
38
- warn options[:format].blank? ? 'Error: Format not defined' : "Error: Invalid format \"#{options[:format]}\""
34
+ unless File.exist?(options[:conf_path])
35
+ warn "Error: Unable to access ”#{options[:conf_path]}"
39
36
  exit(-1)
40
37
  end
41
38
 
42
- unless File.exist?(options[:blacklist_urls_file])
43
- warn "Error: Unable to access ”#{options[:blacklist_urls_file]}”"
44
- exit(-1)
45
- end
46
-
47
- if options[:whitelisted_hosts_file] && !File.exist?(options[:whitelisted_hosts_file])
48
- warn "Error: Unable to access ”#{options[:whitelisted_hosts_file]}”"
39
+ exporter = DNSSniper.const_get("#{options[:format].to_s.split('_').map(&:capitalize).join}Exporter")
40
+ if !exporter
41
+ warn "Error: Invalid format #{options[:format]}"
49
42
  exit(-1)
50
43
  end
51
44
 
52
45
  hostnames = DNSSniper::Hostnames.new
53
- puts hostnames.add_from(File.open(options[:blacklist_urls_file]).readlines).remove_from(options[:whitelisted_hosts_file]).to_format(options[:format])
46
+ hostnames.blacklist += DNSSniper::ConfigurationImporter.new(options[:conf_path], list: :reject).hostnames
47
+ hostnames.whitelist += DNSSniper::ConfigurationImporter.new(options[:conf_path], list: :allow).hostnames
48
+
49
+ exporter = exporter.new(hostnames.blocklist)
50
+ puts exporter.data
@@ -0,0 +1,9 @@
1
+ :sources:
2
+ :allow:
3
+ - :importer: :domains
4
+ :uri: https://example.com/whitelisted.domains.list
5
+ :reject:
6
+ - :importer: :domains
7
+ :uri: https://raw.githubusercontent.com/brodyhoskins/dns-blocklists/master/tracking.list
8
+ - :importer: :hosts
9
+ :uri: https://pgl.yoyo.org/as/serverlist.php?hostformat=hosts;showintro=0;mimetype=plaintext
data/dns-sniper.gemspec CHANGED
@@ -3,8 +3,8 @@
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'dns-sniper'
5
5
  spec.license = 'MIT'
6
- spec.version = '0.0.1.pre3'
7
- spec.date = '2020-11-01'
6
+ spec.version = '0.0.1.pre8'
7
+ spec.date = '2021-06-28'
8
8
 
9
9
  spec.authors = ['Brody Hoskins']
10
10
  spec.email = ['brody@brody.digital']
data/lib/dns-sniper.rb CHANGED
@@ -1,5 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'resolv'
4
+ require 'yaml'
5
+
6
+ require 'dns-sniper/exporter'
7
+ require 'dns-sniper/exporters'
3
8
  require 'dns-sniper/hostnames'
4
- require 'dns-sniper/formatter'
5
- require 'dns-sniper/formatters'
9
+ require 'dns-sniper/importer'
10
+ require 'dns-sniper/importers'
@@ -1,13 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DNSSniper
4
- class Formatter
4
+ class Exporter
5
+ attr_accessor :data, :hostnames
6
+
5
7
  def initialize(hostnames, options = {})
6
8
  @hostnames = hostnames
7
- @options = options
9
+ @data = output(options)
8
10
  end
9
11
 
10
- def output
12
+ def output(*)
11
13
  raise NotImplementedError, "Error: #output isn’t supported by #{self.class.name}"
12
14
  end
13
15
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DNSSniper
4
+ module Exporters
5
+ module_function
6
+
7
+ attr_reader :registered
8
+ @registered = []
9
+
10
+ def register(class_name, autoload_require)
11
+ DNSSniper.autoload(class_name, autoload_require)
12
+ @registered << class_name
13
+ end
14
+
15
+ def all
16
+ @registered.map { |name| DNSSniper.const_get(name) }
17
+ end
18
+
19
+ def find(name)
20
+ all.find { |c| c.name.downcase == name.to_s.downcase } or raise NameError, "Unknown exporter \"#{name}\""
21
+ end
22
+ end
23
+ end
24
+
25
+ DNSSniper::Exporters.register :Bind8Exporter, 'dns-sniper/exporters/bind8_exporter'
26
+ DNSSniper::Exporters.register :DnsmasqExporter, 'dns-sniper/exporters/dnsmasq_exporter'
27
+ DNSSniper::Exporters.register :HostsExporter, 'dns-sniper/exporters/hosts_exporter'
28
+ DNSSniper::Exporters.register :NetgearExporter, 'dns-sniper/exporters/netgear_exporter'
29
+ DNSSniper::Exporters.register :TextExporter, 'dns-sniper/exporters/text_exporter'
30
+ DNSSniper::Exporters.register :UnboundExporter, 'dns-sniper/exporters/unbound_exporter'
@@ -1,12 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DNSSniper
4
- class Bind8 < Formatter
5
- def initialize(hostnames, options = {})
6
- @hostnames = hostnames
7
- @options = options
8
- end
9
-
4
+ class Bind8Exporter < Exporter
10
5
  def output(options = {})
11
6
  raise ArgumentError, 'zone_file is required' unless defined?(options[:zone_file])
12
7
 
@@ -1,13 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DNSSniper
4
- class Dnsmasq < Formatter
5
- def initialize(hostnames, options = {})
6
- @hostnames = hostnames
7
- @options = options
8
- end
9
-
10
- def output(_options = {})
4
+ class DnsmasqExporter < Exporter
5
+ def output(*)
11
6
  str = ''.dup
12
7
  @hostnames.each do |hostname|
13
8
  str << "server=/#{hostname}/#{$/}"
@@ -1,13 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DNSSniper
4
- class Hosts < Formatter
5
- def initialize(hostnames, options = {})
6
- @hostnames = hostnames
7
- @options = options
8
- end
9
-
10
- def output(_options = {})
4
+ class HostsExporter < Exporter
5
+ def output(*)
11
6
  str = ''.dup
12
7
  @hostnames.each do |hostname|
13
8
  str << "127.0.0.1\t#{hostname}#{$/}"
@@ -1,13 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DNSSniper
4
- class Netgear < Formatter
5
- def initialize(hostnames, options = {})
6
- @hostnames = hostnames
7
- @options = options
8
- end
9
-
10
- def output(_options = {})
4
+ class NetgearExporter < Exporter
5
+ def output(*)
11
6
  str = ''.dup
12
7
  @hostnames.each_with_index do |hostname, i|
13
8
  str << "[517003_e]: #{i + 1}) #{hostname}\n"
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DNSSniper
4
+ class TextExporter < Exporter
5
+ def output(_options = {})
6
+ @hostnames.to_a.join($/)
7
+ end
8
+ end
9
+ end
@@ -1,13 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DNSSniper
4
- class Unbound < Formatter
5
- def initialize(hostnames, options = {})
6
- @hostnames = hostnames
7
- @options = options
8
- end
9
-
10
- def output(_options = {})
4
+ class UnboundExporter < Exporter
5
+ def output(*)
11
6
  str = ''.dup
12
7
  str << "server:#{$/}"
13
8
  @hostnames.each do |hostname|
@@ -7,151 +7,28 @@ require 'resolv'
7
7
 
8
8
  module DNSSniper
9
9
  class Hostnames
10
- def initialize(_options = {})
11
- @hostnames = [].to_set
12
- self
13
- end
14
-
15
- def add(hostnames)
16
- hostnames = clean(hostnames.class == String ? [hostnames] : hostnames)
17
- @hostnames += hostnames unless hostnames.empty?
18
- self
19
- end
20
-
21
- def add_from(paths_or_urls)
22
- return self unless paths_or_urls
23
-
24
- paths_or_urls = [paths_or_urls] if paths_or_urls.class == String
25
-
26
- paths_or_urls.each do |path_or_url|
27
- path_or_url = path_or_url.strip
28
-
29
- if File.exist?(path_or_url)
30
- contents = File.open(path_or_url).readlines
31
- else
32
- begin
33
- down = Down.download(path_or_url)
34
- path_or_url = down.path
35
- contents = down.readlines
36
- rescue Down::NotFound
37
- warn "\"#{path_or_url}\" does not exist"
38
- return self
39
- rescue Down::ResponseError
40
- warn "\"#{path_or_url}\": No data from server"
41
- return self
42
- end
43
- end
44
-
45
- case syntax(path_or_url, contents)
46
- when nil
47
- warn "Error: Syntax: Syntax of \"#{path_or_url}\" not recognized, ignored"
48
- return self
49
- when 'hosts'
50
- add from_hosts_file(path_or_url)
51
- when 'hostnames'
52
- add from_hostnames_file(contents)
53
- end
54
- end
55
-
56
- self
57
- end
58
-
59
- def remove(hostnames)
60
- hostnames = clean(hostnames.class == String ? [hostnames] : hostnames)
61
- @hostnames -= hostnames unless hostnames.empty?
62
- self
63
- end
64
-
65
- def remove_from(paths_or_urls)
66
- return self unless paths_or_urls
67
-
68
- paths_or_urls = [paths_or_urls] if paths_or_urls.class == String
69
-
70
- paths_or_urls.each do |path_or_url|
71
- path_or_url = path_or_url.strip
72
-
73
- if File.exist?(path_or_url)
74
- contents = File.open(path_or_url).readlines
75
- else
76
- begin
77
- down = Down.download(path_or_url)
78
- path_or_url = down.path
79
- contents = down.readlines
80
- rescue Down::NotFound
81
- warn "\"#{path_or_url}\" does not exist"
82
- return self
83
- rescue Down::ResponseError
84
- warn "\"#{path_or_url}\": No data from server"
85
- return self
86
- end
87
- end
88
-
89
- case syntax(path_or_url, contents)
90
- when nil
91
- warn "Error: Syntax: Syntax of \"#{path_or_url}\" not recognized, ignored"
92
- return self
93
- when 'hosts'
94
- remove from_hosts_file(path_or_url)
95
- when 'hostnames'
96
- remove from_hostnames_file(contents)
97
- end
98
- end
10
+ attr_accessor :blacklist
11
+ attr_accessor :whitelist
99
12
 
13
+ def initialize
14
+ @blacklist = []
15
+ @whitelist = []
100
16
  self
101
17
  end
102
18
 
103
- def to_format(format, options = {})
104
- format = format.capitalize
105
- begin
106
- klass = DNSSniper.const_get(format)
107
- klass.new(@hostnames.to_a).output(options)
108
- rescue NameError
109
- false
110
- end
111
- end
112
-
113
- def to_a
114
- @hostnames.to_a
115
- end
116
-
117
- private
19
+ def blocklist
20
+ blacklist = @blacklist
21
+ whitelist = @whitelist
118
22
 
119
- def clean(hostnames)
120
- cleaned_hostnames = []
121
- hostnames.each do |hostname|
122
- hostname = hostname.downcase.strip
123
- hostname = hostname.sub('www.', '')
124
- hostname_top_domain = "#{hostname.split('.')[-2]}.#{hostname.split('.')[-1]}"
125
-
126
- if !hostname.include?('#') && !['broadcasthost', 'localhost', ''].include?(hostname) && !@hostnames.include?(hostname_top_domain)
127
- cleaned_hostnames << hostname
128
- end
129
- end
130
- cleaned_hostnames
131
- end
132
-
133
- def syntax(path_or_url, contents)
134
- contents.each do |line|
135
- next if line.include?('#')
136
-
137
- line = line.downcase
138
-
139
- if line.strip.split(/\s/).first =~ Regexp.union([Resolv::IPv4::Regex, Resolv::IPv6::Regex])
140
- return 'hosts'
141
- elsif line.include?('.') && (!line.include? 'http') && path_or_url.end_with?('.list')
142
- return 'hostnames'
23
+ whitelist.each do |domain|
24
+ domain_parts = domain.split('.')
25
+ domain_parts.count.times do |count|
26
+ next if count == 1
27
+ whitelist += [domain_parts[count - 1, domain_parts.length].join('.')]
143
28
  end
144
29
  end
145
- nil
146
- end
147
-
148
- def from_hosts_file(path_or_url)
149
- # TODO: Remove downloading file twice
150
- HostsFile.load(path_or_url).map(&:name)
151
- end
152
30
 
153
- def from_hostnames_file(contents)
154
- contents.each { |line| add(line) }
31
+ blacklist - whitelist
155
32
  end
156
33
  end
157
34
  end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DNSSniper
4
+ class Importer
5
+ attr_accessor :uri, :hostnames
6
+
7
+ def initialize(uri, *)
8
+ @uri = uri
9
+ @hostnames = File.exist?(uri) ? import_file(uri) : import_uri(uri)
10
+ end
11
+
12
+ def import_file(*)
13
+ raise NotImplementedError, "#{self.class.name}: #import_file not supported"
14
+ end
15
+
16
+ def import_uri(*)
17
+ raise NotImplementedError, "#{self.class.name}: #import_uri not supported"
18
+ end
19
+
20
+ # Helper methods
21
+
22
+ def clean(domain)
23
+ domain = domain.split('#')[0] if domain[0] != '#' && domain.include?('#')
24
+ domain = domain.split(':')[0] if domain.include?(':') && !ip_addr?(domain)
25
+ domain = domain.sub('www.', '') if domain.start_with?('www.') && domain.scan('www.').count == 1
26
+
27
+ domain.chomp.gsub(/\s+/, '').downcase
28
+ end
29
+
30
+ def rejector(domain)
31
+ !domain?(domain)
32
+ end
33
+
34
+ def domain?(domain)
35
+ return false if domain == ''
36
+ return false if domain.gsub('#', '').gsub(/\s+/, '').empty?
37
+ return false if domain[0] == '#'
38
+ return false if domain.include?(':')
39
+ return false if domain.include?('?')
40
+ return false if ip_addr?(domain)
41
+ return false unless /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/.match?(domain)
42
+ return false unless /^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}$/.match?(domain)
43
+
44
+ begin
45
+ return false if URI.parse(domain).is_a?(URI::HTTP)
46
+ rescue URI::InvalidURIError; end
47
+ true
48
+ end
49
+
50
+ def ip_addr?(domain)
51
+ domain =~ Regexp.union([Resolv::IPv4::Regex, Resolv::IPv6::Regex])
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DNSSniper
4
+ module Importers
5
+ module_function
6
+
7
+ attr_reader :registered
8
+ @registered = []
9
+
10
+ def register(class_name, autoload_require)
11
+ DNSSniper.autoload(class_name, autoload_require)
12
+ @registered << class_name
13
+ end
14
+
15
+ def all
16
+ @registered.map { |name| DNSSniper.const_get(name) }
17
+ end
18
+
19
+ def find(name)
20
+ all.find { |c| c.name.downcase == name.to_s.downcase } or raise NameError, "Unknown Importer \"#{name}\""
21
+ end
22
+ end
23
+ end
24
+
25
+ DNSSniper::Importers.register :ConfigurationImporter, 'dns-sniper/importers/configuration_importer'
26
+ DNSSniper::Importers.register :DomainsImporter, 'dns-sniper/importers/domains_importer'
27
+ DNSSniper::Importers.register :HostsImporter, 'dns-sniper/importers/hosts_importer'
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DNSSniper
4
+ class ConfigurationImporter < Importer
5
+ def initialize(uri, list:)
6
+ @uri = uri
7
+ @hostnames = File.exist?(uri) ? import_file(uri, list: list) : import_uri(uri, list: list)
8
+ end
9
+
10
+ def import_file(path, list:)
11
+ raise ArgumentError, "#{self.class.name}: #from_path requies list to be defined" unless list
12
+ return [] unless File.exist?(path)
13
+
14
+ yaml = YAML.safe_load(File.read(path), permitted_classes: [Symbol])
15
+ return [] unless yaml.dig(:sources)&.dig(list.to_sym)
16
+
17
+ hostnames = []
18
+ yaml.dig(:sources).dig(list.to_sym).each do |source|
19
+ return [] unless source.dig(:importer)
20
+ return [] unless source.dig(:uri)
21
+
22
+ importer = DNSSniper.const_get("#{source.dig(:importer).to_s.split('_').map(&:capitalize).join}Importer")
23
+ if !importer
24
+ next
25
+ else
26
+ importer = importer.new(source.dig(:uri))
27
+ hostnames += importer.hostnames
28
+ end
29
+ end
30
+
31
+ hostnames
32
+ end
33
+
34
+ def import_uri(_uri, list:)
35
+ raise NotImplementedError, "#{self.class.name}: #from_uri not supported"
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DNSSniper
4
+ class DomainsImporter < Importer
5
+ def import_file(path)
6
+ return [] unless File.exist?(path)
7
+
8
+ File.open(path).readlines(chomp: true).map { |hostname| clean(hostname) }.reject { |hostname| rejector(hostname) }
9
+ end
10
+
11
+ def import_uri(uri)
12
+ begin
13
+ down = Down.download(uri)
14
+ return down.readlines(chomp: true).map { |hostname| clean(hostname) }.reject { |hostname| rejector(hostname) }
15
+ rescue Down::InvalidUrl => e
16
+ warn "#{self.class.name}: #{e}"
17
+ end
18
+
19
+ []
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DNSSniper
4
+ class HostsImporter < Importer
5
+ def import_file(path, *)
6
+ return [] unless File.exist?(path)
7
+
8
+ HostsFile.load(path).map(&:name).map { |hostname| clean(hostname) }.reject { |hostname| rejector(hostname) }
9
+ end
10
+
11
+ def import_uri(uri, *)
12
+ begin
13
+ down = Down.download(uri)
14
+ path = down.path
15
+ rescue Down::InvalidUrl => e
16
+ warn "#{self.class.name}: #{e}"
17
+ end
18
+
19
+ if path
20
+ return HostsFile.load(path).map(&:name).map { |hostname| clean(hostname) }.reject { |hostname| rejector(hostname) }
21
+ end
22
+
23
+ []
24
+ end
25
+ end
26
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dns-sniper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.pre3
4
+ version: 0.0.1.pre8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brody Hoskins
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-01 00:00:00.000000000 Z
11
+ date: 2021-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: down
@@ -54,24 +54,30 @@ files:
54
54
  - README.md
55
55
  - Rakefile
56
56
  - bin/dns-sniper
57
+ - config.yml.example
57
58
  - dns-sniper.gemspec
58
59
  - lib/dns-sniper.rb
59
- - lib/dns-sniper/formatter.rb
60
- - lib/dns-sniper/formatters.rb
61
- - lib/dns-sniper/formatters/bind8.rb
62
- - lib/dns-sniper/formatters/dnsmasq.rb
63
- - lib/dns-sniper/formatters/hosts.rb
64
- - lib/dns-sniper/formatters/netgear.rb
65
- - lib/dns-sniper/formatters/text.rb
66
- - lib/dns-sniper/formatters/unbound.rb
60
+ - lib/dns-sniper/exporter.rb
61
+ - lib/dns-sniper/exporters.rb
62
+ - lib/dns-sniper/exporters/bind8_exporter.rb
63
+ - lib/dns-sniper/exporters/dnsmasq_exporter.rb
64
+ - lib/dns-sniper/exporters/hosts_exporter.rb
65
+ - lib/dns-sniper/exporters/netgear_exporter.rb
66
+ - lib/dns-sniper/exporters/text_exporter.rb
67
+ - lib/dns-sniper/exporters/unbound_exporter.rb
67
68
  - lib/dns-sniper/hostnames.rb
69
+ - lib/dns-sniper/importer.rb
70
+ - lib/dns-sniper/importers.rb
71
+ - lib/dns-sniper/importers/configuration_importer.rb
72
+ - lib/dns-sniper/importers/domains_importer.rb
73
+ - lib/dns-sniper/importers/hosts_importer.rb
68
74
  homepage: https://github.com/brodyhoskins/dns-sniper
69
75
  licenses:
70
76
  - MIT
71
77
  metadata:
72
78
  homepage_uri: https://github.com/brodyhoskins/dns-sniper
73
79
  source_code_uri: https://github.com/brodyhoskins/dns-sniper
74
- post_install_message:
80
+ post_install_message:
75
81
  rdoc_options: []
76
82
  require_paths:
77
83
  - lib
@@ -86,8 +92,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
86
92
  - !ruby/object:Gem::Version
87
93
  version: 1.3.1
88
94
  requirements: []
89
- rubygems_version: 3.0.3
90
- signing_key:
95
+ rubygems_version: 3.2.15
96
+ signing_key:
91
97
  specification_version: 4
92
98
  summary: Combine DNS blacklists into desired configuration format
93
99
  test_files: []
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DNSSniper
4
- module Formatters
5
- extend self
6
-
7
- attr_reader :registered
8
- @registered = []
9
-
10
- def register(class_name, autoload_require)
11
- DNSSniper.autoload(class_name, autoload_require)
12
- @registered << class_name
13
- end
14
-
15
- def all
16
- @registered.map { |name| DNSSniper.const_get(name) }
17
- end
18
-
19
- def find(name)
20
- all.find { |c| c.name.downcase == name.to_s.downcase } or raise NameError, "Unknown formatter \"#{name}\""
21
- end
22
- end
23
- end
24
-
25
- DNSSniper::Formatters.register :Bind8, 'dns-sniper/formatters/bind8'
26
- DNSSniper::Formatters.register :Dnsmasq, 'dns-sniper/formatters/dnsmasq'
27
- DNSSniper::Formatters.register :Hosts, 'dns-sniper/formatters/hosts'
28
- DNSSniper::Formatters.register :Netgear, 'dns-sniper/formatters/netgear'
29
- DNSSniper::Formatters.register :Text, 'dns-sniper/formatters/text'
30
- DNSSniper::Formatters.register :Unbound, 'dns-sniper/formatters/unbound'
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DNSSniper
4
- class Text < Formatter
5
- def initialize(hostnames, options = {})
6
- @hostnames = hostnames
7
- @options = options
8
- end
9
-
10
- def output(_options = {})
11
- @hostnames.to_a.join($/)
12
- end
13
- end
14
- end