diff --git a/common/protocol/raw/client.go b/common/protocol/raw/client.go index c1bcfc2b..94f25bed 100644 --- a/common/protocol/raw/client.go +++ b/common/protocol/raw/client.go @@ -109,12 +109,12 @@ func (this *ClientSession) DecodeResponseHeader(reader io.Reader) (*protocol.Res _, err := io.ReadFull(this.responseReader, buffer.Value[:4]) if err != nil { - log.Error("Raw: Failed to read response header: ", err) + log.Info("Raw: Failed to read response header: ", err) return nil, err } if buffer.Value[0] != this.responseHeader { - log.Warning("Raw: Unexpected response header. Expecting %d, but actually %d", this.responseHeader, buffer.Value[0]) + log.Info("Raw: Unexpected response header. Expecting ", this.responseHeader, " but actually ", buffer.Value[0]) return nil, transport.ErrorCorruptedPacket } @@ -127,7 +127,7 @@ func (this *ClientSession) DecodeResponseHeader(reader io.Reader) (*protocol.Res dataLen := int(buffer.Value[3]) _, err := io.ReadFull(this.responseReader, buffer.Value[:dataLen]) if err != nil { - log.Error("Raw: Failed to read response command: ", err) + log.Info("Raw: Failed to read response command: ", err) return nil, err } data := buffer.Value[:dataLen] diff --git a/proxy/blackhole/config_json.go b/proxy/blackhole/config_json.go index 2bf9696b..e0050e76 100644 --- a/proxy/blackhole/config_json.go +++ b/proxy/blackhole/config_json.go @@ -4,6 +4,7 @@ package blackhole import ( "encoding/json" + "errors" "github.com/v2ray/v2ray-core/common/loader" "github.com/v2ray/v2ray-core/proxy/internal" @@ -15,7 +16,7 @@ func (this *Config) UnmarshalJSON(data []byte) error { } jsonConfig := new(JSONConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { - return err + return errors.New("Blackhole: Failed to parse config: " + err.Error()) } this.Response = new(NoneResponse) @@ -25,7 +26,7 @@ func (this *Config) UnmarshalJSON(data []byte) error { loader.RegisterCreator("http", func() interface{} { return new(HTTPResponse) }) response, err := loader.Load(jsonConfig.Response) if err != nil { - return err + return errors.New("Blackhole: Failed to parse response config: " + err.Error()) } this.Response = response.(Response) } diff --git a/proxy/dokodemo/config.go b/proxy/dokodemo/config.go index 44d02e28..8c281d29 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 d395a584..f13e3de5 100644 --- a/proxy/dokodemo/config_json.go +++ b/proxy/dokodemo/config_json.go @@ -4,6 +4,7 @@ package dokodemo import ( "encoding/json" + "errors" v2net "github.com/v2ray/v2ray-core/common/net" "github.com/v2ray/v2ray-core/proxy/internal" @@ -15,15 +16,17 @@ 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 { - return err + return errors.New("Dokodemo: Failed to parse config: " + err.Error()) } this.Address = rawConfig.Host.Address 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 84b35207..9848b0c9 100644 --- a/proxy/dokodemo/dokodemo.go +++ b/proxy/dokodemo/dokodemo.go @@ -129,7 +129,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 diff --git a/proxy/dokodemo/sockopt_linux.go b/proxy/dokodemo/sockopt_linux.go new file mode 100644 index 00000000..6c329be2 --- /dev/null +++ b/proxy/dokodemo/sockopt_linux.go @@ -0,0 +1,30 @@ +// +build linux + +package dokodemo + +import ( + "syscall" + + "github.com/v2ray/v2ray-core/common/log" + v2net "github.com/v2ray/v2ray-core/common/net" + "github.com/v2ray/v2ray-core/transport/hub" +) + +const SO_ORIGINAL_DST = 80 + +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)) +} diff --git a/proxy/dokodemo/sockopt_other.go b/proxy/dokodemo/sockopt_other.go new file mode 100644 index 00000000..04dedd3d --- /dev/null +++ b/proxy/dokodemo/sockopt_other.go @@ -0,0 +1,12 @@ +// +build !linux + +package dokodemo + +import ( + v2net "github.com/v2ray/v2ray-core/common/net" + "github.com/v2ray/v2ray-core/transport/hub" +) + +func GetOriginalDestination(conn *hub.Connection) v2net.Destination { + return nil +} diff --git a/proxy/freedom/config_json.go b/proxy/freedom/config_json.go index da8e589c..46114692 100644 --- a/proxy/freedom/config_json.go +++ b/proxy/freedom/config_json.go @@ -4,6 +4,7 @@ package freedom import ( "encoding/json" + "errors" "strings" "github.com/v2ray/v2ray-core/proxy/internal" @@ -16,7 +17,7 @@ func (this *Config) UnmarshalJSON(data []byte) error { } jsonConfig := new(JsonConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { - return err + return errors.New("Freedom: Failed to parse config: " + err.Error()) } this.DomainStrategy = DomainStrategyAsIs domainStrategy := strings.ToLower(jsonConfig.DomainStrategy) diff --git a/proxy/http/config_json.go b/proxy/http/config_json.go index a77e9973..7730d86e 100644 --- a/proxy/http/config_json.go +++ b/proxy/http/config_json.go @@ -5,6 +5,7 @@ package http import ( "crypto/tls" "encoding/json" + "errors" "github.com/v2ray/v2ray-core/proxy/internal" ) @@ -18,7 +19,7 @@ func (this *CertificateConfig) UnmarshalJSON(data []byte) error { } jsonConfig := new(JsonConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { - return err + return errors.New("HTTP: Failed to parse certificate config: " + err.Error()) } cert, err := tls.LoadX509KeyPair(jsonConfig.CertFile, jsonConfig.KeyFile) @@ -38,7 +39,7 @@ func (this *TLSConfig) UnmarshalJSON(data []byte) error { } jsonConfig := new(JsonConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { - return err + return errors.New("HTTP: Failed to parse TLS config: " + err.Error()) } this.Enabled = jsonConfig.Enabled @@ -53,7 +54,7 @@ func (this *Config) UnmarshalJSON(data []byte) error { } jsonConfig := new(JsonConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { - return err + return errors.New("HTTP: Failed to parse config: " + err.Error()) } this.TLSConfig = jsonConfig.Tls diff --git a/proxy/shadowsocks/config_json.go b/proxy/shadowsocks/config_json.go index a62451e9..8ab14c6a 100644 --- a/proxy/shadowsocks/config_json.go +++ b/proxy/shadowsocks/config_json.go @@ -4,6 +4,7 @@ package shadowsocks import ( "encoding/json" + "errors" "strings" "github.com/v2ray/v2ray-core/common/log" @@ -21,7 +22,7 @@ func (this *Config) UnmarshalJSON(data []byte) error { } jsonConfig := new(JsonConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { - return err + return errors.New("Shadowsocks: Failed to parse config: " + err.Error()) } this.UDP = jsonConfig.UDP diff --git a/proxy/socks/config_json.go b/proxy/socks/config_json.go index e2dbeba8..e0cafcf4 100644 --- a/proxy/socks/config_json.go +++ b/proxy/socks/config_json.go @@ -4,6 +4,7 @@ package socks import ( "encoding/json" + "errors" "github.com/v2ray/v2ray-core/common/log" v2net "github.com/v2ray/v2ray-core/common/net" @@ -30,7 +31,7 @@ func (this *Config) UnmarshalJSON(data []byte) error { rawConfig := new(SocksConfig) if err := json.Unmarshal(data, rawConfig); err != nil { - return err + return errors.New("Socks: Failed to parse config: " + err.Error()) } if rawConfig.AuthMethod == AuthMethodNoAuth { this.AuthType = AuthTypeNoAuth diff --git a/proxy/vmess/inbound/config_json.go b/proxy/vmess/inbound/config_json.go index 79af526c..0538d235 100644 --- a/proxy/vmess/inbound/config_json.go +++ b/proxy/vmess/inbound/config_json.go @@ -4,6 +4,7 @@ package inbound import ( "encoding/json" + "errors" "github.com/v2ray/v2ray-core/common/protocol" "github.com/v2ray/v2ray-core/proxy/internal" @@ -15,7 +16,7 @@ func (this *DetourConfig) UnmarshalJSON(data []byte) error { } jsonConfig := new(JsonDetourConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { - return err + return errors.New("VMessIn: Failed to parse detour config: " + err.Error()) } this.ToTag = jsonConfig.ToTag return nil @@ -27,7 +28,7 @@ func (this *FeaturesConfig) UnmarshalJSON(data []byte) error { } jsonConfig := new(JsonFeaturesConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { - return err + return errors.New("VMessIn: Failed to parse features config: " + err.Error()) } this.Detour = jsonConfig.Detour return nil @@ -40,7 +41,7 @@ func (this *DefaultConfig) UnmarshalJSON(data []byte) error { } jsonConfig := new(JsonDefaultConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { - return err + return errors.New("VMessIn: Failed to parse default config: " + err.Error()) } this.AlterIDs = jsonConfig.AlterIDs if this.AlterIDs == 0 { @@ -59,7 +60,7 @@ func (this *Config) UnmarshalJSON(data []byte) error { } jsonConfig := new(JsonConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { - return err + return errors.New("VMessIn: Failed to parse config: " + err.Error()) } this.AllowedUsers = jsonConfig.Users this.Features = jsonConfig.Features // Backward compatibility diff --git a/proxy/vmess/outbound/config_json.go b/proxy/vmess/outbound/config_json.go index 06f23d7e..5c637032 100644 --- a/proxy/vmess/outbound/config_json.go +++ b/proxy/vmess/outbound/config_json.go @@ -4,6 +4,7 @@ package outbound import ( "encoding/json" + "errors" "github.com/v2ray/v2ray-core/common/log" "github.com/v2ray/v2ray-core/proxy/internal" @@ -16,10 +17,10 @@ func (this *Config) UnmarshalJSON(data []byte) error { rawOutbound := &RawOutbound{} err := json.Unmarshal(data, rawOutbound) if err != nil { - return err + return errors.New("VMessOut: Failed to parse config: " + err.Error()) } if len(rawOutbound.Receivers) == 0 { - log.Error("VMess: 0 VMess receiver configured.") + log.Error("VMessOut: 0 VMess receiver configured.") return internal.ErrorBadConfiguration } this.Receivers = rawOutbound.Receivers diff --git a/shell/point/config_json.go b/shell/point/config_json.go index 32fbaf77..6c408f35 100644 --- a/shell/point/config_json.go +++ b/shell/point/config_json.go @@ -34,7 +34,7 @@ func (this *Config) UnmarshalJSON(data []byte) error { } jsonConfig := new(JsonConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { - return err + return errors.New("Point: Failed to parse config: " + err.Error()) } this.Port = jsonConfig.Port this.LogConfig = jsonConfig.LogConfig @@ -65,7 +65,7 @@ func (this *InboundConnectionConfig) UnmarshalJSON(data []byte) error { jsonConfig := new(JsonConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { - return err + return errors.New("Point: Failed to parse inbound config: " + err.Error()) } this.Port = v2net.Port(jsonConfig.Port) this.ListenOn = v2net.AnyIP @@ -89,7 +89,7 @@ func (this *OutboundConnectionConfig) UnmarshalJSON(data []byte) error { } jsonConfig := new(JsonConnectionConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { - return err + return errors.New("Point: Failed to parse outbound config: " + err.Error()) } this.Protocol = jsonConfig.Protocol this.Settings = jsonConfig.Settings @@ -112,7 +112,7 @@ func (this *LogConfig) UnmarshalJSON(data []byte) error { } jsonConfig := new(JsonLogConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { - return err + return errors.New("Point: Failed to parse log config: " + err.Error()) } this.AccessLog = jsonConfig.AccessLog this.ErrorLog = jsonConfig.ErrorLog @@ -141,7 +141,7 @@ func (this *InboundDetourAllocationConfig) UnmarshalJSON(data []byte) error { } jsonConfig := new(JsonInboundDetourAllocationConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { - return err + return errors.New("Point: Failed to parse inbound detour allocation config: " + err.Error()) } this.Strategy = jsonConfig.Strategy this.Concurrency = jsonConfig.Concurrency @@ -171,7 +171,7 @@ func (this *InboundDetourConfig) UnmarshalJSON(data []byte) error { } jsonConfig := new(JsonInboundDetourConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { - return err + return errors.New("Point: Failed to parse inbound detour config: " + err.Error()) } if jsonConfig.PortRange == nil { log.Error("Point: Port range not specified in InboundDetour.") @@ -207,7 +207,7 @@ func (this *OutboundDetourConfig) UnmarshalJSON(data []byte) error { } jsonConfig := new(JsonOutboundDetourConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { - return err + return errors.New("Point: Failed to parse outbound detour config: " + err.Error()) } this.Protocol = jsonConfig.Protocol this.Tag = jsonConfig.Tag diff --git a/transport/config.go b/transport/config.go index 4a408198..1e05004c 100644 --- a/transport/config.go +++ b/transport/config.go @@ -2,12 +2,14 @@ package transport import "github.com/v2ray/v2ray-core/transport/hub/kcpv" +// Config for V2Ray transport layer. type Config struct { ConnectionReuse bool enableKcp bool kcpConfig *kcpv.Config } +// Apply applies this Config. func (this *Config) Apply() error { if this.ConnectionReuse { connectionReuse = true diff --git a/transport/hub/connection.go b/transport/hub/connection.go index 0c7c0019..83f2e236 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 +} diff --git a/transport/transport.go b/transport/transport.go index 34ef7ebc..dee265fc 100644 --- a/transport/transport.go +++ b/transport/transport.go @@ -8,6 +8,7 @@ var ( KcpConfig *kcpv.Config ) +// IsConnectionReusable returns true if V2Ray is trying to reuse TCP connections. func IsConnectionReusable() bool { return connectionReuse }