dns-sniper 0.0.1.pre7 → 0.0.1.pre10

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: 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