mirror of
https://github.com/e1732a364fed/v2ray_simple.git
synced 2025-10-07 01:32:57 +08:00
352 lines
8.3 KiB
Go
352 lines
8.3 KiB
Go
package proxy
|
||
|
||
import (
|
||
"log"
|
||
"net/url"
|
||
"strings"
|
||
|
||
"github.com/hahahrfool/v2ray_simple/netLayer"
|
||
"github.com/hahahrfool/v2ray_simple/utils"
|
||
"go.uber.org/zap"
|
||
)
|
||
|
||
type ClientCreator interface {
|
||
//程序从某种配置文件格式中读取出 DialConf
|
||
NewClient(*DialConf) (Client, error)
|
||
NewClientFromURL(url *url.URL) (Client, error)
|
||
}
|
||
|
||
type ServerCreator interface {
|
||
//程序从某种配置文件格式中读取出 ListenConf
|
||
NewServer(*ListenConf) (Server, error)
|
||
NewServerFromURL(url *url.URL) (Server, error)
|
||
}
|
||
|
||
var (
|
||
clientCreatorMap = make(map[string]ClientCreator)
|
||
serverCreatorMap = make(map[string]ServerCreator)
|
||
)
|
||
|
||
// 规定,每个 实现Client的包必须使用本函数进行注册
|
||
func RegisterClient(name string, c ClientCreator) {
|
||
clientCreatorMap[name] = c
|
||
}
|
||
|
||
// 规定,每个 实现 Server 的包必须使用本函数进行注册
|
||
func RegisterServer(name string, c ServerCreator) {
|
||
serverCreatorMap[name] = c
|
||
}
|
||
|
||
func NewClient(dc *DialConf) (Client, error) {
|
||
protocol := dc.Protocol
|
||
creator, ok := clientCreatorMap[protocol]
|
||
if ok {
|
||
c, e := creator.NewClient(dc)
|
||
if e != nil {
|
||
return nil, e
|
||
}
|
||
e = configCommonForClient(c, dc)
|
||
if e != nil {
|
||
return nil, e
|
||
}
|
||
if dc.TLS {
|
||
c.SetUseTLS()
|
||
e = prepareTLS_forClient(c, dc)
|
||
return c, e
|
||
}
|
||
|
||
return c, nil
|
||
} else {
|
||
realScheme := strings.TrimSuffix(protocol, "s")
|
||
creator, ok = clientCreatorMap[realScheme]
|
||
if ok {
|
||
c, err := creator.NewClient(dc)
|
||
if err != nil {
|
||
return c, err
|
||
}
|
||
err = configCommonForClient(c, dc)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
c.SetUseTLS()
|
||
err = prepareTLS_forClient(c, dc)
|
||
return c, err
|
||
|
||
}
|
||
}
|
||
return nil, utils.ErrInErr{ErrDesc: "unknown client protocol ", Data: protocol}
|
||
|
||
}
|
||
|
||
// ClientFromURL calls the registered creator to create client.
|
||
// dialer is the default upstream dialer so cannot be nil, we can use Default when calling this function.
|
||
func ClientFromURL(s string) (Client, bool, utils.ErrInErr) {
|
||
u, err := url.Parse(s)
|
||
if err != nil {
|
||
|
||
return nil, true, utils.ErrInErr{ErrDesc: "can not parse client url", ErrDetail: err, Data: s}
|
||
}
|
||
|
||
schemeName := strings.ToLower(u.Scheme)
|
||
|
||
creator, ok := clientCreatorMap[schemeName]
|
||
if ok {
|
||
c, e := creator.NewClientFromURL(u)
|
||
if e != nil {
|
||
return nil, true, utils.ErrInErr{ErrDesc: "creator.NewClientFromURL err", ErrDetail: e}
|
||
}
|
||
configCommonByURL(c, u)
|
||
return c, false, utils.ErrInErr{}
|
||
} else {
|
||
|
||
//尝试判断是否套tls, 比如vlesss实际上是vless+tls,https实际上是http+tls
|
||
|
||
realScheme := strings.TrimSuffix(schemeName, "s")
|
||
creator, ok = clientCreatorMap[realScheme]
|
||
if ok {
|
||
c, err := creator.NewClientFromURL(u)
|
||
if err != nil {
|
||
return nil, true, utils.ErrInErr{ErrDesc: "creator.NewClientFromURL err", ErrDetail: err}
|
||
}
|
||
configCommonByURL(c, u)
|
||
|
||
c.SetUseTLS()
|
||
prepareTLS_forProxyCommon_withURL(u, true, c)
|
||
|
||
return c, false, utils.ErrInErr{}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
return nil, false, utils.ErrInErr{ErrDesc: "unknown client protocol ", Data: u.Scheme}
|
||
}
|
||
|
||
func NewServer(lc *ListenConf) (Server, error) {
|
||
protocol := lc.Protocol
|
||
creator, ok := serverCreatorMap[protocol]
|
||
if ok {
|
||
ser, err := creator.NewServer(lc)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
err = configCommonForServer(ser, lc)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
if lc.TLS {
|
||
ser.SetUseTLS()
|
||
err = prepareTLS_forServer(ser, lc)
|
||
if err != nil {
|
||
return nil, utils.ErrInErr{ErrDesc: "prepareTLS failed", ErrDetail: err}
|
||
|
||
}
|
||
return ser, nil
|
||
}
|
||
|
||
return ser, nil
|
||
} else {
|
||
realScheme := strings.TrimSuffix(protocol, "s")
|
||
creator, ok = serverCreatorMap[realScheme]
|
||
if ok {
|
||
ser, err := creator.NewServer(lc)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
err = configCommonForServer(ser, lc)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
ser.SetUseTLS()
|
||
err = prepareTLS_forServer(ser, lc)
|
||
if err != nil {
|
||
return nil, utils.ErrInErr{ErrDesc: "prepareTLS failed", ErrDetail: err}
|
||
|
||
}
|
||
return ser, nil
|
||
|
||
}
|
||
}
|
||
|
||
return nil, utils.ErrInErr{ErrDesc: "unknown server protocol ", Data: protocol}
|
||
}
|
||
|
||
// ServerFromURL calls the registered creator to create proxy servers
|
||
// dialer is the default upstream dialer so cannot be nil, we can use Default when calling this function
|
||
// 所有的server都可有 "norule"参数,标明无需路由或者此server不可使用路由,在监听多个ip时是有用的;
|
||
// 路由配置可以在json的其他配置里面设置,如 mycountry项
|
||
func ServerFromURL(s string) (Server, bool, utils.ErrInErr) {
|
||
u, err := url.Parse(s)
|
||
if err != nil {
|
||
return nil, true, utils.ErrInErr{
|
||
ErrDesc: "can not parse server url ",
|
||
ErrDetail: err,
|
||
Data: s,
|
||
}
|
||
}
|
||
|
||
schemeName := strings.ToLower(u.Scheme)
|
||
creator, ok := serverCreatorMap[schemeName]
|
||
if ok {
|
||
ser, err := creator.NewServerFromURL(u)
|
||
if err != nil {
|
||
return nil, true, utils.ErrInErr{
|
||
ErrDesc: "creator.NewServerFromURL err ",
|
||
ErrDetail: err,
|
||
}
|
||
}
|
||
configCommonURLQueryForServer(ser, u)
|
||
|
||
return ser, false, utils.ErrInErr{}
|
||
} else {
|
||
realScheme := strings.TrimSuffix(schemeName, "s")
|
||
creator, ok = serverCreatorMap[realScheme]
|
||
if ok {
|
||
server, err := creator.NewServerFromURL(u)
|
||
if err != nil {
|
||
return nil, true, utils.ErrInErr{
|
||
ErrDesc: "creator.NewServerFromURL err ",
|
||
ErrDetail: err,
|
||
}
|
||
}
|
||
configCommonURLQueryForServer(server, u)
|
||
|
||
server.SetUseTLS()
|
||
prepareTLS_forProxyCommon_withURL(u, false, server)
|
||
return server, false, utils.ErrInErr{}
|
||
|
||
}
|
||
}
|
||
|
||
return nil, true, utils.ErrInErr{ErrDesc: "unknown server protocol ", Data: u.Scheme}
|
||
}
|
||
|
||
//setTag, setCantRoute, call configCommonByURL
|
||
func configCommonURLQueryForServer(ser ProxyCommon, u *url.URL) {
|
||
nr := false
|
||
q := u.Query()
|
||
if q.Get("noroute") != "" {
|
||
nr = true
|
||
}
|
||
|
||
ser.setCantRoute(nr)
|
||
ser.setTag(u.Fragment)
|
||
|
||
configCommonByURL(ser, u)
|
||
|
||
fallbackStr := q.Get("fallback")
|
||
|
||
if fallbackStr != "" {
|
||
fa, err := netLayer.NewAddr(fallbackStr)
|
||
|
||
if err != nil {
|
||
if utils.ZapLogger != nil {
|
||
utils.ZapLogger.Fatal("configCommonURLQueryForServer failed", zap.String("invalid fallback", fallbackStr))
|
||
} else {
|
||
log.Fatalf("invalid fallback %s\n", fallbackStr)
|
||
|
||
}
|
||
}
|
||
|
||
ser.setFallback(fa)
|
||
}
|
||
}
|
||
|
||
//SetAddrStr,setAdvancedLayer
|
||
func configCommonByURL(ser ProxyCommon, u *url.URL) {
|
||
if u.Scheme != "direct" {
|
||
ser.SetAddrStr(u.Host) //若不给出port,那就只有host名,这样不好,我们“默认”, 配置里肯定给了port
|
||
|
||
}
|
||
q := u.Query()
|
||
wsStr := q.Get("ws")
|
||
if wsStr != "" && wsStr != "0" && wsStr != "false" {
|
||
ser.setAdvancedLayer("ws")
|
||
}
|
||
grpcStr := q.Get("grpc")
|
||
if grpcStr != "" && grpcStr != "0" && grpcStr != "false" {
|
||
pathStr := q.Get("path")
|
||
if pathStr != "" && pathStr != "0" && pathStr != "false" {
|
||
|
||
ser.setAdvancedLayer("grpc")
|
||
ser.setPath(pathStr)
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
//setAdvancedLayer
|
||
func configCommon(ser ProxyCommon, cc *CommonConf) {
|
||
ser.setAdvancedLayer(cc.AdvancedLayer)
|
||
if cc.Path != "" {
|
||
ser.setPath(cc.Path)
|
||
}
|
||
|
||
}
|
||
|
||
//SetAddrStr, setNetwork, setIsDial(true),setDialConf(dc), call configCommon(setAdvancedLayer)
|
||
func configCommonForClient(cli ProxyCommon, dc *DialConf) error {
|
||
cli.setNetwork(dc.Network)
|
||
cli.setIsDial(true)
|
||
cli.setDialConf(dc)
|
||
cli.setTag(dc.Tag)
|
||
|
||
if cli.Name() != "direct" {
|
||
cli.SetAddrStr(dc.GetAddrStrForListenOrDial())
|
||
}
|
||
|
||
configCommon(cli, &dc.CommonConf)
|
||
|
||
if dc.AdvancedLayer == "ws" {
|
||
return cli.initWS_client()
|
||
}
|
||
return nil
|
||
}
|
||
|
||
//SetAddrStr,setNetwork, setTag, setCantRoute,setListenConf(lc),setFallback, call configCommon
|
||
func configCommonForServer(ser ProxyCommon, lc *ListenConf) error {
|
||
ser.SetAddrStr(lc.GetAddrStrForListenOrDial())
|
||
ser.setNetwork(lc.Network)
|
||
ser.setListenConf(lc)
|
||
ser.setTag(lc.Tag)
|
||
ser.setCantRoute(lc.NoRoute)
|
||
configCommon(ser, &lc.CommonConf)
|
||
|
||
switch lc.AdvancedLayer {
|
||
case "ws":
|
||
err := ser.initWS_server()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
case "grpc":
|
||
err := ser.initGRPC_server()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
//case "quic":
|
||
|
||
//因为quic接管了tls层, 而我们的configCommonForServer是在tls配置之前被调用的
|
||
// 所以不能在这里配置quic。本作直接在 prepareTLS_forServer 函数里配置 quic的所有配置
|
||
|
||
}
|
||
|
||
fallbackThing := lc.Fallback
|
||
|
||
if fallbackThing != nil {
|
||
fa, err := netLayer.NewAddrFromAny(fallbackThing)
|
||
|
||
if err != nil {
|
||
return utils.ErrInErr{ErrDesc: "configCommonURLQueryForServer failed", Data: fallbackThing}
|
||
|
||
}
|
||
|
||
ser.setFallback(fa)
|
||
}
|
||
|
||
return nil
|
||
}
|