| 
									
										
										
										
											2015-10-30 15:56:46 +01:00
										 |  |  | package dokodemo | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-22 19:32:37 +02:00
										 |  |  | 	"github.com/v2ray/v2ray-core/app" | 
					
						
							| 
									
										
										
										
											2016-01-31 17:01:28 +01:00
										 |  |  | 	"github.com/v2ray/v2ray-core/app/dispatcher" | 
					
						
							| 
									
										
										
										
											2015-10-30 15:56:46 +01:00
										 |  |  | 	"github.com/v2ray/v2ray-core/common/alloc" | 
					
						
							| 
									
										
										
										
											2016-01-29 13:39:55 +00:00
										 |  |  | 	v2io "github.com/v2ray/v2ray-core/common/io" | 
					
						
							| 
									
										
										
										
											2015-10-30 15:56:46 +01:00
										 |  |  | 	"github.com/v2ray/v2ray-core/common/log" | 
					
						
							|  |  |  | 	v2net "github.com/v2ray/v2ray-core/common/net" | 
					
						
							| 
									
										
										
										
											2016-01-19 23:41:40 +01:00
										 |  |  | 	"github.com/v2ray/v2ray-core/proxy" | 
					
						
							| 
									
										
										
										
											2016-05-22 19:32:37 +02:00
										 |  |  | 	"github.com/v2ray/v2ray-core/proxy/internal" | 
					
						
							| 
									
										
										
										
											2016-06-14 22:54:08 +02:00
										 |  |  | 	"github.com/v2ray/v2ray-core/transport/internet" | 
					
						
							|  |  |  | 	"github.com/v2ray/v2ray-core/transport/internet/udp" | 
					
						
							| 
									
										
										
										
											2015-10-30 15:56:46 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type DokodemoDoor struct { | 
					
						
							| 
									
										
										
										
											2016-01-31 17:01:28 +01:00
										 |  |  | 	tcpMutex         sync.RWMutex | 
					
						
							|  |  |  | 	udpMutex         sync.RWMutex | 
					
						
							|  |  |  | 	config           *Config | 
					
						
							|  |  |  | 	accepting        bool | 
					
						
							|  |  |  | 	address          v2net.Address | 
					
						
							|  |  |  | 	port             v2net.Port | 
					
						
							|  |  |  | 	packetDispatcher dispatcher.PacketDispatcher | 
					
						
							| 
									
										
										
										
											2016-06-14 22:54:08 +02:00
										 |  |  | 	tcpListener      *internet.TCPHub | 
					
						
							|  |  |  | 	udpHub           *udp.UDPHub | 
					
						
							|  |  |  | 	udpServer        *udp.UDPServer | 
					
						
							| 
									
										
										
										
											2016-06-04 14:25:13 +02:00
										 |  |  | 	meta             *proxy.InboundHandlerMeta | 
					
						
							| 
									
										
										
										
											2015-10-30 15:56:46 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-04 14:25:13 +02:00
										 |  |  | func NewDokodemoDoor(config *Config, space app.Space, meta *proxy.InboundHandlerMeta) *DokodemoDoor { | 
					
						
							| 
									
										
										
										
											2016-05-22 19:32:37 +02:00
										 |  |  | 	d := &DokodemoDoor{ | 
					
						
							| 
									
										
										
										
											2016-06-04 14:25:13 +02:00
										 |  |  | 		config:  config, | 
					
						
							|  |  |  | 		address: config.Address, | 
					
						
							|  |  |  | 		port:    config.Port, | 
					
						
							|  |  |  | 		meta:    meta, | 
					
						
							| 
									
										
										
										
											2015-10-30 15:56:46 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-05-22 19:32:37 +02:00
										 |  |  | 	space.InitializeApplication(func() error { | 
					
						
							|  |  |  | 		if !space.HasApp(dispatcher.APP_ID) { | 
					
						
							|  |  |  | 			log.Error("Dokodemo: Dispatcher is not found in the space.") | 
					
						
							|  |  |  | 			return app.ErrorMissingApplication | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		d.packetDispatcher = space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher) | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	return d | 
					
						
							| 
									
										
										
										
											2015-10-30 15:56:46 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-19 23:41:40 +01:00
										 |  |  | func (this *DokodemoDoor) Port() v2net.Port { | 
					
						
							| 
									
										
										
										
											2016-06-04 14:25:13 +02:00
										 |  |  | 	return this.meta.Port | 
					
						
							| 
									
										
										
										
											2016-01-19 23:41:40 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-03 23:30:37 +01:00
										 |  |  | func (this *DokodemoDoor) Close() { | 
					
						
							|  |  |  | 	this.accepting = false | 
					
						
							|  |  |  | 	if this.tcpListener != nil { | 
					
						
							| 
									
										
										
										
											2016-01-04 00:33:25 +01:00
										 |  |  | 		this.tcpMutex.Lock() | 
					
						
							| 
									
										
										
										
											2016-01-27 22:11:31 +01:00
										 |  |  | 		this.tcpListener.Close() | 
					
						
							| 
									
										
										
										
											2016-01-03 23:30:37 +01:00
										 |  |  | 		this.tcpListener = nil | 
					
						
							| 
									
										
										
										
											2016-01-04 00:33:25 +01:00
										 |  |  | 		this.tcpMutex.Unlock() | 
					
						
							| 
									
										
										
										
											2016-01-03 23:30:37 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-28 16:43:47 +00:00
										 |  |  | 	if this.udpHub != nil { | 
					
						
							| 
									
										
										
										
											2016-01-04 00:33:25 +01:00
										 |  |  | 		this.udpMutex.Lock() | 
					
						
							| 
									
										
										
										
											2016-01-28 16:43:47 +00:00
										 |  |  | 		this.udpHub.Close() | 
					
						
							|  |  |  | 		this.udpHub = nil | 
					
						
							| 
									
										
										
										
											2016-01-04 00:33:25 +01:00
										 |  |  | 		this.udpMutex.Unlock() | 
					
						
							| 
									
										
										
										
											2016-01-03 23:30:37 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-04 00:38:22 +02:00
										 |  |  | func (this *DokodemoDoor) Start() error { | 
					
						
							| 
									
										
										
										
											2016-01-19 23:41:40 +01:00
										 |  |  | 	if this.accepting { | 
					
						
							| 
									
										
										
										
											2016-06-04 00:38:22 +02:00
										 |  |  | 		return nil | 
					
						
							| 
									
										
										
										
											2016-01-19 23:41:40 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-11 00:08:43 +01:00
										 |  |  | 	this.accepting = true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-15 12:43:06 +01:00
										 |  |  | 	if this.config.Network.HasNetwork(v2net.TCPNetwork) { | 
					
						
							| 
									
										
										
										
											2016-06-04 14:25:13 +02:00
										 |  |  | 		err := this.ListenTCP() | 
					
						
							| 
									
										
										
										
											2015-10-30 15:56:46 +01:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-15 12:43:06 +01:00
										 |  |  | 	if this.config.Network.HasNetwork(v2net.UDPNetwork) { | 
					
						
							| 
									
										
										
										
											2016-06-04 14:25:13 +02:00
										 |  |  | 		err := this.ListenUDP() | 
					
						
							| 
									
										
										
										
											2015-11-11 00:08:43 +01:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-30 15:56:46 +01:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-04 14:25:13 +02:00
										 |  |  | func (this *DokodemoDoor) ListenUDP() error { | 
					
						
							| 
									
										
										
										
											2016-06-14 22:54:08 +02:00
										 |  |  | 	this.udpServer = udp.NewUDPServer(this.packetDispatcher) | 
					
						
							|  |  |  | 	udpHub, err := udp.ListenUDP(this.meta.Address, this.meta.Port, this.handleUDPPackets) | 
					
						
							| 
									
										
										
										
											2015-11-11 00:08:43 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-06-04 14:25:13 +02:00
										 |  |  | 		log.Error("Dokodemo failed to listen on ", this.meta.Address, ":", this.meta.Port, ": ", err) | 
					
						
							| 
									
										
										
										
											2015-11-11 00:08:43 +01:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-04 08:40:24 +01:00
										 |  |  | 	this.udpMutex.Lock() | 
					
						
							| 
									
										
										
										
											2016-01-28 16:43:47 +00:00
										 |  |  | 	this.udpHub = udpHub | 
					
						
							| 
									
										
										
										
											2016-01-04 08:40:24 +01:00
										 |  |  | 	this.udpMutex.Unlock() | 
					
						
							| 
									
										
										
										
											2015-11-11 00:08:43 +01:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-28 16:43:47 +00:00
										 |  |  | func (this *DokodemoDoor) handleUDPPackets(payload *alloc.Buffer, dest v2net.Destination) { | 
					
						
							| 
									
										
										
										
											2016-05-15 23:09:28 -07:00
										 |  |  | 	this.udpServer.Dispatch(dest, v2net.UDPDestination(this.address, this.port), payload, this.handleUDPResponse) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (this *DokodemoDoor) handleUDPResponse(dest v2net.Destination, payload *alloc.Buffer) { | 
					
						
							|  |  |  | 	defer payload.Release() | 
					
						
							|  |  |  | 	this.udpMutex.RLock() | 
					
						
							|  |  |  | 	defer this.udpMutex.RUnlock() | 
					
						
							|  |  |  | 	if !this.accepting { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	this.udpHub.WriteTo(payload.Value, dest) | 
					
						
							| 
									
										
										
										
											2015-11-11 00:08:43 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-04 14:25:13 +02:00
										 |  |  | func (this *DokodemoDoor) ListenTCP() error { | 
					
						
							| 
									
										
										
										
											2016-06-14 22:54:08 +02:00
										 |  |  | 	log.Info("Dokodemo: Stream settings: ", this.meta.StreamSettings) | 
					
						
							|  |  |  | 	tcpListener, err := internet.ListenTCP(this.meta.Address, this.meta.Port, this.HandleTCPConnection, this.meta.StreamSettings) | 
					
						
							| 
									
										
										
										
											2015-10-30 15:56:46 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-06-04 14:25:13 +02:00
										 |  |  | 		log.Error("Dokodemo: Failed to listen on ", this.meta.Address, ":", this.meta.Port, ": ", err) | 
					
						
							| 
									
										
										
										
											2015-10-30 15:56:46 +01:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-04 08:40:24 +01:00
										 |  |  | 	this.tcpMutex.Lock() | 
					
						
							| 
									
										
										
										
											2016-01-03 23:30:37 +01:00
										 |  |  | 	this.tcpListener = tcpListener | 
					
						
							| 
									
										
										
										
											2016-01-04 08:40:24 +01:00
										 |  |  | 	this.tcpMutex.Unlock() | 
					
						
							| 
									
										
										
										
											2015-10-30 15:56:46 +01:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 22:54:08 +02:00
										 |  |  | func (this *DokodemoDoor) HandleTCPConnection(conn internet.Connection) { | 
					
						
							| 
									
										
										
										
											2015-10-30 15:56:46 +01:00
										 |  |  | 	defer conn.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-12 22:54:33 +02:00
										 |  |  | 	var dest v2net.Destination | 
					
						
							| 
									
										
										
										
											2016-06-12 01:30:56 +02:00
										 |  |  | 	if this.config.FollowRedirect { | 
					
						
							|  |  |  | 		originalDest := GetOriginalDestination(conn) | 
					
						
							|  |  |  | 		if originalDest != nil { | 
					
						
							|  |  |  | 			log.Info("Dokodemo: Following redirect to: ", originalDest) | 
					
						
							|  |  |  | 			dest = originalDest | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-06-12 22:54:33 +02:00
										 |  |  | 	if dest == nil && this.address != nil && this.port > v2net.Port(0) { | 
					
						
							|  |  |  | 		dest = v2net.TCPDestination(this.address, this.port) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if dest == nil { | 
					
						
							|  |  |  | 		log.Info("Dokodemo: Unknown destination, stop forwarding...") | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-06-14 22:54:08 +02:00
										 |  |  | 	log.Info("Dokodemo: Handling request to ", dest) | 
					
						
							| 
									
										
										
										
											2016-06-12 01:30:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ray := this.packetDispatcher.DispatchToOutbound(dest) | 
					
						
							| 
									
										
										
										
											2016-04-18 18:44:10 +02:00
										 |  |  | 	defer ray.InboundOutput().Release() | 
					
						
							| 
									
										
										
										
											2015-10-30 15:56:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var inputFinish, outputFinish sync.Mutex | 
					
						
							|  |  |  | 	inputFinish.Lock() | 
					
						
							|  |  |  | 	outputFinish.Lock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-15 12:43:06 +01:00
										 |  |  | 	reader := v2net.NewTimeOutReader(this.config.Timeout, conn) | 
					
						
							| 
									
										
										
										
											2016-05-05 00:24:18 +02:00
										 |  |  | 	defer reader.Release() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-18 18:44:10 +02:00
										 |  |  | 	go func() { | 
					
						
							| 
									
										
										
										
											2016-04-18 19:01:24 +02:00
										 |  |  | 		v2reader := v2io.NewAdaptiveReader(reader) | 
					
						
							|  |  |  | 		defer v2reader.Release() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		v2io.Pipe(v2reader, ray.InboundInput()) | 
					
						
							| 
									
										
										
										
											2016-04-18 18:44:10 +02:00
										 |  |  | 		inputFinish.Unlock() | 
					
						
							|  |  |  | 		ray.InboundInput().Close() | 
					
						
							|  |  |  | 	}() | 
					
						
							| 
									
										
										
										
											2015-10-30 15:56:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-18 18:44:10 +02:00
										 |  |  | 	go func() { | 
					
						
							| 
									
										
										
										
											2016-04-18 19:01:24 +02:00
										 |  |  | 		v2writer := v2io.NewAdaptiveWriter(conn) | 
					
						
							|  |  |  | 		defer v2writer.Release() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		v2io.Pipe(ray.InboundOutput(), v2writer) | 
					
						
							| 
									
										
										
										
											2016-04-18 18:44:10 +02:00
										 |  |  | 		outputFinish.Unlock() | 
					
						
							|  |  |  | 	}() | 
					
						
							| 
									
										
										
										
											2015-10-30 15:56:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-18 18:44:10 +02:00
										 |  |  | 	outputFinish.Lock() | 
					
						
							| 
									
										
										
										
											2016-05-05 00:24:18 +02:00
										 |  |  | 	inputFinish.Lock() | 
					
						
							| 
									
										
										
										
											2015-10-30 15:56:46 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-05-22 19:32:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 22:54:08 +02:00
										 |  |  | type Factory struct{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (this *Factory) StreamCapability() internet.StreamConnectionType { | 
					
						
							|  |  |  | 	return internet.StreamConnectionTypeRawTCP | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (this *Factory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) { | 
					
						
							|  |  |  | 	return NewDokodemoDoor(rawConfig.(*Config), space, meta), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-22 19:32:37 +02:00
										 |  |  | func init() { | 
					
						
							| 
									
										
										
										
											2016-06-14 22:54:08 +02:00
										 |  |  | 	internal.MustRegisterInboundHandlerCreator("dokodemo-door", new(Factory)) | 
					
						
							| 
									
										
										
										
											2016-05-22 19:32:37 +02:00
										 |  |  | } |