Browse Source

allow redirection in dokodemo

v2ray 9 years ago
parent
commit
1c06fc216a

+ 5 - 4
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
 }

+ 2 - 0
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
 }
 

+ 30 - 1
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) {

+ 20 - 0
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
+}