private void ReceivePong(IncomingPacket packet) { ushort answerId = NetUtil.N2Hushort(packet.Data, 0); OutgoingPacket sendPing; lock (sendLoopLock) { if (!packetPingManager.TryGetValue(answerId, out sendPing)) { return; } packetPingManager.Remove(answerId); } NetworkStats.AddPing(Util.Now - sendPing.LastSendTime); }
/// <summary>TS3 uses a new key and nonce for each packet sent and received. This method generates and caches these.</summary> /// <param name="fromServer">True if the packet is from server to client, false for client to server.</param> /// <param name="packetId">The id of the packet, host order.</param> /// <param name="generationId">Each time the packetId reaches 65535 the next packet will go on with 0 and the generationId will be increased by 1.</param> /// <param name="packetType">The packetType.</param> /// <returns>A tuple of (key, nonce)</returns> private Tuple <byte[], byte[]> GetKeyNonce(bool fromServer, ushort packetId, uint generationId, PacketType packetType) { if (!CryptoInitComplete) { return(DummyKeyAndNonceTuple); } // only the lower 4 bits are used for the real packetType byte packetTypeRaw = (byte)packetType; int cacheIndex = packetTypeRaw * (fromServer ? 1 : 2); if (cachedKeyNonces[cacheIndex] == null || cachedKeyNonces[cacheIndex].Item3 != generationId) { // this part of the key/nonce is fixed by the message direction and packetType byte[] tmpToHash = new byte[26]; if (fromServer) { tmpToHash[0] = 0x30; } else { tmpToHash[0] = 0x31; } tmpToHash[1] = packetTypeRaw; Array.Copy(BitConverter.GetBytes(NetUtil.H2N(generationId)), 0, tmpToHash, 2, 4); Array.Copy(ivStruct, 0, tmpToHash, 6, 20); var result = Hash256It(tmpToHash); cachedKeyNonces[cacheIndex] = new Tuple <byte[], byte[], uint>(result.Slice(0, 16).ToArray(), result.Slice(16, 16).ToArray(), generationId); } byte[] key = new byte[16]; byte[] nonce = new byte[16]; Array.Copy(cachedKeyNonces[cacheIndex].Item1, 0, key, 0, 16); Array.Copy(cachedKeyNonces[cacheIndex].Item2, 0, nonce, 0, 16); // finally the first two bytes get xor'd with the packet id key[0] ^= (byte)((packetId >> 8) & 0xFF); key[1] ^= (byte)((packetId) & 0xFF); return(new Tuple <byte[], byte[]>(key, nonce)); }
private void ReceivePing(S2CPacket packet) { var idDiff = packet.PacketId - lastReceivedPingId; if (idDiff > 1 && idDiff < ReceivePacketWindowSize) { NetworkStats.LogLostPings(idDiff - 1); } if (idDiff > 0 || idDiff < -ReceivePacketWindowSize) { lastReceivedPingId = packet.PacketId; } byte[] pongData = new byte[2]; NetUtil.H2N(packet.PacketId, pongData, 0); AddOutgoingPacket(pongData, PacketType.Pong); }
private S2CPacket ReceiveAck(S2CPacket packet) { if (packet.Data.Length < 2) { return(null); } ushort packetId = NetUtil.N2Hushort(packet.Data, 0); lock (sendLoopLock) { if (packetAckManager.TryGetValue(packetId, out var ackPacket)) { UpdateRto(Util.Now - ackPacket.LastSendTime); packetAckManager.Remove(packetId); } } return(packet); }
public void SendAudioGroupWhisper(ReadOnlySpan <byte> data, Codec codec, GroupWhisperType type, GroupWhisperTarget target, ulong targetId = 0) { // [X,X,Y,N,M,U,U,U,U,U,U,U,U,DATA] // > X is a ushort in H2N order of an own audio packet counter // it seems it can be the same as the packet counter so we will let the packethandler do it. // > Y is the codec byte (see Enum) // > N is a byte, specifying the GroupWhisperType // > M is a byte, specifying the GroupWhisperTarget // > U is a ulong in H2N order for the targeted channelId or groupId (0 if not applicable) byte[] tmpBuffer = new byte[data.Length + 13]; tmpBuffer[2] = (byte)codec; tmpBuffer[3] = (byte)type; tmpBuffer[4] = (byte)target; NetUtil.H2N(targetId, tmpBuffer, 5); data.CopyTo(new Span <byte>(tmpBuffer, 13)); packetHandler.AddOutgoingPacket(tmpBuffer, PacketType.VoiceWhisper, PacketFlags.Newprotocol); }
internal IncomingPacket Decrypt(byte[] data) { if (data.Length < InHeaderLen + MacLen) { return(null); } var packet = new IncomingPacket(data) { PacketTypeFlagged = data[MacLen + 2], PacketId = NetUtil.N2Hushort(data, MacLen), }; if (packet.PacketType == PacketType.Init1) { if (!FakeDecrypt(packet, TS3InitMac)) { return(null); } } else { if (packet.UnencryptedFlag) { if (!FakeDecrypt(packet, fakeSignature)) { return(null); } } else { if (!Decrypt(packet)) { return(null); } } } return(packet); }
private void ReceivePing(IncomingPacket packet) { byte[] pongData = new byte[2]; NetUtil.H2N(packet.PacketId, pongData, 0); AddOutgoingPacket(pongData, PacketType.Pong); }
public void BuildHeader() { NetUtil.H2N(PacketId, Header, 0); NetUtil.H2N(ClientId, Header, 2); Header[4] = PacketTypeFlagged; }
public S2CPacket FetchPacket() { while (true) { if (Closed) { return(null); } if (TryFetchPacket(receiveQueue, out var packet)) { return(packet); } if (TryFetchPacket(receiveQueueLow, out packet)) { return(packet); } var dummy = new IPEndPoint(IPAddress.Any, 0); byte[] buffer; try { buffer = udpClient.Receive(ref dummy); } catch (IOException) { return(null); } catch (SocketException) { return(null); } if (dummy.Address.Equals(remoteAddress.Address) && dummy.Port != remoteAddress.Port) { continue; } packet = Ts3Crypt.GetIncommingPacket(buffer); // Invalid packet, ignore if (packet == null) { LoggerRaw.Debug("Dropping invalid packet: {0}", DebugUtil.DebugToHex(buffer)); continue; } GenerateGenerationId(packet); if (!ts3Crypt.Decrypt(packet)) { continue; } NetworkStats.LogInPacket(packet); switch (packet.PacketType) { case PacketType.Voice: case PacketType.VoiceWhisper: LoggerRawVoice.ConditionalTrace("[I] {0}", packet); break; case PacketType.Command: LoggerRaw.Debug("[I] {0}", packet); packet = ReceiveCommand(packet, receiveQueue, PacketType.Ack); break; case PacketType.CommandLow: LoggerRaw.Debug("[I] {0}", packet); packet = ReceiveCommand(packet, receiveQueueLow, PacketType.AckLow); break; case PacketType.Ping: LoggerRaw.ConditionalTrace("[I] Ping {0}", packet.PacketId); ReceivePing(packet); break; case PacketType.Pong: LoggerRaw.ConditionalTrace("[I] Pong {0}", NetUtil.N2Hushort(packet.Data, 0)); ReceivePong(packet); break; case PacketType.Ack: LoggerRaw.ConditionalDebug("[I] Acking: {0}", NetUtil.N2Hushort(packet.Data, 0)); packet = ReceiveAck(packet); break; case PacketType.AckLow: break; case PacketType.Init1: LoggerRaw.Debug("[I] InitID: {0}", packet.Data[0]); LoggerRaw.Trace("[I] {0}", packet); ReceiveInitAck(packet); break; default: throw Util.UnhandledDefault(packet.PacketType); } if (packet != null) { return(packet); } } }
private void SendOutgoingData(ReadOnlySpan <byte> data, PacketType packetType, PacketFlags flags = PacketFlags.None) { var packet = new C2SPacket(data.ToArray(), packetType); lock (sendLoopLock) { var ids = GetPacketCounter(packet.PacketType); if (ts3Crypt.CryptoInitComplete) { IncPacketCounter(packet.PacketType); } packet.PacketId = ids.Id; packet.GenerationId = ids.Generation; packet.ClientId = ClientId; packet.PacketFlags |= flags; switch (packet.PacketType) { case PacketType.Voice: case PacketType.VoiceWhisper: packet.PacketFlags |= PacketFlags.Unencrypted; NetUtil.H2N(packet.PacketId, packet.Data, 0); LoggerRawVoice.ConditionalTrace("[O] {0}", packet); break; case PacketType.Command: case PacketType.CommandLow: packet.PacketFlags |= PacketFlags.Newprotocol; packetAckManager.Add(packet.PacketId, packet); LoggerRaw.Debug("[O] {0}", packet); break; case PacketType.Ping: lastSentPingId = packet.PacketId; packet.PacketFlags |= PacketFlags.Unencrypted; LoggerRaw.ConditionalTrace("[O] Ping {0}", packet.PacketId); break; case PacketType.Pong: packet.PacketFlags |= PacketFlags.Unencrypted; LoggerRaw.ConditionalTrace("[O] Pong {0}", NetUtil.N2Hushort(packet.Data, 0)); break; case PacketType.Ack: case PacketType.AckLow: LoggerRaw.ConditionalDebug("[O] Acking {1}: {0}", NetUtil.N2Hushort(packet.Data, 0), packet.PacketType); break; case PacketType.Init1: packet.PacketFlags |= PacketFlags.Unencrypted; initPacketCheck = packet; LoggerRaw.Debug("[O] InitID: {0}", packet.Data[4]); LoggerRaw.Trace("[O] {0}", packet); break; default: throw Util.UnhandledDefault(packet.PacketType); } ts3Crypt.Encrypt(packet); packet.FirstSendTime = Util.Now; SendRaw(packet); } }
private void AddOutgoingPacket(OutgoingPacket packet, PacketFlags flags = PacketFlags.None) { lock (sendLoopLock) { var ids = GetPacketCounter(packet.PacketType); if (ts3Crypt.CryptoInitComplete) { IncPacketCounter(packet.PacketType); } packet.PacketId = ids.Id; packet.GenerationId = ids.Generation; packet.ClientId = ClientId; packet.PacketFlags |= flags; switch (packet.PacketType) { case PacketType.Voice: case PacketType.VoiceWhisper: packet.PacketFlags |= PacketFlags.Unencrypted; NetUtil.H2N(packet.PacketId, packet.Data, 0); break; case PacketType.Command: case PacketType.CommandLow: packet.PacketFlags |= PacketFlags.Newprotocol; packetAckManager.Add(packet.PacketId, packet); break; case PacketType.Ping: lastSentPingId = packet.PacketId; packet.PacketFlags |= PacketFlags.Unencrypted; break; case PacketType.Pong: packet.PacketFlags |= PacketFlags.Unencrypted; break; case PacketType.Ack: case PacketType.AckLow: break; // Nothing to do case PacketType.Init1: packet.PacketFlags |= PacketFlags.Unencrypted; packetAckManager.Add(packet.PacketId, packet); break; default: throw Util.UnhandledDefault(packet.PacketType); } #if DIAGNOSTICS && DIAG_RAWPKG if (packet.PacketType != PacketType.Ping && packet.PacketType != PacketType.Pong) { Console.WriteLine($"[OT] {packet}"); } #endif ts3Crypt.Encrypt(packet); packet.FirstSendTime = Util.Now; SendRaw(packet); } }
internal byte[] ProcessInit1(byte[] data) { const int versionLen = 4; const int initTypeLen = 1; if (data == null) { var sendData = new byte[versionLen + initTypeLen + 4 + 4 + 8]; Array.Copy(Initversion, 0, sendData, 0, versionLen); // initVersion sendData[versionLen] = 0x00; // initType NetUtil.H2N(Util.UnixNow, sendData, versionLen + initTypeLen); // 4byte timestamp for (int i = 0; i < 4; i++) { sendData[i + versionLen + initTypeLen + 4] = (byte)Util.Random.Next(0, 256); // 4byte random } return(sendData); } if (data.Length < initTypeLen) { return(null); } int type = data[0]; if (type == 1) { var sendData = new byte[versionLen + initTypeLen + 16 + 4]; Array.Copy(Initversion, 0, sendData, 0, versionLen); // initVersion sendData[versionLen] = 0x02; // initType Array.Copy(data, 1, sendData, versionLen + initTypeLen, 20); return(sendData); } else if (type == 3) { byte[] alphaBytes = new byte[10]; Util.Random.NextBytes(alphaBytes); var alpha = Convert.ToBase64String(alphaBytes); string initAdd = Ts3Command.BuildToString("clientinitiv", new ICommandPart[] { new CommandParameter("alpha", alpha), new CommandParameter("omega", Identity.PublicKeyString), new CommandParameter("ip", string.Empty) }); var textBytes = Util.Encoder.GetBytes(initAdd); // Prepare solution int level = NetUtil.N2Hint(data, initTypeLen + 128); byte[] y = SolveRsaChallange(data, initTypeLen, level); // Copy bytes for this result: [Version..., InitType..., data..., y..., text...] var sendData = new byte[versionLen + initTypeLen + 232 + 64 + textBytes.Length]; // Copy this.Version Array.Copy(Initversion, 0, sendData, 0, versionLen); // Write InitType sendData[versionLen] = 0x04; // Copy data Array.Copy(data, initTypeLen, sendData, versionLen + initTypeLen, 232); // Copy y Array.Copy(y, 0, sendData, versionLen + initTypeLen + 232 + (64 - y.Length), y.Length); // Copy text Array.Copy(textBytes, 0, sendData, versionLen + initTypeLen + 232 + 64, textBytes.Length); return(sendData); } else { return(null); } }
private void NetworkLoop(object ctxObject) { var ctx = (ConnectionContext)ctxObject; while (true) { lock (statusLock) { if (ctx.WasExit) { break; } } var packet = packetHandler.FetchPacket(); if (packet == null) { break; } lock (statusLock) { if (ctx.WasExit) { break; } switch (packet.PacketType) { case PacketType.Command: case PacketType.CommandLow: string message = Util.Encoder.GetString(packet.Data, 0, packet.Data.Length); LogCmd.Debug("[I] {0}", message); var result = msgProc.PushMessage(message); if (result.HasValue) { dispatcher.Invoke(result.Value); } break; case PacketType.Voice: case PacketType.VoiceWhisper: OutStream?.Write(packet.Data, new Meta { In = new MetaIn { Whisper = packet.PacketType == PacketType.VoiceWhisper } }); break; case PacketType.Init1: // Init error if (packet.Data.Length == 5 && packet.Data[0] == 1) { var errorNum = NetUtil.N2Huint(packet.Data, 1); if (Enum.IsDefined(typeof(Ts3ErrorCode), errorNum)) { Log.Info("Got init error: {0}", (Ts3ErrorCode)errorNum); } else { Log.Warn("Got undefined init error: {0}", errorNum); } DisconnectInternal(ctx, setStatus: Ts3ClientStatus.Disconnected); } break; } } } lock (statusLock) { DisconnectInternal(ctx, setStatus: Ts3ClientStatus.Disconnected); } }
public override void BuildHeader() { NetUtil.H2N(PacketId, Header, 0); Header[2] = PacketTypeFlagged; }