From 1c06fc216a32b359f4c4fc4a61c45884f3677bf9 Mon Sep 17 00:00:00 2001 From: v2ray Date: Sun, 12 Jun 2016 01:30:56 +0200 Subject: [PATCH] allow redirection in dokodemo --- proxy/dokodemo/config.go | 9 +++++---- proxy/dokodemo/config_json.go | 2 ++ proxy/dokodemo/dokodemo.go | 31 ++++++++++++++++++++++++++++++- transport/hub/connection.go | 20 ++++++++++++++++++++ 4 files changed, 57 insertions(+), 5 deletions(-) diff --git a/proxy/dokodemo/config.go b/proxy/dokodemo/config.go index 44d02e288..8c281d298 100644 --- a/proxy/dokodemo/config.go +++ b/proxy/dokodemo/config.go @@ -5,8 +5,9 @@ import ( ) type Config struct { - Address v2net.Address - Port v2net.Port - Network *v2net.NetworkList - Timeout int + FollowRedirect bool + Address v2net.Address + Port v2net.Port + Network *v2net.NetworkList + Timeout int } diff --git a/proxy/dokodemo/config_json.go b/proxy/dokodemo/config_json.go index b84994714..f13e3de51 100644 --- a/proxy/dokodemo/config_json.go +++ b/proxy/dokodemo/config_json.go @@ -16,6 +16,7 @@ func (this *Config) UnmarshalJSON(data []byte) error { PortValue v2net.Port `json:"port"` NetworkList *v2net.NetworkList `json:"network"` TimeoutValue int `json:"timeout"` + Redirect bool `json:"followRedirect"` } rawConfig := new(DokodemoConfig) if err := json.Unmarshal(data, rawConfig); err != nil { @@ -25,6 +26,7 @@ func (this *Config) UnmarshalJSON(data []byte) error { this.Port = rawConfig.PortValue this.Network = rawConfig.NetworkList this.Timeout = rawConfig.TimeoutValue + this.FollowRedirect = rawConfig.Redirect return nil } diff --git a/proxy/dokodemo/dokodemo.go b/proxy/dokodemo/dokodemo.go index 84b352076..ac2387a5b 100644 --- a/proxy/dokodemo/dokodemo.go +++ b/proxy/dokodemo/dokodemo.go @@ -2,6 +2,7 @@ package dokodemo import ( "sync" + "syscall" "github.com/v2ray/v2ray-core/app" "github.com/v2ray/v2ray-core/app/dispatcher" @@ -14,6 +15,8 @@ import ( "github.com/v2ray/v2ray-core/transport/hub" ) +const SO_ORIGINAL_DST = 80 + type DokodemoDoor struct { tcpMutex sync.RWMutex udpMutex sync.RWMutex @@ -129,7 +132,16 @@ func (this *DokodemoDoor) ListenTCP() error { func (this *DokodemoDoor) HandleTCPConnection(conn *hub.Connection) { defer conn.Close() - ray := this.packetDispatcher.DispatchToOutbound(v2net.TCPDestination(this.address, this.port)) + dest := v2net.TCPDestination(this.address, this.port) + if this.config.FollowRedirect { + originalDest := GetOriginalDestination(conn) + if originalDest != nil { + log.Info("Dokodemo: Following redirect to: ", originalDest) + dest = originalDest + } + } + + ray := this.packetDispatcher.DispatchToOutbound(dest) defer ray.InboundOutput().Release() var inputFinish, outputFinish sync.Mutex @@ -160,6 +172,23 @@ func (this *DokodemoDoor) HandleTCPConnection(conn *hub.Connection) { inputFinish.Lock() } +func GetOriginalDestination(conn *hub.Connection) v2net.Destination { + fd, err := conn.SysFd() + if err != nil { + log.Info("Dokodemo: Failed to get original destination: ", err) + return nil + } + + addr, err := syscall.GetsockoptIPv6Mreq(fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST) + if err != nil { + log.Info("Dokodemo: Failed to call getsockopt: ", err) + return nil + } + ip := v2net.IPAddress(addr.Multiaddr[4:8]) + port := uint16(addr.Multiaddr[2])<<8 + uint16(addr.Multiaddr[3]) + return v2net.TCPDestination(ip, v2net.Port(port)) +} + func init() { internal.MustRegisterInboundHandlerCreator("dokodemo-door", func(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) { diff --git a/transport/hub/connection.go b/transport/hub/connection.go index 0c7c0019e..83f2e236b 100644 --- a/transport/hub/connection.go +++ b/transport/hub/connection.go @@ -1,12 +1,18 @@ package hub import ( + "errors" "net" + "reflect" "time" "github.com/v2ray/v2ray-core/transport" ) +var ( + ErrInvalidConn = errors.New("Invalid Connection.") +) + type ConnectionHandler func(*Connection) type ConnectionManager interface { @@ -73,3 +79,17 @@ func (this *Connection) SetReusable(reusable bool) { func (this *Connection) Reusable() bool { return this.reusable } + +func (this *Connection) SysFd() (int, error) { + cv := reflect.ValueOf(this.conn) + switch ce := cv.Elem(); ce.Kind() { + case reflect.Struct: + netfd := ce.FieldByName("conn").FieldByName("fd") + switch fe := netfd.Elem(); fe.Kind() { + case reflect.Struct: + fd := fe.FieldByName("sysfd") + return int(fd.Int()), nil + } + } + return 0, ErrInvalidConn +}