From 0b93061e2a35dc8e7d77266f85866e887347a0c9 Mon Sep 17 00:00:00 2001 From: "Gui.H" Date: Thu, 30 Jun 2022 14:19:26 +0800 Subject: [PATCH 1/3] 1 --- FastTunnel.Api/FastTunnel.Api.csproj | 2 +- .../Extensions/ListenOptionsSwapExtensions.cs | 9 +- FastTunnel.Core/FastTunnel.Core.csproj | 2 +- ...onMiddleware.cs => ForwarderMiddleware.cs} | 6 +- ...Middleware.cs => InitializerMiddleware.cs} | 6 +- .../Forwarder/Kestrel/MiddleWare/TaskToApm.cs | 112 ------------ .../Forwarder/MiddleWare/DuplexPipeStream.cs | 2 +- FastTunnel.Core/Refs/DuplexPipeStream.cs | 173 ++++++++++++++++++ .../Refs/DuplexPipeStreamAdapter.cs | 57 ++++++ FastTunnel.Core/Refs/TaskToApm.cs | 111 +++++++++++ FastTunnel.Hosting/FastTunnel.Hosting.csproj | 2 +- 11 files changed, 355 insertions(+), 127 deletions(-) rename FastTunnel.Core/Forwarder/Kestrel/MiddleWare/{SwapConnectionMiddleware.cs => ForwarderMiddleware.cs} (94%) rename FastTunnel.Core/Forwarder/Kestrel/MiddleWare/{HandleHttpConnectionMiddleware.cs => InitializerMiddleware.cs} (82%) delete mode 100644 FastTunnel.Core/Forwarder/Kestrel/MiddleWare/TaskToApm.cs create mode 100644 FastTunnel.Core/Refs/DuplexPipeStream.cs create mode 100644 FastTunnel.Core/Refs/DuplexPipeStreamAdapter.cs create mode 100644 FastTunnel.Core/Refs/TaskToApm.cs diff --git a/FastTunnel.Api/FastTunnel.Api.csproj b/FastTunnel.Api/FastTunnel.Api.csproj index 3f9268d..9690092 100644 --- a/FastTunnel.Api/FastTunnel.Api.csproj +++ b/FastTunnel.Api/FastTunnel.Api.csproj @@ -1,7 +1,7 @@ 3.0.0-Beta.1.22511 - net5.0;net6.0 + net6.0;net7.0 diff --git a/FastTunnel.Core/Extensions/ListenOptionsSwapExtensions.cs b/FastTunnel.Core/Extensions/ListenOptionsSwapExtensions.cs index fe0354c..3889ed6 100644 --- a/FastTunnel.Core/Extensions/ListenOptionsSwapExtensions.cs +++ b/FastTunnel.Core/Extensions/ListenOptionsSwapExtensions.cs @@ -23,13 +23,12 @@ public static class ListenOptionsSwapExtensions { var fastTunnelServer = listenOptions.KestrelServerOptions.ApplicationServices.GetRequiredService(); var loggerFactory = listenOptions.KestrelServerOptions.ApplicationServices.GetRequiredService(); - var logger = loggerFactory.CreateLogger(); - var loggerHttp = loggerFactory.CreateLogger(); + var forwardLogger = loggerFactory.CreateLogger(); + var initLogger = loggerFactory.CreateLogger(); - listenOptions.Use(next => new FastTunnelConnectionMiddleware(next, loggerHttp, fastTunnelServer).OnConnectionAsync); - listenOptions.Use(next => new SwapConnectionMiddleware(next, logger, fastTunnelServer).OnConnectionAsync); + listenOptions.Use(next => new InitializerMiddleware(next, initLogger, fastTunnelServer).OnConnectionAsync); + listenOptions.Use(next => new ForwarderMiddleware(next, forwardLogger, fastTunnelServer).OnConnectionAsync); - // 登录频率低,放在后面 return listenOptions; } } diff --git a/FastTunnel.Core/FastTunnel.Core.csproj b/FastTunnel.Core/FastTunnel.Core.csproj index 9828b22..e1716d9 100644 --- a/FastTunnel.Core/FastTunnel.Core.csproj +++ b/FastTunnel.Core/FastTunnel.Core.csproj @@ -2,7 +2,7 @@ 3.0.0-Beta.1.22511 README.md - net5.0;net6.0 + net6.0;net7.0 diff --git a/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/SwapConnectionMiddleware.cs b/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/ForwarderMiddleware.cs similarity index 94% rename from FastTunnel.Core/Forwarder/Kestrel/MiddleWare/SwapConnectionMiddleware.cs rename to FastTunnel.Core/Forwarder/Kestrel/MiddleWare/ForwarderMiddleware.cs index e7bd940..5639b56 100644 --- a/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/SwapConnectionMiddleware.cs +++ b/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/ForwarderMiddleware.cs @@ -26,13 +26,13 @@ namespace FastTunnel.Core.Forwarder.Kestrel.MiddleWare; /// /// 核心逻辑处理中间件 /// -internal class SwapConnectionMiddleware +internal class ForwarderMiddleware { private readonly ConnectionDelegate next; - private readonly ILogger logger; + private readonly ILogger logger; private readonly FastTunnelServer fastTunnelServer; - public SwapConnectionMiddleware(ConnectionDelegate next, ILogger logger, FastTunnelServer fastTunnelServer) + public ForwarderMiddleware(ConnectionDelegate next, ILogger logger, FastTunnelServer fastTunnelServer) { this.next = next; this.logger = logger; diff --git a/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/HandleHttpConnectionMiddleware.cs b/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/InitializerMiddleware.cs similarity index 82% rename from FastTunnel.Core/Forwarder/Kestrel/MiddleWare/HandleHttpConnectionMiddleware.cs rename to FastTunnel.Core/Forwarder/Kestrel/MiddleWare/InitializerMiddleware.cs index ed38482..fc8d041 100644 --- a/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/HandleHttpConnectionMiddleware.cs +++ b/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/InitializerMiddleware.cs @@ -15,13 +15,13 @@ namespace FastTunnel.Core.Forwarder.Kestrel.MiddleWare; /// /// 预处理中间件 /// -internal class FastTunnelConnectionMiddleware +internal class InitializerMiddleware { private readonly ConnectionDelegate next; - private readonly ILogger logger; + private readonly ILogger logger; private readonly FastTunnelServer fastTunnelServer; - public FastTunnelConnectionMiddleware(ConnectionDelegate next, ILogger logger, FastTunnelServer fastTunnelServer) + public InitializerMiddleware(ConnectionDelegate next, ILogger logger, FastTunnelServer fastTunnelServer) { this.next = next; this.logger = logger; diff --git a/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/TaskToApm.cs b/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/TaskToApm.cs deleted file mode 100644 index 7333555..0000000 --- a/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/TaskToApm.cs +++ /dev/null @@ -1,112 +0,0 @@ -// Licensed under the Apache License, Version 2.0 (the "License"). -// You may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE -// Copyright (c) 2019 Gui.H - -using System; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; - -namespace FastTunnel.Core.Forwarder.Kestrel.MiddleWare -{ - internal static class TaskToApm - { - /// - /// Marshals the Task as an IAsyncResult, using the supplied callback and state - /// to implement the APM pattern. - /// - /// The Task to be marshaled. - /// The callback to be invoked upon completion. - /// The state to be stored in the IAsyncResult. - /// An IAsyncResult to represent the task's asynchronous operation. - public static IAsyncResult Begin(Task task, AsyncCallback callback, object state) => - new TaskAsyncResult(task, state, callback); - - /// Processes an IAsyncResult returned by Begin. - /// The IAsyncResult to unwrap. - public static void End(IAsyncResult asyncResult) - { - if (asyncResult is TaskAsyncResult twar) - { - twar._task.GetAwaiter().GetResult(); - return; - } - - throw new ArgumentNullException(nameof(asyncResult)); - } - - /// Processes an IAsyncResult returned by Begin. - /// The IAsyncResult to unwrap. - public static TResult End(IAsyncResult asyncResult) - { - if (asyncResult is TaskAsyncResult twar && twar._task is Task task) - { - return task.GetAwaiter().GetResult(); - } - - throw new ArgumentNullException(nameof(asyncResult)); - } - - /// Provides a simple IAsyncResult that wraps a Task. - /// - /// We could use the Task as the IAsyncResult if the Task's AsyncState is the same as the object state, - /// but that's very rare, in particular in a situation where someone cares about allocation, and always - /// using TaskAsyncResult simplifies things and enables additional optimizations. - /// - internal sealed class TaskAsyncResult : IAsyncResult - { - /// The wrapped Task. - internal readonly Task _task; - /// Callback to invoke when the wrapped task completes. - private readonly AsyncCallback _callback; - - /// Initializes the IAsyncResult with the Task to wrap and the associated object state. - /// The Task to wrap. - /// The new AsyncState value. - /// Callback to invoke when the wrapped task completes. - internal TaskAsyncResult(Task task, object state, AsyncCallback callback) - { - Debug.Assert(task != null); - _task = task; - AsyncState = state; - - if (task.IsCompleted) - { - // Synchronous completion. Invoke the callback. No need to store it. - CompletedSynchronously = true; - callback?.Invoke(this); - } - else if (callback != null) - { - // Asynchronous completion, and we have a callback; schedule it. We use OnCompleted rather than ContinueWith in - // order to avoid running synchronously if the task has already completed by the time we get here but still run - // synchronously as part of the task's completion if the task completes after (the more common case). - _callback = callback; - _task.ConfigureAwait(continueOnCapturedContext: false) - .GetAwaiter() - .OnCompleted(InvokeCallback); // allocates a delegate, but avoids a closure - } - } - - /// Invokes the callback. - private void InvokeCallback() - { - Debug.Assert(!CompletedSynchronously); - Debug.Assert(_callback != null); - _callback.Invoke(this); - } - - /// Gets a user-defined object that qualifies or contains information about an asynchronous operation. - public object AsyncState { get; } - /// Gets a value that indicates whether the asynchronous operation completed synchronously. - /// This is set lazily based on whether the has completed by the time this object is created. - public bool CompletedSynchronously { get; } - /// Gets a value that indicates whether the asynchronous operation has completed. - public bool IsCompleted => _task.IsCompleted; - /// Gets a that is used to wait for an asynchronous operation to complete. - public WaitHandle AsyncWaitHandle => ((IAsyncResult)_task).AsyncWaitHandle; - } - } -} diff --git a/FastTunnel.Core/Forwarder/MiddleWare/DuplexPipeStream.cs b/FastTunnel.Core/Forwarder/MiddleWare/DuplexPipeStream.cs index 705531a..66acaa5 100644 --- a/FastTunnel.Core/Forwarder/MiddleWare/DuplexPipeStream.cs +++ b/FastTunnel.Core/Forwarder/MiddleWare/DuplexPipeStream.cs @@ -13,7 +13,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using FastTunnel.Core.Extensions; -using FastTunnel.Core.Forwarder.Kestrel.MiddleWare; +using FastTunnel.Core.Refs; namespace FastTunnel.Core.Forwarder.MiddleWare; diff --git a/FastTunnel.Core/Refs/DuplexPipeStream.cs b/FastTunnel.Core/Refs/DuplexPipeStream.cs new file mode 100644 index 0000000..a62748c --- /dev/null +++ b/FastTunnel.Core/Refs/DuplexPipeStream.cs @@ -0,0 +1,173 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Buffers; +using System.IO; +using System.IO.Pipelines; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using FastTunnel.Core.Extensions; +using Microsoft.AspNetCore.Internal; + +#nullable enable + +namespace FastTunnel.Core.Refs; + +internal class DuplexPipeStream : Stream +{ + private readonly PipeReader _input; + private readonly PipeWriter _output; + private readonly bool _throwOnCancelled; + private volatile bool _cancelCalled; + + public DuplexPipeStream(PipeReader input, PipeWriter output, bool throwOnCancelled = false) + { + _input = input; + _output = output; + _throwOnCancelled = throwOnCancelled; + } + + public void CancelPendingRead() + { + _cancelCalled = true; + _input.CancelPendingRead(); + } + + public override bool CanRead => true; + + public override bool CanSeek => false; + + public override bool CanWrite => true; + + public override long Length + { + get + { + throw new NotSupportedException(); + } + } + + public override long Position + { + get + { + throw new NotSupportedException(); + } + set + { + throw new NotSupportedException(); + } + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + var vt = ReadAsyncInternal(new Memory(buffer, offset, count), default); + return vt.IsCompleted ? + vt.Result : + vt.AsTask().GetAwaiter().GetResult(); + } + + public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken = default) + { + return ReadAsyncInternal(new Memory(buffer, offset, count), cancellationToken).AsTask(); + } + + public override ValueTask ReadAsync(Memory destination, CancellationToken cancellationToken = default) + { + return ReadAsyncInternal(destination, cancellationToken); + } + + public override void Write(byte[] buffer, int offset, int count) + { + WriteAsync(buffer, offset, count).GetAwaiter().GetResult(); + } + + public override Task WriteAsync(byte[]? buffer, int offset, int count, CancellationToken cancellationToken) + { + return _output.WriteAsync(buffer.AsMemory(offset, count), cancellationToken).GetAsTask(); + } + + public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default) + { + return _output.WriteAsync(source, cancellationToken).GetAsValueTask(); + } + + public override void Flush() + { + FlushAsync(CancellationToken.None).GetAwaiter().GetResult(); + } + + public override Task FlushAsync(CancellationToken cancellationToken) + { + return _output.FlushAsync(cancellationToken).GetAsTask(); + } + + [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder<>))] + private async ValueTask ReadAsyncInternal(Memory destination, CancellationToken cancellationToken) + { + while (true) + { + var result = await _input.ReadAsync(cancellationToken); + var readableBuffer = result.Buffer; + try + { + if (_throwOnCancelled && result.IsCanceled && _cancelCalled) + { + // Reset the bool + _cancelCalled = false; + throw new OperationCanceledException(); + } + + if (!readableBuffer.IsEmpty) + { + // buffer.Count is int + var count = (int)Math.Min(readableBuffer.Length, destination.Length); + readableBuffer = readableBuffer.Slice(0, count); + readableBuffer.CopyTo(destination.Span); + return count; + } + + if (result.IsCompleted) + { + return 0; + } + } + finally + { + _input.AdvanceTo(readableBuffer.End, readableBuffer.End); + } + } + } + + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) + { + return TaskToApm.Begin(ReadAsync(buffer, offset, count), callback, state); + } + + public override int EndRead(IAsyncResult asyncResult) + { + return TaskToApm.End(asyncResult); + } + + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) + { + return TaskToApm.Begin(WriteAsync(buffer, offset, count), callback, state); + } + + public override void EndWrite(IAsyncResult asyncResult) + { + TaskToApm.End(asyncResult); + } +} diff --git a/FastTunnel.Core/Refs/DuplexPipeStreamAdapter.cs b/FastTunnel.Core/Refs/DuplexPipeStreamAdapter.cs new file mode 100644 index 0000000..4ddf2c1 --- /dev/null +++ b/FastTunnel.Core/Refs/DuplexPipeStreamAdapter.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; +using System.IO.Pipelines; +using System.Threading.Tasks; + +namespace FastTunnel.Core.Refs; + +/// +/// A helper for wrapping a Stream decorator from an . +/// +/// +internal class DuplexPipeStreamAdapter : DuplexPipeStream, IDuplexPipe where TStream : Stream +{ + private bool _disposed; + private readonly object _disposeLock = new object(); + + public DuplexPipeStreamAdapter(IDuplexPipe duplexPipe, Func createStream) : + this(duplexPipe, new StreamPipeReaderOptions(leaveOpen: true), new StreamPipeWriterOptions(leaveOpen: true), createStream) + { + } + + public DuplexPipeStreamAdapter(IDuplexPipe duplexPipe, StreamPipeReaderOptions readerOptions, StreamPipeWriterOptions writerOptions, Func createStream) : + base(duplexPipe.Input, duplexPipe.Output) + { + var stream = createStream(this); + Stream = stream; + Input = PipeReader.Create(stream, readerOptions); + Output = PipeWriter.Create(stream, writerOptions); + } + + public TStream Stream { get; } + + public PipeReader Input { get; } + + public PipeWriter Output { get; } + + public override async ValueTask DisposeAsync() + { + lock (_disposeLock) + { + if (_disposed) + { + return; + } + _disposed = true; + } + + await Input.CompleteAsync(); + await Output.CompleteAsync(); + } + + protected override void Dispose(bool disposing) + { + throw new NotSupportedException(); + } +} + diff --git a/FastTunnel.Core/Refs/TaskToApm.cs b/FastTunnel.Core/Refs/TaskToApm.cs new file mode 100644 index 0000000..c5b0480 --- /dev/null +++ b/FastTunnel.Core/Refs/TaskToApm.cs @@ -0,0 +1,111 @@ +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE +// Copyright (c) 2019 Gui.H + +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; + +namespace FastTunnel.Core.Refs; + +internal static class TaskToApm +{ + /// + /// Marshals the Task as an IAsyncResult, using the supplied callback and state + /// to implement the APM pattern. + /// + /// The Task to be marshaled. + /// The callback to be invoked upon completion. + /// The state to be stored in the IAsyncResult. + /// An IAsyncResult to represent the task's asynchronous operation. + public static IAsyncResult Begin(Task task, AsyncCallback callback, object state) => + new TaskAsyncResult(task, state, callback); + + /// Processes an IAsyncResult returned by Begin. + /// The IAsyncResult to unwrap. + public static void End(IAsyncResult asyncResult) + { + if (asyncResult is TaskAsyncResult twar) + { + twar._task.GetAwaiter().GetResult(); + return; + } + + throw new ArgumentNullException(nameof(asyncResult)); + } + + /// Processes an IAsyncResult returned by Begin. + /// The IAsyncResult to unwrap. + public static TResult End(IAsyncResult asyncResult) + { + if (asyncResult is TaskAsyncResult twar && twar._task is Task task) + { + return task.GetAwaiter().GetResult(); + } + + throw new ArgumentNullException(nameof(asyncResult)); + } + + /// Provides a simple IAsyncResult that wraps a Task. + /// + /// We could use the Task as the IAsyncResult if the Task's AsyncState is the same as the object state, + /// but that's very rare, in particular in a situation where someone cares about allocation, and always + /// using TaskAsyncResult simplifies things and enables additional optimizations. + /// + internal sealed class TaskAsyncResult : IAsyncResult + { + /// The wrapped Task. + internal readonly Task _task; + /// Callback to invoke when the wrapped task completes. + private readonly AsyncCallback _callback; + + /// Initializes the IAsyncResult with the Task to wrap and the associated object state. + /// The Task to wrap. + /// The new AsyncState value. + /// Callback to invoke when the wrapped task completes. + internal TaskAsyncResult(Task task, object state, AsyncCallback callback) + { + Debug.Assert(task != null); + _task = task; + AsyncState = state; + + if (task.IsCompleted) + { + // Synchronous completion. Invoke the callback. No need to store it. + CompletedSynchronously = true; + callback?.Invoke(this); + } + else if (callback != null) + { + // Asynchronous completion, and we have a callback; schedule it. We use OnCompleted rather than ContinueWith in + // order to avoid running synchronously if the task has already completed by the time we get here but still run + // synchronously as part of the task's completion if the task completes after (the more common case). + _callback = callback; + _task.ConfigureAwait(continueOnCapturedContext: false) + .GetAwaiter() + .OnCompleted(InvokeCallback); // allocates a delegate, but avoids a closure + } + } + + /// Invokes the callback. + private void InvokeCallback() + { + Debug.Assert(!CompletedSynchronously); + Debug.Assert(_callback != null); + _callback.Invoke(this); + } + + /// Gets a user-defined object that qualifies or contains information about an asynchronous operation. + public object AsyncState { get; } + /// Gets a value that indicates whether the asynchronous operation completed synchronously. + /// This is set lazily based on whether the has completed by the time this object is created. + public bool CompletedSynchronously { get; } + /// Gets a value that indicates whether the asynchronous operation has completed. + public bool IsCompleted => _task.IsCompleted; + /// Gets a that is used to wait for an asynchronous operation to complete. + public WaitHandle AsyncWaitHandle => ((IAsyncResult)_task).AsyncWaitHandle; + } +} diff --git a/FastTunnel.Hosting/FastTunnel.Hosting.csproj b/FastTunnel.Hosting/FastTunnel.Hosting.csproj index e51c130..cb6aff8 100644 --- a/FastTunnel.Hosting/FastTunnel.Hosting.csproj +++ b/FastTunnel.Hosting/FastTunnel.Hosting.csproj @@ -4,7 +4,7 @@ enable enable README.md - net5.0;net6.0 + net6.0;net7.0 From 98ecb294074cb46d41d1c907c90719a450806c97 Mon Sep 17 00:00:00 2001 From: "Gui.H" Date: Fri, 1 Jul 2022 17:18:04 +0800 Subject: [PATCH 2/3] 1 --- FastTunnel.Client/appsettings.json | 2 +- FastTunnel.Core/FastTunnel.Core.csproj | 3 + .../FastTunelProtocol.cs} | 72 +++++++++---------- .../Kestrel/MiddleWare/FastTunnelFeature.cs | 24 +++++++ .../Kestrel/MiddleWare/ForwarderMiddleware.cs | 41 +++++++---- .../Kestrel/MiddleWare/IFastTunnelFeature.cs | 26 +++++++ .../MiddleWare/InitializerMiddleware.cs | 9 ++- .../FastTunnelHostingStartup.cs | 8 +-- FastTunnel.Server/Startup.cs | 6 ++ 9 files changed, 127 insertions(+), 64 deletions(-) rename FastTunnel.Core/Forwarder/Kestrel/{FastTunnelConnectionContext.cs => MiddleWare/FastTunelProtocol.cs} (74%) create mode 100644 FastTunnel.Core/Forwarder/Kestrel/MiddleWare/FastTunnelFeature.cs create mode 100644 FastTunnel.Core/Forwarder/Kestrel/MiddleWare/IFastTunnelFeature.cs diff --git a/FastTunnel.Client/appsettings.json b/FastTunnel.Client/appsettings.json index d0c6540..1975247 100644 --- a/FastTunnel.Client/appsettings.json +++ b/FastTunnel.Client/appsettings.json @@ -27,7 +27,7 @@ // [必选] 内网站点所在内网的ip "LocalIp": "127.0.0.1", // [必选] 内网站点监听的端口号 - "LocalPort": 8080, + "LocalPort": 8090, // [必选] 子域名, 访问本站点时的url为 http://${SubDomain}.${WebDomain}:${ServerPort} "SubDomain": "test" diff --git a/FastTunnel.Core/FastTunnel.Core.csproj b/FastTunnel.Core/FastTunnel.Core.csproj index e1716d9..a2ec8f9 100644 --- a/FastTunnel.Core/FastTunnel.Core.csproj +++ b/FastTunnel.Core/FastTunnel.Core.csproj @@ -4,6 +4,9 @@ README.md net6.0;net7.0 + + + diff --git a/FastTunnel.Core/Forwarder/Kestrel/FastTunnelConnectionContext.cs b/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/FastTunelProtocol.cs similarity index 74% rename from FastTunnel.Core/Forwarder/Kestrel/FastTunnelConnectionContext.cs rename to FastTunnel.Core/Forwarder/Kestrel/MiddleWare/FastTunelProtocol.cs index 4723f77..4ab9406 100644 --- a/FastTunnel.Core/Forwarder/Kestrel/FastTunnelConnectionContext.cs +++ b/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/FastTunelProtocol.cs @@ -8,59 +8,43 @@ using System; using System.Buffers; using System.Collections.Generic; using System.IO.Pipelines; +using System.Linq; +using System.Reflection.PortableExecutable; using System.Text; using System.Threading.Tasks; using FastTunnel.Core.Models; using FastTunnel.Core.Protocol; using FastTunnel.Core.Server; using Microsoft.AspNetCore.Connections; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.FileSystemGlobbing; -namespace FastTunnel.Core.Forwarder.Kestrel; -internal class FastTunnelConnectionContext : ConnectionContext +namespace FastTunnel.Core.Forwarder.Kestrel.MiddleWare; + +public class FastTunelProtocol { - private readonly ConnectionContext _inner; - private readonly FastTunnelServer fastTunnelServer; - private readonly ILogger _logger; - - public FastTunnelConnectionContext(ConnectionContext context, FastTunnelServer fastTunnelServer, ILogger logger) + public FastTunelProtocol(ConnectionContext context, FastTunnelServer fastTunnelServer) { + this.context = context; this.fastTunnelServer = fastTunnelServer; - this._inner = context; - this._logger = logger; } - public override IDuplexPipe Transport { get => _inner.Transport; set => _inner.Transport = value; } - - public override string ConnectionId { get => _inner.ConnectionId; set => _inner.ConnectionId = value; } - - public override IFeatureCollection Features => _inner.Features; - - public override IDictionary Items { get => _inner.Items; set => _inner.Items = value; } - - public bool IsFastTunnel => Method == ProtocolConst.HTTP_METHOD_SWAP || MatchWeb != null; + bool IsFastTunnel => Method == ProtocolConst.HTTP_METHOD_SWAP || MatchWeb != null; public WebInfo MatchWeb { get; private set; } - public override ValueTask DisposeAsync() - { - return _inner.DisposeAsync(); - } + ConnectionContext context { get; } + + IDuplexPipe Transport => context.Transport; - /// - /// 解析FastTunnel协议 - /// internal async Task TryAnalysisPipeAsync() { - var reader = Transport.Input; + var _input = Transport.Input; ReadResult result; ReadOnlySequence readableBuffer; - while (true) { - result = await reader.ReadAsync(); + result = await _input.ReadAsync(); var tempBuffer = readableBuffer = result.Buffer; SequencePosition? position = null; @@ -72,17 +56,28 @@ internal class FastTunnelConnectionContext : ConnectionContext if (position != null) { var readedPosition = readableBuffer.GetPosition(1, position.Value); - if (ProcessLine(tempBuffer.Slice(0, position.Value))) + if (ProcessLine(tempBuffer.Slice(0, position.Value), out string line)) { if (Method == ProtocolConst.HTTP_METHOD_SWAP) { - reader.AdvanceTo(readedPosition, readedPosition); + _input.AdvanceTo(readedPosition, readedPosition); } else { - reader.AdvanceTo(readableBuffer.Start, readableBuffer.Start); + _input.AdvanceTo(readableBuffer.Start, readableBuffer.Start); } + if (IsFastTunnel) + { + context.Features.Set(new FastTunnelFeature() + { + MatchWeb = MatchWeb, + HasReadLInes = HasReadLInes, + Method = Method, + Host = Host, + MessageId = MessageId, + }); + } return; } @@ -93,12 +88,10 @@ internal class FastTunnelConnectionContext : ConnectionContext if (result.IsCompleted) { - reader.AdvanceTo(readableBuffer.End, readableBuffer.End); - break; + _input.AdvanceTo(readableBuffer.End, readableBuffer.End); + return; } } - - return; } public string Method; @@ -107,6 +100,7 @@ internal class FastTunnelConnectionContext : ConnectionContext private bool isFirstLine = true; public IList HasReadLInes { get; private set; } = new List(); + public FastTunnelServer fastTunnelServer { get; } /// /// @@ -122,9 +116,9 @@ internal class FastTunnelConnectionContext : ConnectionContext /// /// /// Header读取完毕? - private bool ProcessLine(ReadOnlySequence readOnlySequence) + private bool ProcessLine(ReadOnlySequence readOnlySequence, out string lineStr) { - var lineStr = Encoding.UTF8.GetString(readOnlySequence); + lineStr = Encoding.UTF8.GetString(readOnlySequence); HasReadLInes.Add(lineStr); if (isFirstLine) diff --git a/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/FastTunnelFeature.cs b/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/FastTunnelFeature.cs new file mode 100644 index 0000000..67f4535 --- /dev/null +++ b/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/FastTunnelFeature.cs @@ -0,0 +1,24 @@ +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE +// Copyright (c) 2019 Gui.H + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using FastTunnel.Core.Models; + +namespace FastTunnel.Core.Forwarder.Kestrel.MiddleWare; + +public class FastTunnelFeature : IFastTunnelFeature +{ + public WebInfo MatchWeb { get; set; } + + public IList HasReadLInes { get; set; } + public string Method { get; set; } + public string Host { get; set; } + public string MessageId { get; set; } +} diff --git a/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/ForwarderMiddleware.cs b/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/ForwarderMiddleware.cs index 5639b56..59851c6 100644 --- a/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/ForwarderMiddleware.cs +++ b/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/ForwarderMiddleware.cs @@ -41,35 +41,45 @@ internal class ForwarderMiddleware internal async Task OnConnectionAsync(ConnectionContext context) { - var ctx = context as FastTunnelConnectionContext; - if (ctx != null && ctx.IsFastTunnel) + logger.LogInformation("=========ForwarderMiddleware SART==========="); + + var feat = context.Features.Get(); + if (feat == null) { - if (ctx.Method == ProtocolConst.HTTP_METHOD_SWAP) + logger.LogInformation("=========ForwarderMiddleware END==========="); + // not fasttunnel request + await next(context); + return; + } + else + { + logger.LogInformation("=========Swap STRART==========="); + if (feat.Method == ProtocolConst.HTTP_METHOD_SWAP) { - await doSwap(ctx); + await doSwap(context); } - else if (ctx.MatchWeb != null) + else if (feat.MatchWeb != null) { - await waitSwap(ctx); + await waitSwap(context); } else { throw new NotSupportedException(); } - } - else - { - await next(context); + + logger.LogInformation("=========Swap END==========="); + logger.LogInformation("=========ForwarderMiddleware END==========="); } } - private async Task waitSwap(FastTunnelConnectionContext context) + private async Task waitSwap(ConnectionContext context) { + var feat = context.Features.Get(); var requestId = Guid.NewGuid().ToString().Replace("-", ""); - var web = context.MatchWeb; + var web = feat.MatchWeb; TaskCompletionSource tcs = new(); - logger.LogDebug($"[Http]Swap开始 {requestId}|{context.Host}=>{web.WebConfig.LocalIp}:{web.WebConfig.LocalPort}"); + logger.LogDebug($"[Http]Swap开始 {requestId}|{feat.Host}=>{web.WebConfig.LocalIp}:{web.WebConfig.LocalPort}"); tcs.SetTimeOut(10000, () => { logger.LogDebug($"[Proxy TimeOut]:{requestId}"); }); fastTunnelServer.ResponseTasks.TryAdd(requestId, tcs); @@ -111,9 +121,10 @@ internal class ForwarderMiddleware } } - private async Task doSwap(FastTunnelConnectionContext context) + private async Task doSwap(ConnectionContext context) { - var requestId = context.MessageId; + var feat = context.Features.Get(); + var requestId = feat.MessageId; if (!fastTunnelServer.ResponseTasks.TryRemove(requestId, out var responseStream)) { throw new Exception($"[PROXY]:RequestId不存在 {requestId}"); diff --git a/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/IFastTunnelFeature.cs b/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/IFastTunnelFeature.cs new file mode 100644 index 0000000..8e8dbe1 --- /dev/null +++ b/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/IFastTunnelFeature.cs @@ -0,0 +1,26 @@ +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE +// Copyright (c) 2019 Gui.H + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using FastTunnel.Core.Models; +using FastTunnel.Core.Protocol; + +namespace FastTunnel.Core.Forwarder.Kestrel.MiddleWare; + +internal interface IFastTunnelFeature +{ + public WebInfo MatchWeb { get; set; } + + public IList HasReadLInes { get; set; } + + public string Method { get; set; } + public string Host { get; set; } + public string MessageId { get; set; } +} diff --git a/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/InitializerMiddleware.cs b/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/InitializerMiddleware.cs index fc8d041..93aab9e 100644 --- a/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/InitializerMiddleware.cs +++ b/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/InitializerMiddleware.cs @@ -30,11 +30,10 @@ internal class InitializerMiddleware internal async Task OnConnectionAsync(ConnectionContext context) { - logger.LogInformation("=========OnConnectionAsync==========="); - var ftContext = new FastTunnelConnectionContext(context, fastTunnelServer, logger); - await ftContext.TryAnalysisPipeAsync(); - + logger.LogInformation("=========TryAnalysisPipeAsync SART==========="); + await new FastTunelProtocol(context, fastTunnelServer).TryAnalysisPipeAsync(); logger.LogInformation("=========TryAnalysisPipeAsync END==========="); - await next(ftContext.IsFastTunnel ? ftContext : context); + + await next(context); } } diff --git a/FastTunnel.Hosting/FastTunnelHostingStartup.cs b/FastTunnel.Hosting/FastTunnelHostingStartup.cs index dec9033..2c64e8c 100644 --- a/FastTunnel.Hosting/FastTunnelHostingStartup.cs +++ b/FastTunnel.Hosting/FastTunnelHostingStartup.cs @@ -31,9 +31,9 @@ public class FastTunnelHostingStartup : IHostingStartup }); }); - builder.Configure((webHostBuilderContext, app) => - { - app.UseFastTunnelServer(); - }); + //builder.Configure((webHostBuilderContext, app) => + //{ + // app.UseFastTunnelServer(); + //}); } } diff --git a/FastTunnel.Server/Startup.cs b/FastTunnel.Server/Startup.cs index 8619b23..eacfd70 100644 --- a/FastTunnel.Server/Startup.cs +++ b/FastTunnel.Server/Startup.cs @@ -102,9 +102,15 @@ public class Startup app.UseAuthorization(); // --------------------- Custom UI ---------------- + app.UseFastTunnelServer(); + app.UseEndpoints(endpoints => { endpoints.MapControllers(); + endpoints.MapFallback(async (HttpContext ctx) => + { + await ctx.Response.Body.WriteAsync(Encoding.UTF8.GetBytes("hello~")); + }); }); } } From c923bd41a71c2f49469f15f0721568b05e9b9b19 Mon Sep 17 00:00:00 2001 From: "Gui.H" Date: Fri, 1 Jul 2022 17:45:26 +0800 Subject: [PATCH 3/3] 1 --- Directory.Build.props | 2 - FastTunnel.Api/FastTunnel.Api.csproj | 1 + FastTunnel.Api/FastTunnelApiHostingStartup.cs | 80 +++++++++ FastTunnel.Client/FastTunnel.Client.csproj | 56 +++--- FastTunnel.Core/FastTunnel.Core.csproj | 1 + .../Kestrel/MiddleWare/FastTunelProtocol.cs | 2 +- FastTunnel.Hosting/FastTunnel.Hosting.csproj | 13 +- FastTunnel.Hosting/README.md | 166 ------------------ FastTunnel.Server/FastTunnel.Server.csproj | 3 +- FastTunnel.Server/Program.cs | 2 +- .../PublishProfiles/FolderProfile.pubxml | 13 +- .../PublishProfiles/FolderProfile1.pubxml | 20 --- .../PublishProfiles/FolderProfile2.pubxml | 16 -- FastTunnel.Server/Startup.cs | 41 +---- .../appsettings.Development.json | 12 -- FastTunnel.Server/appsettings.json | 50 ------ FastTunnel.Server/cmd/install.bat | 2 +- FastTunnel.Server/cmd/uninstall.bat | 2 +- 18 files changed, 131 insertions(+), 351 deletions(-) create mode 100644 FastTunnel.Api/FastTunnelApiHostingStartup.cs delete mode 100644 FastTunnel.Hosting/README.md delete mode 100644 FastTunnel.Server/Properties/PublishProfiles/FolderProfile1.pubxml delete mode 100644 FastTunnel.Server/Properties/PublishProfiles/FolderProfile2.pubxml delete mode 100644 FastTunnel.Server/appsettings.Development.json delete mode 100644 FastTunnel.Server/appsettings.json diff --git a/Directory.Build.props b/Directory.Build.props index 983776d..d7ce8e3 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,5 @@ - 3.0.0-Beta.1.22511 - net6.0 https://github.com/SpringHgui/FastTunnel Apache-2.0 FastTunnel diff --git a/FastTunnel.Api/FastTunnel.Api.csproj b/FastTunnel.Api/FastTunnel.Api.csproj index 9690092..ff58f5e 100644 --- a/FastTunnel.Api/FastTunnel.Api.csproj +++ b/FastTunnel.Api/FastTunnel.Api.csproj @@ -7,6 +7,7 @@ + diff --git a/FastTunnel.Api/FastTunnelApiHostingStartup.cs b/FastTunnel.Api/FastTunnelApiHostingStartup.cs new file mode 100644 index 0000000..412e6a2 --- /dev/null +++ b/FastTunnel.Api/FastTunnelApiHostingStartup.cs @@ -0,0 +1,80 @@ +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE +// Copyright (c) 2019 Gui.H + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using FastTunnel.Api; +using FastTunnel.Api.Filters; +using FastTunnel.Core.Config; +using FastTunnel.Core.Extensions; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.IdentityModel.Tokens; + +[assembly: HostingStartup(typeof(FastTunnelApiHostingStartup))] + +namespace FastTunnel.Api; + +public class FastTunnelApiHostingStartup : IHostingStartup +{ + public void Configure(IWebHostBuilder builder) + { + Debug.WriteLine("FastTunnelApiHostingStartup Configured"); + + builder.ConfigureServices((webHostBuilderContext, services) => + { + services.AddControllers(); + services.AddAuthorization(); + var serverOptions = webHostBuilderContext.Configuration.GetSection("FastTunnel").Get(); + if (serverOptions.Api?.JWT != null) + { + services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + .AddJwtBearer(options => + { + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuer = false, + ValidateAudience = false, + ValidateLifetime = true, + ClockSkew = TimeSpan.FromSeconds(serverOptions.Api.JWT.ClockSkew), + ValidateIssuerSigningKey = true, + ValidAudience = serverOptions.Api.JWT.ValidAudience, + ValidIssuer = serverOptions.Api.JWT.ValidIssuer, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(serverOptions.Api.JWT.IssuerSigningKey)) + }; + + options.Events = new JwtBearerEvents + { + OnChallenge = async context => + { + context.HandleResponse(); + + context.Response.ContentType = "application/json;charset=utf-8"; + context.Response.StatusCode = StatusCodes.Status200OK; + + await context.Response.WriteAsync(new + { + errorCode = 1, + errorMessage = context.Error ?? "Token is Required" + }.ToJson()); + }, + }; + }); + } + + services.AddSingleton(); + }); + } +} diff --git a/FastTunnel.Client/FastTunnel.Client.csproj b/FastTunnel.Client/FastTunnel.Client.csproj index 9d20edd..07c5341 100644 --- a/FastTunnel.Client/FastTunnel.Client.csproj +++ b/FastTunnel.Client/FastTunnel.Client.csproj @@ -1,34 +1,36 @@ - - Exe - + + 3.0.0-Beta.1.22511 + net7.0 + Exe + - - - - - + + + + + - - - + + + - - - Always - - - Always - - - Always - - + + + Always + + + Always + + + Always + + - - - - - + + + + + diff --git a/FastTunnel.Core/FastTunnel.Core.csproj b/FastTunnel.Core/FastTunnel.Core.csproj index a2ec8f9..a01cc20 100644 --- a/FastTunnel.Core/FastTunnel.Core.csproj +++ b/FastTunnel.Core/FastTunnel.Core.csproj @@ -1,6 +1,7 @@ 3.0.0-Beta.1.22511 + net6.0 README.md net6.0;net7.0 diff --git a/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/FastTunelProtocol.cs b/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/FastTunelProtocol.cs index 4ab9406..e6f505b 100644 --- a/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/FastTunelProtocol.cs +++ b/FastTunnel.Core/Forwarder/Kestrel/MiddleWare/FastTunelProtocol.cs @@ -44,7 +44,7 @@ public class FastTunelProtocol ReadOnlySequence readableBuffer; while (true) { - result = await _input.ReadAsync(); + result = await _input.ReadAsync(context.ConnectionClosed); var tempBuffer = readableBuffer = result.Buffer; SequencePosition? position = null; diff --git a/FastTunnel.Hosting/FastTunnel.Hosting.csproj b/FastTunnel.Hosting/FastTunnel.Hosting.csproj index cb6aff8..8bbb7b2 100644 --- a/FastTunnel.Hosting/FastTunnel.Hosting.csproj +++ b/FastTunnel.Hosting/FastTunnel.Hosting.csproj @@ -1,10 +1,10 @@ 3.0.0-Beta.1.22511 + net6.0;net7.0 enable enable README.md - net6.0;net7.0 @@ -15,16 +15,15 @@ - - - - - - + True \ + + + + diff --git a/FastTunnel.Hosting/README.md b/FastTunnel.Hosting/README.md deleted file mode 100644 index e9295b3..0000000 --- a/FastTunnel.Hosting/README.md +++ /dev/null @@ -1,166 +0,0 @@ -
- - - -## FastTunnel -[![License](https://img.shields.io/badge/license-Apache%202-green.svg)](https://www.apache.org/licenses/LICENSE-2.0) -[![Build status](https://github.com/anjoy8/blog.core/workflows/.NET%20Core/badge.svg)](https://github.com/SpringHgui/FastTunnel/actions) -[![Nuget](https://img.shields.io/nuget/v/FastTunnel.Core)](https://www.nuget.org/packages/FastTunnel.Core/) -[![Nuget](https://img.shields.io/nuget/dt/FastTunnel.Core)](https://www.nuget.org/packages/FastTunnel.Core/) - -[README](README.md) | [中文文档](README_zh.md) - - ***This project supports any commercial and secondary development activities, but seriously despises plagiarizing and copying the code, implementation scheme or architecture of this project and repackaging them into their own open source works.*** - -
- - -## What is FastTunnel? -- FastTunnel is a high-performance cross-platform intranet penetration tool. With it, you can expose intranet services to the public network for yourself or anyone to access. -- Unlike other penetration tools, the FastTunnel project is committed to creating an easy-to-extensible and easy-to-maintain intranet penetration framework. -- You can build your own penetration application by referencing the nuget package of `FastTunnel.Core`, and target the business extension functions you need. - - -*** - -Official website : https://suidao.io - -The penetration platform developed based on this framework, if you need intranet penetration, you can register and use it directly, eliminating the cost of building and maintaining yourself. -But do not use this service for important items. - -OpenSource: - -GitHub : [FastTunnel](https://github.com/SpringHgui/FastTunnel) -Gitee: [FastTunnel](https://gitee.com/Hgui/FastTunnel) - -**If helpful, click on ⭐Star to support this project, please submit an issue if you have needs and bugs, and welcome coder to PR** - -## Get GVP - -![img1](images/gvp.png) -*** - -## What can FastTunel do? -- [x] Remote intranet computer Windows/Linux/Mac -- [x] Use a custom domain name to access intranet web services (usually used for WeChat development) -- [x] Port forwarding/port mapping, access services provided by any port on the intranet mysql, redis, ftp, etc. -- [ ] p2p penetration -- [x] Support binding multiple domain names to access intranet services -- [x] Support domain name whitelist restriction -- [x] Support client identity verification - -## Quickstart -1. Download the corresponding program on the [releases](https://github.com/SpringHgui/FastTunnel/releases) page -2. Modify the client and server configuration files according to your needs`appsettings.json` -3. Run FastTunnel.Server -4. Run FastTunnel.Cient - -## Install FastTunel.Sever using Docker Engine -Configuration files and log files are mounted through volume. If this image has been run before, docker may not update to the latest image. Please delete the existing image manually, and then execute the following command - -``` -docker run --detach \ - --publish 1270:1270 --publish 1271:1271 \ - --name FastTunnel \ - --restart always \ - --volume /var/FastTunnel/config:/app/config \ - --volume /var/FastTunnel/Logs:/app/Logs \ - springhgui/fasttunnel:latest -``` -## Run on Linux/Mac os? -#### Windows -Double click directly `FastTunnel.Client.exe` to run -#### Linux -`chmod +x FastTunnel.Client` -`./FastTunnel.Client` -#### Mac -click directly `FastTunnel.Client` to run - -## Configuration example -### 1. Use a custom domain name to access intranet web services -- For example, you have a server with a public IP address of `110.110.110.110`, and you have a domain name with a top-level domain name of `abc.com`, you want to visit a website on the intranet by visiting `test.abc.com` -- You need to add a DNS resolution for the domain name address, the type is `A`, the name is `*`, and the ipv4 address is `110.110.110.110`, so that all domain names of `*.abc.com` will point to `110.110.110.110`’s server, because the default http port of `FastTunnel` is 1270, so you need to visit`http://test.abc.com:1270` - -- #### If you don't want to bring the port number every time you visit, you can use `nginx` forwarding. -``` -http { - # add resolver - resolver 8.8.8.8; - - # set *.abc.com to 1270 port - server { - server_name *.abc.com; - location / { - proxy_pass http://$host:1270; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - } - - # 可选 - error_log /var/log/nginx/error_ft.log error; - } -} -``` - -- If the domain name configured on the server is `ft.suidao.io`, then access the local site through the subdomain name `test.ft.suidao.io:1270`, the IIS configuration is as follows: -![img1](images/iis-web.png) - -### 2. Remote intranet computer Windows/Linux/Mac - -The client configuration is as follows, there are two hosts in the intranet, and the ip is as follows: -appsettings.json -``` - "ClientSettings": { - "Common": { - "ServerAddr": "xxx.xxx.xxx.xxx", - "ServerPort": 1271 - }, - "SSH": [ - { - "LocalIp": "192.168.0.100", // linux pc - "LocalPort": 22, // ssh default port - "RemotePort": 12701 - }, - { - "LocalIp": "192.168.0.101", // windows pc - "LocalPort": 3389, // windows default port for Remote - "RemotePort": 12702 - } - ] - } -``` -#### remote intranet linux host by ssh (ip:192.168.0.100) - -Assuming that the user name of the intranet host is root, the server ip is x.x.x.x, and the two hosts that access the intranet are as follows -``` -ssh -oPort=12701 root@x.x.x.x -``` - -#### remote desktop Windows host by mstsc (ip:192.168.0.101) -#### Controlled terminal setting -- Open cmd and enter the command `sysdm.cpl` in the pop-up dialog box and select Allow remote connection to this computer - -![img1](images/setallow.png) -#### Control terminal settings -- Open cmd and enter the command `mstsc`, open the remote dialog box, enter `x.x.x.x:12701` in the computer input box of the dialog box, and then specify the user name and password to remote the windows host of the intranet -![img1](images/remote.png) - -## Development/PR -- install `vs2019` last version -- install `.net5` or higher `https://dotnet.microsoft.com/download/dotnet/5.0` -- add `test.test.cc 127.0.0.1` in system host file -- run fasttunnel.server -- run fasttunnel.client - -## contributors - - - - -## Join QQ Group - -
- -## License -Apache License 2.0 diff --git a/FastTunnel.Server/FastTunnel.Server.csproj b/FastTunnel.Server/FastTunnel.Server.csproj index 2ebe337..fe8158b 100644 --- a/FastTunnel.Server/FastTunnel.Server.csproj +++ b/FastTunnel.Server/FastTunnel.Server.csproj @@ -1,6 +1,7 @@ - net6.0 + 3.0.0-Beta.1.22511 + net7.0 false diff --git a/FastTunnel.Server/Program.cs b/FastTunnel.Server/Program.cs index 4c08d96..d3d15c5 100644 --- a/FastTunnel.Server/Program.cs +++ b/FastTunnel.Server/Program.cs @@ -54,7 +54,7 @@ public class Program .ConfigureWebHost(webHostBuilder => { webHostBuilder.UseKestrel(); - webHostBuilder.UseSetting(WebHostDefaults.HostingStartupAssembliesKey, "FastTunnel.Hosting"); + webHostBuilder.UseSetting(WebHostDefaults.HostingStartupAssembliesKey, "FastTunnel.Api;FastTunnel.Hosting"); webHostBuilder.ConfigureAppConfiguration((hostingContext, config) => { diff --git a/FastTunnel.Server/Properties/PublishProfiles/FolderProfile.pubxml b/FastTunnel.Server/Properties/PublishProfiles/FolderProfile.pubxml index 040b013..36847ea 100644 --- a/FastTunnel.Server/Properties/PublishProfiles/FolderProfile.pubxml +++ b/FastTunnel.Server/Properties/PublishProfiles/FolderProfile.pubxml @@ -1,16 +1,17 @@  - + - False - False - True + false + false + true Release Any CPU FileSystem - bin\Release\net5.0\publish\ + bin\Release\net6.0\publish\ FileSystem + <_TargetId>Folder \ No newline at end of file diff --git a/FastTunnel.Server/Properties/PublishProfiles/FolderProfile1.pubxml b/FastTunnel.Server/Properties/PublishProfiles/FolderProfile1.pubxml deleted file mode 100644 index cb57135..0000000 --- a/FastTunnel.Server/Properties/PublishProfiles/FolderProfile1.pubxml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - False - False - True - Release - Any CPU - FileSystem - bin\Release\net5.0\publish\ - FileSystem - - net5.0 - def2e322-9075-4c3f-9967-7eaf0ee28ceb - false - - \ No newline at end of file diff --git a/FastTunnel.Server/Properties/PublishProfiles/FolderProfile2.pubxml b/FastTunnel.Server/Properties/PublishProfiles/FolderProfile2.pubxml deleted file mode 100644 index 040b013..0000000 --- a/FastTunnel.Server/Properties/PublishProfiles/FolderProfile2.pubxml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - False - False - True - Release - Any CPU - FileSystem - bin\Release\net5.0\publish\ - FileSystem - - \ No newline at end of file diff --git a/FastTunnel.Server/Startup.cs b/FastTunnel.Server/Startup.cs index eacfd70..287fdc8 100644 --- a/FastTunnel.Server/Startup.cs +++ b/FastTunnel.Server/Startup.cs @@ -35,45 +35,6 @@ public class Startup // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) - .AddJwtBearer(options => - { - var serverOptions = Configuration.GetSection("FastTunnel").Get(); - - options.TokenValidationParameters = new TokenValidationParameters - { - ValidateIssuer = false, - ValidateAudience = false, - ValidateLifetime = true, - ClockSkew = TimeSpan.FromSeconds(serverOptions.Api.JWT.ClockSkew), - ValidateIssuerSigningKey = true, - ValidAudience = serverOptions.Api.JWT.ValidAudience, - ValidIssuer = serverOptions.Api.JWT.ValidIssuer, - IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(serverOptions.Api.JWT.IssuerSigningKey)) - }; - - options.Events = new JwtBearerEvents - { - OnChallenge = async context => - { - context.HandleResponse(); - - context.Response.ContentType = "application/json;charset=utf-8"; - context.Response.StatusCode = StatusCodes.Status200OK; - - await context.Response.WriteAsync(new - { - errorCode = 1, - errorMessage = context.Error ?? "Token is Required" - }.ToJson()); - }, - }; - }); - - services.AddAuthorization(); - - services.AddControllers(); - #if DEBUG services.AddSwaggerGen(c => { @@ -109,7 +70,7 @@ public class Startup endpoints.MapControllers(); endpoints.MapFallback(async (HttpContext ctx) => { - await ctx.Response.Body.WriteAsync(Encoding.UTF8.GetBytes("hello~")); + await ctx.Response.Body.WriteAsync(Encoding.UTF8.GetBytes("404~")); }); }); } diff --git a/FastTunnel.Server/appsettings.Development.json b/FastTunnel.Server/appsettings.Development.json deleted file mode 100644 index 834acb9..0000000 --- a/FastTunnel.Server/appsettings.Development.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "Logging": { - "LogLevel": { - // Trace Debug Information Warning Error - "Default": "Debug", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" - } - }, - "AllowedHosts": "*", - "EnableFileLog": false -} diff --git a/FastTunnel.Server/appsettings.json b/FastTunnel.Server/appsettings.json deleted file mode 100644 index 79066a8..0000000 --- a/FastTunnel.Server/appsettings.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "Logging": { - "LogLevel": { - // Trace Debug Information Warning Error - "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" - } - }, - "AllowedHosts": "*", - - // 是否启用文件日志输出 - "EnableFileLog": false, - "FastTunnel": { - // Http&客户端通讯端口 - "BasePort": 1270, - - // 可选,绑定的根域名, - // 客户端需配置SubDomain,实现 ${SubDomain}.${WebDomain}访问内网的站点,注意:需要通过域名访问网站时必选。 - "WebDomain": "test.cc", - - // 可选,访问白名单,为空时:所有人有权限访问,不为空时:不在白名单的ip拒绝。 - "WebAllowAccessIps": [ "192.168.0.101" ], - - // 可选,是否开启端口转发代理,禁用后不处理Forward类型端口转发.默认false。 - "EnableForward": true, - - // 可选,当不为空时,客户端也必须携带Tokens中的任意一个token,否则拒绝登录。 - "Tokens": [ "TOKEN_FOR_CLIENT_AUTHENTICATION" ], - - /** - * 访问api接口的JWT配置 - */ - "Api": { - "JWT": { - "ClockSkew": 10, - "ValidAudience": "https://suidao.io", - "ValidIssuer": "FastTunnel", - "IssuerSigningKey": "This is IssuerSigningKey", - "Expires": 120 - }, - "Accounts": [ - { - "Name": "admin", - "Password": "admin123" - } - ] - } - } -} diff --git a/FastTunnel.Server/cmd/install.bat b/FastTunnel.Server/cmd/install.bat index 9099578..a2dba30 100644 --- a/FastTunnel.Server/cmd/install.bat +++ b/FastTunnel.Server/cmd/install.bat @@ -4,7 +4,7 @@ color 0e @echo ================================== @echo 提醒:请右键本文件,用管理员方式打开。 @echo ================================== -@echo Start Install FastTunnel.Server +@echo Start Install ./../FastTunnel.Server sc create FastTunnel.Server binPath=%~dp0\FastTunnel.Server.exe start= auto sc description FastTunnel.Server "FastTunnel-开源内网穿透服务,仓库地址:https://github.com/SpringHgui/FastTunnel star项目以支持作者" diff --git a/FastTunnel.Server/cmd/uninstall.bat b/FastTunnel.Server/cmd/uninstall.bat index 27a65bc..809820a 100644 --- a/FastTunnel.Server/cmd/uninstall.bat +++ b/FastTunnel.Server/cmd/uninstall.bat @@ -4,7 +4,7 @@ color 0e @echo ================================== @echo 提醒:请右键本文件,用管理员方式打开。 @echo ================================== -@echo Start Remove FastTunnel.Server +@echo Start Remove ./../FastTunnel.Server Net stop FastTunnel.Server sc delete FastTunnel.Server