2using System.Collections.Generic;
3using System.ComponentModel;
6using System.Net.NetworkInformation;
7using System.Net.Sockets;
8using System.Security.Authentication;
9using System.Security.Cryptography.X509Certificates;
11using System.Threading.Tasks;
26 private readonly LinkedList<TcpListener> tcpListeners =
new LinkedList<TcpListener>();
27 private readonly Dictionary<Guid, ProxyClientConncetion> connections =
new Dictionary<Guid, ProxyClientConncetion>();
28 private readonly
IpCidr[] remoteIps;
30 private readonly
string host;
31 private readonly
int port;
32 private readonly
int listeningPort;
33 private readonly
bool tls;
34 private readonly
bool trustServer;
35 private readonly
bool authorizedAccess;
36 private long nrBytesDownlink = 0;
37 private long nrBytesUplink = 0;
38 private bool closed =
false;
40 private ProxyPort(
IpHostPortProxy Node,
string Host,
int Port,
bool Tls,
bool TrustServer,
int ListeningPort,
bool AuthorizedAccess,
48 this.trustServer = TrustServer;
49 this.listeningPort = ListeningPort;
50 this.authorizedAccess = AuthorizedAccess;
51 this.remoteIps = RemoteIps;
66 public static async Task<ProxyPort>
Create(
IpHostPortProxy Node,
string Host,
int Port,
bool Tls,
bool TrustServer,
int ListeningPort,
67 bool AuthorizedAccess,
IpCidr[] RemoteIps)
69 ProxyPort Result =
new ProxyPort(Node, Host, Port, Tls, TrustServer, ListeningPort, AuthorizedAccess, RemoteIps);
74 private async Task Open()
76 foreach (NetworkInterface Interface
in NetworkInterface.GetAllNetworkInterfaces())
78 if (Interface.OperationalStatus != OperationalStatus.Up)
81 IPInterfaceProperties Properties = Interface.GetIPProperties();
83 foreach (UnicastIPAddressInformation UnicastAddress
in Properties.UnicastAddresses)
85 if ((UnicastAddress.Address.AddressFamily == AddressFamily.InterNetwork && Socket.OSSupportsIPv4) ||
86 (UnicastAddress.Address.AddressFamily == AddressFamily.InterNetworkV6 && Socket.OSSupportsIPv6))
88 IPEndPoint DesiredEndpoint =
new IPEndPoint(UnicastAddress.Address,
this.listeningPort);
92 TcpListener Listener =
new TcpListener(UnicastAddress.Address,
this.listeningPort);
95 Task T = this.ListenForIncomingConnections(Listener);
97 lock (this.tcpListeners)
99 this.tcpListeners.AddLast(Listener);
102 await this.node.RemoveErrorAsync(DesiredEndpoint.ToString());
104 catch (SocketException)
106 await this.node.LogErrorAsync(DesiredEndpoint.ToString(),
"Unable to open Proxy port for listening.");
110 await this.node.LogErrorAsync(DesiredEndpoint.ToString(), ex.Message);
117 private async Task ListenForIncomingConnections(TcpListener Listener)
129 Client = await Listener.AcceptTcpClientAsync();
133 catch (InvalidOperationException)
135 lock (this.tcpListeners)
137 LinkedListNode<TcpListener> Node = this.tcpListeners?.First;
139 while (!(Node is
null))
141 if (Node.Value == Listener)
143 this.tcpListeners.Remove(Node);
154 if (!(Client is
null))
156 if (!(this.remoteIps is
null))
160 if (Client.Client.RemoteEndPoint is IPEndPoint IPEndPoint)
162 foreach (IpCidr Range
in this.remoteIps)
164 if (Range.Matches(IPEndPoint.Address))
174 await this.
Error(
"Remote IP not approved. Conncetion reused.");
180 await this.
Information(
"Connection accepted from " + Client.Client.RemoteEndPoint.ToString() +
".");
193 if (!await Outgoing.
ConnectAsync(
this.host,
this.port,
true))
195 await this.node.LogErrorAsync(
"UnableToConnect",
"Unable to connect to remote endpoint.");
201 await Outgoing.
UpgradeToTlsAsClient(Certificate, SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12,
this.trustServer);
205 await this.node.LogErrorAsync(
"UnableToConnect",
"Unable to connect to remote endpoint: " + ex.Message);
212 await this.node.RemoveErrorAsync(
"UnableToConnect");
214 if ((this.tls || this.authorizedAccess) && !(Certificate is
null))
216 await this.node.RemoveWarningAsync(
"NoCertificate");
218 Task _ = this.SwitchToTls(Incoming, Outgoing, Certificate);
223 await this.node.LogWarningAsync(
"NoCertificate",
"No registered certificate found. Listening port is unencrypted.");
225 ProxyClientConncetion Connection =
new ProxyClientConncetion(
this, Incoming, Outgoing, this.Sniffers);
229 lock (this.connections)
231 this.connections[Connection.Id] = Connection;
236 catch (SocketException)
240 catch (ObjectDisposedException)
244 catch (NullReferenceException)
250 if (this.closed || this.tcpListeners is
null)
255 foreach (TcpListener P
in this.tcpListeners)
273 if (this.closed || this.tcpListeners is
null)
282 string RemoteIpEndpoint;
283 EndPoint EP = Incoming.
Client.Client.RemoteEndPoint;
285 if (EP is IPEndPoint IpEP)
286 RemoteIpEndpoint = IpEP.Address.ToString();
288 RemoteIpEndpoint = EP.ToString();
298 if (this.authorizedAccess)
302 await this.
Error(
"No remote certificate found. mTLS is required.");
310 await this.
Error(
"Remote certificate not valid.");
316 string[] Identities = IpHostPortProxy.GetCertificateIdentities(Incoming.
RemoteCertificate);
319 foreach (
string Identity
in IpHostPortProxy.GetCertificateIdentities(Certificate))
328 if (i > 0 &&
int.TryParse(
RemoteEndpoint.Substring(i + 1), out
int _))
333 string Msg =
"Invalid login: No user found matching certificate subject.";
335 await this.
Error(Msg);
348 ", Hash Strength: " + Incoming.
HashStrength.ToString() +
355 StringBuilder sb =
new StringBuilder();
357 sb.Append(
"Remote Certificate received. Valid: ");
359 sb.Append(
", Subject: ");
361 sb.Append(
", Issuer: ");
363 sb.Append(
", S/N: ");
365 sb.Append(
", Hash: ");
373 ProxyClientConncetion Connection =
new ProxyClientConncetion(
this, Incoming, Outgoing, this.Sniffers);
377 lock (this.connections)
379 this.connections[Connection.Id] = Connection;
382 catch (AuthenticationException ex)
384 await this.LoginFailure(ex, Incoming, Outgoing, RemoteIpEndpoint);
386 catch (Win32Exception ex)
388 if (ex is SocketException)
394 await this.LoginFailure(ex, Incoming, Outgoing, RemoteIpEndpoint);
426 TcpListener[] Listeners;
427 ProxyClientConncetion[] Connections;
431 lock (this.tcpListeners)
433 Listeners =
new TcpListener[this.tcpListeners.Count];
434 this.tcpListeners.CopyTo(Listeners, 0);
435 this.tcpListeners.Clear();
438 lock (this.connections)
440 Connections =
new ProxyClientConncetion[this.connections.Count];
441 this.connections.Values.CopyTo(Connections, 0);
442 this.connections.Clear();
445 foreach (TcpListener Listener
in Listeners)
457 foreach (ProxyClientConncetion Connection
in Connections)
461 Connection.Dispose();
484 lock (this.connections)
486 this.connections.Remove(Connection.
Id);
498 this.nrBytesUplink += NrBytes;
507 this.nrBytesDownlink += NrBytes;
527 lock (this.connections)
529 return this.connections.Count;
Static class managing the application event log. Applications and services log events on this static ...
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
Implements a binary TCP Client, by encapsulating a TcpClient. It also makes the use of TcpClient safe...
void Bind()
Binds to a TcpClient that was already connected when provided to the constructor.
Task UpgradeToTlsAsClient(SslProtocols Protocols)
Upgrades a client connection to TLS.
bool RemoteCertificateValid
If the remote certificate is valid.
TcpClient Client
Underlying TcpClient object.
int HashStrength
Hash algorithm strength. (Nr bits of brute force complexity required to break algorithm).
void DisposeWhenDone()
Disposes the client when done sending all data.
void Continue()
Continues reading from the socket, if paused in an event handler.
X509Certificate RemoteCertificate
Certificate used by the remote endpoint.
int KeyExchangeStrength
Key Exchange strength. (Nr bits of brute force complexity required to break algorithm).
int CipherStrength
Cipher strength. (Nr bits of brute force complexity required to break algorithm).
Task< bool > ConnectAsync(string Host, int Port)
Connects to a host using TCP.
virtual void Dispose()
Disposes of the object. The underlying TcpClient is either disposed directly, or when asynchronous op...
Task UpgradeToTlsAsServer(X509Certificate ServerCertificate)
Upgrades a server connection to TLS.
Simple base class for classes implementing communication protocols.
Task Error(string Error)
Called to inform the viewer of an error state.
Task Exception(Exception Exception)
Called to inform the viewer of an exception state.
ISniffer[] Sniffers
Registered sniffers.
Task Information(string Comment)
Called to inform the viewer of something.
bool HasSniffers
If there are sniffers registered on the object.
Static class that dynamically manages types and interfaces available in the runtime environment.
static bool TryGetModuleParameter(string Name, out object Value)
Tries to get a module parameter value.
Class that monitors login events, and help applications determine malicious intent....
static async void Success(string Message, string UserName, string RemoteEndpoint, string Protocol, params KeyValuePair< string, object >[] Tags)
Handles a successful login attempt.
static async void Fail(string Message, string UserName, string RemoteEndpoint, string Protocol, params KeyValuePair< string, object >[] Tags)
Handles a failed login attempt.
static async Task ReportTlsHackAttempt(string RemoteEndpoint, string Message, string Protocol)
Reports a TLS hacking attempt from an endpoint. Can be used to deny TLS negotiation to proceed,...
static bool CanStartTls(string RemoteEndpoint)
Checks if TLS negotiation can start, for a given endpoint. If the endpoint has tries a TLS hack attem...
Login state information relating to a remote endpoint
Corresponds to a user in the system.
Maintains the collection of all users in the system.
static async Task< User > GetUser(string UserName, bool CreateIfNew)
Gets the User object corresponding to a User Name.
IP Address Rangee, expressed using CIDR format.
Node representing a proxy port node.
Maintains one proxy connection
void Dispose()
IDisposable.Dispose
Node acting as a TCP/IP proxy opening a port for incoming communication and proxying it to another po...
long NrBytesUplink
Number of bytes send uplink
void IncDownlink(int NrBytes)
Increment downlink counter.
void Remove(ProxyClientConncetion Connection)
Removes a proxy client connection.
int NrConnctions
Number of connections.
long NrBytesDownlink
Number of bytes send downlink
void Dispose()
IDisposable.Dispose
static async Task< ProxyPort > Create(IpHostPortProxy Node, string Host, int Port, bool Tls, bool TrustServer, int ListeningPort, bool AuthorizedAccess, IpCidr[] RemoteIps)
Creates a port proxy object.
void IncUplink(int NrBytes)
Increment uplink counter.
Interface for sniffers. Sniffers can be added to ICommunicationLayer classes to eavesdrop on communic...
ClientCertificates
Client Certificate Options