fatedier / frp

A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.
Apache License 2.0
86.46k stars 13.37k forks source link

[Feature Request] Make client IP accessible to upstream by spoofing source IP #4184

Open dong-zeyu opened 6 months ago

dong-zeyu commented 6 months ago

Describe the feature request

As a reverse proxy, FRP currently supports two ways for the upstream server to obtain the client's real IP: HTTP X-Forwarded-For and Proxy Protocol. The former only supports HTTP protocol and the latter supports generic TCP connection but would require support for uptream. My current solution for upstreams that do not support proxy protocol is to use mmproxy or go-mmproxy to wrap the bare TCP with the proxy protocol. However, this requires configuring additional programs and upstream ports and also introduces overhead to copy data between the processes.

Describe alternatives you've considered

The underlying technology that mmproxy uses is TPROXY supported by the Linux kernel. This can be easily implemented in Go by a few lines of code (I referred to go-mmproxy)

dialer := net.Dialer{LocalAddr: saddr}
dialer.Control = func(network, address string, c syscall.RawConn) error {
    return c.Control(func(fd uintptr) {
        syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_TRANSPARENT, 1)
    })
}

saddr is the remote client address obtained from the FRP server. Then the upstream will be connected as if it is directly connected from the IP address of the remote client.

By doing so, the FRP client would support spoofing the client IP to the upstream out-of-box, without further configuration to the upstream or running additional programs.

However, this functionality still has certain limitations: first, this would only work on the Linux system as far as I know; second, configurations to the Linux firewall/routing is still needed (these configurations are global and do not need to be set separately for each service); third, CAP_NET_ADMIN capability is required to set IP_TRANSPARENT socket opt.

I have a simple PoC for this feature in my fork, but maybe more work is needed to make it into the FRP.

Affected area

fatedier commented 6 months ago

However, this functionality still has certain limitations: first, this would only work on the Linux system as far as I know; second, configurations to the Linux firewall/routing is still needed (these configurations are global and do not need to be set separately for each service); third, CAP_NET_ADMIN capability is required to set IP_TRANSPARENT socket opt.

This is one of the reasons we were not too keen on introducing related features before.

Currently, it may be a wiser choice to combine more professional tools.

I hope to see more practical demand scenarios. Changes in this area will only be considered after we have made progress in the refactoring and optimization of our core architecture.

crabdancing commented 2 months ago

One reason this feature is potentially important is that the company I work for is interested in localizing the TLS encryption to the backend server, with the less trusted proxy essentially functioning as a dumb pipe.