mirror of https://github.com/v2ray/v2ray-core
read original addr from x-forwarded-for header if present
parent
a0b2c285b2
commit
91ca88bcff
|
@ -0,0 +1,21 @@
|
||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"v2ray.com/core/common/net"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ParseXForwardedFor(header http.Header) []net.Address {
|
||||||
|
xff := header.Get("X-Forwarded-For")
|
||||||
|
if len(xff) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
list := strings.Split(xff, ",")
|
||||||
|
addrs := make([]net.Address, 0, len(list))
|
||||||
|
for _, proxy := range list {
|
||||||
|
addrs = append(addrs, net.ParseAddress(proxy))
|
||||||
|
}
|
||||||
|
return addrs
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package http_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "v2ray.com/core/common/protocol/http"
|
||||||
|
. "v2ray.com/ext/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseXForwardedFor(t *testing.T) {
|
||||||
|
assert := With(t)
|
||||||
|
|
||||||
|
header := http.Header{}
|
||||||
|
header.Add("X-Forwarded-For", "129.78.138.66, 129.78.64.103")
|
||||||
|
addrs := ParseXForwardedFor(header)
|
||||||
|
assert(len(addrs), Equals, 2)
|
||||||
|
assert(addrs[0].String(), Equals, "129.78.138.66")
|
||||||
|
assert(addrs[1].String(), Equals, "129.78.64.103")
|
||||||
|
}
|
|
@ -16,15 +16,16 @@ var (
|
||||||
|
|
||||||
// connection is a wrapper for net.Conn over WebSocket connection.
|
// connection is a wrapper for net.Conn over WebSocket connection.
|
||||||
type connection struct {
|
type connection struct {
|
||||||
conn *websocket.Conn
|
conn *websocket.Conn
|
||||||
reader io.Reader
|
reader io.Reader
|
||||||
|
|
||||||
mergingWriter *buf.BufferedWriter
|
mergingWriter *buf.BufferedWriter
|
||||||
|
remoteAddr net.Addr
|
||||||
}
|
}
|
||||||
|
|
||||||
func newConnection(conn *websocket.Conn) *connection {
|
func newConnection(conn *websocket.Conn, remoteAddr net.Addr) *connection {
|
||||||
return &connection{
|
return &connection{
|
||||||
conn: conn,
|
conn: conn,
|
||||||
|
remoteAddr: remoteAddr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +87,7 @@ func (c *connection) LocalAddr() net.Addr {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *connection) RemoteAddr() net.Addr {
|
func (c *connection) RemoteAddr() net.Addr {
|
||||||
return c.conn.RemoteAddr()
|
return c.remoteAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *connection) SetDeadline(t time.Time) error {
|
func (c *connection) SetDeadline(t time.Time) error {
|
||||||
|
|
|
@ -62,5 +62,5 @@ func dialWebsocket(ctx context.Context, dest net.Destination) (net.Conn, error)
|
||||||
return nil, newError("failed to dial to (", uri, "): ", reason).Base(err)
|
return nil, newError("failed to dial to (", uri, "): ", reason).Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return newConnection(conn), nil
|
return newConnection(conn, conn.RemoteAddr()), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"v2ray.com/core/app/log"
|
"v2ray.com/core/app/log"
|
||||||
"v2ray.com/core/common"
|
"v2ray.com/core/common"
|
||||||
"v2ray.com/core/common/net"
|
"v2ray.com/core/common/net"
|
||||||
|
http_proto "v2ray.com/core/common/protocol/http"
|
||||||
"v2ray.com/core/transport/internet"
|
"v2ray.com/core/transport/internet"
|
||||||
v2tls "v2ray.com/core/transport/internet/tls"
|
v2tls "v2ray.com/core/transport/internet/tls"
|
||||||
)
|
)
|
||||||
|
@ -38,7 +39,13 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.ln.addConn(h.ln.ctx, newConnection(conn))
|
forwardedAddrs := http_proto.ParseXForwardedFor(request.Header)
|
||||||
|
remoteAddr := conn.RemoteAddr()
|
||||||
|
if len(forwardedAddrs) > 0 && forwardedAddrs[0].Family().Either(net.AddressFamilyIPv4, net.AddressFamilyIPv6) {
|
||||||
|
remoteAddr.(*net.TCPAddr).IP = forwardedAddrs[0].IP()
|
||||||
|
}
|
||||||
|
|
||||||
|
h.ln.addConn(h.ln.ctx, newConnection(conn, remoteAddr))
|
||||||
}
|
}
|
||||||
|
|
||||||
type Listener struct {
|
type Listener struct {
|
||||||
|
|
|
@ -59,15 +59,46 @@ func Test_listenWSAndDial(t *testing.T) {
|
||||||
assert(err, IsNil)
|
assert(err, IsNil)
|
||||||
assert(string(b[:n]), Equals, "Response")
|
assert(string(b[:n]), Equals, "Response")
|
||||||
assert(conn.Close(), IsNil)
|
assert(conn.Close(), IsNil)
|
||||||
<-time.After(time.Second * 15)
|
|
||||||
conn, err = Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), 13146))
|
assert(listen.Close(), IsNil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDialWithRemoteAddr(t *testing.T) {
|
||||||
|
assert := With(t)
|
||||||
|
listen, err := ListenWS(internet.ContextWithTransportSettings(context.Background(), &Config{
|
||||||
|
Path: "ws",
|
||||||
|
}), net.DomainAddress("localhost"), 13146, func(ctx context.Context, conn internet.Connection) bool {
|
||||||
|
go func(c internet.Connection) {
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
assert(c.RemoteAddr().String(), HasPrefix, "1.1.1.1")
|
||||||
|
|
||||||
|
var b [1024]byte
|
||||||
|
n, err := c.Read(b[:])
|
||||||
|
//assert(err, IsNil)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert(bytes.HasPrefix(b[:n], []byte("Test connection")), IsTrue)
|
||||||
|
|
||||||
|
_, err = c.Write([]byte("Response"))
|
||||||
|
assert(err, IsNil)
|
||||||
|
}(conn)
|
||||||
|
return true
|
||||||
|
})
|
||||||
assert(err, IsNil)
|
assert(err, IsNil)
|
||||||
_, err = conn.Write([]byte("Test connection 3"))
|
|
||||||
|
ctx := internet.ContextWithTransportSettings(context.Background(), &Config{Path: "ws", Header: []*Header{{Key: "X-Forwarded-For", Value: "1.1.1.1"}}})
|
||||||
|
conn, err := Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), 13146))
|
||||||
|
|
||||||
assert(err, IsNil)
|
assert(err, IsNil)
|
||||||
n, err = conn.Read(b[:])
|
_, err = conn.Write([]byte("Test connection 1"))
|
||||||
|
assert(err, IsNil)
|
||||||
|
|
||||||
|
var b [1024]byte
|
||||||
|
n, err := conn.Read(b[:])
|
||||||
assert(err, IsNil)
|
assert(err, IsNil)
|
||||||
assert(string(b[:n]), Equals, "Response")
|
assert(string(b[:n]), Equals, "Response")
|
||||||
assert(conn.Close(), IsNil)
|
|
||||||
|
|
||||||
assert(listen.Close(), IsNil)
|
assert(listen.Close(), IsNil)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue