ThreeMammals / Ocelot

.NET API Gateway
https://www.nuget.org/packages/Ocelot
MIT License
8.38k stars 1.64k forks source link

How to forward remote IP address for http? #1747

Closed OnSive closed 1 year ago

OnSive commented 1 year ago

When I send a ws request to the Blazor Server Side then I get the real remote IP address of the remote device, but when the request is a http request to the Rest API then the remote IP is ::1.

Since I cannot test the application on a server without considerable effort, I wonder if it could have to do with the debug environment.

Expected Behavior

Get the remote ip address on http and ws request

Actual Behavior

Remote ip address is ::1 on http and "real" on ws.

Specifications

Configs:

ocelot.json

"Routes": [
  {
    "__ServiceName": "Rest API",
    "DownstreamPathTemplate": "/api/{everything}",
    "DownstreamScheme": "http",
    "DownstreamHostAndPorts": [
      {
        "Host": "localhost",
        "Port": 5000
      }
    ],
    "UpstreamPathTemplate": "/api/{everything}",
    "UpstreamHttpMethod": [ "Get", "Delete", "Patch", "Put", "Post" ],
    "SwaggerKey": "crud"
  },
  {
    "__ServiceName": "Blazor Server Side",
    "DownstreamPathTemplate": "/{catchAll}",
    "DownstreamScheme": "ws",
    "DownstreamHostAndPorts": [
      {
        "Host": "localhost",
        "Port": 5001
      }
    ],
    "UpstreamPathTemplate": "/{catchAll}",
    "UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE", "OPTIONS" ]
  }

IpForwardHandler : DelegatingHandler

public sealed class IpForwardHandler : DelegatingHandler
{
    private readonly IHttpContextAccessor _contextAccessor;
    private readonly ILogger<IpForwardHandler> _logger;

    public IpForwardHandler(IHttpContextAccessor contextAccessor, ILogger<IpForwardHandler> logger)
    {
        _contextAccessor = contextAccessor;
        _logger = logger;
    }

    protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        AddIpHeader(request, cancellationToken);
        return base.Send(request, cancellationToken);
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        AddIpHeader(request, cancellationToken);
        return base.SendAsync(request, cancellationToken);
    }

    private void AddIpHeader(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        const string key = "X-Forwarded-For";
        if (!request.Headers.Any(x => x.Key == key))
        {
            var ip = _contextAccessor.HttpContext.Connection.RemoteIpAddress.ToString();
            request.Headers.Add(key, ip);
            _logger.LogInformation("Added IP {ip}", ip);
        }
    }
}

Additional question

What would be a feasible way to forward the remote ip address? as the:

"UpstreamHeaderTransform": {
  "X-Forwarded-For": "{RemoteIpAddress}"
}

Configuration does not seem to do anything. (at least not in the ASP.NET backend)

raman-m commented 1 year ago

Well...

When I send a ws request to the Blazor Server Side Get the remote ip address on http and ws request

Are you saying about Websockets requests? Websockets feature?


Remote ip address is ::1 on http and "real" on ws.

Yeah, you see such facts because of different protocols, and they behave differently. Don't you ask us, as Ocelot team, to fix that? 🤣


    "DownstreamHostAndPorts": [
      {
        "Host": "localhost", // come on!
        "Port": 5000
      }
    ],

You use localhost and local environment PC to host the solution, and you wonder why do you have localhost addresses? Come on! What is your upstream settings in global section? I mean this:

    "GlobalConfiguration": {
        "BaseUrl": "somehost:someport"
    }

I guess, BaseUrl is also localhost, right? 😉


IpForwardHandler : DelegatingHandler

Why do you write special delegating handler to get remote address IP? It seems you didn't read the documentation...

raman-m commented 1 year ago

I don't see the issue! I'm going to convert to a discussion...