public unsafe Task StartRecvPacket(ILocalAdapter localAdapter, CancellationToken cancellationToken = default) { var tcs = new TaskCompletionSource <object>(); void packetHandler(DatagramSocket socket, DatagramSocketMessageReceivedEventArgs e) { if (cancellationToken.IsCancellationRequested) { return; } try { var buffer = e.GetDataReader().DetachBuffer(); var ptr = ((IBufferByteAccess)buffer).GetBuffer(); localAdapter.WritePacketToLocal(new Span <byte>(ptr.ToPointer(), (int)buffer.Length), cancellationToken); } catch (Exception ex) { tcs.TrySetException(ex); } } udpReceivedHandler = packetHandler; cancellationToken.Register(() => { tcs.TrySetCanceled(); var socket = datagramSocket; if (socket != null) { socket.MessageReceived -= packetHandler; } }); return(tcs.Task); }
public unsafe virtual Task StartRecvPacket(ILocalAdapter localAdapter, CancellationToken cancellationToken = default) { var outDataBuffer = new byte[sendBufferLen + 66]; var tcs = new TaskCompletionSource <object>(); void packetHandler(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs e) { if (cancellationToken.IsCancellationRequested) { return; } try { var buffer = e.GetDataReader().DetachBuffer(); var ptr = ((IBufferByteAccess)buffer).GetBuffer().ToPointer(); var cryptor = ShadowsocksFactory.GlobalCryptorFactory.CreateCryptor(); var decDataLen = Decrypt(new ReadOnlySpan <byte>(ptr, (int)buffer.Length), outDataBuffer, cryptor); // TODO: support IPv6/domain name address type if (decDataLen < 7 || outDataBuffer[0] != 1) { return; } var headerLen = Destination.Destination.TryParseSocks5StyleAddress(outDataBuffer.AsSpan(0, (int)decDataLen), out _, TransportProtocol.Udp); if (headerLen <= 0) { return; } localAdapter.WritePacketToLocal(outDataBuffer.AsSpan(headerLen, (int)decDataLen - headerLen), cancellationToken).ConfigureAwait(false); } catch (Exception ex) { tcs.TrySetException(ex); } } udpReceivedHandler = packetHandler; cancellationToken.Register(() => { tcs.TrySetCanceled(); var socket = udpClient; if (socket != null) { socket.MessageReceived -= packetHandler; } }); return(tcs.Task); }
public async ValueTask Init(ChannelReader <byte[]> outboundChan, ILocalAdapter localAdapter, CancellationToken cancellationToken = default) { if (allowInsecure) { socket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted); socket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.WrongUsage); socket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.IncompleteChain); socket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.Expired); socket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName); } var dev = NetworkInformation.GetInternetConnectionProfile().NetworkAdapter; var connectTask = socket.ConnectAsync(server, port, SocketProtectionLevel.Tls12, dev).AsTask(cancellationToken).ConfigureAwait(false); // TODO: custom certificate, server name var destination = localAdapter.Destination; var firstBuf = Array.Empty <byte>(); var firstBufCancel = new CancellationTokenSource(500); try { if (await outboundChan.WaitToReadAsync(firstBufCancel.Token).ConfigureAwait(false)) { outboundChan.TryRead(out firstBuf); } } catch (OperationCanceledException) { } finally { firstBufCancel.Dispose(); } int firstBufLen = firstBuf.Length; byte[] requestPayload = sendArrayPool.Rent(destination.Host.Size + firstBufLen + 65); try { var headerLen = FillTrojanRequest(requestPayload, destination); firstBuf.CopyTo(requestPayload.AsSpan(headerLen)); await connectTask; inputStream = socket.InputStream; outputStream = socket.OutputStream; _ = outputStream.WriteAsync(requestPayload.AsBuffer(0, firstBuf.Length + headerLen)).AsTask(cancellationToken); } finally { sendArrayPool.Return(requestPayload); } }
public async override ValueTask Init(ChannelReader <byte[]> outboundChan, ILocalAdapter localAdapter, CancellationToken cancellationToken = default) { this.localAdapter = localAdapter; var greeting = await outboundChan.ReadAsync().ConfigureAwait(false); if (greeting.Length < 3 || greeting[0] != 5 || greeting[2] != 0) { throw BadGreetingException; } await WritePacketToLocal(ServerChoicePayload); var request = await outboundChan.ReadAsync().ConfigureAwait(false); Destination = ParseDestinationFromRequest(request); if (Destination.TransportProtocol == TransportProtocol.Udp) { throw UnknownTypeException; } await WritePacketToLocal(DummyResponsePayload); await base.Init(outboundChan, localAdapter, cancellationToken).ConfigureAwait(false); }
public async ValueTask Init(ChannelReader <byte[]> channel, ILocalAdapter localAdapter, CancellationToken cancellationToken = default) { var dev = NetworkInformation.GetInternetConnectionProfile().NetworkAdapter; var port = localAdapter.Destination.Port; switch (localAdapter.Destination.TransportProtocol) { case Destination.TransportProtocol.Tcp: streamSocket = new StreamSocket(); await streamSocket.ConnectAsync((HostName)localAdapter.Destination, port.ToString(), SocketProtectionLevel.PlainSocket, dev).AsTask(cancellationToken).ConfigureAwait(false); break; case Destination.TransportProtocol.Udp: datagramSocket = new DatagramSocket(); datagramSocket.MessageReceived += DatagramSocket_MessageReceived; await datagramSocket.BindServiceNameAsync(string.Empty, dev).AsTask(cancellationToken).ConfigureAwait(false); await datagramSocket.ConnectAsync((HostName)localAdapter.Destination, port.ToString()).AsTask(cancellationToken).ConfigureAwait(false); break; } }
public async ValueTask Init(ChannelReader <byte[]> outboundChan, ILocalAdapter localAdapter, CancellationToken cancellationToken = default) { var destination = localAdapter.Destination; IAsyncAction connectTask; var dev = NetworkInformation.GetInternetConnectionProfile().NetworkAdapter; switch (destination.TransportProtocol) { case TransportProtocol.Tcp: client = new StreamSocket(); client.Control.NoDelay = true; connectTask = client.ConnectAsync(new HostName(server), serviceName, SocketProtectionLevel.PlainSocket, dev); tcpInputStream = client.InputStream; break; case TransportProtocol.Udp: cryptor = null; // Shadowsocks does not require a handshake for UDP transport udpClient = new DatagramSocket(); // MessageReceived must be subscribed at this point udpClient.MessageReceived += UdpClient_MessageReceived; await udpClient.BindServiceNameAsync(string.Empty, dev).AsTask(cancellationToken).ConfigureAwait(false); udpOutputStream = await udpClient.GetOutputStreamAsync(new HostName(server), serviceName).AsTask(cancellationToken).ConfigureAwait(false); return; default: throw new NotImplementedException("Unknown transport protocol"); } byte[] firstBuf = Array.Empty <byte>(); var firstBufCancel = new CancellationTokenSource(500); try { if (await outboundChan.WaitToReadAsync(firstBufCancel.Token).ConfigureAwait(false)) { outboundChan.TryRead(out firstBuf); } } catch (OperationCanceledException) { } finally { firstBufCancel.Dispose(); } int firstBufLen = firstBuf.Length; int requestPayloadLen = firstBufLen + destination.Host.Size + 4; // Later will be reused to store dec iv var requestPayload = sendArrayPool.Rent(Math.Max(requestPayloadLen, (int)cryptor.IvLen)); var headerLen = destination.FillSocks5StyleAddress(requestPayload); firstBuf.CopyTo(requestPayload.AsSpan(headerLen)); var encryptedFirstSeg = sendArrayPool.Rent(requestPayloadLen + 66); // Reserve space for IV or salt + 2 * tag + size var ivLen = Encrypt(Array.Empty <byte>(), encryptedFirstSeg); // Fill IV/salt first var encryptedFirstSegLen = ivLen + Encrypt(requestPayload.AsSpan(0, headerLen + firstBufLen), encryptedFirstSeg.AsSpan((int)ivLen)); try { await connectTask.AsTask(cancellationToken).ConfigureAwait(false); } catch (Exception) { sendArrayPool.Return(requestPayload); sendArrayPool.Return(encryptedFirstSeg, true); throw; } try { // Recv iv first, then GetRecvBufSizeHint will not bother with iv stuff receiveIvTask = ReceiveIv(requestPayload, cancellationToken); _ = client.OutputStream.WriteAsync(encryptedFirstSeg.AsBuffer(0, (int)encryptedFirstSegLen)).AsTask(cancellationToken); } finally { sendArrayPool.Return(encryptedFirstSeg, true); } }
public async Task StartRecvPacket(ILocalAdapter localAdapter, CancellationToken cancellationToken = default) { const int RECV_BUFFER_LEN = 2048; byte[] buf = new byte[RECV_BUFFER_LEN]; var stream = inputStream.AsStreamForRead(); int offset = 0, unconsumedLen = 0; while (!cancellationToken.IsCancellationRequested) { int parseResult = Destination.Destination.TryParseSocks5StyleAddress(buf.AsSpan(offset, unconsumedLen), out _, TransportProtocol.Udp); unconsumedLen -= parseResult; while (parseResult == 0 || unconsumedLen < 4) // Need more data as address header + len + crlf { var readLen = await stream.ReadAsync(buf, offset, RECV_BUFFER_LEN - offset).ConfigureAwait(false); offset += readLen; unconsumedLen += readLen; if (readLen == 0) { goto END; } if (parseResult == 0) { parseResult = Destination.Destination.TryParseSocks5StyleAddress(buf.AsSpan(0, unconsumedLen), out _, TransportProtocol.Udp); unconsumedLen -= parseResult; } } // buf now contains a valid address header, check payload length and CRLF ushort len = (ushort)(buf[parseResult] << 8 | buf[parseResult + 1]); if (buf[parseResult + 2] != 0x0D || buf[parseResult + 3] != 0x0A) { if (DebugLogger.LogNeeded()) { DebugLogger.Log("Received a malformed Trojan UDP response"); } break; } unconsumedLen -= 4; while (unconsumedLen < len) { var readLen = await stream.ReadAsync(buf, offset, RECV_BUFFER_LEN - offset).ConfigureAwait(false); offset += readLen; unconsumedLen += readLen; if (readLen == 0) { goto END; } } await localAdapter.WritePacketToLocal(buf.AsSpan(offset - len, len), cancellationToken).ConfigureAwait(false); unconsumedLen -= len; if (unconsumedLen > 0) { Array.Copy(buf, parseResult + len, buf, 0, unconsumedLen); } offset = unconsumedLen; } END: ; }
public unsafe override Task StartRecvPacket(ILocalAdapter localAdapter, CancellationToken cancellationToken = default) { var outDataBuffer = new byte[sendBufferLen + 66]; var tcs = new TaskCompletionSource <object>(); void packetHandler(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs e) { if (cancellationToken.IsCancellationRequested) { return; } try { var cryptor = ShadowsocksFactory.GlobalCryptorFactory.CreateCryptor(); var buffer = e.GetDataReader().DetachBuffer(); var ptr = ((IBufferByteAccess)buffer).GetBuffer(); var ivLen = (int)cryptor.IvLen; if (buffer.Length < ivLen + TAG_SIZE + 7) { return; } int decDataLen; try { decDataLen = Decrypt( new ReadOnlySpan <byte>(ptr.ToPointer(), (int)(buffer.Length - TAG_SIZE)), new ReadOnlySpan <byte>((void *)(ptr.ToInt64() + buffer.Length - TAG_SIZE), TAG_SIZE), outDataBuffer, cryptor); } catch (AeadOperationException ex) { if (DebugLogger.LogNeeded()) { DebugLogger.Log($"Error decrypting a UDP packet from {localAdapter.Destination}: {ex}"); } throw; } // TODO: support IPv6/domain name address type if (decDataLen < 7 || outDataBuffer[0] != 1) { return; } var headerLen = Destination.Destination.TryParseSocks5StyleAddress(outDataBuffer.AsSpan(0, decDataLen), out _, TransportProtocol.Udp); if (headerLen <= 0) { return; } localAdapter.WritePacketToLocal(outDataBuffer.AsSpan(headerLen, decDataLen - headerLen), cancellationToken).ConfigureAwait(false); } catch (Exception ex) { tcs.TrySetException(ex); } } udpReceivedHandler = packetHandler; cancellationToken.Register(() => { tcs.TrySetCanceled(); var socket = udpClient; if (socket != null) { socket.MessageReceived -= packetHandler; } }); return(tcs.Task); }
public async ValueTask Init(ChannelReader <byte[]> outboundChan, ILocalAdapter localAdapter, CancellationToken cancellationToken = default) { if (localAdapter.Destination.TransportProtocol == TransportProtocol.Udp) { throw UdpNotSupportedException; } var dev = NetworkInformation.GetInternetConnectionProfile().NetworkAdapter; var connectTask = socket.ConnectAsync(new HostName(server), port.ToString(), SocketProtectionLevel.PlainSocket, dev).AsTask(cancellationToken).ConfigureAwait(false); var destination = localAdapter.Destination; var dstPort = destination.Port; var dstPortStrSize = CountDigit(dstPort); var dstHostStrSize = destination.Host.Size; int headerLen = HEADER1.Length + dstHostStrSize + 1 + dstPortStrSize + HEADER2.Length; var firstSeg = sendArrayPool.Rent(headerLen); try { HEADER1.CopyTo(firstSeg, 0); destination.Host.CopyTo(firstSeg.AsSpan(HEADER1.Length)); firstSeg[HEADER1.Length + dstHostStrSize] = (byte)':'; while (dstPortStrSize-- > 0) { firstSeg[HEADER1.Length + dstHostStrSize + 1 + dstPortStrSize] = (byte)(dstPort % 10 + '0'); dstPort /= 10; } HEADER2.CopyTo(firstSeg, headerLen - HEADER2.Length); // Connect and perform handshake await connectTask; inputStream = socket.InputStream; outputStream = socket.OutputStream; await outputStream.WriteAsync(firstSeg.AsBuffer(0, headerLen)).AsTask(cancellationToken).ConfigureAwait(false); } finally { sendArrayPool.Return(firstSeg); } var responseBuf = sendArrayPool.Rent(HEAD_BUFFER_LEN); try { var resBuf = await inputStream.ReadAsync(responseBuf.AsBuffer(), HEAD_BUFFER_LEN, InputStreamOptions.Partial).AsTask(cancellationToken).ConfigureAwait(false); uint responseLen = resBuf.Length; if (responseLen < 14) { throw new InvalidOperationException("Remote response too short"); } if ((responseBuf[9] == (byte)'2') && (responseBuf[10] == (byte)'0') && (responseBuf[11] == (byte)'0')) { // 200 objk } else { var code = 100 * (responseBuf[9] - '0') + 10 * (responseBuf[10] - '0') + responseBuf[11] - '0'; throw new InvalidOperationException("Remote status code: " + code.ToString()); } bool foundHeader = false; for (int headerStart = 12; headerStart < responseLen - 3; headerStart++) { if (responseBuf[headerStart] == '\r') { if (responseBuf[headerStart + 1] == '\n') { if (responseBuf[headerStart + 2] == '\r') { if (responseBuf[headerStart + 3] == '\n') { foundHeader = true; break; } } } } } if (!foundHeader) { throw new InvalidOperationException("Unrecognized remote header: " + Encoding.UTF8.GetString(responseBuf, 0, (int)responseLen)); } } finally { sendArrayPool.Return(responseBuf); } // Initial data? }
public Task StartRecvPacket(ILocalAdapter localAdapter, CancellationToken cancellationToken = default) { return(Task.CompletedTask); }