8291_scanner 1.0.0 → 1.0.2
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 +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
|