170 lines
No EOL
6 KiB
C#
170 lines
No EOL
6 KiB
C#
using Insight.Agent.Network;
|
|
using Insight.Domain.Network;
|
|
using Insight.Domain.Network.Agent.Messages;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
using System.Diagnostics.Eventing.Reader;
|
|
using System.Runtime.Versioning;
|
|
using System.Threading.Channels;
|
|
using Vaitr.Network;
|
|
using static Insight.Domain.Network.Agent.Messages.Event;
|
|
using EventLevel = System.Diagnostics.Tracing.EventLevel;
|
|
|
|
namespace Insight.Agent.Services;
|
|
|
|
[SupportedOSPlatform("windows")]
|
|
internal class EventService : BackgroundService
|
|
{
|
|
private readonly Channel<Event> _queue;
|
|
private readonly ISessionPool<AgentSession, IMessage> _pool;
|
|
private readonly ILogger<EventService> _logger;
|
|
|
|
public EventService(ISessionPool<AgentSession, IMessage> pool, ILogger<EventService> logger)
|
|
{
|
|
_pool = pool;
|
|
_logger = logger;
|
|
|
|
_queue = Channel.CreateBounded<Event>(new BoundedChannelOptions(1000)
|
|
{
|
|
SingleReader = true,
|
|
SingleWriter = true,
|
|
AllowSynchronousContinuations = false,
|
|
FullMode = BoundedChannelFullMode.DropOldest
|
|
});
|
|
}
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
|
|
{
|
|
_logger.LogTrace("ExecuteAsync");
|
|
|
|
while (cancellationToken.IsCancellationRequested is false)
|
|
{
|
|
try
|
|
{
|
|
var tasks = new List<Task>
|
|
{
|
|
HandleQueueAsync(cancellationToken),
|
|
WatchAsync("Application", "*", cancellationToken),
|
|
WatchAsync("Security", "*", cancellationToken),
|
|
WatchAsync("System", "*", cancellationToken),
|
|
WatchAsync("Microsoft-Windows-PrintService/Admin", "*", cancellationToken),
|
|
WatchAsync("Microsoft-Windows-TaskScheduler/Operational", "*", cancellationToken),
|
|
WatchAsync("Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational", "*", cancellationToken),
|
|
WatchAsync("Microsoft-Windows-TerminalServices-LocalSessionManager/Operational", "*", cancellationToken),
|
|
WatchAsync("Microsoft-Windows-TerminalServices-RDPClient/Operational", "*", cancellationToken),
|
|
WatchAsync("Microsoft-Windows-SmbClient/Connectivity", "*", cancellationToken),
|
|
WatchAsync("Microsoft-Windows-SmbClient/Security", "*", cancellationToken),
|
|
WatchAsync("Microsoft-Windows-SMBServer/Security", "*", cancellationToken),
|
|
WatchAsync("Microsoft-Windows-StorageSpaces-Driver/Operational", "*", cancellationToken),
|
|
WatchAsync("Microsoft-Windows-Diagnostics-Performance/Operational", "*", cancellationToken)
|
|
};
|
|
|
|
await Task.WhenAll(tasks);
|
|
}
|
|
catch (OperationCanceledException) { }
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError("{ex}", ex);
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task WatchAsync(string path, string query, CancellationToken cancellationToken)
|
|
{
|
|
var config = new EventLogConfiguration(path);
|
|
if (config is null) return;
|
|
|
|
if (config.IsEnabled is false)
|
|
{
|
|
config.IsEnabled = true;
|
|
config.SaveChanges();
|
|
}
|
|
|
|
var watcher = new EventLogWatcher(new EventLogQuery(path, PathType.LogName, query)
|
|
{
|
|
TolerateQueryErrors = true,
|
|
Session = EventLogSession.GlobalSession
|
|
});
|
|
|
|
try
|
|
{
|
|
watcher.EventRecordWritten += new EventHandler<EventRecordWrittenEventArgs>(OnEvent);
|
|
watcher.Enabled = true;
|
|
|
|
using var semaphore = new SemaphoreSlim(0, 1);
|
|
await semaphore.WaitAsync(cancellationToken);
|
|
}
|
|
catch (Exception) { }
|
|
finally
|
|
{
|
|
watcher.EventRecordWritten -= new EventHandler<EventRecordWrittenEventArgs>(OnEvent);
|
|
watcher.Enabled = false;
|
|
|
|
watcher?.Dispose();
|
|
}
|
|
}
|
|
|
|
private async Task HandleQueueAsync(CancellationToken cancellationToken)
|
|
{
|
|
while (await _queue.Reader.WaitToReadAsync(cancellationToken))
|
|
{
|
|
var session = _pool.FirstOrDefault();
|
|
|
|
if (session.Value is null)
|
|
{
|
|
await Task.Delay(10000, cancellationToken);
|
|
continue;
|
|
}
|
|
|
|
if (_queue.Reader.TryRead(out var item) is false)
|
|
{
|
|
await Task.Delay(1000, cancellationToken);
|
|
continue;
|
|
}
|
|
|
|
try
|
|
{
|
|
await session.Value.SendAsync(item, cancellationToken);
|
|
}
|
|
catch (OperationCanceledException) { }
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError("{ex}", ex);
|
|
await Task.Delay(10000, cancellationToken);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnEvent(object? sender, EventRecordWrittenEventArgs e)
|
|
{
|
|
if (e is null || e.EventRecord is null) return;
|
|
|
|
try
|
|
{
|
|
var @event = new Event
|
|
{
|
|
Timestamp = e?.EventRecord?.TimeCreated,
|
|
EventId = e?.EventRecord?.Id,
|
|
Source = e?.EventRecord?.ProviderName,
|
|
Category = e?.EventRecord?.LogName,
|
|
Task = e?.EventRecord?.TaskDisplayName,
|
|
Message = e?.EventRecord?.FormatDescription(),
|
|
};
|
|
|
|
if (e?.EventRecord?.Level is not null)
|
|
{
|
|
@event.Status = (EventLevel)Convert.ToInt32(e?.EventRecord?.Level) switch
|
|
{
|
|
EventLevel.Informational => StatusType.Information,
|
|
EventLevel.Warning => StatusType.Warning,
|
|
EventLevel.Error => StatusType.Error,
|
|
EventLevel.Critical => StatusType.Critical,
|
|
_ => StatusType.Information,
|
|
};
|
|
}
|
|
|
|
_queue.Writer.WriteAsync(@event, default);
|
|
}
|
|
catch (Exception) { } // app crash
|
|
}
|
|
} |