public void FreshHello() { var connectionId = 15690248817103694251U; var packet = new RegularPacket(connectionId, 1, null); Assert.IsNotNull(packet.ConnectionId); packet.AddFrame(new StreamFrame(ClientHandshakeMessageTest.ClientInchoateGoogleFreshParametersClientMessageFactory.Value, false, 1, 0)); var packetBytes = packet.PadAndNullEncrypt(); Assert.IsNotNull(packet.MessageAuthenticationHash); Debug.WriteLine("Message authentication hash: " + packet.MessageAuthenticationHash.Select(b => b.ToString("x2")).Aggregate((c, n) => c + " " + n)); Debug.WriteLine(packetBytes.GenerateHexDumpWithASCII()); Assert.AreEqual(PacketLibrary.ClientInchoateGoogleFresh.Length, packetBytes.Length); // Soft warn for (var i = 0; i < packetBytes.Length; i++) { if (packetBytes[i] != PacketLibrary.ClientInchoateGoogleFresh[i]) Debug.WriteLine($"Byte difference at position {i}: generated byte is {packetBytes[i]:x2} but reference byte was {PacketLibrary.ClientInchoateGoogleFresh[i]:x2}"); } // Hard test fail for (var i = 0; i < packetBytes.Length; i++) Assert.AreEqual(PacketLibrary.ClientInchoateGoogleFresh[i], packetBytes[i], $"Byte difference at position {i}: generated byte is {packetBytes[i]:x2} but reference byte was {PacketLibrary.ClientInchoateGoogleFresh[i]:x2}"); // Now try to reverse engineer it to ensure packet parsing works. AbstractPacketBase rePacket; AbstractPacketBase.TryParse(packetBytes, out rePacket); Assert.IsNotNull(rePacket); Assert.IsInstanceOfType(rePacket, typeof(RegularPacket)); var rp = (RegularPacket)rePacket; Assert.AreEqual(rp.ConnectionId, packet.ConnectionId.Value); Assert.AreEqual(rp.Entropy, packet.Entropy); Assert.AreEqual(rp.FecGroup, packet.FecGroup); Assert.IsNotNull(rp.MessageAuthenticationHash); Assert.AreEqual(rp.MessageAuthenticationHash.Sum(b => (int)b), packet.MessageAuthenticationHash.Sum(b => (int)b)); Assert.AreEqual(rp.PacketNumber, packet.PacketNumber); var rpBytes = rp.ToByteArray(); //Debug.WriteLine(rpBytes.GenerateHexDumpWithASCII()); Assert.AreEqual(packetBytes.Length, rpBytes.Length); // Soft reverse engineering warn for (var i = 0; i < packetBytes.Length; i++) { if (packetBytes[i] != rpBytes[i]) Debug.WriteLine($"Byte difference at position {i}: generated byte is {rpBytes[i]:x2} but reference byte was {packetBytes[i]:x2}"); } // Hard test fail for (var i = 0; i < packetBytes.Length; i++) Assert.AreEqual(packetBytes[i], rpBytes[i], $"Byte difference at position {i}: generated byte is {rpBytes[i]:x2} but reference byte was {packetBytes[i]:x2}"); }
public async Task ConnectAsync(string hostname, int port, CancellationToken cancellationToken = default(CancellationToken)) { this._udpClient = new UdpClient(hostname, port); // Start listening this._receiveTask = Task.Run(async () => { while (!cancellationToken.IsCancellationRequested) { var received = await this._udpClient.ReceiveAsync(); Debug.WriteLine($"Received {received.Buffer.Length} bytes from {received.RemoteEndPoint}"); } }, cancellationToken); // Setup default destination of client this._udpClient.Connect(hostname, port); // Generate random connection ID var random = new Random(Environment.TickCount); var buffer = new byte[sizeof(long)]; random.NextBytes(buffer); var connectionId = BitConverter.ToUInt64(buffer, 0); var regularPacket = new RegularPacket(connectionId, 1, null); regularPacket.AddFrame(new StreamFrame(new ClientHandshakeMessage { { MessageTags.PAD, Enumerable.Repeat((byte)0x2d, 666).ToArray() }, { MessageTags.SNI, hostname }, { MessageTags.VER, QUIC_VERSION }, { MessageTags.CCS, new byte[] { 0x7b, 0x26, 0xe9, 0xe7, 0xe4, 0x5c, 0x71, 0xff, 0x01, 0xe8, 0x81, 0x60, 0x92, 0x92, 0x1a, 0xe8 } }, { MessageTags.MSPC, 100 }, { MessageTags.UAID, $"QuicDotNet/{Assembly.GetExecutingAssembly().GetName().Version} {System.Environment.OSVersion}" }, { MessageTags.TCID, 0 }, { MessageTags.PDMD, "X509" }, { MessageTags.SRBF, 1048576 }, { MessageTags.ICSL, 30 }, { MessageTags.SCLS, 1 }, { MessageTags.COPT, 1146636614 }, { MessageTags.IRTT, 9248 }, { MessageTags.CFCW, 15728640 }, { MessageTags.SFCW, 6291456 } }, false, 1, 0)); var bytesToSend = regularPacket.PadAndNullEncrypt(); await this._udpClient.SendAsync(bytesToSend, bytesToSend.Length); }
public static bool TryParse(byte[] packetBytes, out AbstractPacketBase packet) { var publicFlags = packetBytes[0]; var index = 1; var versionFlag = (publicFlags & (1 << 0)) != 0; var resetFlag = (publicFlags & (1 << 1)) != 0; var cidFlag1 = (publicFlags & (1 << 2)) != 0; var cidFlag2 = (publicFlags & (1 << 3)) != 0; var pnFlag1 = (publicFlags & (1 << 4)) != 0; var pnFlag2 = (publicFlags & (1 << 5)) != 0; ulong?connectionId; if (cidFlag1 && cidFlag2) { connectionId = BitConverter.ToUInt64(packetBytes, index); index += 8; } else if (!cidFlag1 && cidFlag2) { connectionId = BitConverter.ToUInt32(packetBytes, index); index += 4; } else if (cidFlag1) { connectionId = packetBytes[1]; index += 1; } else { connectionId = null; } uint?version; if (versionFlag) { version = BitConverter.ToUInt32(packetBytes, index); index += 4; } ulong packetNumber; if (pnFlag1 && pnFlag2) { var ba = new byte[8]; Array.Copy(packetBytes, index, ba, 2, 6); packetNumber = BitConverter.ToUInt64(ba, 0); index += 6; } else if (!pnFlag1 && pnFlag2) { packetNumber = BitConverter.ToUInt32(packetBytes, index); index += 4; } else if (pnFlag1) { packetNumber = BitConverter.ToUInt16(packetBytes, index); index += 2; } else { packetNumber = packetBytes[index]; index += 1; } var rp = new RegularPacket(connectionId, packetNumber, null); var payloadBytes = new byte[packetBytes.Length - index]; Array.Copy(packetBytes, index, payloadBytes, 0, payloadBytes.Length); rp.FromByteArray(payloadBytes); packet = rp; return(true); }
public static bool TryParse(byte[] packetBytes, out AbstractPacketBase packet) { var publicFlags = packetBytes[0]; var index = 1; var versionFlag = (publicFlags & (1 << 0)) != 0; var resetFlag = (publicFlags & (1 << 1)) != 0; var cidFlag1 = (publicFlags & (1 << 2)) != 0; var cidFlag2 = (publicFlags & (1 << 3)) != 0; var pnFlag1 = (publicFlags & (1 << 4)) != 0; var pnFlag2 = (publicFlags & (1 << 5)) != 0; ulong? connectionId; if (cidFlag1 && cidFlag2) { connectionId = BitConverter.ToUInt64(packetBytes, index); index += 8; } else if (!cidFlag1 && cidFlag2) { connectionId = BitConverter.ToUInt32(packetBytes, index); index += 4; } else if (cidFlag1) { connectionId = packetBytes[1]; index += 1; } else connectionId = null; uint? version; if (versionFlag) { version = BitConverter.ToUInt32(packetBytes, index); index += 4; } ulong packetNumber; if (pnFlag1 && pnFlag2) { var ba = new byte[8]; Array.Copy(packetBytes, index, ba, 2, 6); packetNumber = BitConverter.ToUInt64(ba, 0); index += 6; } else if (!pnFlag1 && pnFlag2) { packetNumber = BitConverter.ToUInt32(packetBytes, index); index += 4; } else if (pnFlag1) { packetNumber = BitConverter.ToUInt16(packetBytes, index); index += 2; } else { packetNumber = packetBytes[index]; index += 1; } var rp = new RegularPacket(connectionId, packetNumber, null); var payloadBytes = new byte[packetBytes.Length - index]; Array.Copy(packetBytes, index, payloadBytes, 0, payloadBytes.Length); rp.FromByteArray(payloadBytes); packet = rp; return true; }
public async Task <Packets.RegularPacket> CutNextPacketAsync() { if (!this._connectionid.HasValue) { throw new InvalidOperationException("Connection ID is not established!"); } if (this.Count == 0) { return(null); } uint remaining = Packets.AbstractPacketBase.MTU; ulong packetNumber; lock (this._packetNumberLock) { this._packetNumber++; packetNumber = this._packetNumber; } var regular = new Packets.RegularPacket(this._connectionid.Value, packetNumber, null); // TODO: FEC GROUP's. remaining -= regular.GetHeaderLength(); MultiplexedTransfer nextTransfer; long assignedDataSize; bool fin; StreamFrame streamFrame; lock (this._dequeueLock) { MultiplexedTransfer peekedTransfer; do { if (!this.TryPeek(out peekedTransfer)) { return(null); // My queue is _now_ empty, just say nothing to do. } // Prototype our stream frame var streamRemainingByteCount = peekedTransfer.Stream.Length - peekedTransfer.Stream.Position; streamFrame = new StreamFrame(peekedTransfer.StreamId, Convert.ToUInt64(peekedTransfer.Stream.Position)); var prototypeLength = streamFrame.GetMetadataLength(); assignedDataSize = Math.Min(remaining, prototypeLength); var transferDone = assignedDataSize == streamRemainingByteCount; fin = transferDone && peekedTransfer.TerminateStream; if (!this.TryDequeue(out nextTransfer)) { return(null); // My queue is _now_ empty, just say nothing to do. } if (nextTransfer.TransferId != peekedTransfer.TransferId) { this.Enqueue(nextTransfer); // Whoops, something changed outside of our lock... so, redo our calculations. } }while (nextTransfer.TransferId != peekedTransfer.TransferId); } try { // Hydrate our stream frame prototype var streamData = new byte[assignedDataSize]; await nextTransfer.Stream.ReadAsync(streamData, (int)nextTransfer.Stream.Position, streamData.Length); streamFrame.SetData(streamData, fin); } catch (Exception) { // Something went wrong. Requeue the transfer. this.Enqueue(nextTransfer); throw; } return(regular); }