dronebl.rb 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 90452b68385bacb07b71362b95b43f9529c52a00
4
+ data.tar.gz: c6c7ac736b865e46054effce79866393a7174280
5
+ SHA512:
6
+ metadata.gz: cac7d9db9af50b35875a0a596d33e53c4b6c66d82ed3dd09a3cc0b08c02eb3486b7551cc27422e5d081734f92575b79725fa7d793a73a66ed800ff3951d1ad88
7
+ data.tar.gz: afc184cfb563ca52072ae0f87285abd8d1b4344206940966acb47acf13025ec08843594dcba74c813e027608f7930df8b30371cb105fb1a0632dc700558f3f35
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env ruby
2
+ # copyright Rylee Fowler 2014
3
+ # see LICENSE for more details
4
+ require 'dronebl-client'
5
+ require 'resolv'
6
+ require 'optparse'
7
+ class Options
8
+ attr_reader :read_from_stdin, :key_str, :key_file, :type, :comment, :dry_run,
9
+ :use_key_file, :no_check
10
+ attr_accessor :ips
11
+ def initialize
12
+ @key_file = File.expand_path "~/.droneblkey"
13
+ @ips = []
14
+ @opt_parser = OptionParser.new do |opts|
15
+ opts.banner = "Usage: #{$0} [options]"
16
+ opts.separator ""
17
+ opts.separator "Options available:"
18
+ opts.on('-I', '--ips [ip1,ip2,ip3,...]', Array, 'Read in IPs.') do |list|
19
+ @ips += list
20
+ end
21
+ opts.on('-s', '--stdin', 'Read a newline-delimited list of IPs from STDIN') do
22
+ @read_from_stdin = true
23
+ end
24
+ opts.on('-k', '--key KEY', String, 'Use KEY as your DroneBL RPC2 key') do |key|
25
+ @key_str = key
26
+ end
27
+ opts.on('-f', '--keyfile [FILE_PATH]', 'Read the file at FILE_PATH and use it as the RPC key') do |path|
28
+ @use_key_file = true
29
+ @key_file = path
30
+ end
31
+ opts.on('-t', '--type TYPE', String, 'Mark submissions as TYPE. Valid types can be seen with the "-T" option.') do |type|
32
+ @type = type
33
+ end
34
+ opts.on('-T', '--show-types', 'Show all valid types for IP submission') do
35
+ puts DroneBL::TYPES.map { |k, v| "#{k} : #{v}"}.join("\n")
36
+ exit
37
+ end
38
+ opts.on('-c', '--comment [COMMENT]', String, 'Attach the given comment to the listings.') do |comment|
39
+ @comment = comment
40
+ opts.on('-u', '--use-key-file', 'Use the default key file located at ~/.droneblkey') do
41
+ @use_key_file = true
42
+ end
43
+ opts.on('-d', '--dry-run', 'Prints the query to be run to STDOUT instead of sending it as a query to the DroneBL RPC service.') do
44
+ @dry_run = true
45
+ end
46
+ #opts.on('-n', '--no-pre-check', 'Do not check DroneBL for the IPs you are about to submit with a lookup before doing it.') do
47
+ # @no_check = true
48
+ end
49
+ opts.on_tail("-h", "--help", "Show this message") do
50
+ puts opts
51
+ exit
52
+ end
53
+
54
+ end
55
+ end
56
+ def parse! args
57
+ @opt_parser.parse! args
58
+
59
+ if (@use_key_file && !(File.exists? @key_file)) && @key_str.nil?
60
+ abort "No key string provided and #{@key_file} does not exist -- unable to authenticate. See http://dronebl.org/rpckey_signup if you need a key."
61
+ end
62
+ if @use_key_file && !@key_str.nil?
63
+ abort "Trying to use both --use-key-file and --key -- make up your mind!"
64
+ end
65
+ if (@use_key_file)
66
+ DroneBL::key = File.read(File.expand_path(@key_file)).chomp
67
+ else
68
+ DroneBL::key = @key_str
69
+ end
70
+ if @ips.nil? || (@ips.empty? && !@read_from_stdin)
71
+ abort 'No IPs given and you\'re not reading from stdin -- this is a noop!'
72
+ end
73
+ if @type.nil?
74
+ abort "No type given! Please read #{$0} --help again."
75
+ end
76
+
77
+ end
78
+ end
79
+
80
+ # end option parsing logic, begin program logic
81
+ opts = Options.new
82
+ opts.parse! ARGV
83
+
84
+ if opts.read_from_stdin
85
+ while line = STDIN.gets
86
+ opts.ips << line.chomp
87
+ end
88
+ end
89
+
90
+ opts.ips.uniq!
91
+
92
+ prevalid, ipv6 = opts.ips.partition { |ip| (ip.match(Resolv::IPv6::Regex).nil?) }
93
+ valid, invalid = prevalid.partition { |ip| !(ip.match(Resolv::IPv4::Regex).nil?) }
94
+ invalid += ipv6
95
+ if @dry_run
96
+ puts DroneBL::gen_add_query valid
97
+ puts "#{valid.count} IPs will be added as type #{opts.type}#{" with comment 'opts.comment if opts.comment}'"}."
98
+ else
99
+ response = DroneBL::add(valid, type, comment)
100
+ print_table response, opts.long_types
101
+ puts "#{valid.count} IPs looked up. #{response.map { |r| r['ip'] }.uniq.length} unique IPs found in response."
102
+ end
103
+ unless invalid.empty?
104
+ puts "IPs not valid for lookup: "
105
+ invalid.each { |ip| puts ip }
106
+ end
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env ruby
2
+ # copyright Rylee Fowler 2014
3
+ # see LICENSE for more details
4
+ require 'dronebl-client'
5
+ require 'resolv'
6
+ require 'optparse'
7
+ class Options
8
+ attr_reader :read_from_stdin, :key_str, :key_file, :get_archived, :long_types,
9
+ :dry_run, :time_format, :use_key_file
10
+ attr_accessor :ips
11
+ def initialize
12
+ @key_file = File.expand_path "~/.droneblkey"
13
+ @ips = []
14
+ @opt_parser = OptionParser.new do |opts|
15
+ opts.banner = "Usage: #{$0} [options]"
16
+ opts.separator ""
17
+ opts.separator "Options available:"
18
+ opts.on('-I', '--ips [ip1,ip2,ip3,...]', Array, 'Read in IPs.') do |list|
19
+ @ips += list
20
+ end
21
+ opts.on('-s', '--stdin', 'Read a newline-delimited list of IPs from STDIN') do
22
+ @read_from_stdin = true
23
+ end
24
+ opts.on('-k', '--key KEY', String, 'Use KEY as your DroneBL RPC2 key') do |key|
25
+ @key_str = key
26
+ end
27
+ opts.on('-f', '--keyfile [FILE_PATH]', 'Read the file at FILE_PATH and use it as the RPC key') do |path|
28
+ @use_key_file = true
29
+ @key_file = path
30
+ end
31
+ opts.on('-a', '--get-archived', 'Get *all* DroneBL listings of the given IP, not just active ones.') do
32
+ @get_archived = true
33
+ end
34
+ opts.on('-T', '--time-format [FORMAT]', String, 'Interpolate the time format string with FORMAT instead of the default. See `man 3 strftime` for format specifiers.') do |fmt|
35
+ @time_format = fmt
36
+ end
37
+ opts.on('-u', '--use-key-file', 'Use the default key file located at ~/.droneblkey') do
38
+ @use_key_file = true
39
+ end
40
+ opts.on('-L', '--long-types', 'Print type definitions instead of numeric types for record matches.') do
41
+ @long_types = true
42
+ end
43
+ opts.on('-d', '--dry-run', 'Prints the query to be run to STDOUT instead of sending it as a query to the DroneBL RPC service.') do
44
+ @dry_run = true
45
+ end
46
+ opts.on_tail("-h", "--help", "Show this message") do
47
+ puts opts
48
+ exit
49
+ end
50
+
51
+ end
52
+ end
53
+ def parse! args
54
+ @opt_parser.parse! args
55
+
56
+ if (@use_key_file && !(File.exists? @key_file)) && @key_str.nil?
57
+ abort "No key string provided and #{@key_file} does not exist -- unable to authenticate. See http://dronebl.org/rpckey_signup if you need a key."
58
+ end
59
+ if @use_key_file && !@key_str.nil?
60
+ abort "Trying to use both --use-key-file and --key -- make up your mind!"
61
+ end
62
+ if (@use_key_file)
63
+ DroneBL::key = File.read(File.expand_path(@key_file)).chomp
64
+ else
65
+ DroneBL::key = @key_str
66
+ end
67
+ if @ips.nil? || (@ips.empty? && !@read_from_stdin)
68
+ puts @ips
69
+ abort 'No IPs given and you\'re not reading from stdin -- this is a noop!'
70
+ end
71
+ end
72
+ end
73
+
74
+ # end option parsing logic, begin program logic
75
+ def print_table data, long_types=false
76
+ typelen = 5
77
+ if long_types
78
+ typelen = 35
79
+ end
80
+ puts [
81
+ 'IP'.ljust(15),
82
+ 'Currently listed?'.rjust(17),
83
+ 'Type'.rjust(typelen),
84
+ 'Comment'.ljust(25),
85
+ 'ID'.ljust(9),
86
+ 'Time'.ljust(25)
87
+ ].join '|'
88
+ puts '-' * 135
89
+ data.each do |data|
90
+ puts [
91
+ data['ip'].ljust(15),
92
+ (data['listed'] == '1' ? 'YES' : 'NO').rjust(17),
93
+ (long_types ? DroneBL::TYPES[data['type']] : data['type']).rjust(typelen),
94
+ data['comment'].ljust(25),
95
+ data['id'].ljust(9),
96
+ Time.at(data['timestamp'].to_i).to_s.ljust(25)
97
+ ].join '|'
98
+ end
99
+ puts '=' * 135
100
+ end
101
+ opts = Options.new
102
+ opts.parse! ARGV
103
+
104
+ if opts.read_from_stdin
105
+ while line = STDIN.gets
106
+ opts.ips << line.chomp
107
+ end
108
+ end
109
+
110
+ opts.ips.uniq!
111
+
112
+ prevalid, ipv6 = opts.ips.partition { |ip| (ip.match(Resolv::IPv6::Regex).nil?) }
113
+ valid, invalid = prevalid.partition { |ip| !(ip.match(Resolv::IPv4::Regex).nil?) }
114
+ invalid += ipv6
115
+ if @dry_run
116
+ puts DroneBL::gen_lookup_query valid
117
+ puts "#{valid.count} IPs will be looked up."
118
+ else
119
+ response = DroneBL::lookup(valid)
120
+ print_table response, opts.long_types
121
+ puts "#{valid.count} IPs looked up. #{response.map { |r| r['ip'] }.uniq.length} unique IPs found in response."
122
+ end
123
+ unless invalid.empty?
124
+ puts "IPs not valid for lookup: "
125
+ invalid.each { |ip| puts ip }
126
+ end
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+ # copyright Rylee Fowler 2014
3
+ # see LICENSE for more details
4
+
5
+ require 'nokogiri'
6
+ require 'httparty'
7
+ module DroneBL
8
+ include HTTParty
9
+ format :xml
10
+ base_uri 'http://dronebl.org'
11
+ TYPES = {"1"=>"Testing class.",
12
+ "2"=>"Sample data",
13
+ "3"=>"IRC spam drone",
14
+ "5"=>"Bottler (experimental)",
15
+ "6"=>"Unknown worm or spambot",
16
+ "7"=>"DDoS drone",
17
+ "8"=>"Open SOCKS proxy",
18
+ "9"=>"Open HTTP proxy",
19
+ "10"=>"Proxychain",
20
+ "11"=>"Web Page Proxy",
21
+ "13"=>"Automated dictionary attacks",
22
+ "14"=>"Open WINGATE proxy",
23
+ "15"=>"Compromised router / gateway",
24
+ "16"=>"Autorooting worms",
25
+ "17"=>"Automatically determined botnet IP",
26
+ "255"=>"Uncategorized threat class"}
27
+ class << self
28
+ attr_accessor :key
29
+ def parse_response xml
30
+ # This giant mess of hax is needed because the DroneBL response to queries
31
+ # is encased in CDATA for whatever reason.
32
+ resp = Nokogiri::XML(xml).at("response")
33
+ if resp['type'].downcase == 'error'
34
+ abort "call failed: '#{resp.css('message').text}' data: '#{resp.css('data').text}'"
35
+ end
36
+ Nokogiri::XML("<?xml version='1.0'>\n<results>#{resp.text}</results>").css("result").map(&:to_h) # thanks to jhass in #ruby on freenode
37
+ end
38
+
39
+ def gen_lookup_query ips, archived=false
40
+ <<EOF
41
+ <?xml version='1.0'?>
42
+ <request key='#{key}'>
43
+ #{ips.map { |ip| "<lookup ip='#{ip}' listed='#{archived ? 2 : 1}'>"}.join("\n")}
44
+ </request>
45
+ EOF
46
+ end
47
+ def gen_add_query ips, type, comment=''
48
+ "<?xml version='1.0'?>
49
+ <request key='#{key}'>
50
+ #{ips.map { |ip| "<add ip='#{ip}' type='#{type}'#{ " comment='#{comment}'" unless comment.empty?}>"}.join("\n")}
51
+ </request>"
52
+ end
53
+
54
+ def lookup ips, archived=false
55
+ query = gen_lookup_query ips, archived
56
+ parse_response post('/RPC2', {:body => query }).body
57
+ end
58
+
59
+ def add ips, type, comment=''
60
+ query = gen_add_query ips, type, comment
61
+ parse_response post('/RPC2', {:body => query }).body
62
+ end
63
+
64
+ end
65
+ end
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dronebl.rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Rylee Fowler
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-04 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: 'NOTE: You should create a ~/.droneblkey file with your key inside of
14
+ it for the best experience with this.'
15
+ email: rylee@rylee.me
16
+ executables:
17
+ - dronebl-query
18
+ - dronebl-add
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - bin/dronebl-add
23
+ - bin/dronebl-query
24
+ - lib/dronebl-client.rb
25
+ homepage: http://github.com/rylai-/dronebl.rb
26
+ licenses:
27
+ - MIT
28
+ metadata: {}
29
+ post_install_message:
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubyforge_project:
45
+ rubygems_version: 2.2.2
46
+ signing_key:
47
+ specification_version: 4
48
+ summary: Interface to the DroneBL RPC2 service
49
+ test_files: []
50
+ has_rdoc: