ruby_clamdscan 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,204 @@
1
+ ##
2
+ ## Example config file for freshclam
3
+ ## Please read the freshclam.conf(5) manual before editing this file.
4
+ ##
5
+
6
+
7
+ # Comment or remove the line below.
8
+ # Example
9
+
10
+ # Path to the database directory.
11
+ # WARNING: It must match clamd.conf's directive!
12
+ # Default: hardcoded (depends on installation options)
13
+ #DatabaseDirectory /var/lib/clamav
14
+
15
+ # Path to the log file (make sure it has proper permissions)
16
+ # Default: disabled
17
+ UpdateLogFile /var/log/clamav/freshclam.log
18
+
19
+ # Maximum size of the log file.
20
+ # Value of 0 disables the limit.
21
+ # You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)
22
+ # and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes).
23
+ # in bytes just don't use modifiers. If LogFileMaxSize is enabled,
24
+ # log rotation (the LogRotate option) will always be enabled.
25
+ # Default: 1M
26
+ #LogFileMaxSize 2M
27
+
28
+ # Log time with each message.
29
+ # Default: no
30
+ #LogTime yes
31
+
32
+ # Enable verbose logging.
33
+ # Default: no
34
+ #LogVerbose yes
35
+
36
+ # Use system logger (can work together with UpdateLogFile).
37
+ # Default: no
38
+ #LogSyslog yes
39
+
40
+ # Specify the type of syslog messages - please refer to 'man syslog'
41
+ # for facility names.
42
+ # Default: LOG_LOCAL6
43
+ #LogFacility LOG_MAIL
44
+
45
+ # Enable log rotation. Always enabled when LogFileMaxSize is enabled.
46
+ # Default: no
47
+ #LogRotate yes
48
+
49
+ # This option allows you to save the process identifier of the daemon
50
+ # This file will be owned by root, as long as freshclam was started by root.
51
+ # It is recommended that the directory where this file is stored is
52
+ # also owned by root to keep other users from tampering with it.
53
+ # Default: disabled
54
+ PidFile /tmp/freshclam.pid
55
+
56
+ # By default when started freshclam drops privileges and switches to the
57
+ # "clamav" user. This directive allows you to change the database owner.
58
+ # Default: clamav (may depend on installation options)
59
+ DatabaseOwner clamav
60
+
61
+ # Use DNS to verify virus database version. FreshClam uses DNS TXT records
62
+ # to verify database and software versions. With this directive you can change
63
+ # the database verification domain.
64
+ # WARNING: Do not touch it unless you're configuring freshclam to use your
65
+ # own database verification domain.
66
+ # Default: current.cvd.clamav.net
67
+ #DNSDatabaseInfo current.cvd.clamav.net
68
+
69
+ # database.clamav.net is now the primary domain name to be used world-wide.
70
+ # Now that CloudFlare is being used as our Content Delivery Network (CDN),
71
+ # this one domain name works world-wide to direct freshclam to the closest
72
+ # geographic endpoint.
73
+ # If the old db.XY.clamav.net domains are set, freshclam will automatically
74
+ # use database.clamav.net instead.
75
+ DatabaseMirror database.clamav.net
76
+
77
+ # How many attempts to make before giving up.
78
+ # Default: 3 (per mirror)
79
+ #MaxAttempts 5
80
+
81
+ # With this option you can control scripted updates. It's highly recommended
82
+ # to keep it enabled.
83
+ # Default: yes
84
+ ScriptedUpdates yes
85
+
86
+ # By default freshclam will keep the local databases (.cld) uncompressed to
87
+ # make their handling faster. With this option you can enable the compression;
88
+ # the change will take effect with the next database update.
89
+ # Default: no
90
+ #CompressLocalDatabase no
91
+
92
+ # With this option you can provide custom sources for database files.
93
+ # This option can be used multiple times. Support for:
94
+ # http(s)://, ftp(s)://, or file://
95
+ # Default: no custom URLs
96
+ #DatabaseCustomURL http://myserver.example.com/mysigs.ndb
97
+ #DatabaseCustomURL https://myserver.example.com/mysigs.ndb
98
+ #DatabaseCustomURL https://myserver.example.com:4567/allow_list.wdb
99
+ #DatabaseCustomURL ftp://myserver.example.com/example.ldb
100
+ #DatabaseCustomURL ftps://myserver.example.com:4567/example.ndb
101
+ #DatabaseCustomURL file:///mnt/nfs/local.hdb
102
+
103
+ # This option allows you to easily point freshclam to private mirrors.
104
+ # If PrivateMirror is set, freshclam does not attempt to use DNS
105
+ # to determine whether its databases are out-of-date, instead it will
106
+ # use the If-Modified-Since request or directly check the headers of the
107
+ # remote database files. For each database, freshclam first attempts
108
+ # to download the CLD file. If that fails, it tries to download the
109
+ # CVD file. This option overrides DatabaseMirror, DNSDatabaseInfo
110
+ # and ScriptedUpdates. It can be used multiple times to provide
111
+ # fall-back mirrors.
112
+ # Default: disabled
113
+ #PrivateMirror mirror1.example.com
114
+ #PrivateMirror mirror2.example.com
115
+
116
+ # Number of database checks per day.
117
+ # Default: 12 (every two hours)
118
+ #Checks 24
119
+
120
+ # Proxy settings
121
+ # The HTTPProxyServer may be prefixed with [scheme]:// to specify which kind
122
+ # of proxy is used.
123
+ # http:// HTTP Proxy. Default when no scheme or proxy type is specified.
124
+ # https:// HTTPS Proxy. (Added in 7.52.0 for OpenSSL, GnuTLS and NSS)
125
+ # socks4:// SOCKS4 Proxy.
126
+ # socks4a:// SOCKS4a Proxy. Proxy resolves URL hostname.
127
+ # socks5:// SOCKS5 Proxy.
128
+ # socks5h:// SOCKS5 Proxy. Proxy resolves URL hostname.
129
+ # Default: disabled
130
+ #HTTPProxyServer https://proxy.example.com
131
+ #HTTPProxyPort 1234
132
+ #HTTPProxyUsername myusername
133
+ #HTTPProxyPassword mypass
134
+
135
+ # If your servers are behind a firewall/proxy which applies User-Agent
136
+ # filtering you can use this option to force the use of a different
137
+ # User-Agent header.
138
+ # As of ClamAV 0.103.3, this setting may not be used when updating from the
139
+ # clamav.net CDN and can only be used when updating from a private mirror.
140
+ # Default: clamav/version_number (OS: ..., ARCH: ..., CPU: ..., UUID: ...)
141
+ #HTTPUserAgent SomeUserAgentIdString
142
+
143
+ # Use aaa.bbb.ccc.ddd as client address for downloading databases. Useful for
144
+ # multi-homed systems.
145
+ # Default: Use OS'es default outgoing IP address.
146
+ #LocalIPAddress aaa.bbb.ccc.ddd
147
+
148
+ # Send the RELOAD command to clamd.
149
+ # Default: no
150
+ NotifyClamd /etc/clamav/clamd.conf
151
+
152
+ # Run command after successful database update.
153
+ # Use EXIT_1 to return 1 after successful database update.
154
+ # Default: disabled
155
+ #OnUpdateExecute command
156
+
157
+ # Run command when database update process fails.
158
+ # Default: disabled
159
+ #OnErrorExecute command
160
+
161
+ # Run command when freshclam reports outdated version.
162
+ # In the command string %v will be replaced by the new version number.
163
+ # Default: disabled
164
+ #OnOutdatedExecute command
165
+
166
+ # Don't fork into background.
167
+ # Default: no
168
+ #Foreground yes
169
+
170
+ # Enable debug messages in libclamav.
171
+ # Default: no
172
+ #Debug yes
173
+
174
+ # Timeout in seconds when connecting to database server.
175
+ # Default: 30
176
+ #ConnectTimeout 60
177
+
178
+ # Timeout in seconds when reading from database server. 0 means no timeout.
179
+ # Default: 60
180
+ #ReceiveTimeout 300
181
+
182
+ # With this option enabled, freshclam will attempt to load new databases into
183
+ # memory to make sure they are properly handled by libclamav before replacing
184
+ # the old ones.
185
+ # Tip: This feature uses a lot of RAM. If your system has limited RAM and you
186
+ # are actively running ClamD or ClamScan during the update, then you may need
187
+ # to set `TestDatabases no`.
188
+ # Default: yes
189
+ #TestDatabases no
190
+
191
+ # This option enables downloading of bytecode.cvd, which includes additional
192
+ # detection mechanisms and improvements to the ClamAV engine.
193
+ # Default: yes
194
+ #Bytecode no
195
+
196
+ # Include an optional signature databases (opt-in).
197
+ # This option can be used multiple times.
198
+ #ExtraDatabase dbname1
199
+ #ExtraDatabase dbname2
200
+
201
+ # Exclude a standard signature database (opt-out).
202
+ # This option can be used multiple times.
203
+ #ExcludeDatabase dbname1
204
+ #ExcludeDatabase dbname2
@@ -0,0 +1,18 @@
1
+ version: "3.9"
2
+ services:
3
+ clamav:
4
+ image: clamav/clamav:latest
5
+ ports:
6
+ - "3310:3310"
7
+ volumes:
8
+ - clamav-dev:/var/lib/clamav # Virus database
9
+ - ./docker/clamav/config/clamd.conf:/etc/clamav/clamd.conf
10
+ - ./docker/clamav/config/freshclam.conf:/etc/clamav/freshclam.conf
11
+
12
+ volumes:
13
+ clamav-dev:
14
+
15
+ networks:
16
+ ruby-clamdscan:
17
+ external: true
18
+ name: ruby-clamdscan
data/eicar.com ADDED
@@ -0,0 +1 @@
1
+ X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ruby_clamdscan/commands/utils"
4
+
5
+ module RubyClamdscan
6
+ module Commands
7
+ # Management commands for
8
+ module Manage
9
+ # Force ClamAV to reload the virus databases
10
+ # @param configuration [RubyClamdscan::Configuration] configuration for building the ClamAV connection
11
+ def self.reload_server_database(configuration)
12
+ RubyClamdscan::Commands::Utils.send_single_command("RELOAD", configuration)
13
+ end
14
+
15
+ # Shutdown ClamAV server
16
+ # Note: this will completely close socket communication. Server cannot be restarted through this library
17
+ # @param configuration [RubyClamdscan::Configuration] configuration for building the ClamAV connection
18
+ def self.shutdown_server(configuration)
19
+ RubyClamdscan::Commands::Utils.send_single_command("SHUTDOWN", configuration)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "socket"
4
+ require "ruby_clamdscan/models/scan_result"
5
+ require "ruby_clamdscan/errors/clamav_errors"
6
+
7
+ module RubyClamdscan
8
+ module Commands
9
+ # Methods for scanning file contents
10
+ module Scan
11
+ SCAN_COMMAND = "zINSTREAM\0"
12
+
13
+ # Stream file contents to ClamAV
14
+ # @param file_input_stream [IO] Input file_input_stream to scan
15
+ # @param configuration [RubyClamdscan::Configuration] Configuration settings
16
+ # @return [RubyClamdscan::Models::ScanResult]
17
+ # @raise [RubyClamdscan::Errors::VirusDetectedError] if Configuration is set to raise exception and malware is detected
18
+ # @raise [RubyClamdscan::Errors::ClamAVCommunicationError] if communication with ClamAV server fails
19
+ def self.scan(file_input_stream, configuration)
20
+ response = ""
21
+ clam_av_stream = nil
22
+
23
+ begin
24
+ clam_av_stream = RubyClamdscan::Socket.open_clamav_socket(configuration)
25
+ send_contents(clam_av_stream, configuration, file_input_stream)
26
+ response = get_response(clam_av_stream)
27
+ rescue StandardError => e
28
+ raise RubyClamdscan::Errors::ClamAVCommunicationError.new(SCAN_COMMAND, e)
29
+ ensure
30
+ clam_av_stream&.close
31
+ end
32
+
33
+ result = build_result(response)
34
+
35
+ raise RubyClamdscan::Errors::VirusDetectedError, result if configuration.raise_error_on_virus_detected && result.contains_virus
36
+
37
+ result
38
+ end
39
+
40
+ # Stream file contents to ClamAV
41
+ # @param filepath [String] Path to file in local storage to scan
42
+ # @param configuration [RubyClamdscan::Configuration] Configuration settings
43
+ # @return [RubyClamdscan::Models::ScanResult]
44
+ # @raise IOError if there is no file found at filepath
45
+ def self.scan_file(filepath, configuration)
46
+ raise IOError, "Unable to find file #{filepath}" unless File.exist?(filepath)
47
+
48
+ begin
49
+ fd = IO.sysopen(filepath, "rb")
50
+ fin = IO.new(fd)
51
+ result = scan(fin, configuration)
52
+ ensure
53
+ fin.close
54
+ end
55
+ result
56
+ end
57
+
58
+ # Builds a result object after parsing the response from ClamAV
59
+ # @param response [String] Response from ClamAV stream
60
+ # @return [RubyClamdscan::Models::ScanResult] Constructed result object
61
+ def self.build_result(response)
62
+ # OK response: "stream: OK"
63
+ # Malware response: "stream: Win.Test.EICAR_HDB-1 FOUND"
64
+ # Error response "stream: <message> ERROR"
65
+
66
+ response = response.strip # Strip out any trailing empty chars from the buffer
67
+ tokens = response.split(" ")
68
+ puts("RESPONSE:'#{response}'")
69
+
70
+ case tokens
71
+ in ["stream:", "OK"]
72
+ RubyClamdscan::Models::ScanResult.new(is_successful: true, contains_virus: false)
73
+ in ["stream:", virus_info, "FOUND"]
74
+ RubyClamdscan::Models::ScanResult.new(is_successful: true, contains_virus: true, virus_info:)
75
+ in []
76
+ RubyClamdscan::Models::ScanResult.new(is_successful: false, contains_virus: nil,
77
+ error_message: "Empty response from ClamAV, is the server accepting connections?")
78
+ else
79
+ RubyClamdscan::Models::ScanResult.new(is_successful: false, contains_virus: nil, error_message: response)
80
+ end
81
+ end
82
+
83
+ private_class_method :build_result
84
+
85
+ # Gets the response from ClamAV off the stream
86
+ # @param clam_av_stream [IO] Read stream from ClamAV
87
+ # @return [String] Response
88
+ def self.get_response(clam_av_stream)
89
+ response = ""
90
+ while (data = clam_av_stream.gets)
91
+ response += data
92
+ end
93
+ response
94
+ end
95
+
96
+ private_class_method :get_response
97
+
98
+ # Sends file contents from stream to ClamAV
99
+ # @param clam_av_stream [IO] Stream to ClamAV
100
+ # @param configuration [RubyClamdscan::Configuration] Params defining how much data to send per chunk
101
+ # @param file_input_stream [IO] Stream to read file contents from
102
+ def self.send_contents(clam_av_stream, configuration, file_input_stream)
103
+ clam_av_stream.write(SCAN_COMMAND) # Write the command to tell ClamAV to start scanning
104
+ clam_av_stream.flush
105
+ while (chunk = file_input_stream.read(configuration.chunk_size))
106
+ chunk_len = [chunk.length].pack("N")
107
+ clam_av_stream.write(chunk_len + chunk)
108
+ clam_av_stream.flush
109
+ end
110
+ clam_av_stream.write([0x00, 0x00, 0x00, 0x00].pack("NNNN"))
111
+ clam_av_stream.flush
112
+ end
113
+
114
+ private_class_method :send_contents
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ruby_clamdscan/commands/utils"
4
+
5
+ module RubyClamdscan
6
+ module Commands
7
+ # Status commands for ClamAV
8
+ module Status
9
+ # Attempts to ping the ClamAV server
10
+ # @param configuration [RubyClamdscan::Configuration] configuration for building the ClamAV connection
11
+ # @raise [RubyClamdscan::Exceptions::EmptyResponseError] If server response is empty
12
+ def self.ping_server(configuration)
13
+ RubyClamdscan::Commands::Utils.send_single_command("PING", configuration)
14
+ end
15
+
16
+ # Attempts to retrieve the ClamAV server's version information
17
+ # @param configuration [RubyClamdscan::Configuration] configuration for building the ClamAV connection
18
+ # @raise [RubyClamdscan::Exceptions::EmptyResponseError] If server response is empty
19
+ def self.server_version(configuration)
20
+ RubyClamdscan::Commands::Utils.send_single_command("VERSION", configuration)
21
+ end
22
+
23
+ # Replies with statistics about the scan queue, contents of scan queue, and memory usage
24
+ # Because the format of this response is subject to change, this method will only return the string
25
+ # Uses "nSTATS\n", blocks in the returned response will be separated by the \n character
26
+ # @param configuration [RubyClamdscan::Configuration] configuration for building the ClamAV connection
27
+ # @return [String] Format (currently):
28
+ # "POOLS: 1\n\nSTATE: VALID PRIMARY\nTHREADS: live 1 idle 0 max 10 idle-timeout 30\nQUEUE: 0 items\n\tSTATS 0.000375 \n\n
29
+ # MEMSTATS: heap N/A mmap N/A used N/A free N/A releasable N/A pools 1 pools_used 1281.773M pools_total 1281.827M\nEND"
30
+ # @raise [RubyClamdscan::Errors::EmptyResponseError] If server response is empty
31
+ def self.server_stats(configuration)
32
+ RubyClamdscan::Commands::Utils.send_single_command("nSTATS\n", configuration)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ruby_clamdscan/errors/clamav_errors"
4
+
5
+ module RubyClamdscan
6
+ module Commands
7
+ # Utilities for running commands
8
+ module Utils
9
+ # Sends a single command to the ClamAV server and return its response
10
+ # @param command [String] Command to send
11
+ # @param configuration [RubyClamdscan::Configuration] Configuration used for building socket
12
+ # @return [String] Response from ClamAV server
13
+ # @raise [RubyClamdscan::Errors::EmptyResponseError] if configuration.raise_error_on_empty_response is true and server doesn't send response
14
+ # @raise
15
+ def self.send_single_command(command, configuration)
16
+ response = ""
17
+ begin
18
+ clam_av_stream = RubyClamdscan::Socket.open_clamav_socket(configuration)
19
+ clam_av_stream.write(command)
20
+ clam_av_stream.flush
21
+
22
+ while (data = clam_av_stream.gets)
23
+ response += data
24
+ end
25
+
26
+ response = response.strip
27
+ rescue StandardError => e
28
+ raise RubyClamdscan::Errors::ClamAVCommunicationError.new(command, e)
29
+ ensure
30
+ clam_av_stream&.close
31
+ end
32
+
33
+ raise RubyClamdscan::Errors::EmptyResponseError, command if configuration.raise_error_on_empty_response && response.empty?
34
+
35
+ response
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyClamdscan
4
+ # Configuration for the gem
5
+ class Configuration
6
+ # TCP Port ClamAV is listening on if using TCP
7
+ # Default: 3310
8
+ # @return [Integer]
9
+ attr_accessor :tcp_port
10
+
11
+ # Host ClamAV is listening on if using TCP
12
+ # Default: localhost
13
+ # @return [String]
14
+ attr_accessor :tcp_host
15
+
16
+ # Unix Socket for ClamAV
17
+ # Default: /tmp/clamd.socket
18
+ # @return [String]
19
+ attr_accessor :unix_socket
20
+
21
+ # Chunk size in bytes for streaming files
22
+ # Default: 1024
23
+ # @return [Integer]
24
+ attr_accessor :chunk_size
25
+
26
+ # If TCP socket should be used. If false, the Unix socket will be used instead
27
+ # Note, if running ClamAV on the same host, it is recommended to use the Unix socket as it's much faster
28
+ # Default: false
29
+ # @return [Boolean]
30
+ attr_accessor :use_tcp_socket
31
+
32
+ # If the server responds with an empty string, raise an error instead of just returning the empty string
33
+ # Default: true
34
+ # @return [Boolean]
35
+ attr_accessor :raise_error_on_empty_response
36
+
37
+ # If a virus is detected in the scanned contents, raise an error
38
+ # RubyClamdscan::Commands::Scan methods will raise RubyClamdscan::Errors::VirusDetected
39
+ # Default: true
40
+ # @return [Boolean]
41
+ attr_accessor :raise_error_on_virus_detected
42
+
43
+ def initialize
44
+ @tcp_host = "localhost"
45
+ @tcp_port = 3310
46
+ @chunk_size = 1024
47
+ @unix_socket = "/tmp/clamd.socket"
48
+ @raise_error_on_empty_response = true
49
+ @raise_error_on_virus_detected = true
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyClamdscan
4
+ module Errors
5
+ # Raised when ClamAV returns an empty response - usually means that the server has not finished starting or is shutdown
6
+ class EmptyResponseError < StandardError
7
+ # @param command [String] Command that failed
8
+ # @param msg [String, nil] Optional message
9
+ def initialize(command, msg: nil)
10
+ msg = "Got empty response when attempting to run command: #{command}. Are you sure the ClamAV server is running?" unless msg.nil?
11
+ super(msg)
12
+ end
13
+ end
14
+
15
+ # Raised when there is some error in communicating with the ClamAV server
16
+ # @param command [String] Command that failed
17
+ # @param cause [StandardError, nil] Underlying error if found
18
+ # @param msg [String, nil] Optional message
19
+ class ClamAVCommunicationError < StandardError
20
+ # @return [StandardError, nil] Underlying error if found
21
+ attr_reader :cause
22
+
23
+ def initialize(command, cause, msg: nil)
24
+ @cause = cause
25
+ msg = "Error while communicating with ClamAV - cause: #{cause&.msg} command: #{command}." unless msg.nil?
26
+ super(msg)
27
+ end
28
+ end
29
+
30
+ # Raised if ClamAV detects malware in the scanned contents
31
+ class VirusDetectedError < StandardError
32
+ # @return [RubyClamdscan::Models::ScanResult] Information about scan and virus
33
+ attr_reader :scan_result
34
+
35
+ # @param scan_result [RubyClamdscan::Models::ScanResult] Information about scan result
36
+ # @param msg [String, nil] Optional message
37
+ def initialize(scan_result, msg: nil)
38
+ @scan_result = scan_result
39
+ msg = "Detected malware in scanned contents: #{scan_result.virus_info}" unless msg.nil?
40
+ super(msg)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyClamdscan
4
+ module Models
5
+ # Represents the result from scanning a file with ClamAV
6
+ class ScanResult
7
+ # If the command successfully - does not indicate file was safe! Check contains_virus for that information
8
+ # @return [Boolean]
9
+ attr_reader :is_successful
10
+
11
+ # If ClamAV detected malware in the passed file, will be nil if there was an error running the command
12
+ # @return [Boolean, nil]
13
+ attr_reader :contains_virus
14
+
15
+ # Returns the error string if the command failed
16
+ # @return [Exception, nil]
17
+ attr_reader :exception
18
+
19
+ # Returns the error string if the command failed
20
+ # @return [String, nil]
21
+ attr_reader :error_message
22
+
23
+ # Returns virus information if a virus was detected
24
+ # Value is the response from ClamAV, the malware classification - should be in the form of "Win.Test.EICAR_HDB-1"
25
+ # @return [String, nil]
26
+ attr_reader :virus_info
27
+
28
+ def initialize(is_successful:, contains_virus:, virus_info: nil, exception: nil, error_message: nil)
29
+ @is_successful = is_successful
30
+ @contains_virus = contains_virus
31
+ @exception = exception
32
+ @error_message = error_message
33
+ @virus_info = virus_info
34
+ end
35
+ end
36
+
37
+ class StatsResult
38
+ attr_reader :total_pools, :state, :threads_live, :threads_idle, :threads_max
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "socket"
4
+
5
+ module RubyClamdscan
6
+ # Socket related methods to open communication
7
+ module Socket
8
+ # Open a socket to ClamAV based on RubyClamdscan.Configuration
9
+ # @param configuration [RubyClamdscan::Configuration] configuration used to determine socket
10
+ # @return [IO]
11
+ def self.open_clamav_socket(configuration)
12
+ if configuration.use_tcp_socket
13
+ open_tcp_socket(configuration)
14
+ else
15
+ open_unix_socket(configuration)
16
+ end
17
+ end
18
+
19
+ def self.open_tcp_socket(configuration)
20
+ TCPSocket.open(configuration.tcp_host, configuration.tcp_port)
21
+ end
22
+
23
+ private_class_method :open_tcp_socket
24
+
25
+ def self.open_unix_socket(configuration)
26
+ UNIXSocket.new(configuration.unix_socket)
27
+ end
28
+
29
+ private_class_method :open_unix_socket
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyClamdscan
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ruby_clamdscan/socket"
4
+ require "ruby_clamdscan/commands/scan"
5
+ require "ruby_clamdscan/commands/manage"
6
+ require "ruby_clamdscan/commands/status"
7
+ require "ruby_clamdscan/configuration"
8
+ require "ruby_clamdscan/version"
9
+
10
+ # Utility for interacting with ClamAV
11
+ module RubyClamdscan
12
+ class << self
13
+ # Configuration to use interacting with the ClamAV server
14
+ def configuration
15
+ @configuration ||= Configuration.new
16
+ @configuration.use_tcp_socket = true
17
+ @configuration.tcp_host = "localhost"
18
+ @configuration.tcp_port = 3310
19
+
20
+ @configuration
21
+ end
22
+
23
+ # Configure RubyClamdscan
24
+ def configure
25
+ yield(configuration)
26
+ end
27
+
28
+ # Scans a file
29
+ # @param filepath [String] Path to file in local storage
30
+ # @return [RubyClamdscan::Models::ScanResult] Result from the scan attempt
31
+ def scan_file_from_path(filepath)
32
+ RubyClamdscan::Commands::Scan.scan_file(filepath, @configuration)
33
+ end
34
+
35
+ # Scans the contents of the stream passed in
36
+ # @param stream [IO] stream of file contents
37
+ # @return [RubyClamdscan::Models::ScanResult] Result from the scan attempt
38
+ def scan_contents(stream)
39
+ RubyClamdscan::Commands::Scan.scan(stream, @configuration)
40
+ end
41
+
42
+ def ping_server
43
+ RubyClamdscan::Commands::Status.ping_server(@configuration)
44
+ end
45
+
46
+ def server_version
47
+ RubyClamdscan::Commands::Status.server_version(@configuration)
48
+ end
49
+
50
+ def server_stats
51
+ RubyClamdscan::Commands::Status.server_stats(@configuration)
52
+ end
53
+
54
+ def reload_server_database
55
+ RubyClamdscan::Commands::Manage.reload_server_database(@configuration)
56
+ end
57
+
58
+ def shutdown_server
59
+ RubyClamdscan::Commands::Manage.shutdown_server(@configuration)
60
+ end
61
+ end
62
+ end