dns-sniper 0.0.1pre
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 +7 -0
- data/.gitignore +9 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +26 -0
- data/Rakefile +6 -0
- data/bin/dns-sniper +52 -0
- data/dns-sniper.gemspec +23 -0
- data/lib/dns-sniper.rb +3 -0
- data/lib/dns-sniper/formatter.rb +12 -0
- data/lib/dns-sniper/formatters.rb +24 -0
- data/lib/dns-sniper/formatters/text.rb +12 -0
- data/lib/dns-sniper/formatters/unbound.rb +16 -0
- data/lib/dns-sniper/hostnames.rb +176 -0
- metadata +100 -0
checksums.yaml
ADDED
@@ -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
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -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
|
data/Rakefile
ADDED
data/bin/dns-sniper
ADDED
@@ -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])
|
data/dns-sniper.gemspec
ADDED
@@ -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
|
data/lib/dns-sniper.rb
ADDED
@@ -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,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: []
|