|  | @@ -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) {
 |