dns-sniper 0.0.1.pre7 → 0.0.1.pre10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fdb713f65960730a1ac99906c65aeb79b30b69514eedab948ee20eb27bf30920
4
- data.tar.gz: 28d04385a9759e9bada850e6c4dde26d7f3d983ddedd9d5782d31c6001cab19d
3
+ metadata.gz: 04db0c0c25e714a9540154cef9dcc6352101fc4111dec94804d298f70fa609c3
4
+ data.tar.gz: 8d55fd5b07b905aaf1ee93261b78e9d1c9429a7bf0baafc7144d04557ffbab5f
5
5
  SHA512:
6
- metadata.gz: c02d1bb299780f04041d8899aeb72b7457ec8954184c95a0bae61731c1b36763f44055b41d4e8115c42bf0ccfdb68b407db3aef5ff71a3dc0e01d8dde0bcee99
7
- data.tar.gz: fd3f08b34762d39e3610ad23810736a667e83f7b77459d8508e625f67007b0fa7adcd028091c65c4f05e28f39eacc6d805313e6733c9d8592f4657b5ade50e2b
6
+ metadata.gz: e7a5b16bc843c1e593e7cca234fd4dfff5c6347f0af2723a863d420bf045cd1a1e0f53e181581ce273738e1e7e24ac078d1f92b6671101d0980379ce9f13f64e
7
+ data.tar.gz: 5e73efea0322fc1662312619dca0cac2333ea8fd2b6842f85fbe5fecf2e71621433726fdecc07c8f01054eeed13cc150b84d616bc2969a1bc76848cc577e55cc
data/Gemfile.lock CHANGED
@@ -1,19 +1,31 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dns-sniper (0.0.1.pre6)
4
+ dns-sniper (0.0.1.pre10)
5
+ activesupport (>= 4.2, < 7.0.3)
5
6
  down (~> 5.1)
6
7
  hosts_file (~> 1.0)
7
8
 
8
9
  GEM
9
10
  remote: https://rubygems.org/
10
11
  specs:
11
- addressable (2.7.0)
12
+ activesupport (7.0.2.4)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 1.6, < 2)
15
+ minitest (>= 5.1)
16
+ tzinfo (~> 2.0)
17
+ addressable (2.8.0)
12
18
  public_suffix (>= 2.0.2, < 5.0)
13
- down (5.2.2)
14
- addressable (~> 2.5)
19
+ concurrent-ruby (1.1.10)
20
+ down (5.3.1)
21
+ addressable (~> 2.8)
15
22
  hosts_file (1.0.3)
23
+ i18n (1.10.0)
24
+ concurrent-ruby (~> 1.0)
25
+ minitest (5.15.0)
16
26
  public_suffix (4.0.6)
27
+ tzinfo (2.0.4)
28
+ concurrent-ruby (~> 1.0)
17
29
 
18
30
  PLATFORMS
19
31
  ruby
@@ -22,4 +34,4 @@ DEPENDENCIES
22
34
  dns-sniper!
23
35
 
24
36
  BUNDLED WITH
