public void runUdp()
        {
            try
            {
                IPAddress localAdd = IPAddress.Parse(StarryboundServer.config.proxyIP);

                udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

                IPEndPoint ipEndPoint = new IPEndPoint(localAdd, StarryboundServer.config.proxyPort);

                udpSocket.Bind(ipEndPoint);

                IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 0);
                //The epSender identifies the incoming clients
                EndPoint epSender = (EndPoint)ipeSender;

                StarryboundServer.logInfo("RCON listener has been started on UDP " + localAdd.ToString() + ":" + StarryboundServer.config.proxyPort);

                while (true)
                {
                    int bytesRead = udpSocket.ReceiveFrom(udpByteData, ref epSender);

                    StarryboundServer.logInfo("Receiving RCON Data...");
                    OnReceive(udpByteData, bytesRead, epSender);
                }
            }
            catch (Exception e)
            {
                StarryboundServer.logError("Something went wrong while trying to setup the UDP listener. " + e.ToString());
            }
        }
        private void OnReceive(byte[] dataBuffer, int bytesRead, EndPoint remote)
        {
            byte[] data = new byte[bytesRead];

            try
            {
                Buffer.BlockCopy(dataBuffer, 0, data, 0, bytesRead);

                /*
                 * Source Query packets begin with 0xFF (x4)
                 */

                if (bytesRead > 4)
                {
                    byte[] sourceCheck = new byte[] { data[0], data[1], data[2], data[3] };

                    if (sourceCheck.SequenceEqual(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }))
                    {
                        SourceRequest(data, remote);
                        return;
                    }
                }

                string text = Encoding.UTF8.GetString(data, 0, bytesRead);

                StarryboundServer.logInfo(String.Format("RCON: Received non-source request of {0} bytes from {1}: {2}", bytesRead, remote, text));
            }
            catch (Exception e)
            {
                StarryboundServer.logError("Bad RCON request received. " + e.ToString());
                StarryboundServer.logError("RCON: Binary data: " + Utils.ByteArrayToString(data));
            }
        }
