// Starts the Network Client Manager. First it connects to one of the seed nodes in order to fetch the Presence List.
        // Afterwards, it starts the reconnect and keepalive threads
        public static void start()
        {
            if (running)
            {
                return;
            }
            running        = true;
            networkClients = new List <NetworkClient>();

            PeerStorage.readPeersFile();

            // Now add the seed nodes to the list
            foreach (string[] addr in CoreNetworkUtils.getSeedNodes(Config.isTestNet))
            {
                byte[] wallet_addr = null;
                if (addr[1] != null)
                {
                    wallet_addr = Base58Check.Base58CheckEncoding.DecodePlain(addr[1]);
                }
                PeerStorage.addPeerToPeerList(addr[0], wallet_addr, false);
            }

            // Connect to a random node first
            bool firstSeedConnected = false;

            while (firstSeedConnected == false)
            {
                Peer p = PeerStorage.getRandomMasterNodeAddress();
                if (p != null)
                {
                    firstSeedConnected = connectTo(p.hostname, p.walletAddress);
                }
                if (firstSeedConnected == false)
                {
                    Thread.Sleep(1000);
                }
            }

            // Start the reconnect thread
            TLC                  = new ThreadLiveCheck();
            reconnectThread      = new Thread(reconnectClients);
            reconnectThread.Name = "Network_Client_Manager_Reconnect";
            autoReconnect        = true;
            reconnectThread.Start();
        }
        // Starts the Network Client Manager. First it connects to one of the seed nodes in order to fetch the Presence List.
        // Afterwards, it starts the reconnect and keepalive threads
        public static void start()
        {
            if (running)
            {
                return;
            }
            running        = true;
            networkClients = new List <NetworkClient>();

            PeerStorage.readPeersFile();

            // Now add the seed nodes to the list
            foreach (string addr in CoreNetworkUtils.getSeedNodes(Config.isTestNet))
            {
                PeerStorage.addPeerToPeerList(addr, null, false);
            }

            // Connect to a random node first
            bool firstSeedConnected = false;

            while (firstSeedConnected == false)
            {
                string address = PeerStorage.getRandomMasterNodeAddress();
                if (address != "")
                {
                    firstSeedConnected = connectTo(address);
                }
                if (firstSeedConnected == false)
                {
                    Thread.Sleep(1000);
                }
            }

            // Start the reconnect thread
            TLC                  = new ThreadLiveCheck();
            reconnectThread      = new Thread(reconnectClients);
            reconnectThread.Name = "Network_Client_Manager_Reconnect";
            autoReconnect        = true;
            reconnectThread.Start();
        }
