mirror of
https://github.com/volodymyrsmirnov/MalwareMultiScan.git
synced 2025-08-24 05:22:22 +00:00
refactoring and adding clamav scanning backend
This commit is contained in:
parent
7e63c77419
commit
b1a2357b50
24
.idea/.idea.MalwareMultiScan/.idea/runConfigurations/Dockerfiles_Clamav_Dockerfile.xml
generated
Normal file
24
.idea/.idea.MalwareMultiScan/.idea/runConfigurations/Dockerfiles_Clamav_Dockerfile.xml
generated
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Dockerfiles/Clamav.Dockerfile" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||||
|
<deployment type="dockerfile">
|
||||||
|
<settings>
|
||||||
|
<option name="imageTag" value="mindcollapse/malware-multi-scan-worker-clamav" />
|
||||||
|
<option name="buildCliOptions" value="" />
|
||||||
|
<option name="command" value="" />
|
||||||
|
<option name="containerName" value="malware-multi-scan-worker-clamav" />
|
||||||
|
<option name="entrypoint" value="" />
|
||||||
|
<option name="portBindings">
|
||||||
|
<list>
|
||||||
|
<DockerPortBindingImpl>
|
||||||
|
<option name="containerPort" value="9901" />
|
||||||
|
<option name="hostPort" value="9901" />
|
||||||
|
</DockerPortBindingImpl>
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
<option name="commandLineOptions" value="" />
|
||||||
|
<option name="sourceFilePath" value="MalwareMultiScan.Backends/Dockerfiles/Clamav.Dockerfile" />
|
||||||
|
</settings>
|
||||||
|
</deployment>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
@ -13,6 +13,11 @@ namespace MalwareMultiScan.Backends.Backends.Abstracts
|
|||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
|
protected AbstractLocalProcessScanBackend(ILogger logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual Regex MatchRegex { get; }
|
protected virtual Regex MatchRegex { get; }
|
||||||
protected virtual string BackendPath { get; }
|
protected virtual string BackendPath { get; }
|
||||||
protected virtual bool ParseStdErr { get; }
|
protected virtual bool ParseStdErr { get; }
|
||||||
@ -22,11 +27,6 @@ namespace MalwareMultiScan.Backends.Backends.Abstracts
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AbstractLocalProcessScanBackend(ILogger logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async Task<string[]> ScanAsync(string path, CancellationToken cancellationToken)
|
public override async Task<string[]> ScanAsync(string path, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var process = new Process
|
var process = new Process
|
||||||
|
@ -41,7 +41,9 @@ namespace MalwareMultiScan.Backends.Backends.Abstracts
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await using (var tempFileStream = File.OpenWrite(tempFile))
|
await using (var tempFileStream = File.OpenWrite(tempFile))
|
||||||
|
{
|
||||||
await stream.CopyToAsync(tempFileStream, cancellationToken);
|
await stream.CopyToAsync(tempFileStream, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
return await ScanAsync(tempFile, cancellationToken);
|
return await ScanAsync(tempFile, cancellationToken);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using MalwareMultiScan.Backends.Backends.Abstracts;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace MalwareMultiScan.Backends.Backends.Implementations
|
||||||
|
{
|
||||||
|
public class ClamavScanBackend : AbstractLocalProcessScanBackend
|
||||||
|
{
|
||||||
|
public ClamavScanBackend(ILogger logger) : base(logger)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Name { get; } = "Clamav";
|
||||||
|
|
||||||
|
public override DateTime DatabaseLastUpdate =>
|
||||||
|
File.GetLastWriteTime("/var/lib/clamav/daily.cvd");
|
||||||
|
|
||||||
|
protected override string BackendPath { get; } = "/usr/bin/clamscan";
|
||||||
|
|
||||||
|
protected override Regex MatchRegex { get; } =
|
||||||
|
new Regex(@"(\S+): (?<threat>[\S]+) FOUND", RegexOptions.Compiled | RegexOptions.Multiline);
|
||||||
|
|
||||||
|
protected override bool ParseStdErr { get; } = false;
|
||||||
|
|
||||||
|
protected override string GetBackendArguments(string path)
|
||||||
|
{
|
||||||
|
return $"--no-summary {path}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using MalwareMultiScan.Backends.Backends.Abstracts;
|
using MalwareMultiScan.Backends.Backends.Abstracts;
|
||||||
@ -9,22 +8,26 @@ namespace MalwareMultiScan.Backends.Backends.Implementations
|
|||||||
{
|
{
|
||||||
public class WindowsDefenderScanBackend : AbstractLocalProcessScanBackend
|
public class WindowsDefenderScanBackend : AbstractLocalProcessScanBackend
|
||||||
{
|
{
|
||||||
|
public WindowsDefenderScanBackend(ILogger logger) : base(logger)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public override string Name { get; } = "Windows Defender";
|
public override string Name { get; } = "Windows Defender";
|
||||||
|
|
||||||
public override DateTime DatabaseLastUpdate =>
|
public override DateTime DatabaseLastUpdate =>
|
||||||
File.GetLastWriteTime("/opt/engine/mpavbase.vdm");
|
File.GetLastWriteTime("/opt/engine/mpavbase.vdm");
|
||||||
|
|
||||||
protected override string BackendPath { get; } = "/opt/mpclient";
|
protected override string BackendPath { get; } = "/opt/mpclient";
|
||||||
|
|
||||||
protected override Regex MatchRegex { get; } =
|
protected override Regex MatchRegex { get; } =
|
||||||
new Regex(@"EngineScanCallback\(\)\: Threat (?<threat>[\S]+) identified",
|
new Regex(@"EngineScanCallback\(\): Threat (?<threat>[\S]+) identified",
|
||||||
RegexOptions.Compiled | RegexOptions.Multiline);
|
RegexOptions.Compiled | RegexOptions.Multiline);
|
||||||
|
|
||||||
protected override bool ParseStdErr { get; } = true;
|
protected override bool ParseStdErr { get; } = true;
|
||||||
|
|
||||||
protected override string GetBackendArguments(string path) => path;
|
protected override string GetBackendArguments(string path)
|
||||||
|
|
||||||
public WindowsDefenderScanBackend(ILogger logger) : base(logger)
|
|
||||||
{
|
{
|
||||||
|
return path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
FROM mindcollapse/malware-multi-scan-base:latest
|
FROM mindcollapse/malware-multi-scan-worker:latest
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND noninteractive
|
ENV DEBIAN_FRONTEND noninteractive
|
||||||
|
|
||||||
@ -6,3 +6,5 @@ RUN apt-get update && apt-get install -y clamav
|
|||||||
RUN freshclam --quiet
|
RUN freshclam --quiet
|
||||||
|
|
||||||
ENV MULTI_SCAN_BACKEND_BIN=/usr/bin/clamscan
|
ENV MULTI_SCAN_BACKEND_BIN=/usr/bin/clamscan
|
||||||
|
|
||||||
|
ENV BackendType=Clamav
|
@ -19,4 +19,3 @@ COPY --from=backend /opt/loadlibrary/engine /opt/engine
|
|||||||
COPY --from=backend /opt/loadlibrary/mpclient /opt/mpclient
|
COPY --from=backend /opt/loadlibrary/mpclient /opt/mpclient
|
||||||
|
|
||||||
ENV BackendType=Defender
|
ENV BackendType=Defender
|
||||||
ENV ScanTimeout=300
|
|
@ -2,6 +2,7 @@ namespace MalwareMultiScan.Shared.Data.Enums
|
|||||||
{
|
{
|
||||||
public enum BackendType
|
public enum BackendType
|
||||||
{
|
{
|
||||||
Defender
|
Defender,
|
||||||
|
Clamav
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -21,7 +21,9 @@ namespace MalwareMultiScan.Worker.Controllers
|
|||||||
var temporaryFile = Path.GetTempFileName();
|
var temporaryFile = Path.GetTempFileName();
|
||||||
|
|
||||||
await using (var temporaryFileSteam = System.IO.File.OpenWrite(temporaryFile))
|
await using (var temporaryFileSteam = System.IO.File.OpenWrite(temporaryFile))
|
||||||
|
{
|
||||||
await request.InputFile.CopyToAsync(temporaryFileSteam);
|
await request.InputFile.CopyToAsync(temporaryFileSteam);
|
||||||
|
}
|
||||||
|
|
||||||
BackgroundJob.Enqueue<ScanJob>(
|
BackgroundJob.Enqueue<ScanJob>(
|
||||||
x => x.ScanFile(temporaryFile, request.CallbackUrl));
|
x => x.ScanFile(temporaryFile, request.CallbackUrl));
|
||||||
@ -33,7 +35,7 @@ namespace MalwareMultiScan.Worker.Controllers
|
|||||||
[ProducesResponseType(StatusCodes.Status202Accepted)]
|
[ProducesResponseType(StatusCodes.Status202Accepted)]
|
||||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
[Route("/scan/url")]
|
[Route("/scan/url")]
|
||||||
public IActionResult ScanUrl(UrlRequest request)
|
public IActionResult ScanUrl([FromForm] UrlRequest request)
|
||||||
{
|
{
|
||||||
BackgroundJob.Enqueue<ScanJob>(
|
BackgroundJob.Enqueue<ScanJob>(
|
||||||
x => x.ScanUrl(request.InputUrl, request.CallbackUrl));
|
x => x.ScanUrl(request.InputUrl, request.CallbackUrl));
|
||||||
|
@ -6,8 +6,7 @@ COPY MalwareMultiScan.Worker /src/MalwareMultiScan.Worker
|
|||||||
COPY MalwareMultiScan.Shared /src/MalwareMultiScan.Shared
|
COPY MalwareMultiScan.Shared /src/MalwareMultiScan.Shared
|
||||||
COPY MalwareMultiScan.Backends /src/MalwareMultiScan.Backends
|
COPY MalwareMultiScan.Backends /src/MalwareMultiScan.Backends
|
||||||
|
|
||||||
RUN dotnet publish -c Release -r linux-x64 /p:PublishSingleFile=true -o ./publish \
|
RUN dotnet publish -c Release -r linux-x64 -o ./publish MalwareMultiScan.Worker/MalwareMultiScan.Worker.csproj
|
||||||
MalwareMultiScan.Worker/MalwareMultiScan.Worker.csproj
|
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
|
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
|
||||||
|
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Hangfire;
|
||||||
using MalwareMultiScan.Backends.Backends.Implementations;
|
using MalwareMultiScan.Backends.Backends.Implementations;
|
||||||
using MalwareMultiScan.Shared.Data.Enums;
|
using MalwareMultiScan.Shared.Data.Enums;
|
||||||
using MalwareMultiScan.Shared.Data.Responses;
|
using MalwareMultiScan.Shared.Data.Responses;
|
||||||
@ -14,23 +17,27 @@ namespace MalwareMultiScan.Worker.Jobs
|
|||||||
{
|
{
|
||||||
public class ScanJob
|
public class ScanJob
|
||||||
{
|
{
|
||||||
private readonly ILogger<ScanJob> _logger;
|
|
||||||
private readonly IScanBackend _backend;
|
private readonly IScanBackend _backend;
|
||||||
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
|
private readonly ILogger<ScanJob> _logger;
|
||||||
private readonly int _scanTimeout;
|
private readonly int _scanTimeout;
|
||||||
|
|
||||||
public ScanJob(IConfiguration configuration, ILogger<ScanJob> logger)
|
public ScanJob(IConfiguration configuration, ILogger<ScanJob> logger,
|
||||||
|
IHttpClientFactory httpClientFactory)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_httpClientFactory = httpClientFactory;
|
||||||
_scanTimeout = configuration.GetValue<int>("ScanTimeout");
|
_scanTimeout = configuration.GetValue<int>("ScanTimeout");
|
||||||
|
|
||||||
_backend = configuration.GetValue<BackendType>("BackendType") switch
|
_backend = configuration.GetValue<BackendType>("BackendType") switch
|
||||||
{
|
{
|
||||||
BackendType.Defender => new WindowsDefenderScanBackend(logger),
|
BackendType.Defender => new WindowsDefenderScanBackend(logger),
|
||||||
|
BackendType.Clamav => new ClamavScanBackend(logger),
|
||||||
_ => throw new NotImplementedException()
|
_ => throw new NotImplementedException()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PostResult(ResultResponse response, Uri callbackUrl, CancellationToken cancellationToken)
|
private async Task PostResult(ResultResponse response, Uri callbackUrl, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var serializedResponse = JsonSerializer.Serialize(
|
var serializedResponse = JsonSerializer.Serialize(
|
||||||
response, typeof(ResultResponse), new JsonSerializerOptions
|
response, typeof(ResultResponse), new JsonSerializerOptions
|
||||||
@ -38,7 +45,15 @@ namespace MalwareMultiScan.Worker.Jobs
|
|||||||
WriteIndented = true
|
WriteIndented = true
|
||||||
});
|
});
|
||||||
|
|
||||||
_logger.LogInformation(serializedResponse);
|
_logger.LogInformation(
|
||||||
|
$"Sending following payload to {callbackUrl}: {serializedResponse}");
|
||||||
|
|
||||||
|
using var httpClient = _httpClientFactory.CreateClient();
|
||||||
|
|
||||||
|
var callbackResponse = await httpClient.PostAsync(callbackUrl,
|
||||||
|
new StringContent(serializedResponse, Encoding.UTF8, "application/json"), cancellationToken);
|
||||||
|
|
||||||
|
_logger.LogInformation($"Callback URL {callbackUrl} returned a status {callbackResponse.StatusCode}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Scan(Func<CancellationToken, Task<string[]>> scanMethod, Uri callbackUrl)
|
private async Task Scan(Func<CancellationToken, Task<string[]>> scanMethod, Uri callbackUrl)
|
||||||
@ -70,11 +85,13 @@ namespace MalwareMultiScan.Worker.Jobs
|
|||||||
await PostResult(response, callbackUrl, cancellationToken);
|
await PostResult(response, callbackUrl, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AutomaticRetry(Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Delete)]
|
||||||
public async Task ScanUrl(Uri url, Uri callbackUrl)
|
public async Task ScanUrl(Uri url, Uri callbackUrl)
|
||||||
{
|
{
|
||||||
await Scan(async t => await _backend.ScanAsync(url, t), callbackUrl);
|
await Scan(async t => await _backend.ScanAsync(url, t), callbackUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AutomaticRetry(Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Delete)]
|
||||||
public async Task ScanFile(string file, Uri callbackUrl)
|
public async Task ScanFile(string file, Uri callbackUrl)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -13,6 +13,7 @@ namespace MalwareMultiScan.Worker
|
|||||||
{
|
{
|
||||||
services.AddLogging();
|
services.AddLogging();
|
||||||
services.AddControllers();
|
services.AddControllers();
|
||||||
|
services.AddHttpClient();
|
||||||
|
|
||||||
services.AddSingleton<ScanJob>();
|
services.AddSingleton<ScanJob>();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user