BotnetV2 1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/BotnetV2.gemspec +31 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +81 -0
- data/Rakefile +2 -0
- data/lib/BotnetV2.rb +56 -0
- data/lib/BotnetV2/Client.rb +60 -0
- data/lib/BotnetV2/Master.rb +85 -0
- data/lib/BotnetV2/Network.rb +122 -0
- data/lib/BotnetV2/Worker.rb +56 -0
- data/lib/BotnetV2/version.rb +3 -0
- data/test/cert.pem +15 -0
- data/test/master_test.rb +41 -0
- data/test/private.pem +15 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b511120a79c8dfb4146818da5f14c7c83b0fe440
|
4
|
+
data.tar.gz: 360c51c97647b13819c9588d18d8201122c1f074
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b7341772937b5c9486ad63b925f9ed66f05cf8802a6df17e4f2b70857d04f7ef0116033793ca76f7e56ddf0bc0bef9bcabb87c04e8c8128cffacf60d12e47f7f
|
7
|
+
data.tar.gz: 33f04c08ca82956da34879ddc3955feb2f02784dbb4d77cf0723f8ffe5c8c645d03d0e85476ccea97105037b82aa5affcde0afe4cdd680161ddf08cd6be404f4
|
data/.gitignore
ADDED
data/BotnetV2.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "BotnetV2/version"
|
5
|
+
require 'BotnetV2/Master'
|
6
|
+
require 'BotnetV2/Worker'
|
7
|
+
require 'BotnetV2/Client'
|
8
|
+
require 'openssl'
|
9
|
+
require 'socket'
|
10
|
+
require 'openssl'
|
11
|
+
require 'json'
|
12
|
+
require 'securerandom'
|
13
|
+
|
14
|
+
Gem::Specification.new do |spec|
|
15
|
+
spec.name = "BotnetV2"
|
16
|
+
spec.version = BotnetV2::VERSION
|
17
|
+
spec.authors = ["Michael Fürst"]
|
18
|
+
spec.email = ["penguinmenac3@gmail.com"]
|
19
|
+
spec.summary = %q{A bot net to calculate intense tasks on remote machines.}
|
20
|
+
spec.description = %q{A bot net to calculate intense tasks on remote machines.}
|
21
|
+
spec.homepage = "https://fuersts1.homeip.net/penguinmenac3/botnetv2"
|
22
|
+
spec.license = "MIT"
|
23
|
+
|
24
|
+
spec.files = `git ls-files -z`.split("\x0")
|
25
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
26
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
27
|
+
spec.require_paths = ["lib"]
|
28
|
+
|
29
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
30
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
31
|
+
end
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Michael Fürst
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# BotnetV2
|
2
|
+
|
3
|
+
A bot net to calculate intense tasks on remote machines.
|
4
|
+
Outsource your tasks to your bots. While a worker bot is not executing a task, it is passively waiting.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'BotnetV2'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install BotnetV2
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
First create a certificate and distribute the cert.pem. The private.pem is only for the master.
|
25
|
+
|
26
|
+
$ BotnetV2.create_certificate
|
27
|
+
|
28
|
+
Start a master server on any system.
|
29
|
+
Whereas it does not require much calculation power a raspberrypi is also ok.
|
30
|
+
Make sure your ruby program does not exit.
|
31
|
+
Do not use hybrid_mode or no ssl, because it opens your bot net to anyone.
|
32
|
+
|
33
|
+
$ BotnetV2.create_master(ssl_port = 8008, no_ssl_port = 8009, ssl = true, hybrid_mode = false)
|
34
|
+
|
35
|
+
|
36
|
+
Create workers on any high performance computer that you can find with ruby.
|
37
|
+
The more workers, the more tasks you can execute in parallel.
|
38
|
+
Make sure your ruby program does not exit.
|
39
|
+
|
40
|
+
$ BotnetV2.create_worker(host, port = 8008, ssl = true)
|
41
|
+
|
42
|
+
Your local Machine, which delegates tasks.
|
43
|
+
|
44
|
+
$ client = BotnetV2.create_client(client_id, host, port = 8008, ssl = true)
|
45
|
+
$ client.execute (task_src, callback)
|
46
|
+
|
47
|
+
## Contributing
|
48
|
+
|
49
|
+
1. Fork it ( https://fuersts1.homeip.net/penguinmenac3/botnetv2 )
|
50
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
51
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
52
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
53
|
+
5. Create a new Pull Request
|
54
|
+
|
55
|
+
|
56
|
+
## Sample
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
def test
|
60
|
+
unless File.exists? 'private.pem' and File.exists? 'cert.pem'
|
61
|
+
File.delete 'private.pem' if File.exists? 'private.pem'
|
62
|
+
File.delete 'cert.pem' if File.exists? 'cert.pem'
|
63
|
+
BotnetV2::BotnetV2.create_certificate
|
64
|
+
end
|
65
|
+
|
66
|
+
master = BotnetV2::BotnetV2.create_master 'your_password_goes_here'
|
67
|
+
worker = BotnetV2::BotnetV2.create_worker 'your_password_goes_here', 'localhost'
|
68
|
+
client = BotnetV2::BotnetV2.create_client 'your_password_goes_here', 1, 'localhost'
|
69
|
+
client.execute("1+1", Proc.new do |res| on_result(res) end)
|
70
|
+
sleep(0) until @done
|
71
|
+
client.exit!
|
72
|
+
worker.exit!
|
73
|
+
master.exit!
|
74
|
+
assert_equal(@result, 2, 'Wrong result')
|
75
|
+
end
|
76
|
+
|
77
|
+
def on_result(result)
|
78
|
+
@result = result
|
79
|
+
@done = true
|
80
|
+
end
|
81
|
+
```
|
data/Rakefile
ADDED
data/lib/BotnetV2.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require "BotnetV2/version"
|
2
|
+
require 'BotnetV2/Master'
|
3
|
+
require 'BotnetV2/Worker'
|
4
|
+
require 'BotnetV2/Client'
|
5
|
+
require 'openssl'
|
6
|
+
|
7
|
+
#
|
8
|
+
# Author: Michael Fürst
|
9
|
+
# Version: 1.0
|
10
|
+
#
|
11
|
+
|
12
|
+
module BotnetV2
|
13
|
+
class BotnetV2
|
14
|
+
def self.create_master(password, ssl_port = 8008, no_ssl_port = 8009, ssl = true, hybrid_mode = false)
|
15
|
+
Master.new password, ssl_port, no_ssl_port, ssl, hybrid_mode
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.create_client(password, client_id, host, port = 8008, ssl = true)
|
19
|
+
Client.new password, client_id, host, port, ssl
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.create_worker(password, host, port = 8008, ssl = true)
|
23
|
+
Worker.new password, host, port, ssl
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.create_certificate(private_path = 'private.pem', cert_path = 'cert.pem',
|
27
|
+
country = 'DE', organization = 'none', organization_unit = 'none', common_name = 'botnet_v2')
|
28
|
+
key = OpenSSL::PKey::RSA.new(1024)
|
29
|
+
public_key = key.public_key
|
30
|
+
subject = '/C='+country+'/O='+organization+'/OU='+organization_unit+'/CN='+common_name
|
31
|
+
cert = OpenSSL::X509::Certificate.new
|
32
|
+
cert.subject = cert.issuer = OpenSSL::X509::Name.parse(subject)
|
33
|
+
cert.not_before = Time.now
|
34
|
+
cert.not_after = Time.now + 365 * 24 * 60 * 60
|
35
|
+
cert.public_key = public_key
|
36
|
+
cert.serial = 0x0
|
37
|
+
cert.version = 2
|
38
|
+
ef = OpenSSL::X509::ExtensionFactory.new
|
39
|
+
ef.subject_certificate = cert
|
40
|
+
ef.issuer_certificate = cert
|
41
|
+
cert.extensions = [
|
42
|
+
ef.create_extension('basicConstraints','CA:TRUE', true),
|
43
|
+
ef.create_extension('subjectKeyIdentifier', 'hash')
|
44
|
+
]
|
45
|
+
cert.add_extension ef.create_extension('authorityKeyIdentifier', 'keyid:always,issuer:always')
|
46
|
+
cert.sign key, OpenSSL::Digest::SHA1.new
|
47
|
+
|
48
|
+
open (private_path), 'w' do |io|
|
49
|
+
io.write key
|
50
|
+
end
|
51
|
+
open (cert_path), 'w' do |io|
|
52
|
+
io.write cert.to_pem
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#
|
2
|
+
# Author: Michael Fürst
|
3
|
+
# Version: 1.0
|
4
|
+
#
|
5
|
+
|
6
|
+
require 'BotnetV2/Network'
|
7
|
+
require 'securerandom'
|
8
|
+
|
9
|
+
module BotnetV2
|
10
|
+
class Client
|
11
|
+
def initialize(password, client_id, host, port = 8008, ssl = true)
|
12
|
+
@exit = false
|
13
|
+
@callbacks = Hash.new
|
14
|
+
@onReady = Hash.new
|
15
|
+
@onReady['client_onReady'] = client_id
|
16
|
+
@onReady['verify'] = password
|
17
|
+
|
18
|
+
network = BotNetwork.new
|
19
|
+
network.connect host, port if ssl
|
20
|
+
network.connect_no_ssl host, port unless ssl
|
21
|
+
|
22
|
+
@connection = BotConnection.new network.socket, network
|
23
|
+
@t = Thread.start do
|
24
|
+
@connection.on_message_handler_loop(Proc.new do |msg| on_message(msg) end)
|
25
|
+
end
|
26
|
+
|
27
|
+
@connection.send @onReady
|
28
|
+
end
|
29
|
+
|
30
|
+
def execute (task_src, callback)
|
31
|
+
message = Hash.new
|
32
|
+
message['onWork'] = Hash.new
|
33
|
+
message['onWork']['task_id'] = SecureRandom.hex
|
34
|
+
message['onWork']['clientId'] = @onReady['client_onReady']
|
35
|
+
message['onWork']['src'] = task_src
|
36
|
+
@callbacks[message['onWork']['task_id']] = callback
|
37
|
+
@connection.send message
|
38
|
+
end
|
39
|
+
|
40
|
+
def on_message (message)
|
41
|
+
if message['onResult'] != nil
|
42
|
+
error = false
|
43
|
+
res = message['onResult']['result']
|
44
|
+
if message['onResult']['error'] != nil
|
45
|
+
res = message['onResult']['error']
|
46
|
+
error = true if message['onResult']['error']
|
47
|
+
end
|
48
|
+
@callbacks[message['onResult']['task_id']].call(res, error)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def exit!
|
53
|
+
@connection.close
|
54
|
+
@t.kill
|
55
|
+
message = Hash.new
|
56
|
+
message['client_onDisconnect'] = @onReady['client_onReady']
|
57
|
+
@connection.send message
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
#
|
2
|
+
# Author: Michael Fürst
|
3
|
+
# Version: 1.0
|
4
|
+
#
|
5
|
+
|
6
|
+
require 'BotnetV2/Network'
|
7
|
+
|
8
|
+
module BotnetV2
|
9
|
+
class Master
|
10
|
+
def initialize(password, ssl_port = 8008, no_ssl_port = 8009, ssl = true, hybrid_mode = false)
|
11
|
+
@password = password
|
12
|
+
@verified_clients = Hash.new
|
13
|
+
@ready_workers = Queue.new
|
14
|
+
@ready_clients = Hash.new
|
15
|
+
@work_bundles = Queue.new
|
16
|
+
@result_bundles = Hash.new
|
17
|
+
@exit = false
|
18
|
+
@t1 = nil
|
19
|
+
@t2 = nil
|
20
|
+
|
21
|
+
if ssl || hybrid_mode
|
22
|
+
network = BotNetwork.new
|
23
|
+
@t1 = network.listen(Proc.new do |connection| on_connect_handler(connection) end, ssl_port)
|
24
|
+
end
|
25
|
+
if !ssl || hybrid_mode
|
26
|
+
network = BotNetwork.new
|
27
|
+
@t2 = network.listen_no_ssl(Proc.new do |connection| on_connect_handler(connection) end, no_ssl_port)
|
28
|
+
end
|
29
|
+
|
30
|
+
@main_loop = Thread.start do main_loop end
|
31
|
+
end
|
32
|
+
|
33
|
+
def main_loop
|
34
|
+
loop do
|
35
|
+
connection = @ready_workers.pop
|
36
|
+
unless connection.closed?
|
37
|
+
msg = Hash.new
|
38
|
+
msg['onWork'] = @work_bundles.pop
|
39
|
+
connection.send msg
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def on_connect_handler(connection)
|
45
|
+
connection.on_message_handler_loop(Proc.new do |msg| on_message(msg, connection) end)
|
46
|
+
end
|
47
|
+
|
48
|
+
def on_message (message, connection)
|
49
|
+
@verified_clients[connection] = true if message['verify'] == @password
|
50
|
+
@ready_workers << connection if message['worker_onReady'] != nil and @verified_clients[connection]
|
51
|
+
@work_bundles << message['onWork'] if message['onWork'] != nil and @verified_clients[connection]
|
52
|
+
@ready_clients[message['client_onDisconnect']] = nil if message['client_onDisconnect'] != nil and @verified_clients[connection]
|
53
|
+
|
54
|
+
if message['client_onReady'] != nil and @verified_clients[connection]
|
55
|
+
client_id = message['client_onReady']
|
56
|
+
@ready_clients[client_id] = connection
|
57
|
+
@result_bundles[client_id] = Queue.new if @result_bundles[client_id] == nil
|
58
|
+
until @result_bundles[client_id].empty?
|
59
|
+
msg = Hash.new
|
60
|
+
msg['onResult'] = @result_bundles[client_id].pop
|
61
|
+
connection.send msg
|
62
|
+
end
|
63
|
+
end
|
64
|
+
if message['onResult'] != nil and @verified_clients[connection]
|
65
|
+
client_id = message['onResult']['clientId']
|
66
|
+
if @ready_clients[client_id] == nil
|
67
|
+
@result_bundles[client_id] = Queue.new if @result_bundles[client_id] == nil
|
68
|
+
@result_bundles[client_id] << message['onResult']
|
69
|
+
else
|
70
|
+
msg = Hash.new
|
71
|
+
msg['onResult'] = message['onResult']
|
72
|
+
@ready_clients[client_id].send msg
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def exit!
|
78
|
+
@exit = true
|
79
|
+
@main_loop.kill
|
80
|
+
@t1.kill if @t1
|
81
|
+
@t2.kill if @t2
|
82
|
+
puts '[' + Time.new.strftime('%Y-%m-%d %H:%M:%S') + '] Killed listeners!'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
#
|
2
|
+
# Author: Michael Fürst
|
3
|
+
# Version: 1.0
|
4
|
+
#
|
5
|
+
|
6
|
+
require 'socket'
|
7
|
+
require 'openssl'
|
8
|
+
require 'json'
|
9
|
+
|
10
|
+
class BotConnection
|
11
|
+
def initialize(socket, network)
|
12
|
+
@socket = socket
|
13
|
+
@network = network
|
14
|
+
end
|
15
|
+
|
16
|
+
def on_message_handler_loop on_message_handler
|
17
|
+
begin
|
18
|
+
until closed? do
|
19
|
+
on_message_handler.call read
|
20
|
+
end
|
21
|
+
rescue
|
22
|
+
# do nothing
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def send msg
|
27
|
+
@network.send msg, @socket unless closed?
|
28
|
+
end
|
29
|
+
|
30
|
+
def read
|
31
|
+
@network.read @socket unless closed?
|
32
|
+
end
|
33
|
+
|
34
|
+
def close
|
35
|
+
@network.disconnect @socket unless closed?
|
36
|
+
end
|
37
|
+
|
38
|
+
def closed?
|
39
|
+
@socket.closed?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# A worker. Dial home to receive ask for tasks.
|
44
|
+
class BotNetwork
|
45
|
+
|
46
|
+
attr_reader :socket
|
47
|
+
|
48
|
+
# Initialize the worker.
|
49
|
+
def initialize
|
50
|
+
end
|
51
|
+
|
52
|
+
def connect(host, port, cert_file = File.open('cert.pem'))
|
53
|
+
socket = TCPSocket.open host, port
|
54
|
+
socket.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
|
55
|
+
expectedCert = OpenSSL::X509::Certificate.new(cert_file)
|
56
|
+
ssl = OpenSSL::SSL::SSLSocket.new(socket)
|
57
|
+
ssl.sync_close = true
|
58
|
+
ssl.connect
|
59
|
+
if ssl.peer_cert.to_s != expectedCert.to_s
|
60
|
+
stderrr.puts 'Unexpected certificate'
|
61
|
+
return nil
|
62
|
+
end
|
63
|
+
@socket = ssl
|
64
|
+
end
|
65
|
+
|
66
|
+
def connect_no_ssl(host, port)
|
67
|
+
socket = TCPSocket.open host, port
|
68
|
+
socket.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
|
69
|
+
@socket = socket
|
70
|
+
end
|
71
|
+
|
72
|
+
def listen(on_connect_handler, port, cert_pem = File.open('cert.pem'), private_pem = File.open('private.pem'))
|
73
|
+
server = TCPServer.open(port)
|
74
|
+
sslContext = OpenSSL::SSL::SSLContext.new
|
75
|
+
sslContext.cert = OpenSSL::X509::Certificate.new(cert_pem)
|
76
|
+
sslContext.key = OpenSSL::PKey::RSA.new(private_pem)
|
77
|
+
sslServer = OpenSSL::SSL::SSLServer.new(server, sslContext)
|
78
|
+
thread = Thread.start do
|
79
|
+
puts '[' + Time.new.strftime('%Y-%m-%d %H:%M:%S') + '] ' + "Listening secured on port #{port}"
|
80
|
+
accept_clients on_connect_handler, sslServer
|
81
|
+
end
|
82
|
+
thread
|
83
|
+
end
|
84
|
+
|
85
|
+
def listen_no_ssl(on_connect_handler, port)
|
86
|
+
server = TCPServer.open(port)
|
87
|
+
thread = Thread.start do
|
88
|
+
puts '[' + Time.new.strftime('%Y-%m-%d %H:%M:%S') + '] ' + "Listening unsecured on port #{port}"
|
89
|
+
accept_clients on_connect_handler, server
|
90
|
+
end
|
91
|
+
thread
|
92
|
+
end
|
93
|
+
|
94
|
+
def accept_clients(on_connect_handler, server)
|
95
|
+
loop do
|
96
|
+
Thread.start(server.accept) do |socket|
|
97
|
+
puts '[' + Time.new.strftime('%Y-%m-%d %H:%M:%S') + '] ' + 'Client connected.!'
|
98
|
+
begin
|
99
|
+
on_connect_handler.call(BotConnection.new socket, self)
|
100
|
+
rescue => e
|
101
|
+
puts e.backtrace
|
102
|
+
unless socket.closed?
|
103
|
+
disconnect socket
|
104
|
+
end
|
105
|
+
end
|
106
|
+
puts '[' + Time.new.strftime('%Y-%m-%d %H:%M:%S') + '] ' + 'Client disconnected!'
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def send(message, socket = @socket)
|
112
|
+
socket.puts(JSON.generate(message)) unless socket.closed?
|
113
|
+
end
|
114
|
+
|
115
|
+
def read(socket = @socket)
|
116
|
+
JSON.parse(socket.gets.chomp)
|
117
|
+
end
|
118
|
+
|
119
|
+
def disconnect(socket = @socket)
|
120
|
+
socket.close unless socket.closed?
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
#
|
2
|
+
# Author: Michael Fürst
|
3
|
+
# Version: 1.0
|
4
|
+
#
|
5
|
+
|
6
|
+
require 'BotnetV2/Network'
|
7
|
+
require 'securerandom'
|
8
|
+
|
9
|
+
module BotnetV2
|
10
|
+
class Worker
|
11
|
+
def initialize(password, host, port = 8008, ssl = true)
|
12
|
+
@exit = false
|
13
|
+
@onReady = Hash.new
|
14
|
+
@onReady['worker_onReady'] = SecureRandom.hex
|
15
|
+
@onReady['verify'] = password
|
16
|
+
|
17
|
+
begin
|
18
|
+
network = BotNetwork.new
|
19
|
+
network.connect host, port if ssl
|
20
|
+
network.connect_no_ssl host, port unless ssl
|
21
|
+
|
22
|
+
@connection = BotConnection.new network.socket, network
|
23
|
+
@t = Thread.start do
|
24
|
+
@connection.on_message_handler_loop(Proc.new do |msg| on_message(msg, @connection) end)
|
25
|
+
end
|
26
|
+
rescue => e
|
27
|
+
puts e
|
28
|
+
end
|
29
|
+
|
30
|
+
@connection.send @onReady
|
31
|
+
end
|
32
|
+
|
33
|
+
def on_message (message, connection)
|
34
|
+
result = Hash.new
|
35
|
+
if message['onWork'] != nil
|
36
|
+
result['onResult'] = Hash.new
|
37
|
+
result['onResult']['task_id'] = message['onWork']['task_id']
|
38
|
+
result['onResult']['clientId'] = message['onWork']['clientId']
|
39
|
+
begin
|
40
|
+
result['onResult']['result'] = eval message['onWork']['src']
|
41
|
+
rescue => error
|
42
|
+
result['onResult']['error'] = error
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
result['worker_onReady'] = @onReady['worker_onReady'] unless @exit
|
47
|
+
connection.send result
|
48
|
+
end
|
49
|
+
|
50
|
+
def exit!
|
51
|
+
@exit = true
|
52
|
+
@connection.close
|
53
|
+
@t.kill
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/test/cert.pem
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIICRzCCAbCgAwIBAgIBATANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQGEwJERTEN
|
3
|
+
MAsGA1UECgwEbm9uZTENMAsGA1UECwwEbm9uZTESMBAGA1UEAwwJYm90bmV0X3Yy
|
4
|
+
MB4XDTE0MTAxMTEyNDgyNFoXDTE1MTAxMTEyNDgyNFowPzELMAkGA1UEBhMCREUx
|
5
|
+
DTALBgNVBAoMBG5vbmUxDTALBgNVBAsMBG5vbmUxEjAQBgNVBAMMCWJvdG5ldF92
|
6
|
+
MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAnZYFMd/sE6bRiuGNYj3VO+ap
|
7
|
+
vzt0K/WjUmvMdRN+BgJqnSMbtuwlsTsUpjbJY/MA8iue/KJWa6TUf1Vcv6qRfSPa
|
8
|
+
QJhVdmPqhfSDfy3WEnzNi/LtI7JlbZlc1U5FLXh9VeQXQfbpDXvx/m/sX8oCFAry
|
9
|
+
QXV7o8SJ3D1EWR/n25ECAwEAAaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
|
10
|
+
FgQUHw+bIIPzvZU0nHa80yN2X0BpvB4wHwYDVR0jBBgwFgQUHw+bIIPzvZU0nHa8
|
11
|
+
0yN2X0BpvB4wDQYJKoZIhvcNAQEFBQADgYEAAEYEp7CC6fdZiIxAHIqpl8CMrHbH
|
12
|
+
Ok6XCmT3ypwmupDiLlursUy0+tEH1vEkATcNBAca4yiCzLnOF2zitxeIB+sfE39o
|
13
|
+
wIg3dzngKEOT9pYI2U+Hej8zaPiToi2kwnJXnMbOvywMKioj3WMtHH1BhCeKHNg4
|
14
|
+
C3aBFNDAaPh/LhY=
|
15
|
+
-----END CERTIFICATE-----
|
data/test/master_test.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require '../lib/BotnetV2'
|
3
|
+
|
4
|
+
class MasterTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
# Called before every test method runs. Can be used
|
7
|
+
# to set up fixture information.
|
8
|
+
def setup
|
9
|
+
# Do nothing
|
10
|
+
unless File.exists? 'private.pem' and File.exists? 'cert.pem'
|
11
|
+
File.delete 'private.pem' if File.exists? 'private.pem'
|
12
|
+
File.delete 'cert.pem' if File.exists? 'cert.pem'
|
13
|
+
BotnetV2::BotnetV2.create_certificate
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Called after every test method runs. Can be used to tear
|
18
|
+
# down fixture information.
|
19
|
+
|
20
|
+
def teardown
|
21
|
+
# Do nothing
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_create
|
25
|
+
master = BotnetV2::BotnetV2.create_master 'foobar'
|
26
|
+
worker = BotnetV2::BotnetV2.create_worker 'foobar12', 'localhost'
|
27
|
+
worker = BotnetV2::BotnetV2.create_worker 'foobar', 'localhost'
|
28
|
+
client = BotnetV2::BotnetV2.create_client 'foobar', 1, 'localhost'
|
29
|
+
client.execute('1+1', Proc.new do |res| on_result(res) end)
|
30
|
+
sleep(0) until @done
|
31
|
+
client.exit!
|
32
|
+
worker.exit!
|
33
|
+
master.exit!
|
34
|
+
assert_equal(@result, 2, 'Wrong result')
|
35
|
+
end
|
36
|
+
|
37
|
+
def on_result(result)
|
38
|
+
@result = result
|
39
|
+
@done = true
|
40
|
+
end
|
41
|
+
end
|
data/test/private.pem
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
2
|
+
MIICWwIBAAKBgQCdlgUx3+wTptGK4Y1iPdU75qm/O3Qr9aNSa8x1E34GAmqdIxu2
|
3
|
+
7CWxOxSmNslj8wDyK578olZrpNR/VVy/qpF9I9pAmFV2Y+qF9IN/LdYSfM2L8u0j
|
4
|
+
smVtmVzVTkUteH1V5BdB9ukNe/H+b+xfygIUCvJBdXujxIncPURZH+fbkQIDAQAB
|
5
|
+
AoGARReHg4yH9z3G1bt6v74YhcDmX9/zWWrDhtmYtSQstvnMQMUp25PCGuiqbw3K
|
6
|
+
UrYyjfsuI9oRRfTo7kNA/RAN5Tlxmba06SlghuRTitg27pFXVISsxOmEwzQX74Mv
|
7
|
+
VnccPhTUOUm8sYHNvnOOM+174Al+OkXOtdeyaipdEmMfFCECQQD72OcsT0rPWlET
|
8
|
+
YEapFX95Bgp8gQtpx8ndO7IdQv5FeeK9AsAeSMBif5lc7gLF4hwSRlsxgU30UMdB
|
9
|
+
HTxjmhX1AkEAoC84z6kEBTuww8A1y2MgYpxiy/U7BwKzSGxMxSUYGjQjMOU7v4UZ
|
10
|
+
UGf3+iF9CfickUkY7G0gNhuFqbZ97zLRrQJAf7B9pQ2e1HrqWHSb3uazdt0FPBMB
|
11
|
+
gmR1iOHXcNairP8bYtGeLrycLlSboW5boZD+wpVBb1wr9g9utyjnkWhycQJAQ//n
|
12
|
+
4RfB0irlviOhcobRH6t9sVGYTkCSNSNsb6Bwm+cYLVCSzZnGBkEsnu2KdCoq5O4f
|
13
|
+
+3XT38RNOJ901I9BPQJAav1Q/Ny334gSk7VcCJIplYMJNkWcv/IbLdDoaX5KdnKG
|
14
|
+
7vED5oI5nvRB9DDJd9dwTvvm/KVrVJGINY35wvOjdA==
|
15
|
+
-----END RSA PRIVATE KEY-----
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: BotnetV2
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.0'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Fürst
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-10-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ~>
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '1.7'
|
19
|
+
name: bundler
|
20
|
+
prerelease: false
|
21
|
+
type: :development
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '10.0'
|
33
|
+
name: rake
|
34
|
+
prerelease: false
|
35
|
+
type: :development
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description: A bot net to calculate intense tasks on remote machines.
|
42
|
+
email:
|
43
|
+
- penguinmenac3@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- .gitignore
|
49
|
+
- BotnetV2.gemspec
|
50
|
+
- Gemfile
|
51
|
+
- LICENSE.txt
|
52
|
+
- README.md
|
53
|
+
- Rakefile
|
54
|
+
- lib/BotnetV2.rb
|
55
|
+
- lib/BotnetV2/Client.rb
|
56
|
+
- lib/BotnetV2/Master.rb
|
57
|
+
- lib/BotnetV2/Network.rb
|
58
|
+
- lib/BotnetV2/Worker.rb
|
59
|
+
- lib/BotnetV2/version.rb
|
60
|
+
- test/cert.pem
|
61
|
+
- test/master_test.rb
|
62
|
+
- test/private.pem
|
63
|
+
homepage: https://fuersts1.homeip.net/penguinmenac3/botnetv2
|
64
|
+
licenses:
|
65
|
+
- MIT
|
66
|
+
metadata: {}
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options: []
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
requirements: []
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 2.1.9
|
84
|
+
signing_key:
|
85
|
+
specification_version: 4
|
86
|
+
summary: A bot net to calculate intense tasks on remote machines.
|
87
|
+
test_files:
|
88
|
+
- test/cert.pem
|
89
|
+
- test/master_test.rb
|
90
|
+
- test/private.pem
|