dns-sniper 0.0.1pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9c6bab67f9579e0762d197d29dd188ced90277fa05573bb84e472be2c42a5a3e
4
+ data.tar.gz: 4123ba5a1c02a7f5d4972055b4b1743aae7bd4f995cd1336626a3f8a68ca7e23
5
+ SHA512:
6
+ metadata.gz: 479adbba0f5d557ef178acadc65461ee0be27684f4a4ab95bdd8f2b129a15b2583658fcea86193ee1c30519c5dba712b6c784619d79eaa345b7fcd993a1a19c1
7
+ data.tar.gz: b5ef2952418417f81d8c47b7cfe3052fe5e18242d5d87c3328f9713b5175bf94f48dc0ac3e3a9c8b4ddcc944637f2d8aea07fef00d15dc2b84c24e8f72fc3b8c
@@ -0,0 +1,9 @@
1
+ .DS_Store
2
+ .DS_Store?
3
+ ._*
4
+ .Spotlight-V100
5
+ .Trashes
6
+ ehthumbs.db
7
+ Thumbs.db
8
+
9
+ .ruby-version
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,26 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ sniper (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ addressable (2.7.0)
10
+ public_suffix (>= 2.0.2, < 5.0)
11
+ down (5.1.1)
12
+ addressable (~> 2.5)
13
+ hosts_file (1.0.3)
14
+ public_suffix (4.0.5)
15
+
16
+ PLATFORMS
17
+ ruby
18
+
19
+ DEPENDENCIES
20
+ bundler (~> 2.1.2)
21
+ down (~> 5.1)
22
+ hosts_file (~> 1.0)
23
+ sniper!
24
+
25
+ BUNDLED WITH
26
+ 2.1.2
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "optparse"
4
+ require "set"
5
+ require "dns-sniper"
6
+
7
+ VALID_FORMATS = ["text", "unbound"]
8
+ Options = Struct.new(:blacklist_urls_file, :whitelisted_hosts_file, :format)
9
+
10
+ class Parser
11
+ def self.parse(options)
12
+ args = Options.new("world")
13
+ opt_parser = OptionParser.new do |opts|
14
+ 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"
15
+ opts.on("-f", "--blacklist=PATH", "PATH to file with line-separated list of URL’s of blacklists") do |path|
16
+ args.blacklist_urls_file = path
17
+ end
18
+ opts.on("-w", "--whitelist=path", "Path to file with line-separated list of whitelisted hostnames") do |path|
19
+ args.whitelisted_hosts_file = path
20
+ end
21
+ opts.on("-o", "--output=FORMAT", "FORMAT to output — one of #{VALID_FORMATS.join(", ")}") do |format|
22
+ args.format = format
23
+ end
24
+ opts.on("-h", "--help", "Prints this help") do
25
+ puts opts
26
+ exit
27
+ end
28
+ end
29
+ opt_parser.parse!(options)
30
+ return args
31
+ end
32
+ end
33
+
34
+ options = Parser.parse ARGV
35
+
36
+ unless VALID_FORMATS.include?(options[:format])
37
+ STDERR.puts "Error: Format ”#{options[:format]}” unrecognized"
38
+ exit(-1)
39
+ end
40
+
41
+ unless File.exist?(options[:blacklist_urls_file])
42
+ STDERR.puts "Error: Unable to access ”#{options[:blacklist_urls_file]}”"
43
+ exit(-1)
44
+ end
45
+
46
+ if options[:whitelisted_hosts_file] and not File.exist?(options[:whitelisted_hosts_file])
47
+ STDERR.puts "Error: Unable to access ”#{options[:whitelisted_hosts_file]}”"
48
+ exit(-1)
49
+ end
50
+
51
+ hostnames = DNSSniper::Hostnames.new
52
+ puts hostnames.add_from(File.open(options[:blacklist_urls_file]).readlines).remove_from(options[:whitelisted_hosts_file]).to_format(options[:format])
@@ -0,0 +1,23 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "dns-sniper"
3
+ spec.license = "MIT"
4
+ spec.version = "0.0.1pre"
5
+ spec.date = "2020-08-13"
6
+ spec.authors = ["Brody Hoskins"]
7
+ spec.email = ["brody@brody.digital"]
8
+
9
+ spec.summary = "Command line utility that combines online DNS blacklists and combines them into the desired configuration format"
10
+ spec.description = "Command line utility that combines online DNS blacklists and combines them into the desired configuration format"
11
+ spec.homepage = "https://github.com/brodyhoskins/dns-sniper"
12
+
13
+ spec.files = `git ls-files`.split($/)
14
+
15
+ spec.bindir = "bin"
16
+ spec.executables = "dns-sniper"
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_development_dependency "bundler", "~> 2.1.2"
20
+
21
+ spec.add_development_dependency "down", "~> 5.1"
22
+ spec.add_development_dependency "hosts_file", "~> 1.0"
23
+ end
@@ -0,0 +1,3 @@
1
+ require "dns-sniper/hostnames"
2
+ require "dns-sniper/formatter"
3
+ require "dns-sniper/formatters"
@@ -0,0 +1,12 @@
1
+ module DNSSniper
2
+ class Formatter
3
+ def initialize(hostnames, options = {})
4
+ @hostnames = hostnames
5
+ @options = options
6
+ end
7
+
8
+ def output
9
+ raise NotImplementedError, "Error: #output isn’t supported by #{self.class.name}"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,24 @@
1
+ module DNSSniper
2
+ module Formatters
3
+ extend self
4
+
5
+ attr_reader :registered
6
+ @registered = []
7
+
8
+ def register(class_name, autoload_require)
9
+ DNSSniper.autoload(class_name, autoload_require)
10
+ self.registered << class_name
11
+ end
12
+
13
+ def all
14
+ Sniper::Formatters.registered.map { |name| Sniper.const_get(name) }
15
+ end
16
+
17
+ def find(name)
18
+ all.find { |c| c.name.downcase == name.to_s.downcase } or raise NameError, "unknown carrier #{name}"
19
+ end
20
+ end
21
+ end
22
+
23
+ DNSSniper::Formatters.register :Text, "dns-sniper/formatters/text"
24
+ DNSSniper::Formatters.register :Unbound, "dns-sniper/formatters/unbound"
@@ -0,0 +1,12 @@
1
+ module DNSSniper
2
+ class Text < Formatter
3
+ def initialize(hostnames, options = {})
4
+ @hostnames = hostnames
5
+ @options = options
6
+ end
7
+
8
+ def output
9
+ @hostnames.to_a.join($/)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ module DNSSniper
2
+ class Unbound < Formatter
3
+ def initialize(hostnames, options = {})
4
+ @hostnames = hostnames
5
+ @options = options
6
+ end
7
+
8
+ def output
9
+ str = "server:#{$/}"
10
+ @hostnames.each do |hostname|
11
+ str << " local-zone: \"#{hostname}\" static#{$/}"
12
+ end
13
+ str
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,176 @@
1
+ require "down"
2
+ require "hosts_file"
3
+ require "open-uri"
4
+ require "resolv"
5
+
6
+ module DNSSniper
7
+ class Hostnames
8
+ def initialize(options = {})
9
+ @hostnames = [].to_set
10
+ self
11
+ end
12
+
13
+ def add(hostname)
14
+ hostname = clean(hostname)
15
+ @hostnames << hostname if hostname
16
+ self
17
+ end
18
+
19
+ def add_many(hostnames)
20
+ hostnames.each { |hostname| add(hostname) }
21
+ self
22
+ end
23
+
24
+ def add_from(paths_or_urls)
25
+ return self unless paths_or_urls
26
+ if (paths_or_urls.class == String)
27
+ paths_or_urls = [paths_or_urls]
28
+ end
29
+
30
+ paths_or_urls.each do |path_or_url|
31
+ path_or_url = path_or_url.strip
32
+
33
+ if File.exist?(path_or_url)
34
+ contents = File.open(path_or_url).readlines
35
+ else
36
+ begin
37
+ down = Down.download(path_or_url)
38
+ path_or_url = down.path
39
+ contents = down.readlines
40
+ rescue Down::NotFound
41
+ STDERR.puts "\"#{path_or_url}\" does not exist"
42
+ return self
43
+ rescue Down::ResponseError
44
+ STDERR.puts "\"#{path_or_url}\": No data from server"
45
+ return self
46
+ end
47
+ end
48
+
49
+ case syntax(path_or_url, contents)
50
+ when nil
51
+ STDERR.puts "Error: Syntax: Syntax of \"#{path_or_url}\" not recognized, ignored"
52
+ return self
53
+ when "hosts"
54
+ add_many from_hosts_file(path_or_url)
55
+ when "hostnames"
56
+ add_many from_hostnames_file(contents)
57
+ end
58
+ end
59
+
60
+ self
61
+ end
62
+
63
+ def remove(hostname)
64
+ hostname = clean(hostname)
65
+ @hostnames = @hostnames - [hostname] if hostname
66
+ self
67
+ end
68
+
69
+ def remove_many(hostnames)
70
+ hostnames.each { |hostname| remove(hostname) }
71
+ self
72
+ end
73
+
74
+ def remove_from(paths_or_urls)
75
+ return self unless paths_or_urls
76
+ if (paths_or_urls.class == String)
77
+ paths_or_urls = [paths_or_urls]
78
+ end
79
+
80
+ paths_or_urls.each do |path_or_url|
81
+ path_or_url = path_or_url.strip
82
+
83
+ if File.exist?(path_or_url)
84
+ contents = File.open(path_or_url).readlines
85
+ else
86
+ begin
87
+ down = Down.download(path_or_url)
88
+ path_or_url = down.path
89
+ contents = down.readlines
90
+ rescue Down::NotFound
91
+ STDERR.puts "\"#{path_or_url}\" does not exist"
92
+ return self
93
+ rescue Down::ResponseError
94
+ STDERR.puts "\"#{path_or_url}\": No data from server"
95
+ return self
96
+ end
97
+ end
98
+
99
+ case syntax(path_or_url, contents)
100
+ when nil
101
+ STDERR.puts "Error: Syntax: Syntax of \"#{path_or_url}\" not recognized, ignored"
102
+ return self
103
+ when "hosts"
104
+ remove_many from_hosts_file(path_or_url)
105
+ when "hostnames"
106
+ remove_many from_hostnames_file(contents)
107
+ end
108
+ end
109
+
110
+ self
111
+ end
112
+
113
+ def to_format(format)
114
+ format = format.capitalize
115
+ begin
116
+ klass = Sniper.const_get(format)
117
+ klass.new(@hostnames.to_a).output
118
+ rescue NameError
119
+ return false
120
+ end
121
+ end
122
+
123
+ def to_a
124
+ @hostnames.to_a
125
+ end
126
+
127
+ def to_text
128
+ @hostnames.to_a.join("\n")
129
+ end
130
+
131
+ def to_unbound
132
+ str = "server:\n"
133
+ @hostnames.each do |hostname|
134
+ str << " local-zone: \"#{hostname}\" static\n"
135
+ end
136
+ str
137
+ end
138
+
139
+ private
140
+
141
+ def clean(hostname)
142
+ hostname = hostname.downcase.strip
143
+ hostname = hostname.sub("www.", "")
144
+ hostname_top_domain = "#{hostname.split(".")[-2]}.#{hostname.split(".")[-1]}"
145
+
146
+ if not hostname.include?("#") and not ["broadcasthost", "localhost", ""].include?(hostname) and not @hostnames.include?(hostname_top_domain)
147
+ hostname
148
+ else
149
+ nil
150
+ end
151
+ end
152
+
153
+ def syntax(path_or_url, contents)
154
+ contents.each do |line|
155
+ next if line.include?("#")
156
+ line = line.downcase
157
+
158
+ if line.strip.split(/\s/).first =~ Regexp.union([Resolv::IPv4::Regex, Resolv::IPv6::Regex])
159
+ return "hosts"
160
+ elsif line.include? "." and not line.include? "http" and path_or_url.end_with?(".list")
161
+ return "hostnames"
162
+ end
163
+ end
164
+ nil
165
+ end
166
+
167
+ def from_hosts_file(path_or_url)
168
+ # TODO: Remove downloading file twice
169
+ HostsFile.load(path_or_url).map(&:name)
170
+ end
171
+
172
+ def from_hostnames_file(contents)
173
+ contents.each { |line| add(line) }
174
+ end
175
+ end
176
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dns-sniper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1pre
5
+ platform: ruby
6
+ authors:
7
+ - Brody Hoskins
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-08-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.1.2
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.1.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: down
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.1'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: hosts_file
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ description: Command line utility that combines online DNS blacklists and combines
56
+ them into the desired configuration format
57
+ email:
58
+ - brody@brody.digital
59
+ executables:
60
+ - dns-sniper
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - ".gitignore"
65
+ - Gemfile
66
+ - Gemfile.lock
67
+ - Rakefile
68
+ - bin/dns-sniper
69
+ - dns-sniper.gemspec
70
+ - lib/dns-sniper.rb
71
+ - lib/dns-sniper/formatter.rb
72
+ - lib/dns-sniper/formatters.rb
73
+ - lib/dns-sniper/formatters/text.rb
74
+ - lib/dns-sniper/formatters/unbound.rb
75
+ - lib/dns-sniper/hostnames.rb
76
+ homepage: https://github.com/brodyhoskins/dns-sniper
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">"
92
+ - !ruby/object:Gem::Version
93
+ version: 1.3.1
94
+ requirements: []
95
+ rubygems_version: 3.0.3
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: Command line utility that combines online DNS blacklists and combines them
99
+ into the desired configuration format
100
+ test_files: []