private byte[] ReplaceIPAdresses(byte[] bytes) { // skip start information for (int k = 10; k < bytes.Length - 3; k++) { if (bytes[k] == 'K' && bytes[k + 1] == '0' && bytes[k + 2] == '4') { if (bytes[k + 3] != 'W') { k--; } var nickLength = bytes[k + 4]; var nickStart = k + 4 + 3; var nickEnd = nickStart + (nickLength << 1); var nick = GetUnicodeString(bytes, nickStart, nickEnd); var stats = CoreContext.MasterServer.GetStatsInfo(nick); var id = new CSteamID(stats.SteamId); var pointStart = nickEnd + 7; bytes[pointStart++] = 127; bytes[pointStart++] = 0; bytes[pointStart++] = 0; bytes[pointStart++] = 1; var port = PortBindingManager.AddOrUpdatePortBinding(id).Port; CoreContext.OpenLogsService.Log($"Replace player port [{GetNickHash(nick)}] to {port}"); var portBytes = BitConverter.IsLittleEndian ? BitConverter.GetBytes(port).Reverse().ToArray() : BitConverter.GetBytes(port); bytes[pointStart++] = portBytes[1]; bytes[pointStart++] = portBytes[0]; k += nickLength + 4 + 6; } } return(bytes); }
private async Task <byte[]> HandleGamelobbyRequest(byte[] bytes) { var nicks = new List <string>(); // skip start information for (int k = 10; k < bytes.Length - 3; k++) { if (bytes[k] == 'K' && bytes[k + 1] == '0' && bytes[k + 2] == '4') { if (bytes[k + 3] != 'W') { k--; } var nickLength = bytes[k + 4]; var nickStart = k + 4 + 3; var nickEnd = nickStart + (nickLength << 1); var nick = GetUnicodeString(bytes, nickStart, nickEnd); if (!IdByNicksCache.ContainsKey(nick)) { nicks.Add(GetUnicodeString(bytes, nickStart, nickEnd)); } k += nickLength + 4 + 6; } } if (nicks.Count > 0) { await LoadSteamIds(nicks); } // skip start information for (int k = 50; k < bytes.Length - 3; k++) { if (bytes[k] == 'K' && bytes[k + 1] == '0' && bytes[k + 2] == '4') { if (bytes[k + 3] != 'W') { k--; } var nickLength = bytes[k + 4]; var nickStart = k + 4 + 3; var nickEnd = nickStart + (nickLength << 1); var nick = GetUnicodeString(bytes, nickStart, nickEnd); if (IdByNicksCache.TryGetValue(nick, out CSteamID id)) { var pointStart = nickEnd + 7; bytes[pointStart++] = 127; bytes[pointStart++] = 0; bytes[pointStart++] = 0; bytes[pointStart++] = 1; var port = PortBindingManager.AddOrUpdatePortBinding(id).Port; var portBytes = BitConverter.IsLittleEndian ? BitConverter.GetBytes(port).Reverse().ToArray() : BitConverter.GetBytes(port); bytes[pointStart++] = portBytes[1]; bytes[pointStart++] = portBytes[0]; } else { throw new Exception("Unknown player nick - " + nick); } k += nickLength + 4 + 6; } } return(bytes); }
/*public static ulong[] RegisteredIds => new ulong[] * { * 76561198408785287ul, // Favelin * 76561198001658409ul, // elamaunt * 76561198064050301ul, // SunRay * 76561198137977374ul, // Anibus * * 76561198011215928ul, // Bukan1 * 76561198005325871ul, // Bukan2 * * 76561198858224000ul, // Igor_kocerev * 76561198233237924ul, // Flashbang * 76561198855597623ul, // onebillygrimm * 76561198856913976ul, // Jabka_X * 76561198174310885ul, // Mizopolak * 76561198842926724ul, // veloziraptor * 76561198098129338ul, // DAG05 Simon * 76561198021093802ul, // ki4a * 76561198072623723ul, // Master Yoba * 76561198137292489ul, // ZADGE * 76561198116829514ul, // Maugan Ra * 76561198036915935ul, // SorroWfuL LivED * 76561198143540732ul, // YbuBaKa * 76561198981516933ul, // Cg_JGHAMO * 76561198003604494ul, // Gigamok * 76561198360256453ul, // Gedeon * 76561198225092112ul, // vladirus * 76561198090267618ul, // deREXte * 76561198027618614ul, // Sm0kEZ * 76561198107179356ul, // Made in USSR * 76561198132447203ul, // Dolorosa * 76561198386642785ul // Super_cega * };*/ private void OnRender(object sender, EventArgs e) { GameServer.RunCallbacks(); SteamAPI.RunCallbacks(); PortBindingManager.UpdateFrame(); }
public Task LaunchGameAndWait() { return(Task.Factory.StartNew(async() => { ProcessManager.KillAllGameProccessesWithoutWindow(); if (ProcessManager.GameIsRunning()) { throw new Exception("Game is running"); } if (!PathFinder.IsPathFound()) { throw new Exception("Path to game not found in Steam"); } IPHostEntry entry = null; try { entry = Dns.GetHostEntry("gamespygp"); } catch (Exception) { FixHosts(); } if (entry != null) { var address = IPAddress.Parse(GameConstants.SERVER_ADDRESS); if (!entry.AddressList.Any(x => x.Equals(address))) { FixHosts(); } } var tcs = new TaskCompletionSource <Process>(); try { Task.Factory.StartNew(() => { while (!tcs.Task.IsCompleted) { GameServer.RunCallbacks(); SteamAPI.RunCallbacks(); PortBindingManager.UpdateFrame(); Thread.Sleep(5); } }, TaskCreationOptions.LongRunning); var exeFileName = Path.Combine(LauncherPath, "GameFiles", "Patch1.2", "Soulstorm.exe"); var procParams = "-nomovies -forcehighpoly"; if (AppSettings.ThunderHawkModAutoSwitch) { procParams += " -modname ThunderHawk"; } var ssProc = Process.Start(new ProcessStartInfo(exeFileName, procParams) { UseShellExecute = true, WorkingDirectory = PathFinder.GamePath }); ServerContext.Start(IPAddress.Any); ssProc.EnableRaisingEvents = true; Task.Run(() => RemoveFogLoop(tcs.Task, ssProc)); ssProc.Exited += (s, e) => { tcs.TrySetResult(ssProc); }; } catch (Exception ex) { Logger.Error(ex); tcs.TrySetException(ex); } await tcs.Task; ServerContext.Stop(); }).Unwrap()); }
private static byte[] PackServerList(SocketState state, IEnumerable <Data.GameServer> servers, string[] fields, bool isAutomatch) { IPEndPoint remoteEndPoint = ((IPEndPoint)state.Socket.RemoteEndPoint); List <byte> data = new List <byte>(); data.AddRange(remoteEndPoint.Address.GetAddressBytes()); byte[] value2 = BitConverter.GetBytes((ushort)remoteEndPoint.Port); data.AddRange(BitConverter.IsLittleEndian ? value2.Reverse() : value2); if (fields.Length == 1 && fields[0] == "\u0004") { fields = new string[0]; } data.Add((byte)fields.Length); data.Add(0); foreach (var field in fields) { data.AddRange(Encoding.UTF8.GetBytes(field)); data.AddRange(new byte[] { 0, 0 }); } PortBindingManager.ClearPortBindings(); foreach (var server in servers) { if (server.Properties.TryGetValue("gamename", out string gamename)) { if (isAutomatch && gamename != "whamdowfram") { continue; } if (!isAutomatch && gamename != "whamdowfr") { continue; } } // commented this stuff out since it caused some issues on testing, might come back to it later and see what's happening... // NAT traversal stuff... // 126 (\x7E) = public ip / public port / private ip / private port / icmp ip // 115 (\x73) = public ip / public port / private ip / private port // 85 (\x55) = public ip / public port // 81 (\x51) = public ip / public port var localip0 = server.Get <string>("localip0"); ushort localport = ushort.Parse(server.Get <string>("localport") ?? "0"); var queryPort = (ushort)server.Get <int>("QueryPort"); var iPAddress = server.Get <string>("IPAddress"); var retranslator = PortBindingManager.AddOrUpdatePortBinding(server.HostSteamId); retranslator.AttachedServer = server; ushort retranslationPort = retranslator.Port; var channelHash = ChatCrypt.PiStagingRoomHash("127.0.0.1", "127.0.0.1", retranslationPort); // start connection establishment SteamNetworking.SendP2PPacket(server.HostSteamId, new byte[] { 0 }, 1, EP2PSend.k_EP2PSendReliable, 1); IDByChannelCache[channelHash] = server.HostSteamId; ChannelByIDCache[server.HostSteamId] = channelHash; var retranslationPortBytes = BitConverter.IsLittleEndian ? BitConverter.GetBytes(retranslationPort).Reverse() : BitConverter.GetBytes(retranslationPort); server["hostport"] = retranslationPort.ToString(); server["localport"] = retranslationPort.ToString(); var flags = ServerFlags.UNSOLICITED_UDP_FLAG | ServerFlags.PRIVATE_IP_FLAG | ServerFlags.NONSTANDARD_PORT_FLAG | ServerFlags.NONSTANDARD_PRIVATE_PORT_FLAG | ServerFlags.HAS_KEYS_FLAG; var loopbackIpBytes = IPAddress.Loopback.GetAddressBytes(); data.Add((byte)flags); data.AddRange(loopbackIpBytes); data.AddRange(retranslationPortBytes); data.AddRange(loopbackIpBytes); data.AddRange(retranslationPortBytes); data.Add(255); for (int i = 0; i < fields.Length; i++) { var name = fields[i]; var f = GetField(server, name); data.AddRange(Encoding.UTF8.GetBytes(f)); if (i < fields.Length - 1) { data.Add(0); data.Add(255); } } data.Add(0); } data.Add(0); data.Add(255); data.Add(255); data.Add(255); data.Add(255); return(data.ToArray()); }
private unsafe void OnGameDataReceived(IAsyncResult async) { SocketState state = (SocketState)async.AsyncState; if (state == null || state.GameSocket == null || !state.GameSocket.Connected) { return; } try { // receive data from the socket int received = state.GameSocket.EndReceive(async); if (received == 0) { return; } var buffer = state.GameBuffer; using (var ms = new MemoryStream(buffer, 0, received)) { if (!state.SendingEncoded) { using (var reader = new StreamReader(ms)) { var asciValue = reader.ReadToEnd(); Log("CHATDATA", asciValue); ms.Position = 0; var line = reader.ReadLine(); if (line.StartsWith("CRYPT")) { state.SendingEncoded = true; /*if (line.Contains("whammer40kdc")) * { * Gamename = "whammer40kdc".ToAssciiBytes(); * Gamekey = "Ue9v3H".ToAssciiBytes(); * }*/ if (line.Contains("whamdowfr")) { Gamename = "whamdowfr".ToAssciiBytes(); Gamekey = "pXL838".ToAssciiBytes(); } if (Gamekey == null) { state.Dispose(); return; } var chall = "0000000000000000".ToAssciiBytes(); var receivingGameKey = new ChatCrypt.GDCryptKey(); var sendingGameKey = new ChatCrypt.GDCryptKey(); var receivingServerKey = new ChatCrypt.GDCryptKey(); var sendingServerKey = new ChatCrypt.GDCryptKey(); fixed(byte *challPtr = chall) { fixed(byte *gamekeyPtr = Gamekey) { ChatCrypt.GSCryptKeyInit(receivingGameKey, challPtr, gamekeyPtr, Gamekey.Length); ChatCrypt.GSCryptKeyInit(sendingGameKey, challPtr, gamekeyPtr, Gamekey.Length); ChatCrypt.GSCryptKeyInit(receivingServerKey, challPtr, gamekeyPtr, Gamekey.Length); ChatCrypt.GSCryptKeyInit(sendingServerKey, challPtr, gamekeyPtr, Gamekey.Length); } } state.ReceivingGameKey = receivingGameKey; state.SendingGameKey = sendingGameKey; state.ReceivingServerKey = receivingServerKey; state.SendingServerKey = sendingServerKey; // Send to server without encoding _serverSocket.Send(buffer, received, SocketFlags.None); } else { // Send to server without encoding _serverSocket.Send(buffer, received, SocketFlags.None); } } } else { using (var reader = new BinaryReader(ms, Encoding.ASCII)) { var start = ms.Position; var bytes = reader.ReadBytes((int)(ms.Length - ms.Position)); if (state.SendingEncoded) { byte *bytesPtr = stackalloc byte[bytes.Length]; for (int i = 0; i < bytes.Length; i++) { bytesPtr[i] = bytes[i]; } ChatCrypt.GSEncodeDecode(state.ReceivingGameKey, bytesPtr, bytes.Length); for (int i = 0; i < bytes.Length; i++) { bytes[i] = bytesPtr[i]; } } var utf8value = Encoding.UTF8.GetString(bytes); Log("CHATDATA", utf8value); if (utf8value.StartsWith("LOGIN", StringComparison.OrdinalIgnoreCase)) { var nick = utf8value.Split(' ')[2]; ChatNick = nick; SendToServerSocket(ref state, bytes); goto CONTINUE; } if (utf8value.StartsWith("USRIP", StringComparison.OrdinalIgnoreCase)) { SendToServerSocket(ref state, bytes); goto CONTINUE; } var hostAddressIndex = utf8value.IndexOf(HOST_ADDRESS_TOKEN, StringComparison.OrdinalIgnoreCase); if (hostAddressIndex != -1) { var port = CutPortValue(utf8value, hostAddressIndex + HOST_ADDRESS_TOKEN.Length, out string portString); port = ByteHelpers.ReverseEndian16(port); var hostSteamId = PortBindingManager.GetSteamIdByPort(port); if (!hostSteamId.HasValue) { port = ByteHelpers.ReverseEndian16(port); hostSteamId = PortBindingManager.GetSteamIdByPort(port); } if (hostSteamId.HasValue) { utf8value = utf8value.Replace(HOST_ADDRESS_TOKEN + portString, HOST_ADDRESS_TOKEN + hostSteamId.Value.m_SteamID); } } var index = utf8value.IndexOf("#GSP!whamdowfr!", StringComparison.OrdinalIgnoreCase); if (index != -1) { var encodedEndPoint = utf8value.Substring(index + 15, 10); CSteamID steamId; if (ServerListReport.CurrentUserRoomHash == encodedEndPoint) { steamId = SteamUser.GetSteamID(); } else { if (!ServerListRetrieve.IDByChannelCache.TryGetValue(encodedEndPoint, out steamId)) { ServerListReport.CurrentUserRoomHash = encodedEndPoint; steamId = SteamUser.GetSteamID(); } } utf8value = utf8value.Replace(encodedEndPoint, steamId.m_SteamID.ToString()); SendToServerSocket(ref state, Encoding.UTF8.GetBytes(utf8value)); goto CONTINUE; } // 16777343 ~ 1.0.0.127 inversed port 63349 port // :QWEQWE!X44vf1Wf1X|[email protected] PRIVMSG elamaunt :ACTION 7; 16777343; 63349; 16777343; 63349; 1; SendToServerSocket(ref state, bytes); } } } } catch (ObjectDisposedException) { if (state != null) { state.Dispose(); } state = null; return; } catch (SocketException e) { switch (e.SocketErrorCode) { case SocketError.ConnectionReset: if (state != null) { state.Dispose(); } state = null; return; case SocketError.Disconnecting: if (state != null) { state.Dispose(); } state = null; return; default: LogError(Category, "Error receiving data"); LogError(Category, String.Format("{0} {1}", e.SocketErrorCode, e)); if (state != null) { state.Dispose(); } state = null; return; } } catch (Exception e) { LogError(Category, "Error receiving data"); LogError(Category, e.ToString()); } // and we wait for more data... CONTINUE : WaitForGameData(state); }
private unsafe void OnServerDataReceived(IAsyncResult async) { SocketState state = (SocketState)async.AsyncState; if (state == null || _serverSocket == null || !_serverSocket.Connected || state.GameSocket == null || !state.GameSocket.Connected) { return; } try { // receive data from the socket int received = _serverSocket.EndReceive(async); if (received == 0) { return; } var bytes = new byte[received]; for (int i = 0; i < received; i++) { bytes[i] = state.ServerBuffer[i]; } if (state.ReceivingEncoded) { fixed(byte *bytesToSendPtr = bytes) ChatCrypt.GSEncodeDecode(state.ReceivingServerKey, bytesToSendPtr, received); } var utf8value = Encoding.UTF8.GetString(bytes); Log(Category, utf8value); if (utf8value.StartsWith(":s 705", StringComparison.OrdinalIgnoreCase)) { SendToGameSocket(ref state, bytes); state.ReceivingEncoded = true; goto CONTINUE; } if (utf8value.IndexOf($@"UTM #GSP!whamdowfr!", StringComparison.OrdinalIgnoreCase) != -1) { ProcessHelper.RestoreGameWindow(); } if (utf8value.StartsWith("ROOMCOUNTERS", StringComparison.OrdinalIgnoreCase)) { var values = utf8value.Split(new string[] { "ROOMCOUNTERS", " ", "\r\n" }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < ChatRoomPlayersCounts.Length; i++) { ChatRoomPlayersCounts[i] = 0; } for (int i = 0; i < values.Length; i += 2) { var roomIndex = values[i]; var count = values[i + 1]; ChatRoomPlayersCounts[int.Parse(roomIndex) - 1] = int.Parse(count); } goto CONTINUE; } var index = utf8value.IndexOf("#GSP!whamdowfr!", StringComparison.OrdinalIgnoreCase); if (index != -1) { int endIndex = index + 15; for (; endIndex < utf8value.Length; endIndex++) { if (!char.IsDigit(utf8value[endIndex])) { break; } } var stringSteamId = utf8value.Substring(index + 15, endIndex - index - 15); var steamId = new CSteamID(ulong.Parse(stringSteamId)); if (steamId != SteamUser.GetSteamID()) { if (ServerListRetrieve.ChannelByIDCache.TryGetValue(steamId, out string roomHash)) { utf8value = utf8value.Replace(stringSteamId, ServerListRetrieve.ChannelByIDCache[steamId]); } else { utf8value = utf8value.Replace(stringSteamId, ServerListReport.CurrentUserRoomHash); } } else { utf8value = utf8value.Replace(stringSteamId, ServerListReport.CurrentUserRoomHash); } SendToGameSocket(ref state, Encoding.UTF8.GetBytes(utf8value)); goto CONTINUE; } var hostAddressIndex = utf8value.IndexOf(HOST_ADDRESS_TOKEN, StringComparison.OrdinalIgnoreCase); if (hostAddressIndex != -1) { var steamIdValue = CutULongValue(utf8value, hostAddressIndex + HOST_ADDRESS_TOKEN.Length, out string idString); if (steamIdValue <= 65536) { return; } var hostSteamId = new CSteamID(steamIdValue); var port = PortBindingManager.AddOrUpdatePortBinding(hostSteamId).Port; utf8value = utf8value.Replace(HOST_ADDRESS_TOKEN + idString, HOST_ADDRESS_TOKEN + port.ToString()); SendToGameSocket(ref state, Encoding.UTF8.GetBytes(utf8value)); goto CONTINUE; } SendToGameSocket(ref state, bytes); } catch (Exception e) { LogError(Category, "Error receiving data"); LogError(Category, e.ToString()); } // and we wait for more data... CONTINUE : WaitForServerData(state); }
private bool ParseServerDetails(IPEndPoint remote, byte[] data) { string receivedData = Encoding.UTF8.GetString(data); //Console.WriteLine(receivedData.Replace("\x00", "\\x00").Replace("\x02", "\\x02")); // split by 000 (info/player separator) and 002 (players/teams separator) // the players/teams separator is really 00, but because 00 may also be used elsewhere (an empty value for example), we hardcode it to 002 // the 2 is the size of the teams, for BF2 this is always 2. string[] sections = receivedData.Split(new string[] { "\x00\x00\x00", "\x00\x00\x02" }, StringSplitOptions.None); //Console.WriteLine(sections.Length); if (sections.Length != 3 && !receivedData.EndsWith("\x00\x00")) { return(true); // true means we don't send back a response } string serverVars = sections[0]; //string playerVars = sections[1]; //string teamVars = sections[2]; string[] serverVarsSplit = serverVars.Split(new string[] { "\x00" }, StringSplitOptions.None); var server = new GameServer(); server["IPAddress"] = remote.Address.ToString(); server["QueryPort"] = remote.Port.ToString(); server["LastRefreshed"] = DateTime.UtcNow.ToString(); server["LastPing"] = DateTime.UtcNow.ToString(); server["country"] = "??"; for (int i = 0; i < serverVarsSplit.Length - 1; i += 2) { if (serverVarsSplit[i] == "hostname") { server.Set(serverVarsSplit[i], Regex.Replace(serverVarsSplit[i + 1], @"\s+", " ").Trim()); } else { server.Set(serverVarsSplit[i], serverVarsSplit[i + 1]); } } var gamename = server.Get <string>("gamename"); if (server.Get <string>("statechanged") == "3" && gamename.Equals("whamdowfram", StringComparison.Ordinal)) { ServerContext.ChatServer.SentServerMessageToClient("Вы создаете хост для игры в авто. Другие игроки увидят ваш хост через некоторое время (до минуты), получат оповещение и смогут подключиться для игры.\n\r"); } server["hostport"] = remote.Port.ToString(); server["localport"] = remote.Port.ToString(); var gamevariant = server.Get <string>("gamevariant"); /*if (!gamevariant.IsNullOrWhiteSpace()) * { * if (gamevariant != SteamConstants.GameVariant) * { * ServerContext.ChatServer.SentServerMessageToClient("Вы используете не ту версию модификации. Вам необходимо использовать Soulstorm Bugfix Mod 1.56a.\r\n"); * } * }*/ // you've got to have all these properties in order for your server to be valid if (!String.IsNullOrWhiteSpace(server.Get <string>("hostname")) && !String.IsNullOrWhiteSpace(gamevariant) && !String.IsNullOrWhiteSpace(server.Get <string>("gamever")) && !String.IsNullOrWhiteSpace(server.Get <string>("gametype")) && server.Get <string>("maxplayers") != "0") { server.Valid = true; } // if the server list doesn't contain this server, we need to return false in order to send a challenge // if the server replies back with the good challenge, it'll be added in AddValidServer if (!SteamLobbyManager.IsInLobbyNow) { return(false); } if (server.Properties.TryGetValue("statechanged", out string value)) { var strValue = value?.ToString(); if (strValue == "2") { SteamLobbyManager.LeaveFromCurrentLobby(); return(true); } } PortBindingManager.ClearPortBindings(); var wasJoinable = SteamLobbyManager.IsLobbyJoinable; SteamLobbyManager.UpdateCurrentLobby(server, CoreContext.ThunderHawkModManager.ActiveModRevision); if (!wasJoinable && SteamLobbyManager.IsLobbyJoinable) { var hostname = server.Get <string>("hostname"); if (gamename == "whamdowfram") { ServerContext.ChatServer.SendAutomatchGameBroadcast(hostname, int.Parse(server.Get <string>("maxplayers"))); } } return(true); }