コード例 #1
0
        private void HostLocalhost(ProxyContext ctx)
        {
            if (TrimHost("userstream.twitter.com"))
            {
                this.HostStreaming(ctx);
                return;
            }

            if (TrimHost("api.twitter.com"))
            {
                this.HostAPI(ctx);
                return;
            }

            ctx.Response.StatusCode = HttpStatusCode.BadRequest;

            bool TrimHost(string host)
            {
                if (ctx.Request.RequestUri.AbsolutePath.StartsWith($"/{host}/"))
                {
                    ctx.Request.RequestUri = new UriBuilder(ctx.Request.RequestUri)
                    {
                        Host = host,
                        Path = ctx.Request.RequestUri.AbsolutePath.Substring(host.Length + 1),
                    }.Uri;

                    return(true);
                }

                return(false);
            }
        }
コード例 #2
0
        public virtual async Task SetContentAsync(
            ProxyContext context,
            HttpResponseMessage upstreamResponse,
            CancellationToken cancellationToken)
        {
            CheckValue(context, nameof(context));
            CheckValue(upstreamResponse, nameof(upstreamResponse));

            cancellationToken.ThrowIfCancellationRequested();

            if (upstreamResponse.Content is null)
            {
                Logger.LogDebug("The inbound upstream response does not have a content body.");
                return;
            }

            var contentLength = upstreamResponse.Content.Headers?.ContentLength;

            if (contentLength is not null && contentLength <= 0)
            {
                Logger.LogDebug("The inbound upstream response has a content length that is less than or equal to zero.");
                return;
            }

            await SetContentHeadersAsync(context, upstreamResponse, cancellationToken);
            await SetContentBodyAsync(context, upstreamResponse, cancellationToken);
        }
コード例 #3
0
        /// <summary>
        /// The Via general header is added by proxies, both forward and reverse proxies, and can appear in
        /// the request headers and the response headers. It is used for tracking message forwards, avoiding
        /// request loops, and identifying the protocol capabilities of senders along the request/response chain.
        /// See <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Via">here</a> for more information.
        /// </summary>
        protected virtual void AddViaHeader(ProxyContext context, HttpRequestMessage upstreamRequest)
        {
            var builder = new StringBuilder();

            if (!context.ProxyUpstreamRequestHeadersSettings.DiscardInboundHeaders)
            {
                if (context.Request.Headers.TryGetValue(HeaderNames.Via, out var values) && values.Count > 0)
                {
                    foreach (var value in values)
                    {
                        builder.Append(value).AppendComma().AppendSpace();
                    }
                }
            }

            if (context.Request.Protocol.StartsWithOrdinalIgnoreCase(HttpProtocolPrefix))
            {
                var version = context.RequestHttpVersion;
                builder.Append(version.Major).AppendDot().Append(version.Minor);
            }
            else
            {
                builder.Append(context.Request.Protocol);
            }

            builder.AppendSpace().Append(context.ProxyName);

            upstreamRequest.Headers.TryAddWithoutValidation(
                HeaderNames.Via,
                builder.ToString());
        }
コード例 #4
0
        private async Task <bool> ProxyAsync(HttpContext httpContext)
        {
            if (!routeResolver.TryResolve(httpContext, out var route))
            {
                return(false);
            }

            logger.LogDebug(
                "Reverse proxy found a matching route for the inbound downstream HTTP '{0}' request.",
                httpContext.Request.Method);

            var context = new ProxyContext(
                evaluator,
                httpContext,
                route);

            var cancellationToken = httpContext.RequestAborted;
            var upstreamRequest   = await CreateUpstreamRequestAsync(context, cancellationToken);

            var upstreamResponse = await SendUpstreamRequestAsync(context, upstreamRequest, cancellationToken);

            await SendDownstreamResponseAsync(context, upstreamResponse, cancellationToken);

            return(true);
        }
コード例 #5
0
 protected virtual void AddServerHeader(ProxyContext context, HttpResponseMessage upstreamResponse)
 {
     AddHeaderValues(
         context,
         HeaderNames.Server,
         Constants.ServerName);
 }
コード例 #6
0
        protected override object GetProperty(object target, string propName, ProxyContext proxyContext)
        {
            if (propName == null)
            {
                throw new ArgumentNullException("propName");
            }
            if (proxyContext == null)
            {
                throw new ArgumentNullException("proxyContext");
            }
            CJG site = target as CJG;

            if (site == null)
            {
                throw new ArgumentNullException("target");
            }
            propName = base.GetMemberName(propName, proxyContext);

            switch (propName)
            {
            case "FirstName":
                base.CheckBlockedGetProperty("FirstName", proxyContext);
                return(site.FirstName);
            }

            return(base.GetProperty(target, propName, proxyContext));
        }
