public static void SetupConfig() { try { if (File.Exists(ConfigPath)) { StarryboundServer.serverConfig = ServerFile.Read(ConfigPath); } StarryboundServer.serverConfig.gamePort = StarryboundServer.config.serverPort; StarryboundServer.privatePassword = Utils.GenerateSecureSalt(); StarryboundServer.serverConfig.serverPasswords = new string[] { StarryboundServer.privatePassword }; StarryboundServer.serverConfig.maxPlayers = StarryboundServer.config.maxClients + 10; StarryboundServer.serverConfig.bind = StarryboundServer.config.proxyIP; if (StarryboundServer.serverConfig.useDefaultWorldCoordinate) { string[] spawnPlanet = StarryboundServer.serverConfig.defaultWorldCoordinate.Split(':'); if (spawnPlanet.Length == 5) { StarryboundServer.spawnPlanet = new WorldCoordinate(spawnPlanet[0], Convert.ToInt32(spawnPlanet[1]), Convert.ToInt32(spawnPlanet[2]), Convert.ToInt32(spawnPlanet[3]), Convert.ToInt32(spawnPlanet[4]), 0); } else { StarryboundServer.spawnPlanet = new WorldCoordinate(spawnPlanet[0], Convert.ToInt32(spawnPlanet[1]), Convert.ToInt32(spawnPlanet[2]), Convert.ToInt32(spawnPlanet[3]), Convert.ToInt32(spawnPlanet[4]), Convert.ToInt32(spawnPlanet[5])); } } StarryboundServer.serverConfig.Write(ConfigPath); } catch (Exception e) { StarryboundServer.logFatal("Failed to parse starbound.config: " + e.ToString()); Thread.Sleep(5000); Environment.Exit(8); } }
public void run() { var executableName = "starbound_server" + (StarryboundServer.IsMono ? "" : ".exe"); try { ProcessStartInfo startInfo = new ProcessStartInfo(executableName) { WindowStyle = ProcessWindowStyle.Hidden, UseShellExecute = false, RedirectStandardOutput = true, CreateNoWindow = true }; process = Process.Start(startInfo); StarryboundServer.parentProcessId = process.Id; File.WriteAllText("starbound_server.pid", process.Id.ToString()); process.OutputDataReceived += (sender, e) => parseOutput(e.Data); process.ErrorDataReceived += (sender, e) => logStarboundError("ErrorDataReceived from starbound_server.exe: " + e.Data); process.BeginOutputReadLine(); process.WaitForExit(); StarryboundServer.changeState(ServerState.Crashed, "ServerThread::run", "starbound_server.exe process has exited."); } catch (ThreadAbortException) { } catch (Exception e) { StarryboundServer.changeState(ServerState.Crashed, "ServerThread::run::Exception", e.ToString()); } }
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)); } }
public static void LoadClaims() { try { String claimPath = Path.Combine(StarryboundServer.SavePath, "claims.json"); StarryboundServer.logInfo("Loading players claims from file " + claimPath); if (File.Exists(claimPath)) { String serializedData = String.Empty; using (StreamReader rdr = new StreamReader(claimPath)) { serializedData = rdr.ReadLine(); } if (!String.IsNullOrEmpty(serializedData)) { _playerToSystem = Newtonsoft.Json.JsonConvert.DeserializeObject <Dictionary <String, List <Extensions.WorldCoordinate> > >(serializedData); } foreach (String plyUUID in _playerToSystem.Keys) { foreach (Extensions.WorldCoordinate coord in _playerToSystem[plyUUID]) { _SystemToPlayer.Add(coord, plyUUID); } } } } catch (Exception e) { StarryboundServer.logException("Unable to load claims from claims.json: {0}", e.Message); } }
public static bool ReleaseClaim(PlayerData player, Extensions.WorldCoordinate loc) { try { stakeClaimMutex.WaitOne(); if (_SystemToPlayer.ContainsKey(loc)) { if (_SystemToPlayer[loc] == player.name) { _SystemToPlayer.Remove(loc); _playerToSystem[player.name].Remove(loc); SaveClaims(); stakeClaimMutex.ReleaseMutex(); return(true); } } } catch (Exception e) { StarryboundServer.logException("Could not release claim to location {0} for player {1}", loc, player.uuid); stakeClaimMutex.ReleaseMutex(); return(false); } return(false); }
public static void ProcessBans() { readLegacyBans(); List <Ban> bans = Read(Path.Combine(StarryboundServer.SavePath, "bans.json")); foreach (Ban ban in bans) { allBans.Add(ban.banID, ban); nextBanID = ban.banID + 1; } foreach (Ban lBan in legacyBans.Values) { if (!allBans.ContainsKey(lBan.banID)) { allBans.Add(lBan.banID, lBan); } } int removedCount = 0; foreach (Ban ban in allBans.Values) { if (ban.hasExpired()) { ban.remove(); removedCount++; } } Write(Path.Combine(StarryboundServer.SavePath, "bans.json")); StarryboundServer.logInfo(allBans.Count + " ban(s) have been loaded from file. " + removedCount + " ban(s) have expired and been removed."); }
public static void SetupConfig() { CreateIfNot(RulesPath, "1) Respect all players 2) No griefing/hacking 3) Have fun!"); CreateIfNot(MotdPath, "This server is running Starrybound Server v%versionNum%. Type /help for a list of commands. There are currently %players% player(s) online."); StarryboundServer.motdData = ReadConfigFile(MotdPath); StarryboundServer.rulesData = ReadConfigFile(RulesPath); if (File.Exists(ConfigPath)) { StarryboundServer.config = ConfigFile.Read(ConfigPath); } if (StarryboundServer.IsMono && StarryboundServer.config == null) { StarryboundServer.config = new ConfigFile(); } StarryboundServer.config.Write(ConfigPath); #if DEBUG StarryboundServer.config.logLevel = LogType.Debug; StarryboundServer.logDebug("SetupConfig", "This was compiled in DEBUG, forcing debug logging!"); #endif }
public bool checkTrigger(int count, Client client) { if (count == countToTrigger) { PlayerData player = client.playerData; switch (actionName) { case "mute": player.isMuted = true; StarryboundServer.sendGlobalMessage("^#f75d5d;" + player.name + " has been muted automatically for spamming."); break; case "kick": client.kickClient(reason); break; case "ban": if (length != 0) { length = Utils.getTimestamp() + (length * 60); } Bans.addNewBan(player.name, player.uuid, player.ip, Utils.getTimestamp(), "[SYSTEM]", length, reason); client.banClient(reason); break; } return(true); } return(false); }
public static bool addNewBan(string username, string uuid, string ipaddress, int timeBanned, string admin, int expiry, string reason) { string[] args = new string[8]; args[0] = nextBanID.ToString(); args[1] = username; args[2] = uuid; args[3] = ipaddress; args[4] = timeBanned.ToString(); args[5] = admin; args[6] = expiry.ToString(); args[7] = reason; try { Ban ban = new Ban(nextBanID, username, uuid, ipaddress, timeBanned, admin, expiry, reason); allBans.Add(nextBanID, ban); Write(Path.Combine(StarryboundServer.SavePath, "bans.json")); nextBanID++; } catch (Exception e) { StarryboundServer.logException("Unable to write ban to banned-players.txt: " + e.Message); return(false); } return(true); }
public void delayDisconnect(string reason) { if (kickTargetTimestamp != 0) { return; } sendChatMessage("^#f75d5d;" + reason); flushChatQueue(); kickTargetTimestamp = Utils.getTimestamp() + 6; sendServerPacket(Packet.ClientDisconnect, new byte[1]); StarryboundServer.logInfo("[" + playerData.client + "] is being kicked for " + reason); }
public static ServerFile Read(Stream stream) { try { DataContractJsonSerializer str = new DataContractJsonSerializer(StarryboundServer.serverConfig.GetType()); return(str.ReadObject(stream) as ServerFile); } catch (Exception) { StarryboundServer.logException("Starbound server config is unreadable - Re-creating config with default values"); return(new ServerFile()); } }
public static void SaveClaims() { try { using (StreamWriter wtr = new StreamWriter(Path.Combine(StarryboundServer.SavePath, "claims.json"))) wtr.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(_playerToSystem)); }catch (Exception e) { StarryboundServer.logException("Unable to write claims to claims.json: {0}", e.Message); } return; }
public static ServerFile Read(string path) { if (!File.Exists(path)) { return(new ServerFile()); } using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { ServerFile file = Read(fs); StarryboundServer.logInfo("Starbound server config loaded successfully."); return(file); } }
public static ConfigFile Read(Stream stream) { try { using (var sr = new StreamReader(stream)) { return(JsonConvert.DeserializeObject <ConfigFile>(sr.ReadToEnd())); } } catch (Exception) { StarryboundServer.logException("Starrybound config is unreadable - Re-creating config with default values"); return(new ConfigFile()); } }
public static List <Ban> Read(Stream stream) { try { using (var sr = new StreamReader(stream)) { return(JsonConvert.DeserializeObject <List <Ban> >(sr.ReadToEnd())); } } catch (Exception) { StarryboundServer.logException("Server ban file is not readable - Bans WILL NOT operate until this issue is fixed."); writeBans = false; return(new List <Ban>()); } }
private void doDisconnect(string logMessage) { if (this.state == ClientState.Disposing) { return; } this.state = ClientState.Disposing; StarryboundServer.logInfo("[" + playerData.client + "] " + logMessage); try { if (this.playerData.name != null) { Client target = StarryboundServer.getClient(this.playerData.name); if (target != null) { Users.SaveUser(this.playerData); StarryboundServer.removeClient(this); if (this.kickTargetTimestamp == 0) { StarryboundServer.sendGlobalMessage(this.playerData.name + " has left the server."); } } } } catch (Exception e) { StarryboundServer.logException("Failed to remove client from clients: " + e.ToString()); } try { this.sendServerPacket(Packet.ClientDisconnect, new byte[1]); } catch (Exception) { } try { this.cSocket.Close(); this.sSocket.Close(); } catch (Exception) { } try { this.ClientForwarder.Abort(); this.ServerForwarder.Abort(); } catch (Exception) { } }
public void runTcp() { try { IPAddress localAdd = IPAddress.Parse(StarryboundServer.config.proxyIP); tcpSocket = new TcpListener(localAdd, StarryboundServer.config.proxyPort); tcpSocket.Start(); StarryboundServer.logInfo("Proxy server has been started on " + localAdd.ToString() + ":" + StarryboundServer.config.proxyPort); StarryboundServer.changeState(ServerState.ListenerReady, "ListenerThread::runTcp"); try { while (true) { TcpClient clientSocket = tcpSocket.AcceptTcpClient(); clientSocket.ReceiveTimeout = StarryboundServer.config.clientSocketTimeout * 1000; clientSocket.SendTimeout = StarryboundServer.config.internalSocketTimeout * 1000; new Thread(new ThreadStart(new Client(clientSocket).run)).Start(); } } catch (ThreadAbortException) { StarryboundServer.changeState(ServerState.Crashed, "ListenerThread::runTcp", "Thread has been aborted"); } catch (Exception e) { if ((int)StarryboundServer.serverState > 3) { return; } StarryboundServer.logException("ListenerThread Exception: " + e.ToString()); StarryboundServer.changeState(ServerState.Crashed, "ListenerThread::runTcp", e.ToString()); } tcpSocket.Stop(); StarryboundServer.logFatal("ListenerThread has failed - No new connections will be possible."); } catch (ThreadAbortException) { } catch (SocketException e) { StarryboundServer.logFatal("TcpListener has failed to start: " + e.Message); StarryboundServer.serverState = ServerState.Crashed; } }
public bool canIBuild() { if (StarryboundServer.serverConfig.useDefaultWorldCoordinate && StarryboundServer.config.spawnWorldProtection) { if (loc != null) { if ((StarryboundServer.spawnPlanet.Equals(loc)) && !group.hasPermission("admin.spawnbuild") && !inPlayerShip) { return(false); } } else { return(false); } } else if (!hasPermission("world.build")) { return(false); } else if (!canBuild) { return(false); } if (this.hasPermission("admin.ignoreshipaccess")) { return(true); //Admins can ignore claims } var player = Claims.GetStakeOwner(loc); if (player == this.name) { return(true); } if (player != null) { List <String> whiteList = StarryboundServer.getClientWhitelist(player); if (!whiteList.Contains(this.name)) { return(false); //Players need to specificly whitelist players to ignore claims } } return(true); }
public static BootstrapFile Read(Stream stream) { try { using (var sr = new StreamReader(stream)) { return(JsonConvert.DeserializeObject <BootstrapFile>(sr.ReadToEnd())); } } catch (Exception) { StarryboundServer.logFatal("bootstrap.config file is unreadable. The server start cannot continue."); Thread.Sleep(5000); Environment.Exit(6); } return(null); }
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 }); } }
void parseOutput(string consoleLine) { try { foreach (string line in filterConsole) { if (consoleLine.Contains(line)) { return; } } if (consoleLine.StartsWith("Error: ") || consoleLine.StartsWith("AssetException:")) { this.parseError = true; } else if ((consoleLine.StartsWith("Warn:") || consoleLine.StartsWith("Info:") || consoleLine.StartsWith("Debug:")) && this.parseError) { logStarboundError(" "); this.parseError = false; } else if (String.IsNullOrWhiteSpace(consoleLine) && this.parseError) { logStarboundError(" "); this.parseError = false; return; } if (consoleLine.StartsWith("Warn: Perf: ")) { string[] perf = consoleLine.Remove(0, 12).Split(' '); string function = perf[0]; float millis = Convert.ToSingle(perf[2]); if (millis > 5000) { StarryboundServer.logWarn("Parent Server [" + function + "] lagged for " + (millis / 1000) + " seconds"); } return; } else if (consoleLine.Contains("Info: Server version")) { string[] versionString = consoleLine.Split('\''); string versionName = versionString[1]; int protocolVersion = int.Parse(versionString[3]); StarryboundServer.starboundVersion.Protocol = protocolVersion; StarryboundServer.starboundVersion.Name = versionName; if (protocolVersion != StarryboundServer.ProtocolVersion) { StarryboundServer.logFatal("Detected protcol version [" + protocolVersion + "] != [" + StarryboundServer.ProtocolVersion + "] to expected protocol version!"); Thread.Sleep(5000); Environment.Exit(4); } StarryboundServer.logInfo("Parent Server Version: [" + versionName + "] Protocol: [" + protocolVersion + "]"); return; } else if (consoleLine.Contains("TcpServer will close, listener thread caught exception")) { StarryboundServer.logFatal("Parent Server TcpServer listener thread caught exception, Forcing a restart."); StarryboundServer.changeState(ServerState.Crashed, "ServerThread::parseOutput", "Starbound Tcp listener has crashed"); } else if (consoleLine.Contains("TcpServer listening on: ")) { StarryboundServer.changeState(ServerState.StarboundReady, "ServerThread::parseOutput"); ServerConfig.RemovePrivateConfig(); } else if (consoleLine.StartsWith("Info: Kicking client ")) { string[] kick = consoleLine.Remove(0, 21).Split(' '); string user = kick[0]; string id = kick[1]; string ip = kick[2]; StarryboundServer.logWarn("Parent Server disconnected " + user + " " + ip + " for inactivity."); return; } if (!this.parseError) { Console.WriteLine("[STAR] " + consoleLine); } else { logStarboundError(consoleLine); } } catch (Exception) { } }
public void run() { try { this.cIn = new BinaryReader(this.cSocket.GetStream()); this.cOut = new BinaryWriter(this.cSocket.GetStream()); IPEndPoint ipep = (IPEndPoint)this.cSocket.Client.RemoteEndPoint; IPAddress ipa = ipep.Address; this.playerData.ip = ipep.Address.ToString(); StarryboundServer.logInfo("[" + playerData.client + "] Accepting new connection."); if ((int)StarryboundServer.serverState < 3) { MemoryStream packet = new MemoryStream(); BinaryWriter packetWrite = new BinaryWriter(packet); packetWrite.WriteBE(StarryboundServer.ProtocolVersion); this.sendClientPacket(Packet.ProtocolVersion, packet.ToArray()); rejectPreConnected("Connection Failed: The server is not ready yet."); return; } else if ((int)StarryboundServer.serverState > 3) { MemoryStream packet = new MemoryStream(); BinaryWriter packetWrite = new BinaryWriter(packet); packetWrite.WriteBE(StarryboundServer.ProtocolVersion); this.sendClientPacket(Packet.ProtocolVersion, packet.ToArray()); rejectPreConnected("Connection Failed: The server is shutting down."); return; } else if (StarryboundServer.restartTime != 0) { MemoryStream packet = new MemoryStream(); BinaryWriter packetWrite = new BinaryWriter(packet); packetWrite.WriteBE(StarryboundServer.ProtocolVersion); this.sendClientPacket(Packet.ProtocolVersion, packet.ToArray()); rejectPreConnected("Connection Failed: The server is restarting."); return; } sSocket = new TcpClient(); sSocket.ReceiveTimeout = StarryboundServer.config.internalSocketTimeout * 1000; sSocket.SendTimeout = StarryboundServer.config.internalSocketTimeout * 1000; IAsyncResult result = sSocket.BeginConnect((StarryboundServer.config.proxyIP.Equals("0.0.0.0") ? IPAddress.Loopback : IPAddress.Parse(StarryboundServer.config.proxyIP)), StarryboundServer.config.serverPort, null, null); bool success = result.AsyncWaitHandle.WaitOne(3000, true); if (!success || !sSocket.Connected) { StarryboundServer.failedConnections++; if (StarryboundServer.failedConnections >= StarryboundServer.config.maxFailedConnections) { StarryboundServer.logFatal(StarryboundServer.failedConnections + " clients failed to connect in a row. Restarting..."); StarryboundServer.serverState = ServerState.Crashed; } MemoryStream packet = new MemoryStream(); BinaryWriter packetWrite = new BinaryWriter(packet); packetWrite.WriteBE(StarryboundServer.ProtocolVersion); this.sendClientPacket(Packet.ProtocolVersion, packet.ToArray()); rejectPreConnected("Connection Failed: Unable to connect to the parent server."); return; } this.sIn = new BinaryReader(this.sSocket.GetStream()); this.sOut = new BinaryWriter(this.sSocket.GetStream()); this.connectedTime = Utils.getTimestamp(); // Forwarding for data from SERVER (sIn) to CLIENT (cOut) this.ServerForwarder = new Thread(new ThreadStart(new ForwardThread(this, this.sIn, this.cOut, Direction.Server).run)); ServerForwarder.Start(); // Forwarding for data from CLIENT (cIn) to SERVER (sOut) this.ClientForwarder = new Thread(new ThreadStart(new ForwardThread(this, this.cIn, this.sOut, Direction.Client).run)); ClientForwarder.Start(); StarryboundServer.failedConnections = 0; } catch (Exception e) { StarryboundServer.logException("ClientThread Exception: " + e.ToString()); StarryboundServer.failedConnections++; MemoryStream packet = new MemoryStream(); BinaryWriter packetWrite = new BinaryWriter(packet); packetWrite.WriteBE(StarryboundServer.ProtocolVersion); this.sendClientPacket(Packet.ProtocolVersion, packet.ToArray()); rejectPreConnected("Connection Failed: A internal server error occurred (1)"); } }
public static void readLegacyBans() { try { StreamReader reader = File.OpenText(Path.Combine(StarryboundServer.SavePath, "banned-players.txt")); string line; int banCount = 0; while ((line = reader.ReadLine()) != null) { string[] args = line.Split('|'); /* * Ban format: * int ID * string Username * string UUID * string IP Address * timestamp UnixTimestamp (Time of Addition) * string Admin * timestamp Expiry * string Reason * * Example: * 2|User|133bfef193364620513ea1980ba39dc3|127.0.0.1|1387767903|Crashdoom|0|Griefing the spawn * */ if (args.Length != 8) { continue; } try { int banID = int.Parse(args[0]); string username = args[1]; string uuid = args[2]; string ipaddress = args[3]; int timeBanned = int.Parse(args[4]); string admin = args[5]; int expiry = int.Parse(args[6]); string reason = args[7]; Ban ban = new Ban(banID, username, uuid, ipaddress, timeBanned, admin, expiry, reason); legacyBans.Add(banID, ban); nextBanID = banID + 1; banCount++; } catch (Exception) { banCount--; StarryboundServer.logWarn("Invalid ban detected in banned-players.txt"); } } reader.Close(); } catch (Exception e) { StarryboundServer.logWarn("Unable to read bans from legacy banned-players.txt: " + e.Message); } }
public void run() { try { for (;;) { if (!this.client.connectionAlive) { this.client.forceDisconnect(direction, "Connection no longer alive"); return; } if (this.client.kickTargetTimestamp != 0) { if (this.client.kickTargetTimestamp < Utils.getTimestamp()) { this.client.closeConnection(); return; } continue; } #region Process Packet //Packet ID and Vaildity Check. uint temp = this.incoming.ReadVarUInt32(); if (temp < 0 || temp > 48) { this.client.forceDisconnect(direction, "Sent invalid packet ID [" + temp + "]."); return; } Packet packetID = (Packet)temp; //Packet Size and Compression Check. bool compressed = false; int packetSize = this.incoming.ReadVarInt32(); if (packetSize < 0) { packetSize = -packetSize; compressed = true; } //Create buffer for forwarding byte[] dataBuffer = this.incoming.ReadFully(packetSize); //Do decompression MemoryStream ms = new MemoryStream(); if (compressed) { ZlibStream compressedStream = new ZlibStream(new MemoryStream(dataBuffer), CompressionMode.Decompress); byte[] buffer = new byte[32768]; for (;;) { int read = compressedStream.Read(buffer, 0, buffer.Length); if (read <= 0) { break; } ms.Write(buffer, 0, read); } ms.Seek(0, SeekOrigin.Begin); } else { ms = new MemoryStream(dataBuffer); } //Create packet parser BinaryReader packetData = new BinaryReader(ms); #endregion //Return data for packet processor object returnData = true; if (packetID != Packet.Heartbeat && packetID != Packet.UniverseTimeUpdate) { if (direction == Direction.Client) #region Handle Client Packets { #region Protocol State Security ClientState curState = this.client.state; if (curState != ClientState.Connected) { if (curState == ClientState.PendingConnect && packetID != Packet.ClientConnect) { this.client.rejectPreConnected("Violated PendingConnect protocol state with " + packetID); return; } else if (curState == ClientState.PendingAuthentication && packetID != Packet.HandshakeResponse) { this.client.rejectPreConnected("Violated PendingAuthentication protocol state with " + packetID); return; } else if (curState == ClientState.PendingConnectResponse) { int startTime = Utils.getTimestamp(); while (true) { if (this.client.state == ClientState.Connected) { break; } if (Utils.getTimestamp() > startTime + StarryboundServer.config.connectTimeout) { this.client.rejectPreConnected("Connection Failed: Server did not respond in time."); return; } } } } #endregion if (packetID == Packet.ChatSend) { returnData = new Packet11ChatSend(this.client, packetData, this.direction).onReceive(); } else if (packetID == Packet.ClientConnect) { this.client.state = ClientState.PendingAuthentication; returnData = new Packet7ClientConnect(this.client, packetData, this.direction).onReceive(); MemoryStream packet = new MemoryStream(); BinaryWriter packetWrite = new BinaryWriter(packet); passwordSalt = Utils.GenerateSecureSalt(); packetWrite.WriteStarString(""); packetWrite.WriteStarString(passwordSalt); packetWrite.WriteBE(StarryboundServer.config.passwordRounds); this.client.sendClientPacket(Packet.HandshakeChallenge, packet.ToArray()); } else if (packetID == Packet.HandshakeResponse) { string claimResponse = packetData.ReadStarString(); string passwordHash = packetData.ReadStarString(); string verifyHash = Utils.StarHashPassword(StarryboundServer.config.proxyPass, this.client.playerData.account + passwordSalt, StarryboundServer.config.passwordRounds); if (passwordHash != verifyHash) { this.client.rejectPreConnected("Your password was incorrect."); return; } this.client.state = ClientState.PendingConnectResponse; returnData = false; } else if (packetID == Packet.WarpCommand) { WarpType cmd = (WarpType)packetData.ReadUInt32BE(); WorldCoordinate coord = packetData.ReadStarWorldCoordinate(); string player = packetData.ReadStarString(); if (cmd == WarpType.WarpToPlayerShip) { Client target = StarryboundServer.getClient(player); if (target != null) { if (!this.client.playerData.canAccessShip(target.playerData)) { this.client.sendChatMessage("^#5dc4f4;You cannot access this player's ship due to their ship access settings."); StarryboundServer.logDebug("ShipAccess", "Preventing " + this.client.playerData.name + " from accessing " + target.playerData.name + "'s ship."); MemoryStream packetWarp = new MemoryStream(); BinaryWriter packetWrite = new BinaryWriter(packetWarp); packetWrite.WriteBE((uint)WarpType.WarpToOwnShip); packetWrite.Write(new WorldCoordinate()); packetWrite.WriteStarString(""); client.sendServerPacket(Packet.WarpCommand, packetWarp.ToArray()); returnData = false; } else { this.client.playerData.inPlayerShip = true; } } } else if (cmd == WarpType.WarpToOwnShip) { this.client.playerData.inPlayerShip = true; } else { this.client.playerData.inPlayerShip = false; } StarryboundServer.logDebug("WarpCommand", "[" + this.client.playerData.client + "][" + cmd + "]" + (coord != null ? "[" + coord.ToString() + "]" : "") + "[" + player + "] inPlayerShip:" + this.client.playerData.inPlayerShip); } else if (packetID == Packet.ModifyTileList || packetID == Packet.DamageTileGroup || packetID == Packet.DamageTile || packetID == Packet.ConnectWire || packetID == Packet.DisconnectAllWires) { if (!this.client.playerData.canIBuild()) { returnData = false; } } else if (packetID == Packet.EntityCreate) { while (true) { EntityType type = (EntityType)packetData.Read(); if (type == EntityType.EOF) { break; } byte[] entityData = packetData.ReadStarByteArray(); int entityId = packetData.ReadVarInt32(); if (type == EntityType.Projectile) { BinaryReader entity = new BinaryReader(new MemoryStream(entityData)); string projectileKey = entity.ReadStarString(); object projParams = entity.ReadStarVariant(); if (StarryboundServer.config.projectileBlacklist.Contains(projectileKey)) { MemoryStream packet = new MemoryStream(); BinaryWriter packetWrite = new BinaryWriter(packet); packetWrite.WriteVarInt32(entityId); packetWrite.Write(false); this.client.sendClientPacket(Packet.EntityDestroy, packet.ToArray()); returnData = false; } if (StarryboundServer.serverConfig.useDefaultWorldCoordinate && StarryboundServer.config.spawnWorldProtection) { if (this.client.playerData.loc != null) { if (StarryboundServer.config.projectileBlacklistSpawn.Contains(projectileKey) ^ StarryboundServer.config.projectileSpawnListIsWhitelist) { if (StarryboundServer.spawnPlanet.Equals(this.client.playerData.loc) && !this.client.playerData.group.hasPermission("admin.spawnbuild") && !this.client.playerData.inPlayerShip) { MemoryStream packet = new MemoryStream(); BinaryWriter packetWrite = new BinaryWriter(packet); packetWrite.WriteVarInt32(entityId); packetWrite.Write(false); this.client.sendClientPacket(Packet.EntityDestroy, packet.ToArray()); returnData = false; } } } else { MemoryStream packet = new MemoryStream(); BinaryWriter packetWrite = new BinaryWriter(packet); packetWrite.WriteVarInt32(entityId); packetWrite.Write(false); this.client.sendClientPacket(Packet.EntityDestroy, packet.ToArray()); returnData = false; } } } else if (type == EntityType.Object || type == EntityType.Plant || type == EntityType.PlantDrop || type == EntityType.Monster) { if (!this.client.playerData.canIBuild()) { MemoryStream packet = new MemoryStream(); BinaryWriter packetWrite = new BinaryWriter(packet); packetWrite.WriteVarInt32(entityId); packetWrite.Write(false); this.client.sendClientPacket(Packet.EntityDestroy, packet.ToArray()); returnData = false; } } } } else if (packetID == Packet.SpawnEntity) { while (true) { EntityType type = (EntityType)packetData.Read(); if (type == EntityType.EOF) { break; } byte[] entityData = packetData.ReadStarByteArray(); if (type == EntityType.Projectile) { BinaryReader entity = new BinaryReader(new MemoryStream(entityData)); string projectileKey = entity.ReadStarString(); object projParams = entity.ReadStarVariant(); if (StarryboundServer.config.projectileBlacklist.Contains(projectileKey)) { returnData = false; } if (StarryboundServer.serverConfig.useDefaultWorldCoordinate && StarryboundServer.config.spawnWorldProtection) { if (this.client.playerData.loc != null) { if (StarryboundServer.config.projectileBlacklistSpawn.Contains(projectileKey) ^ StarryboundServer.config.projectileSpawnListIsWhitelist) { if (StarryboundServer.spawnPlanet.Equals(this.client.playerData.loc) && !this.client.playerData.group.hasPermission("admin.spawnbuild") && !this.client.playerData.inPlayerShip) { returnData = false; } } } else { returnData = false; } } } else if (type == EntityType.Object || type == EntityType.Plant || type == EntityType.PlantDrop || type == EntityType.Monster) { if (!this.client.playerData.canIBuild()) { returnData = false; } } } } } #endregion else #region Handle Server Packets { if (packetID == Packet.ChatReceive) { returnData = new Packet5ChatReceive(this.client, packetData, this.direction).onReceive(); } else if (packetID == Packet.ProtocolVersion) { uint protocolVersion = packetData.ReadUInt32BE(); if (protocolVersion != StarryboundServer.ProtocolVersion) { MemoryStream packet = new MemoryStream(); BinaryWriter packetWrite = new BinaryWriter(packet); packetWrite.WriteBE(protocolVersion); this.client.sendClientPacket(Packet.ProtocolVersion, packet.ToArray()); this.client.rejectPreConnected("Connection Failed: Unable to handle parent server protocol version."); return; } } else if (packetID == Packet.HandshakeChallenge) { string claimMessage = packetData.ReadString(); string passwordSalt = packetData.ReadStarString(); int passwordRounds = packetData.ReadInt32BE(); MemoryStream packet = new MemoryStream(); BinaryWriter packetWrite = new BinaryWriter(packet); string passwordHash = Utils.StarHashPassword(StarryboundServer.privatePassword, passwordSalt, passwordRounds); packetWrite.WriteStarString(""); packetWrite.WriteStarString(passwordHash); this.client.sendServerPacket(Packet.HandshakeResponse, packet.ToArray()); returnData = false; } else if (packetID == Packet.ConnectResponse) { int startTime = Utils.getTimestamp(); while (true) { if (this.client.state == ClientState.PendingConnectResponse) { break; } if (Utils.getTimestamp() > startTime + StarryboundServer.config.connectTimeout) { this.client.rejectPreConnected("Connection Failed: Client did not respond with handshake."); return; } } returnData = new Packet2ConnectResponse(this.client, packetData, this.direction).onReceive(); } else if (packetID == Packet.WorldStart) { if (!this.client.playerData.sentMotd) { this.client.sendChatMessage(Config.GetMotd()); if (!this.client.playerData.group.hasPermission("world.build")) { this.client.sendChatMessage("^#f75d5d;" + StarryboundServer.config.buildErrorMessage); } this.client.playerData.sentMotd = true; } var unk4 = packetData.ReadStarVariant(); var unk3 = packetData.ReadStarVariant(); byte[] unk1 = packetData.ReadStarByteArray(); byte[] unk2 = packetData.ReadStarByteArray(); float spawnX = packetData.ReadSingleBE(); float spawnY = packetData.ReadSingleBE(); var mapParamsSize = packetData.ReadStarVariant(); /* * for (int i = 0; i < mapParamsSize; i++) * { * string key = packetData.ReadStarString(); * var value = packetData.ReadStarVariant(); * mapParams.Add(key, value); * if(key == "fuel.level") * { * isPlayerShip++; * } * else if(key == "fuel.max") * { * isPlayerShip++; * } * } * this.client.playerData.inPlayerShip = (isPlayerShip == 2); */ uint clientID = packetData.ReadUInt32BE(); bool interpolation = packetData.ReadBoolean(); WorldCoordinate coords = Utils.findGlobalCoords(unk1); if (coords != null) { this.client.playerData.loc = coords; StarryboundServer.logDebug("WorldStart", "[" + this.client.playerData.client + "][" + interpolation + ":" + clientID + "] CurLoc:[" + this.client.playerData.loc.ToString() + "][" + this.client.playerData.inPlayerShip + "]"); } else { StarryboundServer.logDebug("WorldStart", "[" + this.client.playerData.client + "][" + interpolation + ":" + clientID + "] InPlayerShip:[" + this.client.playerData.inPlayerShip + "]"); } } else if (packetID == Packet.WorldStop) { string status = packetData.ReadStarString(); } else if (packetID == Packet.GiveItem) { string name = packetData.ReadStarString(); uint count = packetData.ReadVarUInt32(); var itemDesc = packetData.ReadStarVariant(); } else if (packetID == Packet.EnvironmentUpdate) { byte[] sky = packetData.ReadStarByteArray(); byte[] serverWeather = packetData.ReadStarByteArray(); if (this.client.playerData.loc == null) { WorldCoordinate coords = Utils.findGlobalCoords(sky); if (coords != null) { this.client.playerData.loc = coords; StarryboundServer.logDebug("EnvUpdate", "[" + this.client.playerData.client + "] CurLoc:[" + this.client.playerData.loc.ToString() + "]"); } } } else if (packetID == Packet.ClientContextUpdate) { try { byte[] clientContextData = packetData.ReadStarByteArray(); if (clientContextData.Length != 0) { BinaryReader clientContextReader = new BinaryReader(new MemoryStream(clientContextData)); byte[] data = clientContextReader.ReadStarByteArray(); if (data.Length > 8) //Should at least be more than 8 bytes for it to contain the data we want. { BinaryReader dataReader = new BinaryReader(new MemoryStream(data)); byte dataBufferLength = dataReader.ReadByte(); if (dataBufferLength == 2) { byte arrayLength = dataReader.ReadByte(); if (arrayLength == 2 || arrayLength == 4) //Only observed these being used so far for what we want. { byte dataType = dataReader.ReadByte(); //04 = String, 0E = CelestialLog if (dataType == 4) { string string1 = dataReader.ReadStarString(); if (dataReader.BaseStream.Position != dataReader.BaseStream.Length) { if (string1 == "null") { byte[] worldHeader = dataReader.ReadStarByteArray(); //0008020A000C byte[] worldData = dataReader.ReadStarByteArray(); byte typeByte = dataReader.ReadByte(); //0E = CelestialLog if (typeByte == 14) { Dictionary <string, WorldCoordinate> log = dataReader.ReadStarCelestialLog(); log.TryGetValue("loc", out this.client.playerData.loc); if (!log.TryGetValue("home", out this.client.playerData.home)) { this.client.playerData.home = this.client.playerData.loc; } StarryboundServer.logDebug("ClientContext", "[" + this.client.playerData.client + "] CurLoc:[" + this.client.playerData.loc.ToString() + "][" + this.client.playerData.inPlayerShip + "]"); StarryboundServer.logDebug("ClientContext", "[" + this.client.playerData.client + "] CurHome:[" + this.client.playerData.home.ToString() + "]"); } } } } else if (dataType == 14) { Dictionary <string, WorldCoordinate> log = dataReader.ReadStarCelestialLog(); log.TryGetValue("loc", out this.client.playerData.loc); if (!log.TryGetValue("home", out this.client.playerData.home)) { this.client.playerData.home = this.client.playerData.loc; } StarryboundServer.logDebug("ClientContext", "[" + this.client.playerData.client + "] CurLoc:[" + this.client.playerData.loc.ToString() + "][" + this.client.playerData.inPlayerShip + "]"); StarryboundServer.logDebug("ClientContext", "[" + this.client.playerData.client + "] CurHome:[" + this.client.playerData.home.ToString() + "]"); } } } } } } catch (Exception e) { StarryboundServer.logDebug("ClientContext", "[" + this.client.playerData.client + "] Failed to parse ClientContextUpdate from Server: " + e.ToString()); } } else if (packetID == Packet.EntityCreate) { MemoryStream sendStream = new MemoryStream(); BinaryWriter sendWriter = new BinaryWriter(sendStream); bool test = true; while (true) { EntityType type = (EntityType)packetData.Read(); if (type == EntityType.EOF) { break; } byte[] entityData = packetData.ReadStarByteArray(); int entityId = packetData.ReadVarInt32(); if (type == EntityType.Player) { byte[] buffer = new byte[16]; Buffer.BlockCopy(entityData, 0, buffer, 0, 16); buffer = Utils.HashUUID(buffer); Buffer.BlockCopy(buffer, 0, entityData, 0, 16); returnData = test = false; } sendWriter.Write((byte)type); sendWriter.WriteVarUInt64((ulong)entityData.Length); sendWriter.Write(entityData); sendWriter.WriteVarInt32(entityId); } if (test == false) { this.outgoing.WriteVarUInt32((uint)packetID); this.outgoing.WriteVarInt32((int)sendStream.Length); this.outgoing.Write(sendStream.ToArray()); this.outgoing.Flush(); } } } #endregion } //Check return data if (returnData is Boolean) { if ((Boolean)returnData == false) { continue; } } else if (returnData is int) { if ((int)returnData == -1) { this.client.forceDisconnect(direction, "Command processor requested to drop client"); return; } } #region Forward Packet //Write data to dest this.outgoing.WriteVarUInt32((uint)packetID); if (compressed) { this.outgoing.WriteVarInt32(-packetSize); this.outgoing.Write(dataBuffer, 0, packetSize); } else { this.outgoing.WriteVarInt32(packetSize); this.outgoing.Write(dataBuffer, 0, packetSize); } this.outgoing.Flush(); #endregion #region Inject from Packet Queue var chatbuffer = this.client.packetQueue; foreach (Packet11ChatSend chatPacket in chatbuffer) { chatPacket.onSend(); } this.client.packetQueue = new List <Packet11ChatSend>(); #endregion //If disconnect was forwarded to client, lets disconnect. if (packetID == Packet.ServerDisconnect && direction == Direction.Server) { this.client.closeConnection(); } } } catch (ThreadAbortException) { } catch (EndOfStreamException) { this.client.forceDisconnect(direction, "End of stream"); } catch (Exception e) { if (e.InnerException != null) { if (e.InnerException is System.Net.Sockets.SocketException) { this.client.forceDisconnect(direction, e.InnerException.Message); return; } } this.client.forceDisconnect(direction, "ForwardThread Exception: " + e.ToString()); } }
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; } }