Example #3
0
        // Called when receiving a keepalive network message. The PresenceList will update the appropriate entry based on the timestamp.
        // Returns TRUE if it updated an entry in the PL
        // Sets the out address parameter to be the KA wallet's address or null if an error occured
        public static bool receiveKeepAlive(byte[] bytes, out byte[] address)
        {
            address = null;

            // Get the current timestamp
            long currentTime = Core.getCurrentTimestamp();

            try
            {
                using (MemoryStream m = new MemoryStream(bytes))
                {
                    using (BinaryReader reader = new BinaryReader(m))
                    {
                        int    keepAliveVersion = reader.ReadInt32();
                        int    walletLen        = reader.ReadInt32();
                        byte[] wallet           = reader.ReadBytes(walletLen);

                        // Assign the out address parameter
                        address = wallet;

                        string deviceid  = reader.ReadString();
                        long   timestamp = reader.ReadInt64();
                        string hostname  = reader.ReadString();
                        char   node_type = '0';
                        if (keepAliveVersion > 0)
                        {
                            node_type = reader.ReadChar();
                        }
                        int    sigLen    = reader.ReadInt32();
                        byte[] signature = reader.ReadBytes(sigLen);
                        //Logging.info(String.Format("[PL] KEEPALIVE request from {0}", hostname));

                        if (node_type == 'C' || node_type == 'R')
                        {
                            // all good, continue
                        }
                        else if (node_type == 'M' || node_type == 'H')
                        {
                            // check balance
                            if (Node.walletState.getWalletBalance(wallet) < CoreConfig.minimumMasterNodeFunds)
                            {
                                return(false);
                            }
                        }
                        else if (node_type != '0')
                        {
                            // reject everything else
                            return(false);
                        }

                        lock (presences)
                        {
                            Presence listEntry = presences.Find(x => x.wallet.SequenceEqual(wallet));
                            if (listEntry == null && wallet.SequenceEqual(Node.walletStorage.getPrimaryAddress()))
                            {
                                Logging.error(string.Format("My entry was removed from local PL, readding."));
                                updateEntry(curNodePresence);
                                listEntry = presences.Find(x => x.wallet.SequenceEqual(wallet));
                            }

                            // Check if no such wallet found in presence list
                            if (listEntry == null)
                            {
                                // request for additional data
                                using (MemoryStream mw = new MemoryStream())
                                {
                                    using (BinaryWriter writer = new BinaryWriter(mw))
                                    {
                                        writer.Write(wallet.Length);
                                        writer.Write(wallet);

                                        CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'R' }, ProtocolMessageCode.getPresence, mw.ToArray(), null);
                                    }
                                }
                                return(false);
                            }
                            if (keepAliveVersion == 0)
                            {
                                // Verify the signature
                                if (CryptoManager.lib.verifySignature(Encoding.UTF8.GetBytes(CoreConfig.ixianChecksumLockString + "-" + deviceid + "-" + timestamp + "-" + hostname), listEntry.pubkey, signature) == false)
                                {
                                    Logging.warn(string.Format("[PL] KEEPALIVE tampering for {0} {1}, incorrect Sig.", Base58Check.Base58CheckEncoding.EncodePlain(listEntry.wallet), hostname));
                                    return(false);
                                }
                            }
                            else
                            {
                                // Verify the signature
                                if (CryptoManager.lib.verifySignature(bytes.Take(bytes.Length - sigLen - 4).ToArray(), listEntry.pubkey, signature) == false)
                                {
                                    Logging.warn(string.Format("[PL] KEEPALIVE tampering for {0} {1}, incorrect Sig.", Base58Check.Base58CheckEncoding.EncodePlain(listEntry.wallet), hostname));
                                    return(false);
                                }
                            }

                            PresenceAddress pa = listEntry.addresses.Find(x => x.address == hostname && x.device == deviceid);

                            if (pa != null)
                            {
                                // Check the node type
                                if (pa.lastSeenTime != timestamp)
                                {
                                    // Check for outdated timestamp
                                    if (timestamp < pa.lastSeenTime)
                                    {
                                        // We already have a newer timestamp for this entry
                                        return(false);
                                    }

                                    // Check for tampering. Includes a +300, -30 second synchronization zone
                                    if ((currentTime - timestamp) > 300 || (currentTime - timestamp) < -30)
                                    {
                                        Logging.warn(string.Format("[PL] Potential KEEPALIVE tampering for {0} {1}. Timestamp {2}", Base58Check.Base58CheckEncoding.EncodePlain(listEntry.wallet), pa.address, timestamp));
                                        return(false);
                                    }

                                    // Update the timestamp
                                    pa.lastSeenTime = timestamp;
                                    pa.signature    = signature;
                                    if (node_type != '0')
                                    {
                                        if (pa.type != node_type)
                                        {
                                            lock (presenceCount)
                                            {
                                                presenceCount[pa.type]--;
                                                if (!presenceCount.ContainsKey(node_type))
                                                {
                                                    presenceCount.Add(node_type, 0);
                                                }
                                                presenceCount[node_type]++;
                                            }
                                        }
                                        pa.type = node_type;
                                    }

                                    if (pa.type == 'M' || pa.type == 'H')
                                    {
                                        PeerStorage.addPeerToPeerList(hostname, wallet);
                                    }

                                    //Console.WriteLine("[PL] LASTSEEN for {0} - {1} set to {2}", hostname, deviceid, pa.lastSeenTime);
                                    return(true);
                                }
                            }
                            else
                            {
                                if (wallet.SequenceEqual(Node.walletStorage.getPrimaryAddress()))
                                {
                                    updateEntry(curNodePresence);
                                    return(true);
                                }
                                else
                                {
                                    using (MemoryStream mw = new MemoryStream())
                                    {
                                        using (BinaryWriter writer = new BinaryWriter(mw))
                                        {
                                            writer.Write(wallet.Length);
                                            writer.Write(wallet);

                                            CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'R' }, ProtocolMessageCode.getPresence, mw.ToArray(), null);
                                        }
                                    }
                                    return(false);
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Logging.error("Exception occured in receiveKeepAlive: " + e);
                return(false);
            }

            return(false);
        }