コード例 #7
0
        private bool HostAPI(ProxyContext ctx)
        {
            switch (ctx.Request.RequestUri.AbsolutePath)
            {
            // api 호출 후 스트리밍에 destroy 날려주는 함수
            // POST https://api.twitter.com/1.1/statuses/destroy/:id.json
            // POST https://api.twitter.com/1.1/statuses/unretweet/:id.json
            case string path when path.StartsWith("/1.1/statuses/destroy/", StringComparison.OrdinalIgnoreCase) ||
                path.StartsWith("/1.1/statuses/unretweet/", StringComparison.OrdinalIgnoreCase):
                return(HandleDestroyOrUnretweet(ctx));

            // api 호출 후 스트리밍에 리트윗 날려주는 함수
            // 404 : id = 삭제된 트윗일 수 있음
            // 200 : 성공시 스트리밍에 전송해서 한번 더 띄우도록
            // POST https://api.twitter.com/1.1/statuses/retweet/:id.json
            case string path when path.StartsWith("/1.1/statuses/retweet/", StringComparison.OrdinalIgnoreCase):
                return(HandleRetweet(ctx));

            // d @ID 로 DM 보내는 기능 추가된 함수.
            // 401 : in_reply_to_status_id = 삭제된 트윗일 수 있음
            // POST https://api.twitter.com/1.1/statuses/update.json
            case string path when path.Equals("/1.1/statuses/update.json", StringComparison.OrdinalIgnoreCase):
                return(HandleUpdate(ctx));

            default:
                return(HandleTunnel(ctx));
            }
        }
コード例 #8
0
        public virtual Task SetHeadersAsync(
            ProxyContext context,
            HttpResponseMessage upstreamResponse,
            CancellationToken cancellationToken)
        {
            CheckValue(context, nameof(context));
            CheckValue(upstreamResponse, nameof(upstreamResponse));

            cancellationToken.ThrowIfCancellationRequested();

            var settings = context.ProxyDownstreamResponseHeaderSettings;

            if (!settings.DiscardInboundHeaders)
            {
                AddUpstreamResponseHeadersToDownstream(context, upstreamResponse);
            }

            if (settings.AddVia)
            {
                AddViaHeader(context, upstreamResponse);
            }

            if (settings.AddServer)
            {
                AddServerHeader(context, upstreamResponse);
            }

            AddExtraHeaders(context);

            return(Task.CompletedTask);
        }
コード例 #9
0
ファイル: Program.cs プロジェクト: sunsx0/mtproto-proxy
        static void Main(string[] args)
        {
            if (args.Intersect(new[] { "--help", "-h" }).Count() > 0 || args.Length > 1)
            {
                Console.WriteLine("./tgsocks [CONFIG_PATH]");
            }
            var configPath = DefaultConfigPath;

            if (args.Length == 1)
            {
                configPath = args[0];
            }
            if (!File.Exists(configPath))
            {
                Console.WriteLine($"{configPath} not found");
                return;
            }
            var config       = Newtonsoft.Json.JsonConvert.DeserializeObject <Config>(File.ReadAllText(configPath));
            var proxyContext = new ProxyContext();

            proxyContext.CheckProto  = true;
            proxyContext.DataCentres = config.DataCentres.ToArray();
            proxyContext.Secret      = Enumerable.
                                       Range(0, config.Secret.Length / 2).
                                       Select(
                x => Convert.ToByte(
                    config.Secret.Substring(x * 2, 2),
                    16
                    )
                ).
                                       ToArray();
            Log("Secret: " + string.Join("", proxyContext.Secret.Select(x => x.ToString("x2"))));
            var proxyManager = new ProxyManager(
                proxyContext,
                config.ConnectionsPerThread,
                config.SelectTimeout,
                config.ReceiveBufferSize
                );

            foreach (var srv in config.Servers)
            {
                var ip   = IPAddress.Parse(srv.Host);
                var port = srv.Port;
                proxyManager.AddServer(new IPEndPoint(ip, port), ip.AddressFamily, srv.Backlog);
            }

            proxyManager.Connections.OnConnectionRegistered += Connections_OnConnectionRegistered;
            proxyManager.Connections.OnConnectionRemoved    += Connections_OnConnectionRemoved;

            Log("OK, Load config complete, starting");
            Console.CancelKeyPress += (a, b) => {
                Log("Stopping...");
                proxyManager.Stop();
                Log("Stopped");
            };
            proxyManager.Start();
            Log("Server started");
            System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
        }
コード例 #10
0
 private static ForwardedHeaderValue CreateLatestForwardHeaderValue(ProxyContext context)
 {
     return(new ForwardedHeaderValue(
                by: CreateValidForwardedIpAddress(context.HttpContext.Connection.LocalIpAddress),
                @for: CreateValidForwardedIpAddress(context.HttpContext.Connection.RemoteIpAddress),
                host: context.Request.Host.Value,
                proto: context.Request.Scheme));
 }
コード例 #11
0
 private async Task <HttpRequestMessage> CreateUpstreamRequestAsync(
     ProxyContext context,
     CancellationToken cancellationToken)
 {
     return(await requestCreator
            .CreateRequestAsync(context, cancellationToken)
            .TraceOnFaulted(logger, "Failed to create an outbound upstream request.", cancellationToken));
 }
コード例 #12
0
 protected virtual void AddProxyNameHeader(ProxyContext context, HttpRequestMessage upstreamRequest)
 {
     AddHeaderValues(
         context,
         upstreamRequest,
         Names.ProxyName,
         context.ProxyName);
 }
コード例 #13
0
        public TimeSpan EvaluateTimeout(ProxyContext context)
        {
            var result = context.Evaluate(TimeoutInMillisecondsExpression);

            return(long.TryParse(result, out var timeout) && timeout > 0
                ? TimeSpan.FromMilliseconds(timeout)
                : Defaults.Route.Proxy.Upstream.Request.Sender.Timeout);
        }
コード例 #14
0
 public static void CreateNonVerifiableContext()
 {
     var context = new ProxyContext(AssemblyBuilderAccess.RunAndSave, false, false);
     Assert.False(context.Verify);
     Assert.False(context.GenerateDebugging);
     Assert.True((context.Access & AssemblyBuilderAccess.Run) == AssemblyBuilderAccess.Run);
     Assert.True((context.Access & AssemblyBuilderAccess.Save) == AssemblyBuilderAccess.Save);
 }
コード例 #15
0
        /// <summary>
        /// Response 전송 하므로 사용에 주의
        /// 오류 발생 시 false 를 반환함. return 해줘야 함.
        /// </summary>
        private static bool TryCallAPIThenSetContext <T>(ProxyContext ctx, Stream proxyReqBody, TwitterClient client, out HttpStatusCode responseStatusCode, out T response)
            where T : class
        {
            var res = TryCallAPIThenSetContext(ctx, proxyReqBody, client, typeof(T), out responseStatusCode, out var obj);

            response = obj as T;
            return(res);
        }
コード例 #16
0
        public string EvaluateProxyName(ProxyContext context)
        {
            var eval = context.Evaluate(ProxyNameExpression);

            return(string.IsNullOrWhiteSpace(eval)
                ? Defaults.Route.Proxy.ProxyName
                : eval);
        }
コード例 #17
0
        protected override IEnumerable <MethodInformation> GetMethods(ProxyContext proxyContext)
        {
            if (proxyContext == null)
            {
                throw new ArgumentNullException("proxyContext");
            }

            MethodInformation iteratorVariable1 = new MethodInformation
            {
                Name                   = "ReturnInt",
                IsStatic               = false,
                OperationType          = OperationType.Default,
                ClientLibraryTargets   = ClientLibraryTargets.All,
                OriginalName           = "ReturnInt",
                WildcardPath           = false,
                ReturnType             = typeof(int),
                ReturnODataType        = ODataType.Primitive,
                RESTfulExtensionMethod = true,
                ResourceUsageHints     = ResourceUsageHints.None,
                RequiredRight          = ResourceRight.Default
            };

            yield return(iteratorVariable1);

            MethodInformation iteratorVariable2 = new MethodInformation
            {
                Name                   = "ReturnDate",
                IsStatic               = false,
                OperationType          = OperationType.Default,
                ClientLibraryTargets   = ClientLibraryTargets.All,
                OriginalName           = "ReturnDate",
                WildcardPath           = false,
                ReturnType             = typeof(DateTime),
                ReturnODataType        = ODataType.Primitive,
                RESTfulExtensionMethod = true,
                ResourceUsageHints     = ResourceUsageHints.None,
                RequiredRight          = ResourceRight.Default
            };

            yield return(iteratorVariable2);

            MethodInformation iteratorVariable3 = new MethodInformation
            {
                Name                   = ".ctor",
                IsStatic               = false,
                OperationType          = OperationType.Default,
                ClientLibraryTargets   = ClientLibraryTargets.RESTful,
                OriginalName           = ".ctor",
                WildcardPath           = false,
                ReturnType             = null,
                ReturnODataType        = ODataType.Invalid,
                RESTfulExtensionMethod = false,
                ResourceUsageHints     = ResourceUsageHints.None,
                RequiredRight          = ResourceRight.None
            };

            yield return(iteratorVariable3);
        }
コード例 #18
0
        protected virtual void AddUpstreamResponseHeadersToDownstream(
            ProxyContext context,
            HttpResponseMessage upstreamResponse)
        {
            var headers = upstreamResponse.Headers;

            if (headers is null)
            {
                return;
            }

            var options              = context.ProxyDownstreamResponseHeaderSettings;
            var discardEmpty         = options.DiscardEmpty;
            var discardUnderscore    = options.DiscardUnderscore;
            var doNotTransferHeaders = options.DoNotTransferHeaders;
            ICollection <string>?nonStandardHopByHopHeaders = null; // lazy instantiate if and only if needed

            foreach (var header in headers)
            {
                var name = header.Key;

                if (!sanitizer.IsValid(
                        name,
                        header.Value,
                        discardEmpty,
                        discardUnderscore))
                {
                    continue;
                }

                if (doNotTransferHeaders.Contains(name))
                {
                    continue;
                }

                var values = header.Value.AsStringValues();

                if (name.EqualsOrdinalIgnoreCase(HeaderNames.SetCookie))
                {
                    UpdateSetCookiesValues(context, values);
                }
                else
                {
                    if (nonStandardHopByHopHeaders is null)
                    {
                        nonStandardHopByHopHeaders = GetNonStandardHopByHopHeaders(headers);
                    }

                    if (nonStandardHopByHopHeaders.Contains(name))
                    {
                        continue;
                    }
                }

                AddHeaderValues(context, name, values);
            }
        }
コード例 #19
0
 public virtual bool TryGetHeaderValues(
     ProxyContext context,
     string name,
     StringValues downstreamValues,
     out StringValues upstreamValues)
 {
     upstreamValues = downstreamValues;
     return(true);
 }
コード例 #20
0
 protected override object InvokeConstructor(ClientValueCollection xmlargs, ProxyContext proxyContext)
 {
     if (proxyContext == null)
     {
         throw new ArgumentNullException("proxyContext");
     }
     base.CheckBlockedMethod(".ctor", proxyContext);
     return(CJG_ConProxy(xmlargs, proxyContext));
 }
コード例 #21
0
        public static void CreateDefaultContext()
        {
            var context = new ProxyContext();

            Assert.False(context.Verify);
            Assert.False(context.GenerateDebugging);
            Assert.True((context.Access & AssemblyBuilderAccess.Run) == AssemblyBuilderAccess.Run);
            Assert.False((context.Access & AssemblyBuilderAccess.Save) == AssemblyBuilderAccess.Save);
        }
コード例 #22
0
 private async Task SendDownstreamResponseAsync(
     ProxyContext context,
     HttpResponseMessage upstreamResponse,
     CancellationToken cancellationToken)
 {
     await responseSender
     .SendResponseAsync(context, upstreamResponse, cancellationToken)
     .TraceOnFaulted(logger, "Failed to create and send the downstream response message.", cancellationToken);
 }
コード例 #23
0
 public static void CreateSpecificContext()
 {
     var context = new ProxyContext(
          AssemblyBuilderAccess.RunAndSave, true, true);
     Assert.True(context.Verify);
     Assert.True(context.GenerateDebugging);
     Assert.True((context.Access & AssemblyBuilderAccess.Run) == AssemblyBuilderAccess.Run);
     Assert.True((context.Access & AssemblyBuilderAccess.Save) == AssemblyBuilderAccess.Save);
 }
コード例 #24
0
        /// <inheritdoc/>
        public Task <Uri> CreateAsync(ProxyContext context, CancellationToken cancellationToken)
        {
            var toExpression = context.ProxySettings.To;
            var to           = evaluator.Evaluate(context, toExpression);

            string         scheme;
            HostString     host;
            PathString     toPath;
            QueryString    toQueryString;
            FragmentString fragment;

            try
            {
                UriHelper.FromAbsolute(
                    to,
                    out scheme,
                    out host,
                    out toPath,
                    out toQueryString,
                    out fragment);
            }
            catch (FormatException ufe)
            {
                var message = $"Using '{context.ProxySettings.To}' expression to rewrite request URL '{context.Request.Path}'. However, the rewritten URL is not a valid URL format.";
                logger.LogError(ufe, message);
                throw new UriFormatException(message, ufe);
            }

            if (!Uri.CheckSchemeName(scheme))
            {
                throw new UriFormatException($"The HTTP scheme '{scheme}' specified by '{toExpression}' expression is invalid.");
            }

            if (!host.HasValue || Uri.CheckHostName(GetHostValue(host.Value)) == UriHostNameType.Unknown)
            {
                throw new UriFormatException($"The URL host '{host}' specified by '{toExpression}' expression is invalid.");
            }

            var path        = ConcatPathWithSuffix(toPath, context.Route.PathSuffix);
            var queryString = toQueryString + context.Request.QueryString;

            var url = UriHelper.BuildAbsolute(
                scheme,
                host,
                PathString.Empty,
                path,
                queryString,
                fragment);

            if (Uri.TryCreate(url, UriKind.Absolute, out var uri))
            {
                return(Task.FromResult(uri));
            }

            throw new UriFormatException($"The URL '{url}' specified by '{toExpression}' expression is an invalid absolute HTTP URL.");
        }
