1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-06-10 18:00:43 +00:00

massive refactoring for configuration

This commit is contained in:
V2Ray 2015-09-12 11:51:42 +02:00
parent 791ac780f0
commit 0ca7dab49b
15 changed files with 212 additions and 147 deletions

View File

@ -1,37 +0,0 @@
// Package json contains io library for VConfig in Json format.
package json
import (
"encoding/json"
_ "fmt"
"github.com/v2ray/v2ray-core"
)
type JsonVUser struct {
id string `json:"id"`
email string `json:"email"`
}
type JsonVConfig struct {
Port uint8 `json:"port"`
Clients []JsonVUser `json:"users"`
Protocol string `json:"protocol"`
}
type JsonVConfigUnmarshaller struct {
}
func StringToVUser(id string) (u core.VUser, err error) {
return
}
func (*JsonVConfigUnmarshaller) Unmarshall(data []byte) (*core.VConfig, error) {
var jsonConfig JsonVConfig
err := json.Unmarshal(data, &jsonConfig)
if err != nil {
return nil, err
}
var vconfig = new(core.VConfig)
return vconfig, nil
}

View File

@ -13,9 +13,10 @@ import (
const ( const (
socksVersion = uint8(5) socksVersion = uint8(5)
AuthNotRequired = byte(0x00) AuthNotRequired = byte(0x00)
AuthGssApi = byte(0x01) AuthGssApi = byte(0x01)
AuthUserPass = byte(0x02) AuthUserPass = byte(0x02)
AuthNoMatchingMethod = byte(0xFF)
) )
// Authentication request header of Socks5 protocol // Authentication request header of Socks5 protocol

View File

@ -28,6 +28,11 @@ func writeLog(data string, level LogLevel) {
log.Print(data) log.Print(data)
} }
func Debug(format string, v ...interface{}) {
data := fmt.Sprintf(format, v)
writeLog("[Debug]"+data, DebugLevel)
}
func Info(format string, v ...interface{}) { func Info(format string, v ...interface{}) {
data := fmt.Sprintf(format, v) data := fmt.Sprintf(format, v)
writeLog("[Info]"+data, InfoLevel) writeLog("[Info]"+data, InfoLevel)

View File

@ -10,13 +10,11 @@ import (
) )
type VFreeConnection struct { type VFreeConnection struct {
vPoint *core.VPoint dest v2net.VAddress
dest v2net.VAddress
} }
func NewVFreeConnection(vp *core.VPoint, dest v2net.VAddress) *VFreeConnection { func NewVFreeConnection(dest v2net.VAddress) *VFreeConnection {
conn := new(VFreeConnection) conn := new(VFreeConnection)
conn.vPoint = vp
conn.dest = dest conn.dest = dest
return conn return conn
} }

View File

@ -8,6 +8,6 @@ import (
type FreedomFactory struct { type FreedomFactory struct {
} }
func (factory FreedomFactory) Create(vp *core.VPoint, dest v2net.VAddress) (core.OutboundConnectionHandler, error) { func (factory FreedomFactory) Create(vp *core.VPoint, config []byte, dest v2net.VAddress) (core.OutboundConnectionHandler, error) {
return NewVFreeConnection(vp, dest), nil return NewVFreeConnection(dest), nil
} }

22
net/socks/config.go Normal file
View File

@ -0,0 +1,22 @@
package socks
import (
"encoding/json"
)
const (
JsonAuthMethodNoAuth = "noauth"
JsonAuthMethodUserPass = "password"
)
type SocksConfig struct {
AuthMethod string `json:"auth"`
Username string `json:"user"`
Password string `json:"pass"`
}
func loadConfig(rawConfig []byte) (SocksConfig, error) {
config := SocksConfig{}
err := json.Unmarshal(rawConfig, &config)
return config, err
}

View File

@ -3,12 +3,12 @@ package socks
import ( import (
"errors" "errors"
"io" "io"
"log"
"net" "net"
"strconv" "strconv"
"github.com/v2ray/v2ray-core" "github.com/v2ray/v2ray-core"
socksio "github.com/v2ray/v2ray-core/io/socks" socksio "github.com/v2ray/v2ray-core/io/socks"
"github.com/v2ray/v2ray-core/log"
) )
var ( var (
@ -20,18 +20,24 @@ var (
type SocksServer struct { type SocksServer struct {
accepting bool accepting bool
vPoint *core.VPoint vPoint *core.VPoint
config SocksConfig
} }
func NewSocksServer(vp *core.VPoint) *SocksServer { func NewSocksServer(vp *core.VPoint, rawConfig []byte) *SocksServer {
server := new(SocksServer) server := new(SocksServer)
server.vPoint = vp server.vPoint = vp
config, err := loadConfig(rawConfig)
if err != nil {
panic(log.Error("Unable to load socks config: %v", err))
}
server.config = config
return server return server
} }
func (server *SocksServer) Listen(port uint16) error { func (server *SocksServer) Listen(port uint16) error {
listener, err := net.Listen("tcp", ":"+strconv.Itoa(int(port))) listener, err := net.Listen("tcp", ":"+strconv.Itoa(int(port)))
if err != nil { if err != nil {
return err return log.Error("Error on listening port %d: %v", port, err)
} }
server.accepting = true server.accepting = true
go server.AcceptConnections(listener) go server.AcceptConnections(listener)
@ -42,8 +48,7 @@ func (server *SocksServer) AcceptConnections(listener net.Listener) error {
for server.accepting { for server.accepting {
connection, err := listener.Accept() connection, err := listener.Accept()
if err != nil { if err != nil {
log.Print(err) return log.Error("Error on accepting socks connection: %v", err)
return err
} }
go server.HandleConnection(connection) go server.HandleConnection(connection)
} }
@ -55,14 +60,19 @@ func (server *SocksServer) HandleConnection(connection net.Conn) error {
auth, err := socksio.ReadAuthentication(connection) auth, err := socksio.ReadAuthentication(connection)
if err != nil { if err != nil {
log.Print(err) return log.Error("Error on reading authentication: %v", err)
return err
} }
log.Print(auth)
if !auth.HasAuthMethod(socksio.AuthNotRequired) { expectedAuthMethod := socksio.AuthNotRequired
// TODO send response with FF if server.config.AuthMethod == JsonAuthMethodUserPass {
log.Print(ErrorAuthenticationFailed) expectedAuthMethod = socksio.AuthUserPass
}
if !auth.HasAuthMethod(expectedAuthMethod) {
authResponse := socksio.NewAuthenticationResponse(socksio.AuthNoMatchingMethod)
socksio.WriteAuthentication(connection, authResponse)
log.Info("Client doesn't support allowed any auth methods.")
return ErrorAuthenticationFailed return ErrorAuthenticationFailed
} }
@ -71,8 +81,7 @@ func (server *SocksServer) HandleConnection(connection net.Conn) error {
request, err := socksio.ReadRequest(connection) request, err := socksio.ReadRequest(connection)
if err != nil { if err != nil {
log.Print(err) return log.Error("Error on reading socks request: %v", err)
return err
} }
response := socksio.NewSocks5Response() response := socksio.NewSocks5Response()
@ -81,7 +90,7 @@ func (server *SocksServer) HandleConnection(connection net.Conn) error {
response := socksio.NewSocks5Response() response := socksio.NewSocks5Response()
response.Error = socksio.ErrorCommandNotSupported response.Error = socksio.ErrorCommandNotSupported
socksio.WriteResponse(connection, response) socksio.WriteResponse(connection, response)
log.Print(ErrorCommandNotSupported) log.Info("Unsupported socks command %d", request.Command)
return ErrorCommandNotSupported return ErrorCommandNotSupported
} }
@ -114,7 +123,7 @@ func (server *SocksServer) dumpInput(conn net.Conn, input chan<- []byte, finish
for { for {
buffer := make([]byte, 256) buffer := make([]byte, 256)
nBytes, err := conn.Read(buffer) nBytes, err := conn.Read(buffer)
log.Printf("Reading %d bytes, with error %v", nBytes, err) log.Debug("Reading %d bytes, with error %v", nBytes, err)
if err == io.EOF { if err == io.EOF {
close(input) close(input)
finish <- true finish <- true
@ -132,7 +141,7 @@ func (server *SocksServer) dumpOutput(conn net.Conn, output <-chan []byte, finis
break break
} }
nBytes, _ := conn.Write(buffer) nBytes, _ := conn.Write(buffer)
log.Printf("Writing %d bytes", nBytes) log.Debug("Writing %d bytes", nBytes)
} }
} }

View File

@ -7,6 +7,6 @@ import (
type SocksServerFactory struct { type SocksServerFactory struct {
} }
func (factory SocksServerFactory) Create(vp *core.VPoint) (core.InboundConnectionHandler, error) { func (factory SocksServerFactory) Create(vp *core.VPoint, config []byte) (core.InboundConnectionHandler, error) {
return NewSocksServer(vp), nil return NewSocksServer(vp, config), nil
} }

40
net/vmess/config.go Normal file
View File

@ -0,0 +1,40 @@
package vmess
import (
"encoding/json"
"github.com/v2ray/v2ray-core"
v2net "github.com/v2ray/v2ray-core/net"
)
type VMessInboundConfig struct {
AllowedClients []core.VUser `json:"clients"`
}
func loadInboundConfig(rawConfig []byte) (VMessInboundConfig, error) {
config := VMessInboundConfig{}
err := json.Unmarshal(rawConfig, &config)
return config, err
}
type VNextConfig struct {
Address string `json:"address"`
Port uint16 `json:"port"`
Users []core.VUser `json:"users"`
}
func (config VNextConfig) ToVNextServer() VNextServer {
return VNextServer{
v2net.DomainAddress(config.Address, config.Port),
config.Users}
}
type VMessOutboundConfig struct {
VNextList []VNextConfig
}
func loadOutboundConfig(rawConfig []byte) (VMessOutboundConfig, error) {
config := VMessOutboundConfig{}
err := json.Unmarshal(rawConfig, &config)
return config, err
}

View File

@ -8,6 +8,7 @@ import (
"github.com/v2ray/v2ray-core" "github.com/v2ray/v2ray-core"
v2io "github.com/v2ray/v2ray-core/io" v2io "github.com/v2ray/v2ray-core/io"
vmessio "github.com/v2ray/v2ray-core/io/vmess" vmessio "github.com/v2ray/v2ray-core/io/vmess"
"github.com/v2ray/v2ray-core/log"
) )
type VMessInboundHandler struct { type VMessInboundHandler struct {
@ -89,6 +90,7 @@ func (handler *VMessInboundHandler) dumpInput(reader io.Reader, input chan<- []b
buffer := make([]byte, BufferSize) buffer := make([]byte, BufferSize)
nBytes, err := reader.Read(buffer) nBytes, err := reader.Read(buffer)
if err == io.EOF { if err == io.EOF {
close(input)
finish <- true finish <- true
break break
} }
@ -114,18 +116,16 @@ func (handler *VMessInboundHandler) waitForFinish(finish <-chan bool) {
} }
type VMessInboundHandlerFactory struct { type VMessInboundHandlerFactory struct {
allowedClients *core.VUserSet
} }
func NewVMessInboundHandlerFactory(clients []core.VUser) *VMessInboundHandlerFactory { func (factory *VMessInboundHandlerFactory) Create(vp *core.VPoint, rawConfig []byte) *VMessInboundHandler {
factory := new(VMessInboundHandlerFactory) config, err := loadInboundConfig(rawConfig)
factory.allowedClients = core.NewVUserSet() if err != nil {
for _, user := range clients { panic(log.Error("Failed to load VMess inbound config: %v", err))
factory.allowedClients.AddUser(user)
} }
return factory allowedClients := core.NewVUserSet()
} for _, user := range config.AllowedClients {
allowedClients.AddUser(user)
func (factory *VMessInboundHandlerFactory) Create(vp *core.VPoint) *VMessInboundHandler { }
return NewVMessInboundHandler(vp, factory.allowedClients) return NewVMessInboundHandler(vp, allowedClients)
} }

View File

@ -10,28 +10,37 @@ import (
"github.com/v2ray/v2ray-core" "github.com/v2ray/v2ray-core"
v2io "github.com/v2ray/v2ray-core/io" v2io "github.com/v2ray/v2ray-core/io"
vmessio "github.com/v2ray/v2ray-core/io/vmess" vmessio "github.com/v2ray/v2ray-core/io/vmess"
"github.com/v2ray/v2ray-core/log"
v2net "github.com/v2ray/v2ray-core/net" v2net "github.com/v2ray/v2ray-core/net"
) )
type VMessOutboundHandler struct { // VNext is the next VPoint server in the connection chain.
vPoint *core.VPoint type VNextServer struct {
dest v2net.VAddress Address v2net.VAddress // Address of VNext server
Users []core.VUser // User accounts for accessing VNext.
} }
func NewVMessOutboundHandler(vp *core.VPoint, dest v2net.VAddress) *VMessOutboundHandler { type VMessOutboundHandler struct {
vPoint *core.VPoint
dest v2net.VAddress
vNextList []VNextServer
}
func NewVMessOutboundHandler(vp *core.VPoint, vNextList []VNextServer, dest v2net.VAddress) *VMessOutboundHandler {
handler := new(VMessOutboundHandler) handler := new(VMessOutboundHandler)
handler.vPoint = vp handler.vPoint = vp
handler.dest = dest handler.dest = dest
handler.vNextList = vNextList
return handler return handler
} }
func (handler *VMessOutboundHandler) pickVNext() (v2net.VAddress, core.VUser) { func (handler *VMessOutboundHandler) pickVNext() (v2net.VAddress, core.VUser) {
vNextLen := len(handler.vPoint.Config.VNextList) vNextLen := len(handler.vNextList)
if vNextLen == 0 { if vNextLen == 0 {
panic("Zero vNext is configured.") panic("Zero vNext is configured.")
} }
vNextIndex := mrand.Intn(vNextLen) vNextIndex := mrand.Intn(vNextLen)
vNext := handler.vPoint.Config.VNextList[vNextIndex] vNext := handler.vNextList[vNextIndex]
vNextUserLen := len(vNext.Users) vNextUserLen := len(vNext.Users)
if vNextUserLen == 0 { if vNextUserLen == 0 {
panic("Zero User account.") panic("Zero User account.")
@ -91,6 +100,7 @@ func (handler *VMessOutboundHandler) dumpOutput(reader io.Reader, output chan<-
buffer := make([]byte, BufferSize) buffer := make([]byte, BufferSize)
nBytes, err := reader.Read(buffer) nBytes, err := reader.Read(buffer)
if err == io.EOF { if err == io.EOF {
close(output)
finish <- true finish <- true
break break
} }
@ -118,6 +128,14 @@ func (handler *VMessOutboundHandler) waitForFinish(finish <-chan bool) {
type VMessOutboundHandlerFactory struct { type VMessOutboundHandlerFactory struct {
} }
func (factory *VMessOutboundHandlerFactory) Create(vp *core.VPoint, destination v2net.VAddress) *VMessOutboundHandler { func (factory *VMessOutboundHandlerFactory) Create(vp *core.VPoint, rawConfig []byte, destination v2net.VAddress) *VMessOutboundHandler {
return NewVMessOutboundHandler(vp, destination) config, err := loadOutboundConfig(rawConfig)
if err != nil {
panic(log.Error("Failed to load VMess outbound config: %v", err))
}
servers := make([]VNextServer, 0, len(config.VNextList))
for _, server := range config.VNextList {
servers = append(servers, server.ToVNextServer())
}
return NewVMessOutboundHandler(vp, servers, destination)
} }

5
release/server/main.go Normal file
View File

@ -0,0 +1,5 @@
package main
func main() {
}

View File

@ -1,37 +0,0 @@
package main
import (
"log"
"github.com/v2ray/v2ray-core"
"github.com/v2ray/v2ray-core/net/freedom"
"github.com/v2ray/v2ray-core/net/socks"
)
func main() {
port := uint16(8888)
uuid := "2418d087-648d-4990-86e8-19dca1d006d3"
vid, err := core.UUIDToVID(uuid)
if err != nil {
log.Fatal(err)
}
config := core.VConfig{
port,
[]core.VUser{core.VUser{vid}},
"",
[]core.VNext{}}
vpoint, err := core.NewVPoint(&config, socks.SocksServerFactory{}, freedom.FreedomFactory{})
if err != nil {
log.Fatal(err)
}
err = vpoint.Start()
if err != nil {
log.Fatal(err)
}
finish := make(chan bool)
<-finish
}

View File

@ -1,32 +1,28 @@
package core package core
import ( import (
v2net "github.com/v2ray/v2ray-core/net" "encoding/json"
) )
// VUser is the user account that is used for connection to a VPoint // VUser is the user account that is used for connection to a VPoint
type VUser struct { type VUser struct {
Id VID // The ID of this VUser. Id VID `json:"id"` // The ID of this VUser.
} }
// VNext is the next VPoint server in the connection chain. type VConnectionConfig struct {
type VNext struct { Protocol string `json:"protocol"`
Address v2net.VAddress // Address of VNext server File string `json:"file"`
Users []VUser // User accounts for accessing VNext.
} }
// VConfig is the config for VPoint server. // VConfig is the config for VPoint server.
type VConfig struct { type VConfig struct {
Port uint16 // Port of this VPoint server. Port uint16 `json:"port"` // Port of this VPoint server.
AllowedClients []VUser InboundConfig VConnectionConfig `json:"inbound"`
ClientProtocol string OutboundConfig VConnectionConfig `json:"outbound"`
VNextList []VNext
} }
type VConfigMarshaller interface { func LoadVConfig(rawConfig []byte) (VConfig, error) {
Marshal(config VConfig) ([]byte, error) config := VConfig{}
} err := json.Unmarshal(rawConfig, &config)
return config, err
type VConfigUnmarshaller interface {
Unmarshal(data []byte) (VConfig, error)
} }

View File

@ -1,31 +1,76 @@
package core package core
import ( import (
"fmt" "io/ioutil"
"github.com/v2ray/v2ray-core/log"
v2net "github.com/v2ray/v2ray-core/net" v2net "github.com/v2ray/v2ray-core/net"
) )
var (
inboundFactories = make(map[string]InboundConnectionHandlerFactory)
outboundFactories = make(map[string]OutboundConnectionHandlerFactory)
)
func RegisterInboundConnectionHandlerFactory(name string, factory InboundConnectionHandlerFactory) error {
// TODO check name
inboundFactories[name] = factory
return nil
}
func RegisterOutboundConnectionHandlerFactory(name string, factory OutboundConnectionHandlerFactory) error {
// TODO check name
outboundFactories[name] = factory
return nil
}
// VPoint is an single server in V2Ray system. // VPoint is an single server in V2Ray system.
type VPoint struct { type VPoint struct {
Config VConfig port uint16
ichFactory InboundConnectionHandlerFactory ichFactory InboundConnectionHandlerFactory
ichConfig []byte
ochFactory OutboundConnectionHandlerFactory ochFactory OutboundConnectionHandlerFactory
ochConfig []byte
} }
// NewVPoint returns a new VPoint server based on given configuration. // NewVPoint returns a new VPoint server based on given configuration.
// The server is not started at this point. // The server is not started at this point.
func NewVPoint(config *VConfig, ichFactory InboundConnectionHandlerFactory, ochFactory OutboundConnectionHandlerFactory) (*VPoint, error) { func NewVPoint(config VConfig) (*VPoint, error) {
var vpoint = new(VPoint) var vpoint = new(VPoint)
vpoint.Config = *config vpoint.port = config.Port
ichFactory, ok := inboundFactories[config.InboundConfig.Protocol]
if !ok {
panic(log.Error("Unknown inbound connection handler factory %s", config.InboundConfig.Protocol))
}
vpoint.ichFactory = ichFactory vpoint.ichFactory = ichFactory
if len(config.InboundConfig.File) > 0 {
ichConfig, err := ioutil.ReadFile(config.InboundConfig.File)
if err != nil {
panic(log.Error("Unable to read config file %v", err))
}
vpoint.ichConfig = ichConfig
}
ochFactory, ok := outboundFactories[config.OutboundConfig.Protocol]
if !ok {
panic(log.Error("Unknown outbound connection handler factory %s", config.OutboundConfig.Protocol))
}
vpoint.ochFactory = ochFactory vpoint.ochFactory = ochFactory
if len(config.OutboundConfig.File) > 0 {
ochConfig, err := ioutil.ReadFile(config.OutboundConfig.File)
if err != nil {
panic(log.Error("Unable to read config file %v", err))
}
vpoint.ochConfig = ochConfig
}
return vpoint, nil return vpoint, nil
} }
type InboundConnectionHandlerFactory interface { type InboundConnectionHandlerFactory interface {
Create(vPoint *VPoint) (InboundConnectionHandler, error) Create(vp *VPoint, config []byte) (InboundConnectionHandler, error)
} }
type InboundConnectionHandler interface { type InboundConnectionHandler interface {
@ -33,7 +78,7 @@ type InboundConnectionHandler interface {
} }
type OutboundConnectionHandlerFactory interface { type OutboundConnectionHandlerFactory interface {
Create(vPoint *VPoint, dest v2net.VAddress) (OutboundConnectionHandler, error) Create(VP *VPoint, config []byte, dest v2net.VAddress) (OutboundConnectionHandler, error)
} }
type OutboundConnectionHandler interface { type OutboundConnectionHandler interface {
@ -43,21 +88,21 @@ type OutboundConnectionHandler interface {
// Start starts the VPoint server, and return any error during the process. // Start starts the VPoint server, and return any error during the process.
// In the case of any errors, the state of the server is unpredicatable. // In the case of any errors, the state of the server is unpredicatable.
func (vp *VPoint) Start() error { func (vp *VPoint) Start() error {
if vp.Config.Port <= 0 { if vp.port <= 0 {
return fmt.Errorf("Invalid port %d", vp.Config.Port) return log.Error("Invalid port %d", vp.port)
} }
inboundConnectionHandler, err := vp.ichFactory.Create(vp) inboundConnectionHandler, err := vp.ichFactory.Create(vp, vp.ichConfig)
if err != nil { if err != nil {
return err return err
} }
err = inboundConnectionHandler.Listen(vp.Config.Port) err = inboundConnectionHandler.Listen(vp.port)
return nil return nil
} }
func (vp *VPoint) NewInboundConnectionAccepted(destination v2net.VAddress) InboundVRay { func (vp *VPoint) NewInboundConnectionAccepted(destination v2net.VAddress) InboundVRay {
ray := NewVRay() ray := NewVRay()
// TODO: handle error // TODO: handle error
och, _ := vp.ochFactory.Create(vp, destination) och, _ := vp.ochFactory.Create(vp, vp.ochConfig, destination)
_ = och.Start(ray) _ = och.Start(ray)
return ray return ray
} }