25
- 2.1.2
37
+ 2.3.7
data/README.md CHANGED
@@ -51,8 +51,11 @@ hostnames.blacklist += DNSSniper::HostsImporter.new('https://pgl.yoyo.org/as/ser
51
51
  # Blocklist is accessible as an Array
52
52
  hostnames.blocklist
53
53
 
54
- # Use an Exporter to convert to other formats
55
- UnboundExporter.new(hostnames.blocklist).data
54
+ # List available formats
55
+ DNSSniper::Exporters.all
56
+
57
+ # Convert to desired format
58
+ hostnames.to_unbound
56
59
  ```
57
60
 
58
61
  ### From CLI
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.pre7'
7
- spec.date = '2021-07-26'
6
+ spec.version = '0.0.1.pre10'
7
+ spec.date = '2022-03-07'
8
8
 
9
9
  spec.authors = ['Brody Hoskins']
10
10
  spec.email = ['brody@brody.digital']
@@ -30,6 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.bindir = 'bin'
31
31
  spec.executables = 'dns-sniper'
32
32
 
33
+ spec.add_dependency 'activesupport', '>= 4.2', '< 7.0.3'
33
34
  spec.add_dependency 'down', '~> 5.1'
34
35
  spec.add_dependency 'hosts_file', '~> 1.0'
35
36
  end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DNSSniper
4
+ class ConditionalFetch
5
+ attr_reader :data, :headers, :response
6
+
7
+ def initialize(uri, options = {})
8
+ @options = options
9
+ @uri = uri
10
+ @uri = CGI.escape_html(@uri).to_s
11
+ @uri = URI.parse(@uri)
12
+
13
+ @data = nil
14
+ @headers = nil
15
+ @response = nil
16
+
17
+ fetch
18
+ end
19
+
20
+ # Headers
21
+
22
+ def etag
23
+ @etag ||= @headers&.dig('etag')
24
+ end
25
+
26
+ def expires_at
27
+ @expires_at ||= !date || !max_age ? nil : (date + max_age)
28
+ end
29
+
30
+ private
31
+
32
+ def fetch
33
+ last_etag = @options[:last_etag]
34
+ last_updated_at = @options[:last_updated_at]
35
+
36
+ http = Net::HTTP.new(@uri.host, @uri.port)
37
+ http.use_ssl = true if @uri.instance_of?(URI::HTTPS)
38
+
39
+ if @options[:last_updated_at] || @options[:last_etag]
40
+ response = http.head(@uri.request_uri)
41
+ if response.is_a?(Net::HTTPSuccess)
42
+ @headers = response&.each_header.to_h
43
+ @response = response
44
+ @data = response&.body
45
+
46
+ return self unless update?
47
+ end
48
+ end
49
+
50
+ request = Net::HTTP::Get.new(@uri.request_uri)
51
+ response = http.request(request)
52
+
53
+ @headers = response.each_header&.to_h
54
+ @response = response
55
+ @data = response&.body
56
+
57
+ self
58
+ end
59
+
60
+ def update?
61
+ last_etag = @options[:last_etag]
62
+ last_updated_at = @options[:last_updated_at]
63
+
64
+ return last_etag != etag if last_etag && etag && etag.strip != ''
65
+
66
+ if last_updated_at && created_at
67
+ if max_age
68
+ return (last_updated_at + max_age) < created_at
69
+ elsif age
70
+ return (last_updated_at + age) < created_at
71
+ else
72
+ return last_updated_at < created_at
73
+ end
74
+ end
75
+
76
+ true
77
+ end
78
+
79
+ # Headers
80
+
81
+ def age
82
+ @age ||= @headers&.dig('age')&.to_i
83
+ end
84
+
85
+ def cache_control
86
+ return @cache_control if @cache_control
87
+
88
+ header = @headers&.dig('cache-control')
89
+ @cache_control = if !header || !header.include?('max-age=')
90
+ nil
91
+ else
92
+ header
93
+ end
94
+ end
95
+
96
+ def created_at
97
+ !date || !age ? nil : (date - age)
98
+ end
99
+
100
+ def date
101
+ return @date if @date
102
+
103
+ date = @headers&.dig('date')
104
+ @date = date ? Time.rfc2822(date) : nil
105
+ end
106
+
107
+ def max_age
108
+ @max_age ||= cache_control ? cache_control.split('=')[1]&.to_i : nil
109
+ end
110
+ end
111
+ end
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'down'
4
- require 'hosts_file'
5
- require 'open-uri'
6
- require 'resolv'
7
-
8
3
  module DNSSniper
9
4
  class Hostnames
10
- attr_accessor :blacklist
11
- attr_accessor :whitelist
5
+ attr_accessor :blacklist, :whitelist
6
+
7
+ Exporters.all.each do |exporter|
8
+ format = exporter.to_s.split('::').last[..-9].tableize.singularize
9
+
10
+ define_method(:"to_#{format}") { exporter.new(blocklist).data }
11
+ end
12
12
 
13
13
  def initialize
14
14
  @blacklist = []
@@ -24,6 +24,7 @@ module DNSSniper
24
24
  domain_parts = domain.split('.')
25
25
  domain_parts.count.times do |count|
26
26
  next if count == 1
27
+
27
28
  whitelist += [domain_parts[count - 1, domain_parts.length].join('.')]
28
29
  end
29
30
  end
@@ -4,16 +4,16 @@ module DNSSniper
4
4
  class Importer
5
5
  attr_accessor :uri, :hostnames
6
6
 
7
- def initialize(uri, *)
7
+ def initialize(uri, options = {})
8
8
  @uri = uri
9
- @hostnames = File.exist?(uri) ? import_file(uri) : import_uri(uri)
9
+ @hostnames = File.exist?(uri) ? import_file(uri, options) : import_uri(uri, options)
10
10
  end
11
11
 
12
12
  def import_file(*)
13
13
  raise NotImplementedError, "#{self.class.name}: #import_file not supported"
14
14
  end
15
15
 
16
- def import_uri(*)
16
+ def import_uri(_uri, _options = {})
17
17
  raise NotImplementedError, "#{self.class.name}: #import_uri not supported"
18
18
  end
19
19
 
@@ -39,7 +39,7 @@ module DNSSniper
39
39
  return false if domain.include?('?')
40
40
  return false if ip_addr?(domain)
41
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)
42
+ return false unless /^[a-z0-9]+([\-.]{1}[a-z0-9]+)*\.[a-z]{2,5}$/.match?(domain)
43
43
 
44
44
  begin
45
45
  return false if URI.parse(domain).is_a?(URI::HTTP)
@@ -9,15 +9,15 @@ module DNSSniper
9
9
 
10
10
  def import_file(path, list:)
11
11
  raise ArgumentError, "#{self.class.name}: #from_path requies list to be defined" unless list
12
- return [].to_set unless File.exist?(path)
12
+ return [] unless File.exist?(path)
13
13
 
14
14
  yaml = YAML.safe_load(File.read(path), permitted_classes: [Symbol])
15
- return [].to_set unless yaml.dig(:sources)&.dig(list.to_sym)
15
+ return [] unless yaml.dig(:sources)&.dig(list.to_sym)
16
16
 
17
- hostnames = [].to_set
17
+ hostnames = []
18
18
  yaml.dig(:sources).dig(list.to_sym).each do |source|
19
- return [].to_set unless source.dig(:importer)
20
- return [].to_set unless source.dig(:uri)
19
+ return [] unless source.dig(:importer)
20
+ return [] unless source.dig(:uri)
21
21
 
22
22
  importer = DNSSniper.const_get("#{source.dig(:importer).to_s.split('_').map(&:capitalize).join}Importer")
23
23
  if !importer
@@ -2,21 +2,17 @@
2
2
 
3
3
  module DNSSniper
4
4
  class DomainsImporter < Importer
5
- def import_file(path)
6
- return [].to_set unless File.exist?(path)
5
+ def import_file(path, *)
6
+ return [] unless File.exist?(path)
7
7
 
8
- File.open(path).readlines(chomp: true).map { |hostname| clean(hostname) }.reject { |hostname| rejector(hostname) }.to_set
8
+ File.open(path).readlines(chomp: true).map { |hostname| clean(hostname) }.reject { |hostname| rejector(hostname) }
9
9
  end
10
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) }.to_set
15
- rescue Down::InvalidUrl => e
16
- warn "#{self.class.name}: #{e}"
17
- end
11
+ def import_uri(uri, options = {})
12
+ data = ConditionalFetch.new(uri, options).data
13
+ return [] unless data
18
14
 
19
- [].to_set
15
+ data.split(/\n+|\r+/).reject(&:empty?)
20
16
  end
21
17
  end
22
18
  end
@@ -3,24 +3,19 @@
3
3
  module DNSSniper
4
4
  class HostsImporter < Importer
5
5
  def import_file(path, *)
6
- return [].to_set unless File.exist?(path)
6
+ return [] unless File.exist?(path)
7
7
 
8
- HostsFile.load(path).map(&:name).map { |hostname| clean(hostname) }.reject { |hostname| rejector(hostname) }.to_set
8
+ HostsFile.load(path).map(&:name).map { |hostname| clean(hostname) }.reject { |hostname| rejector(hostname) }
9
9
  end
10
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
11
+ def import_uri(uri, options = {})
12
+ data = ConditionalFetch.new(uri, options).data || ''
18
13
 
19
- if path
20
- return HostsFile.load(path).map(&:name).map { |hostname| clean(hostname) }.reject { |hostname| rejector(hostname) }.to_set
21
- end
14
+ arr = []
15
+ domains = HostsFile::Parser.new(data)
16
+ domains.each { |domain| arr << domain.name }
22
17
 
23
- [].to_set
18
+ arr
24
19
  end
25
20
  end
26
21
  end
data/lib/dns-sniper.rb CHANGED
@@ -1,10 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'active_support/all'
4
+ require 'cgi'
5
+ require 'down'
6
+ require 'hosts_file'
7
+ require 'net/http'
8
+ require 'net/https'
9
+ require 'open-uri'
3
10
  require 'resolv'
11
+ require 'time'
4
12
  require 'yaml'
5
13
 
14
+ require 'dns-sniper/conditional_fetch'
6
15
  require 'dns-sniper/exporter'
7
16
  require 'dns-sniper/exporters'
8
17
  require 'dns-sniper/hostnames'
9
18
  require 'dns-sniper/importer'
10
- require 'dns-sniper/importers'
19
+ require 'dns-sniper/importers'
metadata CHANGED
@@ -1,15 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dns-sniper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.pre7
4
+ version: 0.0.1.pre10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brody Hoskins
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-26 00:00:00.000000000 Z
11
+ date: 2022-03-07 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.2'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: 7.0.3
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '4.2'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: 7.0.3
13
33
  - !ruby/object:Gem::Dependency
14
34
  name: down
15
35
  requirement: !ruby/object:Gem::Requirement
@@ -57,6 +77,7 @@ files:
57
77
  - config.yml.example
58
78
  - dns-sniper.gemspec
59
79
  - lib/dns-sniper.rb
80
+ - lib/dns-sniper/conditional_fetch.rb
60
81
  - lib/dns-sniper/exporter.rb
61
82
  - lib/dns-sniper/exporters.rb
62
83
  - lib/dns-sniper/exporters/bind8_exporter.rb
@@ -92,7 +113,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
92
113
  - !ruby/object:Gem::Version
93
114
  version: 1.3.1
94
115
  requirements: []
95
- rubygems_version: 3.2.15
116
+ rubygems_version: 3.4.19
96
117
  signing_key:
97
118
  specification_version: 4
98
119
  summary: Combine DNS blacklists into desired configuration format