From 2fb3546b7671c670ba62f2981e2e55dc5e282cd0 Mon Sep 17 00:00:00 2001 From: Peter Kurfer Date: Tue, 23 Feb 2021 17:59:37 +0100 Subject: [PATCH] Add PCAP API client --- .editorconfig | 12 ++- .../Audit/Client/AuditApiClient.cs | 2 +- src/INetMock.Client/Audit/IAuditApiClient.cs | 2 +- .../PCAP/Client/PcapApiClient.cs | 96 +++++++++++++++++++ src/INetMock.Client/PCAP/IPcapApiClient.cs | 29 ++++++ 5 files changed, 137 insertions(+), 4 deletions(-) create mode 100644 src/INetMock.Client/PCAP/Client/PcapApiClient.cs create mode 100644 src/INetMock.Client/PCAP/IPcapApiClient.cs diff --git a/.editorconfig b/.editorconfig index 13fb40e..01e1042 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,10 +1,18 @@ root = true [*] +indent_style = space end_of_line = lf -insert_final_newline = true charset = utf-8 +insert_final_newline = true +max_line_length = 120 + +[*.xml] +indent_size = 4 [*.cs] -indent_style = space indent_size = 4 + +[*.json] +indent_size = 2 +insert_final_newline = false diff --git a/src/INetMock.Client/Audit/Client/AuditApiClient.cs b/src/INetMock.Client/Audit/Client/AuditApiClient.cs index 7435912..b737ebe 100644 --- a/src/INetMock.Client/Audit/Client/AuditApiClient.cs +++ b/src/INetMock.Client/Audit/Client/AuditApiClient.cs @@ -27,7 +27,7 @@ namespace INetMock.Client.Audit.Client _auditClient = new AuditService.AuditServiceClient(channel); } - public async Task> ListSinksAsync(CancellationToken token = default) + public async Task> ListSinksAsync(CancellationToken token = default) { var sinks = await _auditClient.ListSinksAsync(new ListSinksRequest(), Metadata.Empty, null, token); return sinks.Sinks; diff --git a/src/INetMock.Client/Audit/IAuditApiClient.cs b/src/INetMock.Client/Audit/IAuditApiClient.cs index 6d29f8e..45baca9 100644 --- a/src/INetMock.Client/Audit/IAuditApiClient.cs +++ b/src/INetMock.Client/Audit/IAuditApiClient.cs @@ -7,7 +7,7 @@ namespace INetMock.Client.Audit public interface IAuditApiClient { IProtoEventReader EventStreamAsync(string watcherName, CancellationToken token = default); - Task> ListSinksAsync(CancellationToken token = default); + Task> ListSinksAsync(CancellationToken token = default); Task RegisterFileSinkAsync(string targetPath, CancellationToken token = default); Task RemoveFileSinkAsync(string targetPath, CancellationToken token = default); } diff --git a/src/INetMock.Client/PCAP/Client/PcapApiClient.cs b/src/INetMock.Client/PCAP/Client/PcapApiClient.cs new file mode 100644 index 0000000..c2ce6ef --- /dev/null +++ b/src/INetMock.Client/PCAP/Client/PcapApiClient.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Google.Protobuf.WellKnownTypes; +using Grpc.Core; +using Grpc.Net.Client; +using INetMock.Client.Rpc; + +namespace INetMock.Client.PCAP.Client +{ + public class PcapApiClient : IPcapApiClient + { + private readonly PCAPService.PCAPServiceClient _pcapServiceClient; + + public PcapApiClient(string address, GrpcChannelOptions? options = null) + : this(new Uri(address), options) + { + } + + public PcapApiClient(Uri address, GrpcChannelOptions? options = null) + : this(GrpcChannel.ForAddress(address, options ?? new GrpcChannelOptions())) + { + } + + public PcapApiClient(ChannelBase channel) + { + _pcapServiceClient = new PCAPService.PCAPServiceClient(channel); + } + + public async Task> ListAvailableDevicesAsync(CancellationToken token = default) + { + var devices = await _pcapServiceClient.ListAvailableDevicesAsync(new(), Metadata.Empty, null, token); + return devices.AvailableDevices + .Select(d => new RecordingDevice( + d.Name, + d.Addresses + .Select(addr => new IPAddress(addr.Span)) + .ToList() + ) + ) + .ToList(); + } + + public async Task> ListActiveRecordingsAsync(CancellationToken token = default) + { + var recordings = await _pcapServiceClient.ListActiveRecordingsAsync(new(), Metadata.Empty, null, token); + return recordings.Subscriptions.Select(SplitKeyIntoSubscription).ToList(); + } + + public async Task StartPcapFileRecordingAsync(RecordingRequest request, + CancellationToken token = default) + { + var clientRequest = new StartPCAPFileRecordingRequest + { + Device = request.Device, + Promiscuous = request.Promiscuous, + TargetPath = request.TargetPath, + ReadTimeout = Duration.FromTimeSpan(request.ReadTimeout) + }; + + var result = await _pcapServiceClient.StartPCAPFileRecordingAsync( + clientRequest, + Metadata.Empty, + null, + token); + + return result.ResolvedPath; + } + + public async Task StopPcapFileRecord(string consumerKey, CancellationToken token = default) + { + var clientRequest = new StopPCAPFileRecordRequest {ConsumerKey = consumerKey}; + var result = await _pcapServiceClient.StopPCAPFileRecordAsync( + clientRequest, + Metadata.Empty, + null, + token + ); + return result.Removed; + } + + private static Subscription SplitKeyIntoSubscription(string key) + { + var splitIndex = key.IndexOf(':'); + if (splitIndex < 0) + { + throw new ArgumentOutOfRangeException(); + } + + return new Subscription(key.Substring(0, splitIndex), key.Substring(splitIndex), key); + } + } +} diff --git a/src/INetMock.Client/PCAP/IPcapApiClient.cs b/src/INetMock.Client/PCAP/IPcapApiClient.cs new file mode 100644 index 0000000..43d24b5 --- /dev/null +++ b/src/INetMock.Client/PCAP/IPcapApiClient.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading; +using System.Threading.Tasks; + +namespace INetMock.Client.PCAP +{ + public record RecordingDevice(string Name, IReadOnlyList Addresses); + + public record Subscription(string ConsumerName, string Device, string ConsumerKey); + public record RecordingRequest(string Device, string TargetPath, bool Promiscuous = false) + { + public RecordingRequest(string device, string targetPath, bool promiscuous, TimeSpan readTimeout) : this(device, + targetPath, promiscuous) + { + ReadTimeout = readTimeout; + } + + public TimeSpan ReadTimeout { get; } = TimeSpan.FromSeconds(30); + } + + public interface IPcapApiClient + { + Task> ListAvailableDevicesAsync(CancellationToken token = default); + Task> ListActiveRecordingsAsync(CancellationToken token = default); + Task StartPcapFileRecordingAsync(RecordingRequest request, CancellationToken token = default); + } +}