BotnetV2 1.0
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 +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
|