diff --git a/io/aes.go b/io/aes.go index f416e3b09..8c0d4f357 100644 --- a/io/aes.go +++ b/io/aes.go @@ -12,8 +12,8 @@ func NewAesDecryptReader(key []byte, iv []byte, reader io.Reader) (io.Reader, er return nil, err } - aesMode := cipher.NewCBCDecrypter(aesBlock, iv) - return NewCryptionReader(aesMode, reader), nil + aesStream := cipher.NewCFBDecrypter(aesBlock, iv) + return NewCryptionReader(aesStream, reader), nil } func NewAesEncryptWriter(key []byte, iv []byte, writer io.Writer) (io.Writer, error) { @@ -22,6 +22,6 @@ func NewAesEncryptWriter(key []byte, iv []byte, writer io.Writer) (io.Writer, er return nil, err } - aesMode := cipher.NewCBCEncrypter(aesBlock, iv) - return NewCryptionWriter(aesMode, writer), nil + aesStream := cipher.NewCFBEncrypter(aesBlock, iv) + return NewCryptionWriter(aesStream, writer), nil } diff --git a/io/encryption.go b/io/encryption.go index 75aa52c43..8467e725e 100644 --- a/io/encryption.go +++ b/io/encryption.go @@ -3,18 +3,20 @@ package io import ( "crypto/cipher" "io" + + "github.com/v2ray/v2ray-core/log" ) // CryptionReader is a general purpose reader that applies // block cipher on top of a regular reader. type CryptionReader struct { - mode cipher.BlockMode + stream cipher.Stream reader io.Reader } -func NewCryptionReader(mode cipher.BlockMode, reader io.Reader) *CryptionReader { +func NewCryptionReader(stream cipher.Stream, reader io.Reader) *CryptionReader { this := new(CryptionReader) - this.mode = mode + this.stream = stream this.reader = reader return this } @@ -23,32 +25,26 @@ func NewCryptionReader(mode cipher.BlockMode, reader io.Reader) *CryptionReader // a multiply of BlockSize() func (reader CryptionReader) Read(blocks []byte) (int, error) { nBytes, err := reader.reader.Read(blocks) - if err != nil && err != io.EOF { - return nBytes, err + log.Debug("CryptionReader: Read %d bytes", nBytes) + if nBytes > 0 { + reader.stream.XORKeyStream(blocks[:nBytes], blocks[:nBytes]) } - if nBytes < len(blocks) { - for i, _ := range blocks[nBytes:] { - blocks[i] = 0 - } + if err != nil { + log.Error("Error reading blocks: %v", err) } - reader.mode.CryptBlocks(blocks, blocks) return nBytes, err } -func (reader CryptionReader) BlockSize() int { - return reader.mode.BlockSize() -} - // Cryption writer is a general purpose of byte stream writer that applies // block cipher on top of a regular writer. type CryptionWriter struct { - mode cipher.BlockMode + stream cipher.Stream writer io.Writer } -func NewCryptionWriter(mode cipher.BlockMode, writer io.Writer) *CryptionWriter { +func NewCryptionWriter(stream cipher.Stream, writer io.Writer) *CryptionWriter { this := new(CryptionWriter) - this.mode = mode + this.stream = stream this.writer = writer return this } @@ -56,10 +52,7 @@ func NewCryptionWriter(mode cipher.BlockMode, writer io.Writer) *CryptionWriter // Write writes the give blocks to underlying writer. The length of the blocks // must be a multiply of BlockSize() func (writer CryptionWriter) Write(blocks []byte) (int, error) { - writer.mode.CryptBlocks(blocks, blocks) + log.Debug("CryptionWriter writing %d bytes", len(blocks)) + writer.stream.XORKeyStream(blocks, blocks) return writer.writer.Write(blocks) } - -func (writer CryptionWriter) BlockSize() int { - return writer.mode.BlockSize() -} diff --git a/io/vmess/decryptionreader.go b/io/vmess/decryptionreader.go index 2ee0a6543..9fb2d49e8 100644 --- a/io/vmess/decryptionreader.go +++ b/io/vmess/decryptionreader.go @@ -29,8 +29,8 @@ func NewDecryptionReader(reader io.Reader, key []byte, iv []byte) (*DecryptionRe if err != nil { return nil, err } - aesBlockMode := cipher.NewCBCDecrypter(aesCipher, iv) - decryptionReader.reader = v2io.NewCryptionReader(aesBlockMode, reader) + aesStream := cipher.NewCFBDecrypter(aesCipher, iv) + decryptionReader.reader = v2io.NewCryptionReader(aesStream, reader) decryptionReader.buffer = bytes.NewBuffer(make([]byte, 0, 2*blockSize)) return decryptionReader, nil } diff --git a/io/vmess/decryptionreader_test.go b/io/vmess/decryptionreader_test.go index 0f33dd329..264db0342 100644 --- a/io/vmess/decryptionreader_test.go +++ b/io/vmess/decryptionreader_test.go @@ -35,10 +35,10 @@ func TestNormalReading(t *testing.T) { aesBlock, err := aes.NewCipher(key) assert.Error(err).IsNil() - aesMode := cipher.NewCBCEncrypter(aesBlock, iv) + aesStream := cipher.NewCFBEncrypter(aesBlock, iv) ciphertext := make([]byte, testSize) - aesMode.CryptBlocks(ciphertext, plaintext) + aesStream.XORKeyStream(ciphertext, plaintext) ciphertextcopy := make([]byte, testSize) copy(ciphertextcopy, ciphertext) diff --git a/io/vmess/vmess.go b/io/vmess/vmess.go index 16dca5efc..dc60eae6c 100644 --- a/io/vmess/vmess.go +++ b/io/vmess/vmess.go @@ -224,8 +224,8 @@ func (w *VMessRequestWriter) Write(writer io.Writer, request *VMessRequest) erro if err != nil { return err } - aesMode := cipher.NewCBCEncrypter(aesCipher, make([]byte, blockSize)) - cWriter := v2io.NewCryptionWriter(aesMode, writer) + aesStream := cipher.NewCFBEncrypter(aesCipher, make([]byte, blockSize)) + cWriter := v2io.NewCryptionWriter(aesStream, writer) _, err = writer.Write(buffer[0:encryptionBegin]) if err != nil { diff --git a/log/log.go b/log/log.go index 45f936214..c7c478d1b 100644 --- a/log/log.go +++ b/log/log.go @@ -21,30 +21,33 @@ func SetLogLevel(level LogLevel) { logLevel = level } -func writeLog(data string, level LogLevel) { +func writeLog(level LogLevel, prefix, format string, v ...interface{}) string { if level < logLevel { - return + return "" } - log.Print(data) + var data string + if v == nil || len(v) == 0 { + data = format + } else { + data = fmt.Sprintf(format, v...) + } + log.Print(prefix + data) + return data } func Debug(format string, v ...interface{}) { - data := fmt.Sprintf(format, v) - writeLog("[Debug]"+data, DebugLevel) + writeLog(DebugLevel, "[Debug]", format, v...) } func Info(format string, v ...interface{}) { - data := fmt.Sprintf(format, v) - writeLog("[Info]"+data, InfoLevel) + writeLog(InfoLevel, "[Info]", format, v...) } func Warning(format string, v ...interface{}) { - data := fmt.Sprintf(format, v) - writeLog("[Warning]"+data, WarningLevel) + writeLog(WarningLevel, "[Warning]", format, v...) } func Error(format string, v ...interface{}) error { - data := fmt.Sprintf(format, v) - writeLog("[Error]"+data, ErrorLevel) + data := writeLog(ErrorLevel, "[Error]", format, v...) return errors.New(data) } diff --git a/net/freedom/freedom.go b/net/freedom/freedom.go index 8d5242229..5204b301c 100644 --- a/net/freedom/freedom.go +++ b/net/freedom/freedom.go @@ -2,10 +2,10 @@ package freedom import ( "io" - "log" "net" "github.com/v2ray/v2ray-core" + "github.com/v2ray/v2ray-core/log" v2net "github.com/v2ray/v2ray-core/net" ) @@ -24,10 +24,9 @@ func (vconn *VFreeConnection) Start(vRay core.OutboundVRay) error { output := vRay.OutboundOutput() conn, err := net.Dial("tcp", vconn.dest.String()) if err != nil { - log.Print(err) - return err + return log.Error("Failed to open tcp: %s", vconn.dest.String()) } - log.Print("Working on tcp:" + vconn.dest.String()) + log.Debug("Sending outbound tcp: %s", vconn.dest.String()) finish := make(chan bool, 2) go vconn.DumpInput(conn, input, finish) @@ -41,22 +40,25 @@ func (vconn *VFreeConnection) DumpInput(conn net.Conn, input <-chan []byte, fini data, open := <-input if !open { finish <- true + log.Debug("Freedom finishing input.") break } - conn.Write(data) + nBytes, err := conn.Write(data) + log.Debug("Freedom wrote %d bytes with error %v", nBytes, err) } } func (vconn *VFreeConnection) DumpOutput(conn net.Conn, output chan<- []byte, finish chan<- bool) { for { - buffer := make([]byte, 128) + buffer := make([]byte, 512) nBytes, err := conn.Read(buffer) + log.Debug("Freedom reading %d bytes with error %v", nBytes, err) if err == io.EOF { close(output) finish <- true + log.Debug("Freedom finishing output.") break } - log.Print(buffer[:nBytes]) output <- buffer[:nBytes] } } diff --git a/net/freedom/freedomfactory.go b/net/freedom/freedomfactory.go index a9ed27081..11261cd6a 100644 --- a/net/freedom/freedomfactory.go +++ b/net/freedom/freedomfactory.go @@ -11,3 +11,7 @@ type FreedomFactory struct { func (factory FreedomFactory) Create(vp *core.VPoint, config []byte, dest v2net.VAddress) (core.OutboundConnectionHandler, error) { return NewVFreeConnection(dest), nil } + +func init() { + core.RegisterOutboundConnectionHandlerFactory("freedom", FreedomFactory{}) +} diff --git a/net/socks/socks.go b/net/socks/socks.go index f4c341319..e84c3b064 100644 --- a/net/socks/socks.go +++ b/net/socks/socks.go @@ -37,8 +37,10 @@ func NewSocksServer(vp *core.VPoint, rawConfig []byte) *SocksServer { func (server *SocksServer) Listen(port uint16) error { listener, err := net.Listen("tcp", ":"+strconv.Itoa(int(port))) if err != nil { - return log.Error("Error on listening port %d: %v", port, err) + log.Error("Error on listening port %d: %v", port, err) + return err } + log.Debug("Working on tcp:%d", port) server.accepting = true go server.AcceptConnections(listener) return nil @@ -48,7 +50,8 @@ func (server *SocksServer) AcceptConnections(listener net.Listener) error { for server.accepting { connection, err := listener.Accept() if err != nil { - return log.Error("Error on accepting socks connection: %v", err) + log.Error("Error on accepting socks connection: %v", err) + return err } go server.HandleConnection(connection) } @@ -60,7 +63,8 @@ func (server *SocksServer) HandleConnection(connection net.Conn) error { auth, err := socksio.ReadAuthentication(connection) if err != nil { - return log.Error("Error on reading authentication: %v", err) + log.Error("Error on reading authentication: %v", err) + return err } expectedAuthMethod := socksio.AuthNotRequired @@ -76,12 +80,14 @@ func (server *SocksServer) HandleConnection(connection net.Conn) error { return ErrorAuthenticationFailed } + log.Debug("Auth accepted, responding auth.") authResponse := socksio.NewAuthenticationResponse(socksio.AuthNotRequired) socksio.WriteAuthentication(connection, authResponse) request, err := socksio.ReadRequest(connection) if err != nil { - return log.Error("Error on reading socks request: %v", err) + log.Error("Error on reading socks request: %v", err) + return err } response := socksio.NewSocks5Response() @@ -105,6 +111,7 @@ func (server *SocksServer) HandleConnection(connection net.Conn) error { case socksio.AddrTypeDomain: response.Domain = request.Domain } + log.Debug("Socks response port = %d", response.Port) socksio.WriteResponse(connection, response) ray := server.vPoint.NewInboundConnectionAccepted(request.Destination()) @@ -121,12 +128,13 @@ func (server *SocksServer) HandleConnection(connection net.Conn) error { func (server *SocksServer) dumpInput(conn net.Conn, input chan<- []byte, finish chan<- bool) { for { - buffer := make([]byte, 256) + buffer := make([]byte, 512) nBytes, err := conn.Read(buffer) log.Debug("Reading %d bytes, with error %v", nBytes, err) if err == io.EOF { close(input) finish <- true + log.Debug("Socks finishing input.") break } input <- buffer[:nBytes] @@ -138,10 +146,11 @@ func (server *SocksServer) dumpOutput(conn net.Conn, output <-chan []byte, finis buffer, open := <-output if !open { finish <- true + log.Debug("Socks finishing output") break } - nBytes, _ := conn.Write(buffer) - log.Debug("Writing %d bytes", nBytes) + nBytes, err := conn.Write(buffer) + log.Debug("Writing %d bytes with error %v", nBytes, err) } } diff --git a/net/socks/socks_test.go b/net/socks/socks_test.go index 627c6c5b2..97a2e02cd 100644 --- a/net/socks/socks_test.go +++ b/net/socks/socks_test.go @@ -11,29 +11,29 @@ import ( func TestSocksTcpConnect(t *testing.T) { t.Skip("Not ready yet.") - /* - assert := unit.Assert(t) + /* + assert := unit.Assert(t) - port := uint16(12384) + port := uint16(12384) - uuid := "2418d087-648d-4990-86e8-19dca1d006d3" - vid, err := core.UUIDToVID(uuid) - assert.Error(err).IsNil() + uuid := "2418d087-648d-4990-86e8-19dca1d006d3" + vid, err := core.UUIDToVID(uuid) + assert.Error(err).IsNil() - config := core.VConfig{ - port, - []core.VUser{core.VUser{vid}}, - "", - []core.VNext{}} + config := core.VConfig{ + port, + []core.VUser{core.VUser{vid}}, + "", + []core.VNext{}} - och := new(mocks.FakeOutboundConnectionHandler) - och.Data2Send = bytes.NewBuffer(make([]byte, 1024)) - och.Data2Return = []byte("The data to be returned to socks server.") + och := new(mocks.FakeOutboundConnectionHandler) + och.Data2Send = bytes.NewBuffer(make([]byte, 1024)) + och.Data2Return = []byte("The data to be returned to socks server.") - vpoint, err := core.NewVPoint(&config, SocksServerFactory{}, och) - assert.Error(err).IsNil() + vpoint, err := core.NewVPoint(&config, SocksServerFactory{}, och) + assert.Error(err).IsNil() - err = vpoint.Start() - assert.Error(err).IsNil() - */ + err = vpoint.Start() + assert.Error(err).IsNil() + */ } diff --git a/net/socks/socksfactory.go b/net/socks/socksfactory.go index 8c7635676..9461b6767 100644 --- a/net/socks/socksfactory.go +++ b/net/socks/socksfactory.go @@ -10,3 +10,7 @@ type SocksServerFactory struct { func (factory SocksServerFactory) Create(vp *core.VPoint, config []byte) (core.InboundConnectionHandler, error) { return NewSocksServer(vp, config), nil } + +func init() { + core.RegisterInboundConnectionHandlerFactory("socks", SocksServerFactory{}) +} diff --git a/net/vmess/config.go b/net/vmess/config.go index b6c426e6e..da902bf20 100644 --- a/net/vmess/config.go +++ b/net/vmess/config.go @@ -4,11 +4,22 @@ import ( "encoding/json" "github.com/v2ray/v2ray-core" + "github.com/v2ray/v2ray-core/log" v2net "github.com/v2ray/v2ray-core/net" ) +type VMessUser struct { + Id string `json:"id"` + Email string `json:"email"` +} + +func (u *VMessUser) ToVUser() (core.VUser, error) { + id, err := core.UUIDToVID(u.Id) + return core.VUser{id}, err +} + type VMessInboundConfig struct { - AllowedClients []core.VUser `json:"clients"` + AllowedClients []VMessUser `json:"clients"` } func loadInboundConfig(rawConfig []byte) (VMessInboundConfig, error) { @@ -18,19 +29,27 @@ func loadInboundConfig(rawConfig []byte) (VMessInboundConfig, error) { } type VNextConfig struct { - Address string `json:"address"` - Port uint16 `json:"port"` - Users []core.VUser `json:"users"` + Address string `json:"address"` + Port uint16 `json:"port"` + Users []VMessUser `json:"users"` } func (config VNextConfig) ToVNextServer() VNextServer { + users := make([]core.VUser, 0, len(config.Users)) + for _, user := range config.Users { + vuser, err := user.ToVUser() + if err != nil { + panic(log.Error("Failed to convert %v to VUser.", user)) + } + users = append(users, vuser) + } return VNextServer{ v2net.DomainAddress(config.Address, config.Port), - config.Users} + users} } type VMessOutboundConfig struct { - VNextList []VNextConfig + VNextList []VNextConfig `json:"vnext"` } func loadOutboundConfig(rawConfig []byte) (VMessOutboundConfig, error) { diff --git a/net/vmess/vmess.go b/net/vmess/vmess.go index 60f17caa1..59eb0ac8f 100644 --- a/net/vmess/vmess.go +++ b/net/vmess/vmess.go @@ -1,5 +1,5 @@ package vmess const ( - BufferSize = 256 + BufferSize = 512 ) diff --git a/net/vmess/vmessin.go b/net/vmess/vmessin.go index 9e041040b..df404b6e4 100644 --- a/net/vmess/vmessin.go +++ b/net/vmess/vmessin.go @@ -4,6 +4,7 @@ import ( "crypto/md5" "io" "net" + "strconv" "github.com/v2ray/v2ray-core" v2io "github.com/v2ray/v2ray-core/io" @@ -24,10 +25,10 @@ func NewVMessInboundHandler(vp *core.VPoint, clients *core.VUserSet) *VMessInbou return handler } -func (handler *VMessInboundHandler) Listen(port uint8) error { - listener, err := net.Listen("tcp", ":"+string(port)) +func (handler *VMessInboundHandler) Listen(port uint16) error { + listener, err := net.Listen("tcp", ":"+strconv.Itoa(int(port))) if err != nil { - return err + return log.Error("Unable to listen tcp:%d", port) } handler.accepting = true go handler.AcceptConnections(listener) @@ -39,7 +40,7 @@ func (handler *VMessInboundHandler) AcceptConnections(listener net.Listener) err for handler.accepting { connection, err := listener.Accept() if err != nil { - return err + return log.Error("Failed to accpet connection: %s", err.Error()) } go handler.HandleConnection(connection) } @@ -54,9 +55,14 @@ func (handler *VMessInboundHandler) HandleConnection(connection net.Conn) error if err != nil { return err } + log.Debug("Received request for %s", request.Address.String()) response := vmessio.NewVMessResponse(request) - connection.Write(response[:]) + nBytes, err := connection.Write(response[:]) + log.Debug("Writing VMess response %v", response) + if err != nil { + return log.Error("Failed to write VMess response (%d bytes): %v", nBytes, err) + } requestKey := request.RequestKey[:] requestIV := request.RequestIV[:] @@ -65,12 +71,12 @@ func (handler *VMessInboundHandler) HandleConnection(connection net.Conn) error requestReader, err := v2io.NewAesDecryptReader(requestKey, requestIV, connection) if err != nil { - return err + return log.Error("Failed to create decrypt reader: %v", err) } responseWriter, err := v2io.NewAesEncryptWriter(responseKey[:], responseIV[:], connection) if err != nil { - return err + return log.Error("Failed to create encrypt writer: %v", err) } ray := handler.vPoint.NewInboundConnectionAccepted(request.Address) @@ -89,8 +95,10 @@ func (handler *VMessInboundHandler) dumpInput(reader io.Reader, input chan<- []b for { buffer := make([]byte, BufferSize) nBytes, err := reader.Read(buffer) + log.Debug("VMessInbound: Reading %d bytes with error %v", nBytes, err) if err == io.EOF { close(input) + log.Debug("VMessInbound finishing input.") finish <- true break } @@ -103,9 +111,11 @@ func (handler *VMessInboundHandler) dumpOutput(writer io.Writer, output <-chan [ buffer, open := <-output if !open { finish <- true + log.Debug("VMessInbound finishing output.") break } - writer.Write(buffer) + nBytes, err := writer.Write(buffer) + log.Debug("VmessInbound: Wrote %d bytes with error %v", nBytes, err) } } @@ -118,14 +128,22 @@ func (handler *VMessInboundHandler) waitForFinish(finish <-chan bool) { type VMessInboundHandlerFactory struct { } -func (factory *VMessInboundHandlerFactory) Create(vp *core.VPoint, rawConfig []byte) *VMessInboundHandler { +func (factory *VMessInboundHandlerFactory) Create(vp *core.VPoint, rawConfig []byte) (core.InboundConnectionHandler, error) { config, err := loadInboundConfig(rawConfig) if err != nil { panic(log.Error("Failed to load VMess inbound config: %v", err)) } allowedClients := core.NewVUserSet() - for _, user := range config.AllowedClients { + for _, client := range config.AllowedClients { + user, err := client.ToVUser() + if err != nil { + panic(log.Error("Failed to parse user id %s: %v", client.Id, err)) + } allowedClients.AddUser(user) } - return NewVMessInboundHandler(vp, allowedClients) + return NewVMessInboundHandler(vp, allowedClients), nil +} + +func init() { + core.RegisterInboundConnectionHandlerFactory("vmess", &VMessInboundHandlerFactory{}) } diff --git a/net/vmess/vmessout.go b/net/vmess/vmessout.go index 567809321..ef862618a 100644 --- a/net/vmess/vmessout.go +++ b/net/vmess/vmessout.go @@ -62,26 +62,48 @@ func (handler *VMessOutboundHandler) Start(ray core.OutboundVRay) error { request.Command = byte(0x01) request.Address = handler.dest - conn, err := net.Dial("tcp", vNextAddress.String()) + go handler.startCommunicate(request, vNextAddress, ray) + return nil +} + +func (handler *VMessOutboundHandler) startCommunicate(request *vmessio.VMessRequest, dest v2net.VAddress, ray core.OutboundVRay) error { + conn, err := net.Dial("tcp", dest.String()) + log.Debug("VMessOutbound dialing tcp: %s", dest.String()) if err != nil { + log.Error("Failed to open tcp (%s): %v", dest.String(), err) return err } defer conn.Close() requestWriter := vmessio.NewVMessRequestWriter() - requestWriter.Write(conn, request) + err = requestWriter.Write(conn, request) + if err != nil { + log.Error("Failed to write VMess request: %v", err) + return err + } requestKey := request.RequestKey[:] requestIV := request.RequestIV[:] responseKey := md5.Sum(requestKey) responseIV := md5.Sum(requestIV) - encryptRequestWriter, err := v2io.NewAesEncryptWriter(requestKey, requestIV, conn) + response := vmessio.VMessResponse{} + nBytes, err := conn.Read(response[:]) if err != nil { + log.Error("Failed to read VMess response (%d bytes): %v", nBytes, err) return err } - responseReader, err := v2io.NewAesDecryptReader(responseKey[:], responseIV[:], conn) + log.Debug("Got response %v", response) + // TODO: check response + + encryptRequestWriter, err := v2io.NewAesEncryptWriter(requestKey, requestIV, conn) if err != nil { + log.Error("Failed to create encrypt writer: %v", err) + return err + } + decryptResponseReader, err := v2io.NewAesDecryptReader(responseKey[:], responseIV[:], conn) + if err != nil { + log.Error("Failed to create decrypt reader: %v", err) return err } @@ -90,7 +112,7 @@ func (handler *VMessOutboundHandler) Start(ray core.OutboundVRay) error { finish := make(chan bool, 2) go handler.dumpInput(encryptRequestWriter, input, finish) - go handler.dumpOutput(responseReader, output, finish) + go handler.dumpOutput(decryptResponseReader, output, finish) handler.waitForFinish(finish) return nil } @@ -99,9 +121,11 @@ func (handler *VMessOutboundHandler) dumpOutput(reader io.Reader, output chan<- for { buffer := make([]byte, BufferSize) nBytes, err := reader.Read(buffer) + log.Debug("VMessOutbound: Reading %d bytes, with error %v", nBytes, err) if err == io.EOF { close(output) finish <- true + log.Debug("VMessOutbound finishing output.") break } output <- buffer[:nBytes] @@ -113,9 +137,11 @@ func (handler *VMessOutboundHandler) dumpInput(writer io.Writer, input <-chan [] buffer, open := <-input if !open { finish <- true + log.Debug("VMessOutbound finishing input.") break } - writer.Write(buffer) + nBytes, err := writer.Write(buffer) + log.Debug("VMessOutbound: Wrote %d bytes with error %v", nBytes, err) } } @@ -123,12 +149,13 @@ func (handler *VMessOutboundHandler) waitForFinish(finish <-chan bool) { for i := 0; i < 2; i++ { <-finish } + log.Debug("Finishing waiting for VMessOutbound ending.") } type VMessOutboundHandlerFactory struct { } -func (factory *VMessOutboundHandlerFactory) Create(vp *core.VPoint, rawConfig []byte, destination v2net.VAddress) *VMessOutboundHandler { +func (factory *VMessOutboundHandlerFactory) Create(vp *core.VPoint, rawConfig []byte, destination v2net.VAddress) (core.OutboundConnectionHandler, error) { config, err := loadOutboundConfig(rawConfig) if err != nil { panic(log.Error("Failed to load VMess outbound config: %v", err)) @@ -137,5 +164,9 @@ func (factory *VMessOutboundHandlerFactory) Create(vp *core.VPoint, rawConfig [] for _, server := range config.VNextList { servers = append(servers, server.ToVNextServer()) } - return NewVMessOutboundHandler(vp, servers, destination) + return NewVMessOutboundHandler(vp, servers, destination), nil +} + +func init() { + core.RegisterOutboundConnectionHandlerFactory("vmess", &VMessOutboundHandlerFactory{}) } diff --git a/release/config/in_socks.json b/release/config/in_socks.json new file mode 100644 index 000000000..06cb86b0e --- /dev/null +++ b/release/config/in_socks.json @@ -0,0 +1,3 @@ +{ + "auth": "noauth" +} diff --git a/release/config/in_vmess.json b/release/config/in_vmess.json new file mode 100644 index 000000000..5df3150db --- /dev/null +++ b/release/config/in_vmess.json @@ -0,0 +1,5 @@ +{ + "clients": [ + {"id": "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"} + ] +} diff --git a/release/config/out_vmess.json b/release/config/out_vmess.json new file mode 100644 index 000000000..4675cc8ee --- /dev/null +++ b/release/config/out_vmess.json @@ -0,0 +1,11 @@ +{ + "vnext": [ + { + "address": "127.0.0.1", + "port": 27183, + "users": [ + {"id": "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"} + ] + } + ] +} diff --git a/release/config/vpoint_socks_vmess.json b/release/config/vpoint_socks_vmess.json new file mode 100644 index 000000000..db43a157e --- /dev/null +++ b/release/config/vpoint_socks_vmess.json @@ -0,0 +1,11 @@ +{ + "port": 1080, + "inbound": { + "protocol": "socks", + "file": "in_socks.json" + }, + "outbound": { + "protocol": "vmess", + "file": "out_vmess.json" + } +} diff --git a/release/config/vpoint_vmess_freedom.json b/release/config/vpoint_vmess_freedom.json new file mode 100644 index 000000000..af5992cb8 --- /dev/null +++ b/release/config/vpoint_vmess_freedom.json @@ -0,0 +1,11 @@ +{ + "port": 27183, + "inbound": { + "protocol": "vmess", + "file": "in_vmess.json" + }, + "outbound": { + "protocol": "freedom", + "file": "" + } +} diff --git a/release/server/main.go b/release/server/main.go index 790580777..c8c16b9c5 100644 --- a/release/server/main.go +++ b/release/server/main.go @@ -1,5 +1,57 @@ package main -func main() { +import ( + "flag" + "io/ioutil" + "path" + "github.com/v2ray/v2ray-core" + "github.com/v2ray/v2ray-core/log" + + _ "github.com/v2ray/v2ray-core/net/freedom" + _ "github.com/v2ray/v2ray-core/net/socks" + _ "github.com/v2ray/v2ray-core/net/vmess" +) + +var ( + configFile = flag.String("config", "", "Config file for this VPoint server.") +) + +func main() { + flag.Parse() + + log.SetLogLevel(log.DebugLevel) + + if configFile == nil || len(*configFile) == 0 { + panic(log.Error("Config file is not set.")) + } + rawVConfig, err := ioutil.ReadFile(*configFile) + if err != nil { + panic(log.Error("Failed to read config file (%s): %v", *configFile, err)) + } + vconfig, err := core.LoadVConfig(rawVConfig) + if err != nil { + panic(log.Error("Failed to parse VConfig: %v", err)) + } + + if !path.IsAbs(vconfig.InboundConfig.File) && len(vconfig.InboundConfig.File) > 0 { + vconfig.InboundConfig.File = path.Join(path.Dir(*configFile), vconfig.InboundConfig.File) + } + + if !path.IsAbs(vconfig.OutboundConfig.File) && len(vconfig.OutboundConfig.File) > 0 { + vconfig.OutboundConfig.File = path.Join(path.Dir(*configFile), vconfig.OutboundConfig.File) + } + + vPoint, err := core.NewVPoint(vconfig) + if err != nil { + panic(log.Error("Failed to create VPoint server: %v", err)) + } + + err = vPoint.Start() + if err != nil { + log.Error("Error starting VPoint server.") + } + + finish := make(chan bool) + <-finish }