Exemple #3
0
        public static int[] GetSpamSettings()
        {
            if (!StarryboundServer.config.enableSpamProtection)
            {
                return new int[] { 0, 0 }
            }
            ;

            string[] spamSplit = StarryboundServer.config.spamInterval.Split(':');

            try
            {
                int numMessages = int.Parse(spamSplit[0]);

                int numSeconds = int.Parse(spamSplit[1]);

                return(new int[] { numMessages, numSeconds });
            }
            catch (Exception)
            {
                StarryboundServer.logError("Unable to read settings for anti-spam system - Is it in numMessages:numSeconds format?");
                return(new int[] { 0, 0 });
            }
        }
        private void SourceRequest(byte[] data, EndPoint remote)
        {
            byte headerByte = data[4];

            byte[] dataArray;

            switch (headerByte)
            {
            case 0x54:
                dataArray = new byte[data.Length - 6];

                Buffer.BlockCopy(data, 5, dataArray, 0, dataArray.Length);

                string text   = Encoding.UTF8.GetString(dataArray);
                string needle = "Source Engine Query";

                if (text != needle)
                {
                    StarryboundServer.logError("RCON: Received invalid A2S_INFO request: " + text + " is invalid.");
                    return;
                }
                else
                {
                    StarryboundServer.logDebug("ListenerThread::SourceRequest", "RCON: Matched A2S_INFO request!");
                }

                try
                {
                    byte   header      = 0x49;
                    byte   protocol    = 0x02;
                    byte[] name        = encodeString(StarryboundServer.config.serverName);
                    byte[] map         = encodeString("Starbound");
                    byte[] folder      = encodeString("na");
                    byte[] game        = encodeString("Starbound");
                    byte[] appID       = BitConverter.GetBytes(Convert.ToUInt16(1337));
                    byte   players     = Convert.ToByte((uint)StarryboundServer.clientCount);
                    byte   maxplayers  = Convert.ToByte((uint)StarryboundServer.config.maxClients);
                    byte   bots        = Convert.ToByte((uint)0);
                    byte   servertype  = Convert.ToByte('d');
                    byte   environment = Convert.ToByte((StarryboundServer.IsMono ? 'l' : 'w'));
                    byte   visibility  = Convert.ToByte((uint)(StarryboundServer.config.proxyPass == "" ? 0 : 1));
                    byte   vac         = Convert.ToByte((uint)0);
                    byte[] version     = encodeString(StarryboundServer.starboundVersion.Name);

                    var s = new MemoryStream();
                    s.Write(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }, 0, 4);
                    s.WriteByte(header);
                    s.WriteByte(protocol);
                    s.Write(name, 0, name.Length);
                    s.Write(map, 0, map.Length);
                    s.Write(folder, 0, folder.Length);
                    s.Write(game, 0, game.Length);
                    s.Write(appID, 0, appID.Length);
                    s.WriteByte(players);
                    s.WriteByte(maxplayers);
                    s.WriteByte(bots);
                    s.WriteByte(servertype);
                    s.WriteByte(environment);
                    s.WriteByte(visibility);
                    s.WriteByte(vac);
                    s.Write(version, 0, version.Length);

                    StarryboundServer.logInfo("RCON: Sending A2S_INFO Response packet to " + remote);
                    udpSocket.SendTo(s.ToArray(), remote);
                }
                catch (Exception e)
                {
                    StarryboundServer.logError("RCON: Unable to send data to stream! An error occurred.");
                    StarryboundServer.logError("RCON: " + e.ToString());
                }
                break;

            case 0x55:
                StarryboundServer.logDebug("ListenerThread::SourceRequest", "RCON: Received A2S_PLAYER request from " + remote);

                dataArray = new byte[4];
                Buffer.BlockCopy(data, 5, dataArray, 0, dataArray.Length);

                if (dataArray.SequenceEqual(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }))
                {
                    var buffer = new byte[4];
                    new Random().NextBytes(buffer);

                    if (challengeData.ContainsKey(remote))
                    {
                        challengeData.Remove(remote);
                    }
                    challengeData.Add(remote, buffer);

                    var s = new MemoryStream();
                    s.Write(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }, 0, 4);
                    s.WriteByte(0x41);
                    s.Write(buffer, 0, 4);

                    StarryboundServer.logInfo("RCON: Sending A2S_PLAYER Challenge Response packet to " + remote);
                    udpSocket.SendTo(s.ToArray(), remote);
                }
                else
                {
                    if (!challengeData.ContainsKey(remote))
                    {
                        StarryboundServer.logError("RCON: Illegal A2S_PLAYER request received from " + remote + ". No challenge number has been issued to this address.");
                    }
                    else
                    {
                        var s = new MemoryStream();
                        s.Write(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }, 0, 4);
                        s.WriteByte(0x44);

                        s.WriteByte(Convert.ToByte((uint)StarryboundServer.clientCount));

                        List <Client> clientList = StarryboundServer.getClients();

                        for (var i = 0; i < clientList.Count; i++)
                        {
                            Client client = clientList[i];
                            s.WriteByte(Convert.ToByte((uint)i));

                            byte[] name = encodeString(client.playerData.name);
                            s.Write(name, 0, name.Length);

                            byte[] score = new byte[4];
                            score = BitConverter.GetBytes((int)0);
                            s.Write(score, 0, score.Length);

                            float  seconds   = Utils.getTimestamp() - client.connectedTime;
                            byte[] connected = new byte[4];
                            connected = BitConverter.GetBytes(seconds);
                            s.Write(connected, 0, connected.Length);

                            //StarryboundServer.logDebug("ListenerThread::SourceA2SPlayer", "Client ID #" + i + ": " + Utils.ByteArrayToString(new byte[] { Convert.ToByte((uint)i) }) + Utils.ByteArrayToString(name) + Utils.ByteArrayToString(score) + Utils.ByteArrayToString(connected));
                        }

                        StarryboundServer.logInfo("RCON: Sending A2S_PLAYER Response packet for " + StarryboundServer.clientCount + " player(s) to " + remote);
                        //StarryboundServer.logDebug("ListenerThread::SourceA2SPlayer", "RCON: Dump packet: " + Utils.ByteArrayToString(s.ToArray()));
                        udpSocket.SendTo(s.ToArray(), remote);
                    }
                }
                break;

            default:
                StarryboundServer.logError("RCON: Received unknown or unsupported header byte - " + headerByte);
                break;
            }
        }