8291_scanner 1.0.0 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/8291_scanner +4 -4
- data/lib/8291_scanner/errors.rb +13 -10
- data/lib/8291_scanner/winbox_connection.rb +74 -74
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b2c610d2d178592045fa499f7242336739fea9dd064c2fb572f2194b16663e5
|
4
|
+
data.tar.gz: dbf44c21d5b52f8ebc9e10a34848b12daa48ff9884bc8d78060379b978f69bca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7fbe53e33e2f281e961b7b1ae80179d3049cc301ba094f2996613e453c42ba0cebb476d58362606710366a637b80ad823ecbd4cf2f8d14561c847481b19846e6
|
7
|
+
data.tar.gz: 5de9242e4d98f4d01c2cb3967e76cc04fa2a287d6db4e6ae05169b9ec5296f2fa70cac8bbc67f8633b85465fb38d8fc33b3a541098afc28c159c3d25d8bc65c0
|
data/bin/8291_scanner
CHANGED
@@ -4,12 +4,12 @@
|
|
4
4
|
|
5
5
|
require '8291_scanner/winbox_connection'
|
6
6
|
|
7
|
-
if ARGV.
|
7
|
+
if ARGV.empty?
|
8
8
|
puts 'Too few arguments.'
|
9
9
|
puts 'Usage: 8291_scanner host [port]'
|
10
10
|
exit!
|
11
11
|
elsif ARGV.length > 2
|
12
|
-
puts
|
12
|
+
puts 'Too much arguments.'
|
13
13
|
puts 'Usage: 8291_scanner host [port]'
|
14
14
|
exit!
|
15
15
|
end
|
@@ -17,6 +17,6 @@ end
|
|
17
17
|
host = ARGV[0]
|
18
18
|
port = ARGV[1]&.to_i
|
19
19
|
|
20
|
-
connection = (port ? WinboxConnection.new(host, port) : WinboxConnection.new(host))
|
20
|
+
connection = (port ? WinboxAPIScanner::WinboxConnection.new(host, port) : WinboxAPIScanner::WinboxConnection.new(host))
|
21
21
|
|
22
|
-
puts connection.
|
22
|
+
puts connection.request_version
|
data/lib/8291_scanner/errors.rb
CHANGED
@@ -1,17 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
# sharable_constant_value: literal
|
3
3
|
|
4
|
-
#
|
5
|
-
|
4
|
+
# Scanner that connects to the Winbox API of Mikrotik's RouterOS and attempts to read the version of the operating system.
|
5
|
+
module WinboxAPIScanner
|
6
|
+
# General Winbox error
|
7
|
+
class WinboxError < StandardError; end
|
6
8
|
|
7
|
-
# Error in the connection to the Winbox API
|
8
|
-
class WinboxConnectionError <
|
9
|
+
# Error in the connection to the Winbox API
|
10
|
+
class WinboxConnectionError < WinboxError; end
|
9
11
|
|
10
|
-
# An invalid or unexpected magic number has occurred in the response
|
11
|
-
class InvalidMagicNumberError < WinboxError; end
|
12
|
+
# An invalid or unexpected magic number has occurred in the response
|
13
|
+
class InvalidMagicNumberError < WinboxError; end
|
12
14
|
|
13
|
-
# A different file was returned than was requested
|
14
|
-
class FilenameError < WinboxError; end
|
15
|
+
# A different file was returned than was requested
|
16
|
+
class FilenameError < WinboxError; end
|
15
17
|
|
16
|
-
# The list is invalid
|
17
|
-
class InvalidListError < WinboxError; end
|
18
|
+
# The list is invalid
|
19
|
+
class InvalidListError < WinboxError; end
|
20
|
+
end
|
@@ -1,98 +1,98 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
# sharable_constant_value: literal
|
3
3
|
|
4
|
-
#
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
4
|
+
# Scanner that connects to the Winbox API of Mikrotik's RouterOS and attempts to read the version of the operating system.
|
5
|
+
module WinboxAPIScanner
|
6
|
+
# Models a connection to the Winbox API with an underlying TCP connection
|
7
|
+
class WinboxConnection
|
8
|
+
# Reference implementation: https://github.com/tenable/routeros/tree/master/8291_scanner
|
9
|
+
|
10
|
+
require 'socket'
|
11
|
+
require 'psych'
|
12
|
+
require_relative 'errors'
|
13
|
+
|
14
|
+
# Initializes a Winbox API connection
|
15
|
+
#
|
16
|
+
# @param host [String]
|
17
|
+
# @param port [Integer]
|
18
|
+
def initialize(host, port = 8291)
|
19
|
+
raise ArgumentError, 'Host must be a string' unless host.is_a? String
|
20
|
+
raise ArgumentError, 'Port must be an integer' unless port.is_a? Integer
|
21
|
+
|
22
|
+
begin
|
23
|
+
@socket = TCPSocket.new(host, port)
|
24
|
+
rescue SocketError, EncodingError, EOFError, IO::TimeoutError, Errno::EHOSTUNREACH, Errno::ECONNRESET => e
|
25
|
+
raise WinboxConnectionError, "Failed to connect to Winbox API: #{e.message}"
|
26
|
+
end
|
25
27
|
end
|
26
|
-
end
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
29
|
+
# Fetches the first 128 bytes of a file
|
30
|
+
#
|
31
|
+
# @param file [String]
|
32
|
+
# @return [String]
|
33
|
+
def old_mproxy_get_file(file)
|
34
|
+
raise ArgumentError, 'File must be a string' unless file.is_a? String
|
35
|
+
raise ArgumentError, 'Filename too long' if file.length > 12
|
35
36
|
|
36
|
-
|
37
|
-
|
37
|
+
# Prepare the file name
|
38
|
+
file_request = file.ljust(12, "\x00")
|
38
39
|
|
39
|
-
|
40
|
-
|
40
|
+
# Request only the first 128 bytes of the response.
|
41
|
+
file_request += "\x00\x80\x00\x00\x00\x00"
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
# Create and send request
|
44
|
+
request = "#{[file_request.length].pack 'C'}\x02#{file_request}"
|
45
|
+
@socket.send request, 0
|
46
|
+
@socket.flush
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
# Receive short length and first magic number
|
49
|
+
short_length = @socket.recv(1).unpack1('C')
|
50
|
+
magic_number1 = @socket.recv(1)
|
51
|
+
raise InvalidMagicNumberError, "Unknown magic number 1 in answer: #{magic_number1.dump}" unless magic_number1 == "\x02"
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
# Receive the name of the file in the response and the second magic number (probably an error code?)
|
54
|
+
name = @socket.recv(11).rstrip
|
55
|
+
magic_number2 = @socket.recv 1
|
56
|
+
raise InvalidMagicNumberError, "Unknown magic number 2 in answer: #{magic_number2.dump}" unless magic_number2 == "\x01"
|
56
57
|
|
57
|
-
|
58
|
+
raise FilenameError, 'Returned file is not requested file' unless name == file
|
58
59
|
|
59
|
-
|
60
|
+
long_length = @socket.recv(2).unpack1('n')
|
60
61
|
|
61
|
-
|
62
|
-
|
62
|
+
magic_number3 = @socket.recv 4
|
63
|
+
raise InvalidMagicNumberError, "Unknown magic number 3 in answer: #{magic_number3.dump}" unless magic_number3 == "\x00\x00\x00\x00"
|
63
64
|
|
64
|
-
|
65
|
-
|
65
|
+
# Use the short length if possible. If the short length has the maximum value, use the long length.
|
66
|
+
length = (short_length == 255 ? long_length : short_length)
|
66
67
|
|
67
|
-
|
68
|
-
|
68
|
+
# Read the answer
|
69
|
+
buffer = @socket.recv length
|
69
70
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
71
|
+
# Return the answer
|
72
|
+
return buffer
|
73
|
+
rescue SocketError, EncodingError, EOFError, IO::TimeoutError, Errno::EHOSTUNREACH, Errno::ECONNRESET => e
|
74
|
+
raise WinboxConnectionError, "Failed to connect to Winbox API: #{e.message}"
|
75
|
+
end
|
75
76
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
77
|
+
# @return [String]
|
78
|
+
def request_version
|
79
|
+
# Receive the first bytes of the list
|
80
|
+
answer = old_mproxy_get_file('list')
|
80
81
|
|
81
|
-
|
82
|
-
|
82
|
+
# Extract the first file information (formatted as JSON) from the response
|
83
|
+
json_raw = answer[0...(answer.index("\n") - 1)]
|
83
84
|
|
84
|
-
|
85
|
+
raise InvalidListError, 'JSON is empty' if json_raw.empty?
|
85
86
|
|
86
|
-
|
87
|
-
|
87
|
+
# Load the JSON
|
88
|
+
first_file = Psych.safe_load json_raw
|
88
89
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
version = first_file['version']
|
90
|
+
raise InvalidListError, 'List is not JSON' unless first_file.is_a? Hash
|
91
|
+
raise InvalidListError, 'File does not have a version information' unless first_file['version']
|
93
92
|
|
94
|
-
|
95
|
-
end
|
93
|
+
version = first_file['version']
|
96
94
|
|
95
|
+
return version
|
96
|
+
end
|
97
|
+
end
|
97
98
|
end
|
98
|
-
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: 8291_scanner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marek Küthe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-07-
|
11
|
+
date: 2024-07-22 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: This tool connects to the Winbox API of Mikrotik's RouterOS and tries
|
14
14
|
to read the operating system version.
|
@@ -27,7 +27,7 @@ files:
|
|
27
27
|
- lib/8291_scanner/winbox_connection.rb
|
28
28
|
homepage: https://codeberg.org/mark22k/8291_scanner
|
29
29
|
licenses:
|
30
|
-
-
|
30
|
+
- GPL-3.0-or-later
|
31
31
|
metadata:
|
32
32
|
source_code_uri: https://codeberg.org/mark22k/8291_scanner
|
33
33
|
bug_tracker_uri: https://codeberg.org/mark22k/8291_scanner/issues
|
@@ -47,7 +47,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
47
47
|
- !ruby/object:Gem::Version
|
48
48
|
version: '0'
|
49
49
|
requirements: []
|
50
|
-
rubygems_version: 3.5.
|
50
|
+
rubygems_version: 3.5.11
|
51
51
|
signing_key:
|
52
52
|
specification_version: 4
|
53
53
|
summary: connects to the Winbox API of Mikrotik's RouterOS and tries to read the operating
|