kerryjiang / SuperSocket

SuperSocket is a light weight, cross platform and extensible socket server application framework.
Apache License 2.0
3.9k stars 1.15k forks source link

Proxy Protocol Support #739

Open alberk8 opened 1 month ago

alberk8 commented 1 month ago

Is it possible to add ProxyProtocol support for SuperSocket?. Thank you.

kerryjiang commented 1 month ago

Do you mean this? https://github.com/SuperSocket/SuperSocket.ProxyServer

This one is still based on SuperSocket 1.6.*. I will spend some time to upgrade it to SuperSocket 2.0.

alberk8 commented 1 month ago

Do you mean this? https://github.com/SuperSocket/SuperSocket.ProxyServer

This one is still based on SuperSocket 1.6.*. I will spend some time to upgrade it to SuperSocket 2.0.

I think is different. The proxy protocol is more from Reverse Proxy Server. A good example is if the SuperSocket docker is sitting behind Traefik then I get the IP of traefik and not the client remote IP. With Proxy Protocol where the Reverse Proxy server will add data related to the remote IP much like Http X-Forwarded-For but at the packet level.

https://developers.cloudflare.com/spectrum/how-to/enable-proxy-protocol/
https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt

AsenLins commented 1 month ago

I also asked a similar question before. I used Haproxy reverse proxy, so the client IP becomes the IP of the reverse proxy. Haproxy supports the send-proxy protocol and can be parsed from the send-proxy protocol. To the source IP, does SuperSocket 2.0 support it?

alberk8 commented 1 month ago

I also asked a similar question before. I used Haproxy reverse proxy, so the client IP becomes the IP of the reverse proxy. Haproxy supports the send-proxy protocol and can be parsed from the send-proxy protocol. To the source IP, does SuperSocket 2.0 support it?

No at the moment because SuperSocket does not not process the Proxy Protocol if that is switched on in the Reverse Proxy server.

kerryjiang commented 4 weeks ago

It's on the way: https://github.com/kerryjiang/SuperSocket/commit/49df1f2998a7e488a31140ca337b555b4d38505d

alberk8 commented 4 weeks ago

I tried to adding EnabledProxyProtocol into appsettings and it does not seems to work what else do I need to do? Thank you.

Update: The latest myget nuget seems to fix the issue.

kerryjiang commented 4 weeks ago

Yes, haven't pushed the latest package to nuget.

Please help me confirm if this feature can work. I will push a new version to nuget ASAP.

@alberk8

alberk8 commented 4 weeks ago

I have tested and it looks like the Server EndPoint IP is in reverse order. The Server Endpoint should read 192.168.2.15
The Client IP 172.27.0.3 is the IP of the SuperSocket Docker Container and supersocket is behind the Traefik Proxy Server.

We also need to better define the IP source and target differentiation

.UsePackageHandler(async (session, package) =>
{
  Console.WriteLine($"Server EndPioint {((IPEndPoint)session.RemoteEndPoint).Address.ToString()} Client EndPoint {((IPEndPoint)session.Connection.RemoteEndPoint).Address.ToString()} ");
}

Server EndPioint 15.2.168.192 Client EndPoint 172.27.0.3

kerryjiang commented 4 weeks ago

Try this instead.

.UsePackageHandler(async (session, package) =>
{
  Console.WriteLine($"Server EndPioint {((IPEndPoint)session.LocalEndPoint).Address.ToString()} Client EndPoint {((IPEndPoint)session.RemoteEndPoint).Address.ToString()} ");
}
kerryjiang commented 4 weeks ago

If you want to access the original destination endpoint, you can use the statement below:

session.Connection.ProxyInfo.DestinationIPAddress;

or

session.Connection.ProxyInfo.DestinationEndPoint;
kerryjiang commented 4 weeks ago

I have tested and it looks like the Server EndPoint IP is in reverse order. The Server Endpoint should read 192.168.2.15 The Client IP 172.27.0.3 is the IP of the SuperSocket Docker Container and supersocket is behind the Traefik Proxy Server.

We also need to better define the IP source and target differentiation

.UsePackageHandler(async (session, package) =>
{
  Console.WriteLine($"Server EndPioint {((IPEndPoint)session.RemoteEndPoint).Address.ToString()} Client EndPoint {((IPEndPoint)session.Connection.RemoteEndPoint).Address.ToString()} ");
}

Server EndPioint 15.2.168.192 Client EndPoint 172.27.0.3

15.2.168.192 was read as original client ip, 172.27.0.3 was read as proxy server's ip.

kerryjiang commented 4 weeks ago

That means the addresses (at least ipv4) are read in reverse order.

alberk8 commented 4 weeks ago

Yes the IP for the ProxyInfo is in reverse order

.UsePackageHandler(async (session, package) =>
{
   Console.WriteLine($"Server EndPioint {((IPEndPoint)session.RemoteEndPoint).Address.ToString()} Client EndPoint {((IPEndPoint)session.Connection.RemoteEndPoint).Address.ToString()} ");
  Console.WriteLine($"Proxy Info Source: {session.Connection.ProxyInfo.SourceIPAddress.ToString()} Destination: {session.Connection.ProxyInfo.SourceIPAddress.ToString()}");
}

Server EndPioint 15.2.168.192 Client EndPoint 172.20.0.3 Proxy Info Source: 15.2.168.192 Destination: 15.2.168.192

kerryjiang commented 4 weeks ago

Pushed one fix.

alberk8 commented 4 weeks ago

I am using Proxy Protocol Version 2 and you code looks right according to Proxy Protocol specs. The reverse proxy I am using is traefik v3.1.1, Have you tested with Proxy protocol with any other Reverse proxy server?

Update: I tried this Aspnet with ProxyProtocol example and it looks ok. I think you need to check for endianess

alberk8 commented 4 weeks ago

Pushed one fix.

Tested and now the IPV4 is the correct order. I looked at your code again, I think you need to reverse the IPV6 also (I have not tested that yet).

There is one thing I notice is that the session.Connection.ProxyInfo.SourceIPAddress and session.Connection.ProxyInfo.SourceIPAddress are exactly identical. I will dig in further once I get more time.

kerryjiang commented 3 weeks ago

Probably reversing bytes for ipv6 is not necessary because original bytes are taken directly. But I will do further confirming.

Do you mean ProxyInfo.SourceIPAddress and ProxyInfo.DestinationIPAddress are same?

alberk8 commented 3 weeks ago

Probably reversing bytes for ipv6 is not necessary because original bytes are taken directly. But I will do further confirming.

Do you mean ProxyInfo.SourceIPAddress and ProxyInfo.DestinationIPAddress are same?

The IPV6 address from the ProxyProtocol is in BigEndian format so on a little endian platform it will look reverse if the reversing is not done.

yes both source and destination IP are the same.

kerryjiang commented 3 weeks ago

I am working on more unit tests and already noticed the problem of ipv6.

alberk8 commented 3 weeks ago

One more thing. if I call the session.Connection.ProxyInfo.SourceIPAddress when the enableProxyProtocol is not set it will throw a null reference. Can this not throw?

kerryjiang commented 3 weeks ago

One more thing. if I call the session.Connection.ProxyInfo.SourceIPAddress when the enableProxyProtocol is not set it will throw a null reference. Can this not throw?

Can you use session.RemoteEndPoint.Address? That uses source ip address from proxy info at first. If proxy address is not set, the address will be the physical source ip address.

kerryjiang commented 3 weeks ago

@alberk8 @AsenLins

I think I have fixed the problem of ipv6 just now.

kerryjiang commented 3 weeks ago

Please help me confirm if you can.