Exemple #1
0
 private void AdministrationOnDisconnected(object sender, EventArgs e)
 {
     lock (_administrationListLock)
         Administrations.Remove(((Administration)sender).Id);
     AdministrationsChanged?.Invoke(this, EventArgs.Empty);
 }
Exemple #2
0
        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();
        }