コード例 #25
0
        private static void HandleTunnel(ProxyContext ctx)
        {
            TryGetTwitterClient(ctx, null, out var twitClient);

            if (!TryCallAPIThenSetContext(ctx, null, twitClient, null, out _, out _))
            {
                ctx.Response.Headers.Clear();
                ctx.Response.StatusCode = HttpStatusCode.InternalServerError;
            }
        }
コード例 #26
0
        private void SetStatusCode(ProxyContext context, HttpResponseMessage upstreamResponse)
        {
            if (context.Response.HasStarted)
            {
                logger.LogError("It is not possible to transfer the HTTP status code from the inbound upstream response to the outbound downstream response. This should never happen!");
                return;
            }

            context.Response.StatusCode = (int)upstreamResponse.StatusCode;
        }
コード例 #27
0
        public static void CreateSpecificContext()
        {
            var context = new ProxyContext(
                AssemblyBuilderAccess.RunAndSave, true, true);

            Assert.True(context.Verify);
            Assert.True(context.GenerateDebugging);
            Assert.True((context.Access & AssemblyBuilderAccess.Run) == AssemblyBuilderAccess.Run);
            Assert.True((context.Access & AssemblyBuilderAccess.Save) == AssemblyBuilderAccess.Save);
        }
コード例 #28
0
        protected override object GetProperty(object target, string propName, ProxyContext proxyContext)
        {
            propName = GetMemberName(propName, proxyContext);
            switch (propName)
            {
            case "About":
                CheckBlockedGetProperty("About", proxyContext);
                return(((CustomService)target).About);
            }

            return(base.GetProperty(target, propName, proxyContext));
        }
コード例 #29
0
        public static T CreateProxy <T>(this T @this, ProxyContext context, params IInvocationHandler[] handlers)
            where T : class
        {
            @this.CheckCreatePreconditions(handlers);

            var targetType = @this.GetType();

            ProxyBuilder.Build(targetType, context);
            var arguments = new object[] { @this, handlers };

            return(Activator.CreateInstance(BuiltProxies.Mappings[targetType], arguments) as T);
        }
コード例 #30
0
        private async Task SetHeadersAsync(
            ProxyContext context,
            HttpResponseMessage upstreamResponse,
            CancellationToken cancellationToken)
        {
            logger.LogDebug("Appending the HTTP headers to the outbound downstream response");

            await headerSetter
            .SetHeadersAsync(context, upstreamResponse, cancellationToken)
            .TraceOnFaulted(logger, "Failed to set the headers on the outbound downstream response", cancellationToken);

            logger.LogDebug("Appended the HTTP headers to the outbound downstream response");
        }
コード例 #31
0
        private async Task SetHeadersAsync(
            ProxyContext context,
            HttpRequestMessage upstreamRequest,
            CancellationToken cancellationToken)
        {
            logger.LogDebug("Appending the HTTP headers to the outbound upstream request");

            await headerSetter
            .SetHeadersAsync(context, upstreamRequest, cancellationToken)
            .TraceOnFaulted(logger, "Failed to set the content body of the outbound upstream request", cancellationToken);

            logger.LogDebug("Appended the HTTP headers to the outbound upstream request");
        }
コード例 #32
0
        private async Task SetContentAsync(
            ProxyContext context,
            HttpResponseMessage upstreamResponse,
            CancellationToken cancellationToken)
        {
            logger.LogDebug("Transferring the content of the inbound upstream response to the outbound downstream response");

            await contentSetter
            .SetContentAsync(context, upstreamResponse, cancellationToken)
            .TraceOnFaulted(logger, "Failed to set the content body of the outbound downstream response", cancellationToken);

            logger.LogDebug("Transferred the content of the inbound upstream response to the outbound downstream response");
        }