using Insight.Agent.Interfaces; using Insight.Agent.Messages; using Insight.Infrastructure; using Insight.Infrastructure.Entities; using MongoDB.Bson; using MongoDB.Driver; namespace Insight.Server.Network.Handlers.Agent { public class InterfaceHandler : IAgentMessageHandler { private readonly IMongoDatabase _database; public InterfaceHandler(IMongoDatabase database) { _database = database; } public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage { if (message is InterfaceList interfaces) { await OnInterfacesAsync(sender, interfaces, cancellationToken); } } private async ValueTask OnInterfacesAsync(AgentSession session, List interfaces, CancellationToken cancellationToken) { var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); if (agentEntity is null) return; var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); if (hostEntity is null) return; var batch = ObjectId.GenerateNewId().ToString(); var date = DateTime.Now; // interfaces if (interfaces is not null && interfaces.Any()) { var interfaceBulk = new List>(); foreach (var @interface in interfaces) { var interfaceFilter = Builders.Filter.And(new List> { Builders.Filter.Eq(x => x.Host, hostEntity.Id), Builders.Filter.Eq(x => x.Index, @interface.Index) }); var interfaceUpdate = Builders.Update .SetOnInsert(p => p.Insert, date) .SetOnInsert(p => p.Host, hostEntity.Id) .SetOnInsert(p => p.Index, @interface.Index) .Set(p => p.Update, date) .Set(p => p.Batch, batch) .Set(p => p.Mac, @interface?.Mac) .Set(p => p.Name, @interface?.Name) .Set(p => p.Description, @interface?.Description) .Set(p => p.Physical, @interface?.Physical) .Set(p => p.Status, @interface?.Status?.ToString()) .Set(p => p.Suffix, @interface?.Suffix) .Set(p => p.Speed, @interface?.Speed) .Set(p => p.Ipv4Mtu, @interface?.Ipv4Mtu) .Set(p => p.Ipv4Dhcp, @interface?.Ipv4Dhcp) .Set(p => p.Ipv4Forwarding, @interface?.Ipv4Forwarding) .Set(p => p.Ipv6Mtu, @interface?.Ipv6Mtu) .Set(p => p.Sent, @interface?.Sent) .Set(p => p.Received, @interface?.Received) .Set(p => p.IncomingPacketsDiscarded, @interface?.IncomingPacketsDiscarded) .Set(p => p.IncomingPacketsWithErrors, @interface?.IncomingPacketsWithErrors) .Set(p => p.IncomingUnknownProtocolPackets, @interface?.IncomingUnknownProtocolPackets) .Set(p => p.OutgoingPacketsDiscarded, @interface?.OutgoingPacketsDiscarded) .Set(p => p.OutgoingPacketsWithErrors, @interface?.OutgoingPacketsWithErrors); interfaceBulk.Add(new UpdateOneModel(interfaceFilter, interfaceUpdate) { IsUpsert = true }); } interfaceBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> { Builders.Filter.Eq(x => x.Host, hostEntity.Id), Builders.Filter.Ne(x => x.Batch, batch) }))); var interfaceResult = await _database.HostInterface().BulkWriteAsync(interfaceBulk, cancellationToken: cancellationToken); } // addresses if (interfaces is not null && interfaces.Any()) { var addressBulk = new List>(); foreach (var @interface in interfaces) { var interfaceId = await _database.HostInterface() .Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index) .Project(p => p.Id) .FirstOrDefaultAsync(); if (@interface.Addresses is not null && @interface.Addresses.Any()) { foreach (var address in @interface.Addresses) { var addressFilter = Builders.Filter.And(new List> { Builders.Filter.Eq(x => x.Host, hostEntity.Id), Builders.Filter.Eq(x => x.Interface, interfaceId), Builders.Filter.Eq(x => x.Address, address?.IpAddress?.Address), Builders.Filter.Eq(x => x.Mask, address?.Ipv4Mask?.Address) }); var addressUpdate = Builders.Update .SetOnInsert(p => p.Insert, date) .SetOnInsert(p => p.Host, hostEntity.Id) .SetOnInsert(p => p.Interface, interfaceId) .SetOnInsert(p => p.Address, address?.IpAddress?.Address) .SetOnInsert(p => p.Mask, address?.Ipv4Mask?.Address) .Set(p => p.Update, date) .Set(p => p.Batch, batch); addressBulk.Add(new UpdateOneModel(addressFilter, addressUpdate) { IsUpsert = true }); } } } addressBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> { Builders.Filter.Eq(x => x.Host, hostEntity.Id), Builders.Filter.Ne(x => x.Batch, batch) }))); var addressResult = await _database.HostInterfaceAddress().BulkWriteAsync(addressBulk, cancellationToken: cancellationToken); } // gateways if (interfaces is not null && interfaces.Any()) { var gatewayBulk = new List>(); foreach (var @interface in interfaces) { var interfaceId = await _database.HostInterface() .Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index) .Project(p => p.Id) .FirstOrDefaultAsync(); if (@interface.Gateways is not null && @interface.Gateways.Any()) { foreach (var gateway in @interface.Gateways) { var gatewayFilter = Builders.Filter.And(new List> { Builders.Filter.Eq(x => x.Host, hostEntity.Id), Builders.Filter.Eq(x => x.Interface, interfaceId), Builders.Filter.Eq(x => x.Address, gateway?.Address) }); var gatewayUpdate = Builders.Update .SetOnInsert(p => p.Insert, date) .SetOnInsert(p => p.Host, hostEntity.Id) .SetOnInsert(p => p.Interface, interfaceId) .SetOnInsert(p => p.Address, gateway?.Address) .Set(p => p.Update, date) .Set(p => p.Batch, batch); gatewayBulk.Add(new UpdateOneModel(gatewayFilter, gatewayUpdate) { IsUpsert = true }); } } } gatewayBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> { Builders.Filter.Eq(x => x.Host, hostEntity.Id), Builders.Filter.Ne(x => x.Batch, batch) }))); var gatewayResult = await _database.HostInterfaceGateway().BulkWriteAsync(gatewayBulk, cancellationToken: cancellationToken); } // nameservers if (interfaces is not null && interfaces.Any()) { var nameserverBulk = new List>(); foreach (var @interface in interfaces) { var interfaceId = await _database.HostInterface() .Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index) .Project(p => p.Id) .FirstOrDefaultAsync(); if (@interface.Dns is not null && @interface.Dns.Any()) { foreach (var nameserver in @interface.Dns) { var nameserverFilter = Builders.Filter.And(new List> { Builders.Filter.Eq(x => x.Host, hostEntity.Id), Builders.Filter.Eq(x => x.Interface, interfaceId), Builders.Filter.Eq(x => x.Address, nameserver?.Address) }); var nameserverUpdate = Builders.Update .SetOnInsert(p => p.Insert, date) .SetOnInsert(p => p.Host, hostEntity.Id) .SetOnInsert(p => p.Interface, interfaceId) .SetOnInsert(p => p.Address, nameserver?.Address) .Set(p => p.Update, date) .Set(p => p.Batch, batch); nameserverBulk.Add(new UpdateOneModel(nameserverFilter, nameserverUpdate) { IsUpsert = true }); } } } nameserverBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> { Builders.Filter.Eq(x => x.Host, hostEntity.Id), Builders.Filter.Ne(x => x.Batch, batch) }))); var nameserverResult = await _database.HostInterfaceNameserver().BulkWriteAsync(nameserverBulk, cancellationToken: cancellationToken); } // routes if (interfaces is not null && interfaces.Any()) { var routeBulk = new List>(); foreach (var @interface in interfaces) { var interfaceId = await _database.HostInterface() .Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index) .Project(p => p.Id) .FirstOrDefaultAsync(); if (@interface.Routes is not null && @interface.Routes.Any()) { foreach (var route in @interface.Routes) { var routeFilter = Builders.Filter.And(new List> { Builders.Filter.Eq(x => x.Host, hostEntity.Id), Builders.Filter.Eq(x => x.Interface, interfaceId), Builders.Filter.Eq(x => x.Destination, route?.Destination?.Address), Builders.Filter.Eq(x => x.Gateway, route?.Gateway?.Address), Builders.Filter.Eq(x => x.Mask, route?.Mask), }); var routeUpdate = Builders.Update .SetOnInsert(p => p.Insert, date) .SetOnInsert(p => p.Host, hostEntity.Id) .SetOnInsert(p => p.Interface, interfaceId) .SetOnInsert(p => p.Destination, route?.Destination?.Address) .SetOnInsert(p => p.Gateway, route?.Gateway?.Address) .SetOnInsert(p => p.Mask, route?.Mask) .Set(p => p.Update, date) .Set(p => p.Batch, batch) .Set(p => p.Metric, route?.Metric); routeBulk.Add(new UpdateOneModel(routeFilter, routeUpdate) { IsUpsert = true }); } } } routeBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> { Builders.Filter.Eq(x => x.Host, hostEntity.Id), Builders.Filter.Ne(x => x.Batch, batch) }))); var routeResult = await _database.HostInterfaceRoute().BulkWriteAsync(routeBulk, cancellationToken: cancellationToken); } } } }