add reload and plugin support for hop
This commit is contained in:
87
config/parsing/admission/parse.go
Normal file
87
config/parsing/admission/parse.go
Normal file
@ -0,0 +1,87 @@
|
||||
package admission
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"strings"
|
||||
|
||||
"github.com/go-gost/core/admission"
|
||||
"github.com/go-gost/core/logger"
|
||||
xadmission "github.com/go-gost/x/admission"
|
||||
"github.com/go-gost/x/config"
|
||||
"github.com/go-gost/x/internal/loader"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"github.com/go-gost/x/registry"
|
||||
)
|
||||
|
||||
func ParseAdmission(cfg *config.AdmissionConfig) admission.Admission {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if cfg.Plugin != nil {
|
||||
var tlsCfg *tls.Config
|
||||
if cfg.Plugin.TLS != nil {
|
||||
tlsCfg = &tls.Config{
|
||||
ServerName: cfg.Plugin.TLS.ServerName,
|
||||
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
|
||||
}
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xadmission.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return xadmission.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
opts := []xadmission.Option{
|
||||
xadmission.MatchersOption(cfg.Matchers),
|
||||
xadmission.WhitelistOption(cfg.Reverse || cfg.Whitelist),
|
||||
xadmission.ReloadPeriodOption(cfg.Reload),
|
||||
xadmission.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "admission",
|
||||
"admission": cfg.Name,
|
||||
})),
|
||||
}
|
||||
if cfg.File != nil && cfg.File.Path != "" {
|
||||
opts = append(opts, xadmission.FileLoaderOption(loader.FileLoader(cfg.File.Path)))
|
||||
}
|
||||
if cfg.Redis != nil && cfg.Redis.Addr != "" {
|
||||
opts = append(opts, xadmission.RedisLoaderOption(loader.RedisSetLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
}
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
opts = append(opts, xadmission.HTTPLoaderOption(loader.HTTPLoader(
|
||||
cfg.HTTP.URL,
|
||||
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||
)))
|
||||
}
|
||||
|
||||
return xadmission.NewAdmission(opts...)
|
||||
}
|
||||
|
||||
func List(name string, names ...string) []admission.Admission {
|
||||
var admissions []admission.Admission
|
||||
if adm := registry.AdmissionRegistry().Get(name); adm != nil {
|
||||
admissions = append(admissions, adm)
|
||||
}
|
||||
for _, s := range names {
|
||||
if adm := registry.AdmissionRegistry().Get(s); adm != nil {
|
||||
admissions = append(admissions, adm)
|
||||
}
|
||||
}
|
||||
|
||||
return admissions
|
||||
}
|
120
config/parsing/auth/parse.go
Normal file
120
config/parsing/auth/parse.go
Normal file
@ -0,0 +1,120 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/url"
|
||||
|
||||
"github.com/go-gost/core/auth"
|
||||
"github.com/go-gost/core/logger"
|
||||
xauth "github.com/go-gost/x/auth"
|
||||
"github.com/go-gost/x/config"
|
||||
"github.com/go-gost/x/internal/loader"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"github.com/go-gost/x/registry"
|
||||
)
|
||||
|
||||
func ParseAuther(cfg *config.AutherConfig) auth.Authenticator {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if cfg.Plugin != nil {
|
||||
var tlsCfg *tls.Config
|
||||
if cfg.Plugin.TLS != nil {
|
||||
tlsCfg = &tls.Config{
|
||||
ServerName: cfg.Plugin.TLS.ServerName,
|
||||
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
|
||||
}
|
||||
}
|
||||
switch cfg.Plugin.Type {
|
||||
case "http":
|
||||
return xauth.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return xauth.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
m := make(map[string]string)
|
||||
|
||||
for _, user := range cfg.Auths {
|
||||
if user.Username == "" {
|
||||
continue
|
||||
}
|
||||
m[user.Username] = user.Password
|
||||
}
|
||||
|
||||
opts := []xauth.Option{
|
||||
xauth.AuthsOption(m),
|
||||
xauth.ReloadPeriodOption(cfg.Reload),
|
||||
xauth.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "auther",
|
||||
"auther": cfg.Name,
|
||||
})),
|
||||
}
|
||||
if cfg.File != nil && cfg.File.Path != "" {
|
||||
opts = append(opts, xauth.FileLoaderOption(loader.FileLoader(cfg.File.Path)))
|
||||
}
|
||||
if cfg.Redis != nil && cfg.Redis.Addr != "" {
|
||||
opts = append(opts, xauth.RedisLoaderOption(loader.RedisHashLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
}
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
opts = append(opts, xauth.HTTPLoaderOption(loader.HTTPLoader(
|
||||
cfg.HTTP.URL,
|
||||
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||
)))
|
||||
}
|
||||
return xauth.NewAuthenticator(opts...)
|
||||
}
|
||||
|
||||
func ParseAutherFromAuth(au *config.AuthConfig) auth.Authenticator {
|
||||
if au == nil || au.Username == "" {
|
||||
return nil
|
||||
}
|
||||
return xauth.NewAuthenticator(
|
||||
xauth.AuthsOption(
|
||||
map[string]string{
|
||||
au.Username: au.Password,
|
||||
},
|
||||
),
|
||||
xauth.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "auther",
|
||||
})),
|
||||
)
|
||||
}
|
||||
|
||||
func Info(cfg *config.AuthConfig) *url.Userinfo {
|
||||
if cfg == nil || cfg.Username == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if cfg.Password == "" {
|
||||
return url.User(cfg.Username)
|
||||
}
|
||||
return url.UserPassword(cfg.Username, cfg.Password)
|
||||
}
|
||||
|
||||
func List(name string, names ...string) []auth.Authenticator {
|
||||
var authers []auth.Authenticator
|
||||
if auther := registry.AutherRegistry().Get(name); auther != nil {
|
||||
authers = append(authers, auther)
|
||||
}
|
||||
for _, s := range names {
|
||||
if auther := registry.AutherRegistry().Get(s); auther != nil {
|
||||
authers = append(authers, auther)
|
||||
}
|
||||
}
|
||||
return authers
|
||||
}
|
86
config/parsing/bypass/parse.go
Normal file
86
config/parsing/bypass/parse.go
Normal file
@ -0,0 +1,86 @@
|
||||
package bypass
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"strings"
|
||||
|
||||
"github.com/go-gost/core/bypass"
|
||||
"github.com/go-gost/core/logger"
|
||||
xbypass "github.com/go-gost/x/bypass"
|
||||
"github.com/go-gost/x/config"
|
||||
"github.com/go-gost/x/internal/loader"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"github.com/go-gost/x/registry"
|
||||
)
|
||||
|
||||
func ParseBypass(cfg *config.BypassConfig) bypass.Bypass {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if cfg.Plugin != nil {
|
||||
var tlsCfg *tls.Config
|
||||
if cfg.Plugin.TLS != nil {
|
||||
tlsCfg = &tls.Config{
|
||||
ServerName: cfg.Plugin.TLS.ServerName,
|
||||
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
|
||||
}
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xbypass.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return xbypass.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
opts := []xbypass.Option{
|
||||
xbypass.MatchersOption(cfg.Matchers),
|
||||
xbypass.WhitelistOption(cfg.Reverse || cfg.Whitelist),
|
||||
xbypass.ReloadPeriodOption(cfg.Reload),
|
||||
xbypass.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "bypass",
|
||||
"bypass": cfg.Name,
|
||||
})),
|
||||
}
|
||||
if cfg.File != nil && cfg.File.Path != "" {
|
||||
opts = append(opts, xbypass.FileLoaderOption(loader.FileLoader(cfg.File.Path)))
|
||||
}
|
||||
if cfg.Redis != nil && cfg.Redis.Addr != "" {
|
||||
opts = append(opts, xbypass.RedisLoaderOption(loader.RedisSetLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
}
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
opts = append(opts, xbypass.HTTPLoaderOption(loader.HTTPLoader(
|
||||
cfg.HTTP.URL,
|
||||
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||
)))
|
||||
}
|
||||
|
||||
return xbypass.NewBypass(opts...)
|
||||
}
|
||||
|
||||
func List(name string, names ...string) []bypass.Bypass {
|
||||
var bypasses []bypass.Bypass
|
||||
if bp := registry.BypassRegistry().Get(name); bp != nil {
|
||||
bypasses = append(bypasses, bp)
|
||||
}
|
||||
for _, s := range names {
|
||||
if bp := registry.BypassRegistry().Get(s); bp != nil {
|
||||
bypasses = append(bypasses, bp)
|
||||
}
|
||||
}
|
||||
return bypasses
|
||||
}
|
@ -1,270 +0,0 @@
|
||||
package parsing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-gost/core/bypass"
|
||||
"github.com/go-gost/core/chain"
|
||||
"github.com/go-gost/core/connector"
|
||||
"github.com/go-gost/core/dialer"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/core/metadata"
|
||||
mdutil "github.com/go-gost/core/metadata/util"
|
||||
auther "github.com/go-gost/x/auth"
|
||||
xchain "github.com/go-gost/x/chain"
|
||||
"github.com/go-gost/x/config"
|
||||
tls_util "github.com/go-gost/x/internal/util/tls"
|
||||
mdx "github.com/go-gost/x/metadata"
|
||||
"github.com/go-gost/x/registry"
|
||||
)
|
||||
|
||||
func ParseChain(cfg *config.ChainConfig) (chain.Chainer, error) {
|
||||
if cfg == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
chainLogger := logger.Default().WithFields(map[string]any{
|
||||
"kind": "chain",
|
||||
"chain": cfg.Name,
|
||||
})
|
||||
|
||||
var md metadata.Metadata
|
||||
if cfg.Metadata != nil {
|
||||
md = mdx.NewMetadata(cfg.Metadata)
|
||||
}
|
||||
|
||||
c := xchain.NewChain(cfg.Name,
|
||||
xchain.MetadataChainOption(md),
|
||||
xchain.LoggerChainOption(chainLogger),
|
||||
)
|
||||
|
||||
for _, ch := range cfg.Hops {
|
||||
var hop chain.Hop
|
||||
var err error
|
||||
|
||||
if len(ch.Nodes) > 0 {
|
||||
if hop, err = ParseHop(ch); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
hop = registry.HopRegistry().Get(ch.Name)
|
||||
}
|
||||
if hop != nil {
|
||||
c.AddHop(hop)
|
||||
}
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func ParseHop(cfg *config.HopConfig) (chain.Hop, error) {
|
||||
if cfg == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
hopLogger := logger.Default().WithFields(map[string]any{
|
||||
"kind": "hop",
|
||||
"hop": cfg.Name,
|
||||
})
|
||||
|
||||
var nodes []*chain.Node
|
||||
for _, v := range cfg.Nodes {
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if v.Connector == nil {
|
||||
v.Connector = &config.ConnectorConfig{
|
||||
Type: "http",
|
||||
}
|
||||
}
|
||||
|
||||
if v.Dialer == nil {
|
||||
v.Dialer = &config.DialerConfig{
|
||||
Type: "tcp",
|
||||
}
|
||||
}
|
||||
|
||||
nodeLogger := hopLogger.WithFields(map[string]any{
|
||||
"kind": "node",
|
||||
"node": v.Name,
|
||||
"connector": v.Connector.Type,
|
||||
"dialer": v.Dialer.Type,
|
||||
})
|
||||
|
||||
serverName, _, _ := net.SplitHostPort(v.Addr)
|
||||
|
||||
tlsCfg := v.Connector.TLS
|
||||
if tlsCfg == nil {
|
||||
tlsCfg = &config.TLSConfig{}
|
||||
}
|
||||
if tlsCfg.ServerName == "" {
|
||||
tlsCfg.ServerName = serverName
|
||||
}
|
||||
tlsConfig, err := tls_util.LoadClientConfig(
|
||||
tlsCfg.CertFile, tlsCfg.KeyFile, tlsCfg.CAFile,
|
||||
tlsCfg.Secure, tlsCfg.ServerName)
|
||||
if err != nil {
|
||||
hopLogger.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var nm metadata.Metadata
|
||||
if v.Metadata != nil {
|
||||
nm = mdx.NewMetadata(v.Metadata)
|
||||
}
|
||||
|
||||
connectorLogger := nodeLogger.WithFields(map[string]any{
|
||||
"kind": "connector",
|
||||
})
|
||||
var cr connector.Connector
|
||||
if rf := registry.ConnectorRegistry().Get(v.Connector.Type); rf != nil {
|
||||
cr = rf(
|
||||
connector.AuthOption(parseAuth(v.Connector.Auth)),
|
||||
connector.TLSConfigOption(tlsConfig),
|
||||
connector.LoggerOption(connectorLogger),
|
||||
)
|
||||
} else {
|
||||
return nil, fmt.Errorf("unregistered connector: %s", v.Connector.Type)
|
||||
}
|
||||
|
||||
if v.Connector.Metadata == nil {
|
||||
v.Connector.Metadata = make(map[string]any)
|
||||
}
|
||||
if err := cr.Init(mdx.NewMetadata(v.Connector.Metadata)); err != nil {
|
||||
connectorLogger.Error("init: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tlsCfg = v.Dialer.TLS
|
||||
if tlsCfg == nil {
|
||||
tlsCfg = &config.TLSConfig{}
|
||||
}
|
||||
if tlsCfg.ServerName == "" {
|
||||
tlsCfg.ServerName = serverName
|
||||
}
|
||||
tlsConfig, err = tls_util.LoadClientConfig(
|
||||
tlsCfg.CertFile, tlsCfg.KeyFile, tlsCfg.CAFile,
|
||||
tlsCfg.Secure, tlsCfg.ServerName)
|
||||
if err != nil {
|
||||
hopLogger.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ppv int
|
||||
if nm != nil {
|
||||
ppv = mdutil.GetInt(nm, mdKeyProxyProtocol)
|
||||
}
|
||||
|
||||
dialerLogger := nodeLogger.WithFields(map[string]any{
|
||||
"kind": "dialer",
|
||||
})
|
||||
|
||||
var d dialer.Dialer
|
||||
if rf := registry.DialerRegistry().Get(v.Dialer.Type); rf != nil {
|
||||
d = rf(
|
||||
dialer.AuthOption(parseAuth(v.Dialer.Auth)),
|
||||
dialer.TLSConfigOption(tlsConfig),
|
||||
dialer.LoggerOption(dialerLogger),
|
||||
dialer.ProxyProtocolOption(ppv),
|
||||
)
|
||||
} else {
|
||||
return nil, fmt.Errorf("unregistered dialer: %s", v.Dialer.Type)
|
||||
}
|
||||
|
||||
if v.Dialer.Metadata == nil {
|
||||
v.Dialer.Metadata = make(map[string]any)
|
||||
}
|
||||
if err := d.Init(mdx.NewMetadata(v.Dialer.Metadata)); err != nil {
|
||||
dialerLogger.Error("init: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if v.Resolver == "" {
|
||||
v.Resolver = cfg.Resolver
|
||||
}
|
||||
if v.Hosts == "" {
|
||||
v.Hosts = cfg.Hosts
|
||||
}
|
||||
if v.Interface == "" {
|
||||
v.Interface = cfg.Interface
|
||||
}
|
||||
if v.SockOpts == nil {
|
||||
v.SockOpts = cfg.SockOpts
|
||||
}
|
||||
|
||||
var sockOpts *chain.SockOpts
|
||||
if v.SockOpts != nil {
|
||||
sockOpts = &chain.SockOpts{
|
||||
Mark: v.SockOpts.Mark,
|
||||
}
|
||||
}
|
||||
|
||||
tr := chain.NewTransport(d, cr,
|
||||
chain.AddrTransportOption(v.Addr),
|
||||
chain.InterfaceTransportOption(v.Interface),
|
||||
chain.SockOptsTransportOption(sockOpts),
|
||||
chain.TimeoutTransportOption(10*time.Second),
|
||||
)
|
||||
|
||||
// convert *.example.com to .example.com
|
||||
// convert *example.com to example.com
|
||||
host := v.Host
|
||||
if strings.HasPrefix(host, "*") {
|
||||
host = host[1:]
|
||||
if !strings.HasPrefix(host, ".") {
|
||||
host = "." + host
|
||||
}
|
||||
}
|
||||
|
||||
opts := []chain.NodeOption{
|
||||
chain.TransportNodeOption(tr),
|
||||
chain.BypassNodeOption(bypass.BypassGroup(bypassList(v.Bypass, v.Bypasses...)...)),
|
||||
chain.ResoloverNodeOption(registry.ResolverRegistry().Get(v.Resolver)),
|
||||
chain.HostMapperNodeOption(registry.HostsRegistry().Get(v.Hosts)),
|
||||
chain.MetadataNodeOption(nm),
|
||||
chain.HostNodeOption(host),
|
||||
chain.ProtocolNodeOption(v.Protocol),
|
||||
}
|
||||
if v.HTTP != nil {
|
||||
opts = append(opts, chain.HTTPNodeOption(&chain.HTTPNodeSettings{
|
||||
Host: v.HTTP.Host,
|
||||
Header: v.HTTP.Header,
|
||||
}))
|
||||
}
|
||||
if v.TLS != nil {
|
||||
opts = append(opts, chain.TLSNodeOption(&chain.TLSNodeSettings{
|
||||
ServerName: v.TLS.ServerName,
|
||||
Secure: v.TLS.Secure,
|
||||
}))
|
||||
}
|
||||
if v.Auth != nil {
|
||||
opts = append(opts, chain.AutherNodeOption(
|
||||
auther.NewAuthenticator(
|
||||
auther.AuthsOption(map[string]string{v.Auth.Username: v.Auth.Password}),
|
||||
auther.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "node",
|
||||
"node": v.Name,
|
||||
"addr": v.Addr,
|
||||
"host": v.Host,
|
||||
"protocol": v.Protocol,
|
||||
})),
|
||||
)))
|
||||
}
|
||||
node := chain.NewNode(v.Name, v.Addr, opts...)
|
||||
nodes = append(nodes, node)
|
||||
}
|
||||
|
||||
sel := parseNodeSelector(cfg.Selector)
|
||||
if sel == nil {
|
||||
sel = defaultNodeSelector()
|
||||
}
|
||||
return xchain.NewChainHop(nodes,
|
||||
xchain.SelectorHopOption(sel),
|
||||
xchain.BypassHopOption(bypass.BypassGroup(bypassList(cfg.Bypass, cfg.Bypasses...)...)),
|
||||
xchain.LoggerHopOption(hopLogger),
|
||||
), nil
|
||||
}
|
52
config/parsing/chain/parse.go
Normal file
52
config/parsing/chain/parse.go
Normal file
@ -0,0 +1,52 @@
|
||||
package chain
|
||||
|
||||
import (
|
||||
"github.com/go-gost/core/chain"
|
||||
"github.com/go-gost/core/hop"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/core/metadata"
|
||||
xchain "github.com/go-gost/x/chain"
|
||||
"github.com/go-gost/x/config"
|
||||
hop_parser "github.com/go-gost/x/config/parsing/hop"
|
||||
mdx "github.com/go-gost/x/metadata"
|
||||
"github.com/go-gost/x/registry"
|
||||
)
|
||||
|
||||
func ParseChain(cfg *config.ChainConfig) (chain.Chainer, error) {
|
||||
if cfg == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
chainLogger := logger.Default().WithFields(map[string]any{
|
||||
"kind": "chain",
|
||||
"chain": cfg.Name,
|
||||
})
|
||||
|
||||
var md metadata.Metadata
|
||||
if cfg.Metadata != nil {
|
||||
md = mdx.NewMetadata(cfg.Metadata)
|
||||
}
|
||||
|
||||
c := xchain.NewChain(cfg.Name,
|
||||
xchain.MetadataChainOption(md),
|
||||
xchain.LoggerChainOption(chainLogger),
|
||||
)
|
||||
|
||||
for _, ch := range cfg.Hops {
|
||||
var hop hop.Hop
|
||||
var err error
|
||||
|
||||
if ch.Nodes != nil || ch.Plugin != nil {
|
||||
if hop, err = hop_parser.ParseHop(ch); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
hop = registry.HopRegistry().Get(ch.Name)
|
||||
}
|
||||
if hop != nil {
|
||||
c.AddHop(hop)
|
||||
}
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
124
config/parsing/hop/parse.go
Normal file
124
config/parsing/hop/parse.go
Normal file
@ -0,0 +1,124 @@
|
||||
package hop
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"strings"
|
||||
|
||||
"github.com/go-gost/core/bypass"
|
||||
"github.com/go-gost/core/chain"
|
||||
"github.com/go-gost/core/hop"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/x/config"
|
||||
bypass_parser "github.com/go-gost/x/config/parsing/bypass"
|
||||
node_parser "github.com/go-gost/x/config/parsing/node"
|
||||
selector_parser "github.com/go-gost/x/config/parsing/selector"
|
||||
xhop "github.com/go-gost/x/hop"
|
||||
"github.com/go-gost/x/internal/loader"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
)
|
||||
|
||||
func ParseHop(cfg *config.HopConfig) (hop.Hop, error) {
|
||||
if cfg == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if cfg.Plugin != nil {
|
||||
var tlsCfg *tls.Config
|
||||
if cfg.Plugin.TLS != nil {
|
||||
tlsCfg = &tls.Config{
|
||||
ServerName: cfg.Plugin.TLS.ServerName,
|
||||
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
|
||||
}
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xhop.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
), nil
|
||||
default:
|
||||
return xhop.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
), nil
|
||||
}
|
||||
}
|
||||
|
||||
var nodes []*chain.Node
|
||||
for _, v := range cfg.Nodes {
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if v.Resolver == "" {
|
||||
v.Resolver = cfg.Resolver
|
||||
}
|
||||
if v.Hosts == "" {
|
||||
v.Hosts = cfg.Hosts
|
||||
}
|
||||
if v.Interface == "" {
|
||||
v.Interface = cfg.Interface
|
||||
}
|
||||
if v.SockOpts == nil {
|
||||
v.SockOpts = cfg.SockOpts
|
||||
}
|
||||
|
||||
if v.Connector == nil {
|
||||
v.Connector = &config.ConnectorConfig{
|
||||
Type: "http",
|
||||
}
|
||||
}
|
||||
|
||||
if v.Dialer == nil {
|
||||
v.Dialer = &config.DialerConfig{
|
||||
Type: "tcp",
|
||||
}
|
||||
}
|
||||
|
||||
node, err := node_parser.ParseNode(cfg.Name, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if node != nil {
|
||||
nodes = append(nodes, node)
|
||||
}
|
||||
}
|
||||
|
||||
sel := selector_parser.ParseNodeSelector(cfg.Selector)
|
||||
if sel == nil {
|
||||
sel = selector_parser.DefaultNodeSelector()
|
||||
}
|
||||
|
||||
opts := []xhop.Option{
|
||||
xhop.NameOption(cfg.Name),
|
||||
xhop.NodeOption(nodes...),
|
||||
xhop.SelectorOption(sel),
|
||||
xhop.BypassOption(bypass.BypassGroup(bypass_parser.List(cfg.Bypass, cfg.Bypasses...)...)),
|
||||
xhop.ReloadPeriodOption(cfg.Reload),
|
||||
xhop.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "hop",
|
||||
"hop": cfg.Name,
|
||||
})),
|
||||
}
|
||||
|
||||
if cfg.File != nil && cfg.File.Path != "" {
|
||||
opts = append(opts, xhop.FileLoaderOption(loader.FileLoader(cfg.File.Path)))
|
||||
}
|
||||
if cfg.Redis != nil && cfg.Redis.Addr != "" {
|
||||
opts = append(opts, xhop.RedisLoaderOption(loader.RedisStringLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
}
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
opts = append(opts, xhop.HTTPLoaderOption(loader.HTTPLoader(
|
||||
cfg.HTTP.URL,
|
||||
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||
)))
|
||||
}
|
||||
return xhop.NewHop(opts...), nil
|
||||
}
|
96
config/parsing/hosts/parse.go
Normal file
96
config/parsing/hosts/parse.go
Normal file
@ -0,0 +1,96 @@
|
||||
package hosts
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/go-gost/core/hosts"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/x/config"
|
||||
xhosts "github.com/go-gost/x/hosts"
|
||||
"github.com/go-gost/x/internal/loader"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
)
|
||||
|
||||
func ParseHostMapper(cfg *config.HostsConfig) hosts.HostMapper {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if cfg.Plugin != nil {
|
||||
var tlsCfg *tls.Config
|
||||
if cfg.Plugin.TLS != nil {
|
||||
tlsCfg = &tls.Config{
|
||||
ServerName: cfg.Plugin.TLS.ServerName,
|
||||
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
|
||||
}
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xhosts.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return xhosts.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var mappings []xhosts.Mapping
|
||||
for _, mapping := range cfg.Mappings {
|
||||
if mapping.IP == "" || mapping.Hostname == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
ip := net.ParseIP(mapping.IP)
|
||||
if ip == nil {
|
||||
continue
|
||||
}
|
||||
mappings = append(mappings, xhosts.Mapping{
|
||||
Hostname: mapping.Hostname,
|
||||
IP: ip,
|
||||
})
|
||||
}
|
||||
opts := []xhosts.Option{
|
||||
xhosts.MappingsOption(mappings),
|
||||
xhosts.ReloadPeriodOption(cfg.Reload),
|
||||
xhosts.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "hosts",
|
||||
"hosts": cfg.Name,
|
||||
})),
|
||||
}
|
||||
if cfg.File != nil && cfg.File.Path != "" {
|
||||
opts = append(opts, xhosts.FileLoaderOption(loader.FileLoader(cfg.File.Path)))
|
||||
}
|
||||
if cfg.Redis != nil && cfg.Redis.Addr != "" {
|
||||
switch cfg.Redis.Type {
|
||||
case "list": // redis list
|
||||
opts = append(opts, xhosts.RedisLoaderOption(loader.RedisListLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
default: // redis set
|
||||
opts = append(opts, xhosts.RedisLoaderOption(loader.RedisSetLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
}
|
||||
}
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
opts = append(opts, xhosts.HTTPLoaderOption(loader.HTTPLoader(
|
||||
cfg.HTTP.URL,
|
||||
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||
)))
|
||||
}
|
||||
return xhosts.NewHostMapper(opts...)
|
||||
}
|
91
config/parsing/ingress/parse.go
Normal file
91
config/parsing/ingress/parse.go
Normal file
@ -0,0 +1,91 @@
|
||||
package ingress
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"strings"
|
||||
|
||||
"github.com/go-gost/core/ingress"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/x/config"
|
||||
xingress "github.com/go-gost/x/ingress"
|
||||
"github.com/go-gost/x/internal/loader"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
)
|
||||
|
||||
func ParseIngress(cfg *config.IngressConfig) ingress.Ingress {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if cfg.Plugin != nil {
|
||||
var tlsCfg *tls.Config
|
||||
if cfg.Plugin.TLS != nil {
|
||||
tlsCfg = &tls.Config{
|
||||
ServerName: cfg.Plugin.TLS.ServerName,
|
||||
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
|
||||
}
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xingress.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return xingress.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var rules []xingress.Rule
|
||||
for _, rule := range cfg.Rules {
|
||||
if rule.Hostname == "" || rule.Endpoint == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
rules = append(rules, xingress.Rule{
|
||||
Hostname: rule.Hostname,
|
||||
Endpoint: rule.Endpoint,
|
||||
})
|
||||
}
|
||||
opts := []xingress.Option{
|
||||
xingress.RulesOption(rules),
|
||||
xingress.ReloadPeriodOption(cfg.Reload),
|
||||
xingress.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "ingress",
|
||||
"ingress": cfg.Name,
|
||||
})),
|
||||
}
|
||||
if cfg.File != nil && cfg.File.Path != "" {
|
||||
opts = append(opts, xingress.FileLoaderOption(loader.FileLoader(cfg.File.Path)))
|
||||
}
|
||||
if cfg.Redis != nil && cfg.Redis.Addr != "" {
|
||||
switch cfg.Redis.Type {
|
||||
case "set": // redis set
|
||||
opts = append(opts, xingress.RedisLoaderOption(loader.RedisSetLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
default: // redis hash
|
||||
opts = append(opts, xingress.RedisLoaderOption(loader.RedisHashLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
}
|
||||
}
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
opts = append(opts, xingress.HTTPLoaderOption(loader.HTTPLoader(
|
||||
cfg.HTTP.URL,
|
||||
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||
)))
|
||||
}
|
||||
return xingress.NewIngress(opts...)
|
||||
}
|
151
config/parsing/limiter/parse.go
Normal file
151
config/parsing/limiter/parse.go
Normal file
@ -0,0 +1,151 @@
|
||||
package limiter
|
||||
|
||||
import (
|
||||
"github.com/go-gost/core/limiter/conn"
|
||||
"github.com/go-gost/core/limiter/rate"
|
||||
"github.com/go-gost/core/limiter/traffic"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/x/config"
|
||||
"github.com/go-gost/x/internal/loader"
|
||||
xconn "github.com/go-gost/x/limiter/conn"
|
||||
xrate "github.com/go-gost/x/limiter/rate"
|
||||
xtraffic "github.com/go-gost/x/limiter/traffic"
|
||||
)
|
||||
|
||||
func ParseTrafficLimiter(cfg *config.LimiterConfig) (lim traffic.TrafficLimiter) {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var opts []xtraffic.Option
|
||||
|
||||
if cfg.File != nil && cfg.File.Path != "" {
|
||||
opts = append(opts, xtraffic.FileLoaderOption(loader.FileLoader(cfg.File.Path)))
|
||||
}
|
||||
if cfg.Redis != nil && cfg.Redis.Addr != "" {
|
||||
switch cfg.Redis.Type {
|
||||
case "list": // redis list
|
||||
opts = append(opts, xtraffic.RedisLoaderOption(loader.RedisListLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
default: // redis set
|
||||
opts = append(opts, xtraffic.RedisLoaderOption(loader.RedisSetLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
}
|
||||
}
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
opts = append(opts, xtraffic.HTTPLoaderOption(loader.HTTPLoader(
|
||||
cfg.HTTP.URL,
|
||||
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||
)))
|
||||
}
|
||||
opts = append(opts,
|
||||
xtraffic.LimitsOption(cfg.Limits...),
|
||||
xtraffic.ReloadPeriodOption(cfg.Reload),
|
||||
xtraffic.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "limiter",
|
||||
"limiter": cfg.Name,
|
||||
})),
|
||||
)
|
||||
|
||||
return xtraffic.NewTrafficLimiter(opts...)
|
||||
}
|
||||
|
||||
func ParseConnLimiter(cfg *config.LimiterConfig) (lim conn.ConnLimiter) {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var opts []xconn.Option
|
||||
|
||||
if cfg.File != nil && cfg.File.Path != "" {
|
||||
opts = append(opts, xconn.FileLoaderOption(loader.FileLoader(cfg.File.Path)))
|
||||
}
|
||||
if cfg.Redis != nil && cfg.Redis.Addr != "" {
|
||||
switch cfg.Redis.Type {
|
||||
case "list": // redis list
|
||||
opts = append(opts, xconn.RedisLoaderOption(loader.RedisListLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
default: // redis set
|
||||
opts = append(opts, xconn.RedisLoaderOption(loader.RedisSetLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
}
|
||||
}
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
opts = append(opts, xconn.HTTPLoaderOption(loader.HTTPLoader(
|
||||
cfg.HTTP.URL,
|
||||
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||
)))
|
||||
}
|
||||
opts = append(opts,
|
||||
xconn.LimitsOption(cfg.Limits...),
|
||||
xconn.ReloadPeriodOption(cfg.Reload),
|
||||
xconn.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "limiter",
|
||||
"limiter": cfg.Name,
|
||||
})),
|
||||
)
|
||||
|
||||
return xconn.NewConnLimiter(opts...)
|
||||
}
|
||||
|
||||
func ParseRateLimiter(cfg *config.LimiterConfig) (lim rate.RateLimiter) {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var opts []xrate.Option
|
||||
|
||||
if cfg.File != nil && cfg.File.Path != "" {
|
||||
opts = append(opts, xrate.FileLoaderOption(loader.FileLoader(cfg.File.Path)))
|
||||
}
|
||||
if cfg.Redis != nil && cfg.Redis.Addr != "" {
|
||||
switch cfg.Redis.Type {
|
||||
case "list": // redis list
|
||||
opts = append(opts, xrate.RedisLoaderOption(loader.RedisListLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
default: // redis set
|
||||
opts = append(opts, xrate.RedisLoaderOption(loader.RedisSetLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
}
|
||||
}
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
opts = append(opts, xrate.HTTPLoaderOption(loader.HTTPLoader(
|
||||
cfg.HTTP.URL,
|
||||
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||
)))
|
||||
}
|
||||
opts = append(opts,
|
||||
xrate.LimitsOption(cfg.Limits...),
|
||||
xrate.ReloadPeriodOption(cfg.Reload),
|
||||
xrate.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "limiter",
|
||||
"limiter": cfg.Name,
|
||||
})),
|
||||
)
|
||||
|
||||
return xrate.NewRateLimiter(opts...)
|
||||
}
|
198
config/parsing/node/parse.go
Normal file
198
config/parsing/node/parse.go
Normal file
@ -0,0 +1,198 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-gost/core/bypass"
|
||||
"github.com/go-gost/core/chain"
|
||||
"github.com/go-gost/core/connector"
|
||||
"github.com/go-gost/core/dialer"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/core/metadata"
|
||||
mdutil "github.com/go-gost/core/metadata/util"
|
||||
xauth "github.com/go-gost/x/auth"
|
||||
"github.com/go-gost/x/config"
|
||||
"github.com/go-gost/x/config/parsing"
|
||||
auth_parser "github.com/go-gost/x/config/parsing/auth"
|
||||
bypass_parser "github.com/go-gost/x/config/parsing/bypass"
|
||||
tls_util "github.com/go-gost/x/internal/util/tls"
|
||||
mdx "github.com/go-gost/x/metadata"
|
||||
"github.com/go-gost/x/registry"
|
||||
)
|
||||
|
||||
func ParseNode(hop string, cfg *config.NodeConfig) (*chain.Node, error) {
|
||||
if cfg == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if cfg.Connector == nil {
|
||||
cfg.Connector = &config.ConnectorConfig{
|
||||
Type: "http",
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.Dialer == nil {
|
||||
cfg.Dialer = &config.DialerConfig{
|
||||
Type: "tcp",
|
||||
}
|
||||
}
|
||||
|
||||
nodeLogger := logger.Default().WithFields(map[string]any{
|
||||
"hop": hop,
|
||||
"kind": "node",
|
||||
"node": cfg.Name,
|
||||
"connector": cfg.Connector.Type,
|
||||
"dialer": cfg.Dialer.Type,
|
||||
})
|
||||
|
||||
serverName, _, _ := net.SplitHostPort(cfg.Addr)
|
||||
|
||||
tlsCfg := cfg.Connector.TLS
|
||||
if tlsCfg == nil {
|
||||
tlsCfg = &config.TLSConfig{}
|
||||
}
|
||||
if tlsCfg.ServerName == "" {
|
||||
tlsCfg.ServerName = serverName
|
||||
}
|
||||
tlsConfig, err := tls_util.LoadClientConfig(
|
||||
tlsCfg.CertFile, tlsCfg.KeyFile, tlsCfg.CAFile,
|
||||
tlsCfg.Secure, tlsCfg.ServerName)
|
||||
if err != nil {
|
||||
nodeLogger.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var nm metadata.Metadata
|
||||
if cfg.Metadata != nil {
|
||||
nm = mdx.NewMetadata(cfg.Metadata)
|
||||
}
|
||||
|
||||
connectorLogger := nodeLogger.WithFields(map[string]any{
|
||||
"kind": "connector",
|
||||
})
|
||||
var cr connector.Connector
|
||||
if rf := registry.ConnectorRegistry().Get(cfg.Connector.Type); rf != nil {
|
||||
cr = rf(
|
||||
connector.AuthOption(auth_parser.Info(cfg.Connector.Auth)),
|
||||
connector.TLSConfigOption(tlsConfig),
|
||||
connector.LoggerOption(connectorLogger),
|
||||
)
|
||||
} else {
|
||||
return nil, fmt.Errorf("unregistered connector: %s", cfg.Connector.Type)
|
||||
}
|
||||
|
||||
if cfg.Connector.Metadata == nil {
|
||||
cfg.Connector.Metadata = make(map[string]any)
|
||||
}
|
||||
if err := cr.Init(mdx.NewMetadata(cfg.Connector.Metadata)); err != nil {
|
||||
connectorLogger.Error("init: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tlsCfg = cfg.Dialer.TLS
|
||||
if tlsCfg == nil {
|
||||
tlsCfg = &config.TLSConfig{}
|
||||
}
|
||||
if tlsCfg.ServerName == "" {
|
||||
tlsCfg.ServerName = serverName
|
||||
}
|
||||
tlsConfig, err = tls_util.LoadClientConfig(
|
||||
tlsCfg.CertFile, tlsCfg.KeyFile, tlsCfg.CAFile,
|
||||
tlsCfg.Secure, tlsCfg.ServerName)
|
||||
if err != nil {
|
||||
nodeLogger.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ppv int
|
||||
if nm != nil {
|
||||
ppv = mdutil.GetInt(nm, parsing.MDKeyProxyProtocol)
|
||||
}
|
||||
|
||||
dialerLogger := nodeLogger.WithFields(map[string]any{
|
||||
"kind": "dialer",
|
||||
})
|
||||
|
||||
var d dialer.Dialer
|
||||
if rf := registry.DialerRegistry().Get(cfg.Dialer.Type); rf != nil {
|
||||
d = rf(
|
||||
dialer.AuthOption(auth_parser.Info(cfg.Dialer.Auth)),
|
||||
dialer.TLSConfigOption(tlsConfig),
|
||||
dialer.LoggerOption(dialerLogger),
|
||||
dialer.ProxyProtocolOption(ppv),
|
||||
)
|
||||
} else {
|
||||
return nil, fmt.Errorf("unregistered dialer: %s", cfg.Dialer.Type)
|
||||
}
|
||||
|
||||
if cfg.Dialer.Metadata == nil {
|
||||
cfg.Dialer.Metadata = make(map[string]any)
|
||||
}
|
||||
if err := d.Init(mdx.NewMetadata(cfg.Dialer.Metadata)); err != nil {
|
||||
dialerLogger.Error("init: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var sockOpts *chain.SockOpts
|
||||
if cfg.SockOpts != nil {
|
||||
sockOpts = &chain.SockOpts{
|
||||
Mark: cfg.SockOpts.Mark,
|
||||
}
|
||||
}
|
||||
|
||||
tr := chain.NewTransport(d, cr,
|
||||
chain.AddrTransportOption(cfg.Addr),
|
||||
chain.InterfaceTransportOption(cfg.Interface),
|
||||
chain.SockOptsTransportOption(sockOpts),
|
||||
chain.TimeoutTransportOption(10*time.Second),
|
||||
)
|
||||
|
||||
// convert *.example.com to .example.com
|
||||
// convert *example.com to example.com
|
||||
host := cfg.Host
|
||||
if strings.HasPrefix(host, "*") {
|
||||
host = host[1:]
|
||||
if !strings.HasPrefix(host, ".") {
|
||||
host = "." + host
|
||||
}
|
||||
}
|
||||
|
||||
opts := []chain.NodeOption{
|
||||
chain.TransportNodeOption(tr),
|
||||
chain.BypassNodeOption(bypass.BypassGroup(bypass_parser.List(cfg.Bypass, cfg.Bypasses...)...)),
|
||||
chain.ResoloverNodeOption(registry.ResolverRegistry().Get(cfg.Resolver)),
|
||||
chain.HostMapperNodeOption(registry.HostsRegistry().Get(cfg.Hosts)),
|
||||
chain.MetadataNodeOption(nm),
|
||||
chain.HostNodeOption(host),
|
||||
chain.ProtocolNodeOption(cfg.Protocol),
|
||||
}
|
||||
if cfg.HTTP != nil {
|
||||
opts = append(opts, chain.HTTPNodeOption(&chain.HTTPNodeSettings{
|
||||
Host: cfg.HTTP.Host,
|
||||
Header: cfg.HTTP.Header,
|
||||
}))
|
||||
}
|
||||
if cfg.TLS != nil {
|
||||
opts = append(opts, chain.TLSNodeOption(&chain.TLSNodeSettings{
|
||||
ServerName: cfg.TLS.ServerName,
|
||||
Secure: cfg.TLS.Secure,
|
||||
}))
|
||||
}
|
||||
if cfg.Auth != nil {
|
||||
opts = append(opts, chain.AutherNodeOption(
|
||||
xauth.NewAuthenticator(
|
||||
xauth.AuthsOption(map[string]string{cfg.Auth.Username: cfg.Auth.Password}),
|
||||
xauth.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "node",
|
||||
"node": cfg.Name,
|
||||
"addr": cfg.Addr,
|
||||
"host": cfg.Host,
|
||||
"protocol": cfg.Protocol,
|
||||
})),
|
||||
)))
|
||||
}
|
||||
return chain.NewNode(cfg.Name, cfg.Addr, opts...), nil
|
||||
}
|
@ -1,820 +1,17 @@
|
||||
package parsing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/go-gost/core/admission"
|
||||
"github.com/go-gost/core/auth"
|
||||
"github.com/go-gost/core/bypass"
|
||||
"github.com/go-gost/core/chain"
|
||||
"github.com/go-gost/core/hosts"
|
||||
"github.com/go-gost/core/ingress"
|
||||
"github.com/go-gost/core/limiter/conn"
|
||||
"github.com/go-gost/core/limiter/rate"
|
||||
"github.com/go-gost/core/limiter/traffic"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/core/recorder"
|
||||
"github.com/go-gost/core/resolver"
|
||||
"github.com/go-gost/core/selector"
|
||||
admission_impl "github.com/go-gost/x/admission"
|
||||
auth_impl "github.com/go-gost/x/auth"
|
||||
bypass_impl "github.com/go-gost/x/bypass"
|
||||
"github.com/go-gost/x/config"
|
||||
xhosts "github.com/go-gost/x/hosts"
|
||||
xingress "github.com/go-gost/x/ingress"
|
||||
"github.com/go-gost/x/internal/loader"
|
||||
"github.com/go-gost/x/internal/util/plugin"
|
||||
xconn "github.com/go-gost/x/limiter/conn"
|
||||
xrate "github.com/go-gost/x/limiter/rate"
|
||||
xtraffic "github.com/go-gost/x/limiter/traffic"
|
||||
xrecorder "github.com/go-gost/x/recorder"
|
||||
"github.com/go-gost/x/registry"
|
||||
resolver_impl "github.com/go-gost/x/resolver"
|
||||
xs "github.com/go-gost/x/selector"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/backoff"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
const (
|
||||
mdKeyProxyProtocol = "proxyProtocol"
|
||||
mdKeyInterface = "interface"
|
||||
mdKeySoMark = "so_mark"
|
||||
mdKeyHash = "hash"
|
||||
mdKeyPreUp = "preUp"
|
||||
mdKeyPreDown = "preDown"
|
||||
mdKeyPostUp = "postUp"
|
||||
mdKeyPostDown = "postDown"
|
||||
mdKeyIgnoreChain = "ignoreChain"
|
||||
MDKeyProxyProtocol = "proxyProtocol"
|
||||
MDKeyInterface = "interface"
|
||||
MDKeySoMark = "so_mark"
|
||||
MDKeyHash = "hash"
|
||||
MDKeyPreUp = "preUp"
|
||||
MDKeyPreDown = "preDown"
|
||||
MDKeyPostUp = "postUp"
|
||||
MDKeyPostDown = "postDown"
|
||||
MDKeyIgnoreChain = "ignoreChain"
|
||||
|
||||
mdKeyRecorderDirection = "direction"
|
||||
mdKeyRecorderTimestampFormat = "timeStampFormat"
|
||||
mdKeyRecorderHexdump = "hexdump"
|
||||
MDKeyRecorderDirection = "direction"
|
||||
MDKeyRecorderTimestampFormat = "timeStampFormat"
|
||||
MDKeyRecorderHexdump = "hexdump"
|
||||
)
|
||||
|
||||
func ParseAuther(cfg *config.AutherConfig) auth.Authenticator {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if cfg.Plugin != nil {
|
||||
var tlsCfg *tls.Config
|
||||
if cfg.Plugin.TLS != nil {
|
||||
tlsCfg = &tls.Config{
|
||||
ServerName: cfg.Plugin.TLS.ServerName,
|
||||
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
|
||||
}
|
||||
}
|
||||
switch cfg.Plugin.Type {
|
||||
case "http":
|
||||
return auth_impl.NewHTTPPluginAuthenticator(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return auth_impl.NewGRPCPluginAuthenticator(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
m := make(map[string]string)
|
||||
|
||||
for _, user := range cfg.Auths {
|
||||
if user.Username == "" {
|
||||
continue
|
||||
}
|
||||
m[user.Username] = user.Password
|
||||
}
|
||||
|
||||
opts := []auth_impl.Option{
|
||||
auth_impl.AuthsOption(m),
|
||||
auth_impl.ReloadPeriodOption(cfg.Reload),
|
||||
auth_impl.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "auther",
|
||||
"auther": cfg.Name,
|
||||
})),
|
||||
}
|
||||
if cfg.File != nil && cfg.File.Path != "" {
|
||||
opts = append(opts, auth_impl.FileLoaderOption(loader.FileLoader(cfg.File.Path)))
|
||||
}
|
||||
if cfg.Redis != nil && cfg.Redis.Addr != "" {
|
||||
opts = append(opts, auth_impl.RedisLoaderOption(loader.RedisHashLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
}
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
opts = append(opts, auth_impl.HTTPLoaderOption(loader.HTTPLoader(
|
||||
cfg.HTTP.URL,
|
||||
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||
)))
|
||||
}
|
||||
return auth_impl.NewAuthenticator(opts...)
|
||||
}
|
||||
|
||||
func ParseAutherFromAuth(au *config.AuthConfig) auth.Authenticator {
|
||||
if au == nil || au.Username == "" {
|
||||
return nil
|
||||
}
|
||||
return auth_impl.NewAuthenticator(
|
||||
auth_impl.AuthsOption(
|
||||
map[string]string{
|
||||
au.Username: au.Password,
|
||||
},
|
||||
),
|
||||
auth_impl.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "auther",
|
||||
})),
|
||||
)
|
||||
}
|
||||
|
||||
func parseAuth(cfg *config.AuthConfig) *url.Userinfo {
|
||||
if cfg == nil || cfg.Username == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if cfg.Password == "" {
|
||||
return url.User(cfg.Username)
|
||||
}
|
||||
return url.UserPassword(cfg.Username, cfg.Password)
|
||||
}
|
||||
|
||||
func parseChainSelector(cfg *config.SelectorConfig) selector.Selector[chain.Chainer] {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var strategy selector.Strategy[chain.Chainer]
|
||||
switch cfg.Strategy {
|
||||
case "round", "rr":
|
||||
strategy = xs.RoundRobinStrategy[chain.Chainer]()
|
||||
case "random", "rand":
|
||||
strategy = xs.RandomStrategy[chain.Chainer]()
|
||||
case "fifo", "ha":
|
||||
strategy = xs.FIFOStrategy[chain.Chainer]()
|
||||
case "hash":
|
||||
strategy = xs.HashStrategy[chain.Chainer]()
|
||||
default:
|
||||
strategy = xs.RoundRobinStrategy[chain.Chainer]()
|
||||
}
|
||||
return xs.NewSelector(
|
||||
strategy,
|
||||
xs.FailFilter[chain.Chainer](cfg.MaxFails, cfg.FailTimeout),
|
||||
xs.BackupFilter[chain.Chainer](),
|
||||
)
|
||||
}
|
||||
|
||||
func parseNodeSelector(cfg *config.SelectorConfig) selector.Selector[*chain.Node] {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var strategy selector.Strategy[*chain.Node]
|
||||
switch cfg.Strategy {
|
||||
case "round", "rr":
|
||||
strategy = xs.RoundRobinStrategy[*chain.Node]()
|
||||
case "random", "rand":
|
||||
strategy = xs.RandomStrategy[*chain.Node]()
|
||||
case "fifo", "ha":
|
||||
strategy = xs.FIFOStrategy[*chain.Node]()
|
||||
case "hash":
|
||||
strategy = xs.HashStrategy[*chain.Node]()
|
||||
default:
|
||||
strategy = xs.RoundRobinStrategy[*chain.Node]()
|
||||
}
|
||||
|
||||
return xs.NewSelector(
|
||||
strategy,
|
||||
xs.FailFilter[*chain.Node](cfg.MaxFails, cfg.FailTimeout),
|
||||
xs.BackupFilter[*chain.Node](),
|
||||
)
|
||||
}
|
||||
|
||||
func ParseAdmission(cfg *config.AdmissionConfig) admission.Admission {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if cfg.Plugin != nil {
|
||||
var tlsCfg *tls.Config
|
||||
if cfg.Plugin.TLS != nil {
|
||||
tlsCfg = &tls.Config{
|
||||
ServerName: cfg.Plugin.TLS.ServerName,
|
||||
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
|
||||
}
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return admission_impl.NewHTTPPluginAdmission(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return admission_impl.NewGRPCPluginAdmission(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
opts := []admission_impl.Option{
|
||||
admission_impl.MatchersOption(cfg.Matchers),
|
||||
admission_impl.WhitelistOption(cfg.Reverse || cfg.Whitelist),
|
||||
admission_impl.ReloadPeriodOption(cfg.Reload),
|
||||
admission_impl.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "admission",
|
||||
"admission": cfg.Name,
|
||||
})),
|
||||
}
|
||||
if cfg.File != nil && cfg.File.Path != "" {
|
||||
opts = append(opts, admission_impl.FileLoaderOption(loader.FileLoader(cfg.File.Path)))
|
||||
}
|
||||
if cfg.Redis != nil && cfg.Redis.Addr != "" {
|
||||
opts = append(opts, admission_impl.RedisLoaderOption(loader.RedisSetLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
}
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
opts = append(opts, admission_impl.HTTPLoaderOption(loader.HTTPLoader(
|
||||
cfg.HTTP.URL,
|
||||
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||
)))
|
||||
}
|
||||
|
||||
return admission_impl.NewAdmission(opts...)
|
||||
}
|
||||
|
||||
func ParseBypass(cfg *config.BypassConfig) bypass.Bypass {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if cfg.Plugin != nil {
|
||||
var tlsCfg *tls.Config
|
||||
if cfg.Plugin.TLS != nil {
|
||||
tlsCfg = &tls.Config{
|
||||
ServerName: cfg.Plugin.TLS.ServerName,
|
||||
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
|
||||
}
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return bypass_impl.NewHTTPPluginBypass(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return bypass_impl.NewGRPCPluginBypass(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
opts := []bypass_impl.Option{
|
||||
bypass_impl.MatchersOption(cfg.Matchers),
|
||||
bypass_impl.WhitelistOption(cfg.Reverse || cfg.Whitelist),
|
||||
bypass_impl.ReloadPeriodOption(cfg.Reload),
|
||||
bypass_impl.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "bypass",
|
||||
"bypass": cfg.Name,
|
||||
})),
|
||||
}
|
||||
if cfg.File != nil && cfg.File.Path != "" {
|
||||
opts = append(opts, bypass_impl.FileLoaderOption(loader.FileLoader(cfg.File.Path)))
|
||||
}
|
||||
if cfg.Redis != nil && cfg.Redis.Addr != "" {
|
||||
opts = append(opts, bypass_impl.RedisLoaderOption(loader.RedisSetLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
}
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
opts = append(opts, bypass_impl.HTTPLoaderOption(loader.HTTPLoader(
|
||||
cfg.HTTP.URL,
|
||||
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||
)))
|
||||
}
|
||||
|
||||
return bypass_impl.NewBypass(opts...)
|
||||
}
|
||||
|
||||
func ParseResolver(cfg *config.ResolverConfig) (resolver.Resolver, error) {
|
||||
if cfg == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if cfg.Plugin != nil {
|
||||
var tlsCfg *tls.Config
|
||||
if cfg.Plugin.TLS != nil {
|
||||
tlsCfg = &tls.Config{
|
||||
ServerName: cfg.Plugin.TLS.ServerName,
|
||||
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
|
||||
}
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return resolver_impl.NewHTTPPluginResolver(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
), nil
|
||||
default:
|
||||
return resolver_impl.NewGRPCPluginResolver(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var nameservers []resolver_impl.NameServer
|
||||
for _, server := range cfg.Nameservers {
|
||||
nameservers = append(nameservers, resolver_impl.NameServer{
|
||||
Addr: server.Addr,
|
||||
Chain: registry.ChainRegistry().Get(server.Chain),
|
||||
TTL: server.TTL,
|
||||
Timeout: server.Timeout,
|
||||
ClientIP: net.ParseIP(server.ClientIP),
|
||||
Prefer: server.Prefer,
|
||||
Hostname: server.Hostname,
|
||||
})
|
||||
}
|
||||
|
||||
return resolver_impl.NewResolver(
|
||||
nameservers,
|
||||
resolver_impl.LoggerOption(
|
||||
logger.Default().WithFields(map[string]any{
|
||||
"kind": "resolver",
|
||||
"resolver": cfg.Name,
|
||||
}),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func ParseHosts(cfg *config.HostsConfig) hosts.HostMapper {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if cfg.Plugin != nil {
|
||||
var tlsCfg *tls.Config
|
||||
if cfg.Plugin.TLS != nil {
|
||||
tlsCfg = &tls.Config{
|
||||
ServerName: cfg.Plugin.TLS.ServerName,
|
||||
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
|
||||
}
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xhosts.NewHTTPPluginHostMapper(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return xhosts.NewGRPCPluginHostMapper(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var mappings []xhosts.Mapping
|
||||
for _, mapping := range cfg.Mappings {
|
||||
if mapping.IP == "" || mapping.Hostname == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
ip := net.ParseIP(mapping.IP)
|
||||
if ip == nil {
|
||||
continue
|
||||
}
|
||||
mappings = append(mappings, xhosts.Mapping{
|
||||
Hostname: mapping.Hostname,
|
||||
IP: ip,
|
||||
})
|
||||
}
|
||||
opts := []xhosts.Option{
|
||||
xhosts.MappingsOption(mappings),
|
||||
xhosts.ReloadPeriodOption(cfg.Reload),
|
||||
xhosts.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "hosts",
|
||||
"hosts": cfg.Name,
|
||||
})),
|
||||
}
|
||||
if cfg.File != nil && cfg.File.Path != "" {
|
||||
opts = append(opts, xhosts.FileLoaderOption(loader.FileLoader(cfg.File.Path)))
|
||||
}
|
||||
if cfg.Redis != nil && cfg.Redis.Addr != "" {
|
||||
switch cfg.Redis.Type {
|
||||
case "list": // redis list
|
||||
opts = append(opts, xhosts.RedisLoaderOption(loader.RedisListLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
default: // redis set
|
||||
opts = append(opts, xhosts.RedisLoaderOption(loader.RedisSetLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
}
|
||||
}
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
opts = append(opts, xhosts.HTTPLoaderOption(loader.HTTPLoader(
|
||||
cfg.HTTP.URL,
|
||||
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||
)))
|
||||
}
|
||||
return xhosts.NewHostMapper(opts...)
|
||||
}
|
||||
|
||||
func ParseIngress(cfg *config.IngressConfig) ingress.Ingress {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if cfg.Plugin != nil {
|
||||
var tlsCfg *tls.Config
|
||||
if cfg.Plugin.TLS != nil {
|
||||
tlsCfg = &tls.Config{
|
||||
ServerName: cfg.Plugin.TLS.ServerName,
|
||||
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
|
||||
}
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xingress.NewHTTPPluginIngress(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return xingress.NewGRPCPluginIngress(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var rules []xingress.Rule
|
||||
for _, rule := range cfg.Rules {
|
||||
if rule.Hostname == "" || rule.Endpoint == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
rules = append(rules, xingress.Rule{
|
||||
Hostname: rule.Hostname,
|
||||
Endpoint: rule.Endpoint,
|
||||
})
|
||||
}
|
||||
opts := []xingress.Option{
|
||||
xingress.RulesOption(rules),
|
||||
xingress.ReloadPeriodOption(cfg.Reload),
|
||||
xingress.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "ingress",
|
||||
"ingress": cfg.Name,
|
||||
})),
|
||||
}
|
||||
if cfg.File != nil && cfg.File.Path != "" {
|
||||
opts = append(opts, xingress.FileLoaderOption(loader.FileLoader(cfg.File.Path)))
|
||||
}
|
||||
if cfg.Redis != nil && cfg.Redis.Addr != "" {
|
||||
switch cfg.Redis.Type {
|
||||
case "set": // redis set
|
||||
opts = append(opts, xingress.RedisLoaderOption(loader.RedisSetLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
default: // redis hash
|
||||
opts = append(opts, xingress.RedisLoaderOption(loader.RedisHashLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
}
|
||||
}
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
opts = append(opts, xingress.HTTPLoaderOption(loader.HTTPLoader(
|
||||
cfg.HTTP.URL,
|
||||
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||
)))
|
||||
}
|
||||
return xingress.NewIngress(opts...)
|
||||
}
|
||||
|
||||
func ParseRecorder(cfg *config.RecorderConfig) (r recorder.Recorder) {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if cfg.Plugin != nil {
|
||||
var tlsCfg *tls.Config
|
||||
if cfg.Plugin.TLS != nil {
|
||||
tlsCfg = &tls.Config{
|
||||
ServerName: cfg.Plugin.TLS.ServerName,
|
||||
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
|
||||
}
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xrecorder.NewHTTPPluginRecorder(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return xrecorder.NewGRPCPluginRecorder(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.File != nil && cfg.File.Path != "" {
|
||||
return xrecorder.FileRecorder(cfg.File.Path,
|
||||
xrecorder.SepRecorderOption(cfg.File.Sep),
|
||||
)
|
||||
}
|
||||
|
||||
if cfg.TCP != nil && cfg.TCP.Addr != "" {
|
||||
return xrecorder.TCPRecorder(cfg.TCP.Addr, xrecorder.TimeoutTCPRecorderOption(cfg.TCP.Timeout))
|
||||
}
|
||||
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
return xrecorder.HTTPRecorder(cfg.HTTP.URL, xrecorder.TimeoutHTTPRecorderOption(cfg.HTTP.Timeout))
|
||||
}
|
||||
|
||||
if cfg.Redis != nil &&
|
||||
cfg.Redis.Addr != "" &&
|
||||
cfg.Redis.Key != "" {
|
||||
switch cfg.Redis.Type {
|
||||
case "list": // redis list
|
||||
return xrecorder.RedisListRecorder(cfg.Redis.Addr,
|
||||
xrecorder.DBRedisRecorderOption(cfg.Redis.DB),
|
||||
xrecorder.KeyRedisRecorderOption(cfg.Redis.Key),
|
||||
xrecorder.PasswordRedisRecorderOption(cfg.Redis.Password),
|
||||
)
|
||||
case "sset": // sorted set
|
||||
return xrecorder.RedisSortedSetRecorder(cfg.Redis.Addr,
|
||||
xrecorder.DBRedisRecorderOption(cfg.Redis.DB),
|
||||
xrecorder.KeyRedisRecorderOption(cfg.Redis.Key),
|
||||
xrecorder.PasswordRedisRecorderOption(cfg.Redis.Password),
|
||||
)
|
||||
default: // redis set
|
||||
return xrecorder.RedisSetRecorder(cfg.Redis.Addr,
|
||||
xrecorder.DBRedisRecorderOption(cfg.Redis.DB),
|
||||
xrecorder.KeyRedisRecorderOption(cfg.Redis.Key),
|
||||
xrecorder.PasswordRedisRecorderOption(cfg.Redis.Password),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func defaultNodeSelector() selector.Selector[*chain.Node] {
|
||||
return xs.NewSelector(
|
||||
xs.RoundRobinStrategy[*chain.Node](),
|
||||
xs.FailFilter[*chain.Node](xs.DefaultMaxFails, xs.DefaultFailTimeout),
|
||||
xs.BackupFilter[*chain.Node](),
|
||||
)
|
||||
}
|
||||
|
||||
func defaultChainSelector() selector.Selector[chain.Chainer] {
|
||||
return xs.NewSelector(
|
||||
xs.RoundRobinStrategy[chain.Chainer](),
|
||||
xs.FailFilter[chain.Chainer](xs.DefaultMaxFails, xs.DefaultFailTimeout),
|
||||
xs.BackupFilter[chain.Chainer](),
|
||||
)
|
||||
}
|
||||
|
||||
func ParseTrafficLimiter(cfg *config.LimiterConfig) (lim traffic.TrafficLimiter) {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var opts []xtraffic.Option
|
||||
|
||||
if cfg.File != nil && cfg.File.Path != "" {
|
||||
opts = append(opts, xtraffic.FileLoaderOption(loader.FileLoader(cfg.File.Path)))
|
||||
}
|
||||
if cfg.Redis != nil && cfg.Redis.Addr != "" {
|
||||
switch cfg.Redis.Type {
|
||||
case "list": // redis list
|
||||
opts = append(opts, xtraffic.RedisLoaderOption(loader.RedisListLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
default: // redis set
|
||||
opts = append(opts, xtraffic.RedisLoaderOption(loader.RedisSetLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
}
|
||||
}
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
opts = append(opts, xtraffic.HTTPLoaderOption(loader.HTTPLoader(
|
||||
cfg.HTTP.URL,
|
||||
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||
)))
|
||||
}
|
||||
opts = append(opts,
|
||||
xtraffic.LimitsOption(cfg.Limits...),
|
||||
xtraffic.ReloadPeriodOption(cfg.Reload),
|
||||
xtraffic.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "limiter",
|
||||
"limiter": cfg.Name,
|
||||
})),
|
||||
)
|
||||
|
||||
return xtraffic.NewTrafficLimiter(opts...)
|
||||
}
|
||||
|
||||
func ParseConnLimiter(cfg *config.LimiterConfig) (lim conn.ConnLimiter) {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var opts []xconn.Option
|
||||
|
||||
if cfg.File != nil && cfg.File.Path != "" {
|
||||
opts = append(opts, xconn.FileLoaderOption(loader.FileLoader(cfg.File.Path)))
|
||||
}
|
||||
if cfg.Redis != nil && cfg.Redis.Addr != "" {
|
||||
switch cfg.Redis.Type {
|
||||
case "list": // redis list
|
||||
opts = append(opts, xconn.RedisLoaderOption(loader.RedisListLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
default: // redis set
|
||||
opts = append(opts, xconn.RedisLoaderOption(loader.RedisSetLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
}
|
||||
}
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
opts = append(opts, xconn.HTTPLoaderOption(loader.HTTPLoader(
|
||||
cfg.HTTP.URL,
|
||||
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||
)))
|
||||
}
|
||||
opts = append(opts,
|
||||
xconn.LimitsOption(cfg.Limits...),
|
||||
xconn.ReloadPeriodOption(cfg.Reload),
|
||||
xconn.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "limiter",
|
||||
"limiter": cfg.Name,
|
||||
})),
|
||||
)
|
||||
|
||||
return xconn.NewConnLimiter(opts...)
|
||||
}
|
||||
|
||||
func ParseRateLimiter(cfg *config.LimiterConfig) (lim rate.RateLimiter) {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var opts []xrate.Option
|
||||
|
||||
if cfg.File != nil && cfg.File.Path != "" {
|
||||
opts = append(opts, xrate.FileLoaderOption(loader.FileLoader(cfg.File.Path)))
|
||||
}
|
||||
if cfg.Redis != nil && cfg.Redis.Addr != "" {
|
||||
switch cfg.Redis.Type {
|
||||
case "list": // redis list
|
||||
opts = append(opts, xrate.RedisLoaderOption(loader.RedisListLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
default: // redis set
|
||||
opts = append(opts, xrate.RedisLoaderOption(loader.RedisSetLoader(
|
||||
cfg.Redis.Addr,
|
||||
loader.DBRedisLoaderOption(cfg.Redis.DB),
|
||||
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
|
||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||
)))
|
||||
}
|
||||
}
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
opts = append(opts, xrate.HTTPLoaderOption(loader.HTTPLoader(
|
||||
cfg.HTTP.URL,
|
||||
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||
)))
|
||||
}
|
||||
opts = append(opts,
|
||||
xrate.LimitsOption(cfg.Limits...),
|
||||
xrate.ReloadPeriodOption(cfg.Reload),
|
||||
xrate.LoggerOption(logger.Default().WithFields(map[string]any{
|
||||
"kind": "limiter",
|
||||
"limiter": cfg.Name,
|
||||
})),
|
||||
)
|
||||
|
||||
return xrate.NewRateLimiter(opts...)
|
||||
}
|
||||
|
||||
func newGRPCPluginConn(cfg *config.PluginConfig) (*grpc.ClientConn, error) {
|
||||
grpcOpts := []grpc.DialOption{
|
||||
// grpc.WithBlock(),
|
||||
grpc.WithConnectParams(grpc.ConnectParams{
|
||||
Backoff: backoff.DefaultConfig,
|
||||
}),
|
||||
grpc.FailOnNonTempDialError(true),
|
||||
}
|
||||
if tlsCfg := cfg.TLS; tlsCfg != nil && tlsCfg.Secure {
|
||||
grpcOpts = append(grpcOpts,
|
||||
grpc.WithAuthority(tlsCfg.ServerName),
|
||||
grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
|
||||
ServerName: tlsCfg.ServerName,
|
||||
InsecureSkipVerify: !tlsCfg.Secure,
|
||||
})))
|
||||
} else {
|
||||
grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
}
|
||||
if cfg.Token != "" {
|
||||
grpcOpts = append(grpcOpts, grpc.WithPerRPCCredentials(&rpcCredentials{token: cfg.Token}))
|
||||
}
|
||||
return grpc.Dial(cfg.Addr, grpcOpts...)
|
||||
}
|
||||
|
||||
type rpcCredentials struct {
|
||||
token string
|
||||
}
|
||||
|
||||
func (c *rpcCredentials) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
|
||||
return map[string]string{
|
||||
"token": c.token,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *rpcCredentials) RequireTransportSecurity() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func newHTTPPluginClient(cfg *config.PluginConfig) *http.Client {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
tr := &http.Transport{}
|
||||
if cfg.TLS != nil {
|
||||
if cfg.TLS.Secure {
|
||||
tr.TLSClientConfig = &tls.Config{
|
||||
ServerName: cfg.TLS.ServerName,
|
||||
}
|
||||
} else {
|
||||
tr.TLSClientConfig = &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
return &http.Client{
|
||||
Timeout: cfg.Timeout,
|
||||
Transport: tr,
|
||||
}
|
||||
}
|
||||
|
82
config/parsing/recorder/parse.go
Normal file
82
config/parsing/recorder/parse.go
Normal file
@ -0,0 +1,82 @@
|
||||
package recorder
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"strings"
|
||||
|
||||
"github.com/go-gost/core/recorder"
|
||||
"github.com/go-gost/x/config"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
xrecorder "github.com/go-gost/x/recorder"
|
||||
)
|
||||
|
||||
func ParseRecorder(cfg *config.RecorderConfig) (r recorder.Recorder) {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if cfg.Plugin != nil {
|
||||
var tlsCfg *tls.Config
|
||||
if cfg.Plugin.TLS != nil {
|
||||
tlsCfg = &tls.Config{
|
||||
ServerName: cfg.Plugin.TLS.ServerName,
|
||||
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
|
||||
}
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xrecorder.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return xrecorder.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.File != nil && cfg.File.Path != "" {
|
||||
return xrecorder.FileRecorder(cfg.File.Path,
|
||||
xrecorder.SepRecorderOption(cfg.File.Sep),
|
||||
)
|
||||
}
|
||||
|
||||
if cfg.TCP != nil && cfg.TCP.Addr != "" {
|
||||
return xrecorder.TCPRecorder(cfg.TCP.Addr, xrecorder.TimeoutTCPRecorderOption(cfg.TCP.Timeout))
|
||||
}
|
||||
|
||||
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||
return xrecorder.HTTPRecorder(cfg.HTTP.URL, xrecorder.TimeoutHTTPRecorderOption(cfg.HTTP.Timeout))
|
||||
}
|
||||
|
||||
if cfg.Redis != nil &&
|
||||
cfg.Redis.Addr != "" &&
|
||||
cfg.Redis.Key != "" {
|
||||
switch cfg.Redis.Type {
|
||||
case "list": // redis list
|
||||
return xrecorder.RedisListRecorder(cfg.Redis.Addr,
|
||||
xrecorder.DBRedisRecorderOption(cfg.Redis.DB),
|
||||
xrecorder.KeyRedisRecorderOption(cfg.Redis.Key),
|
||||
xrecorder.PasswordRedisRecorderOption(cfg.Redis.Password),
|
||||
)
|
||||
case "sset": // sorted set
|
||||
return xrecorder.RedisSortedSetRecorder(cfg.Redis.Addr,
|
||||
xrecorder.DBRedisRecorderOption(cfg.Redis.DB),
|
||||
xrecorder.KeyRedisRecorderOption(cfg.Redis.Key),
|
||||
xrecorder.PasswordRedisRecorderOption(cfg.Redis.Password),
|
||||
)
|
||||
default: // redis set
|
||||
return xrecorder.RedisSetRecorder(cfg.Redis.Addr,
|
||||
xrecorder.DBRedisRecorderOption(cfg.Redis.DB),
|
||||
xrecorder.KeyRedisRecorderOption(cfg.Redis.Key),
|
||||
xrecorder.PasswordRedisRecorderOption(cfg.Redis.Password),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
67
config/parsing/resolver/parse.go
Normal file
67
config/parsing/resolver/parse.go
Normal file
@ -0,0 +1,67 @@
|
||||
package resolver
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/core/resolver"
|
||||
"github.com/go-gost/x/config"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"github.com/go-gost/x/registry"
|
||||
xresolver "github.com/go-gost/x/resolver"
|
||||
)
|
||||
|
||||
func ParseResolver(cfg *config.ResolverConfig) (resolver.Resolver, error) {
|
||||
if cfg == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if cfg.Plugin != nil {
|
||||
var tlsCfg *tls.Config
|
||||
if cfg.Plugin.TLS != nil {
|
||||
tlsCfg = &tls.Config{
|
||||
ServerName: cfg.Plugin.TLS.ServerName,
|
||||
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
|
||||
}
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xresolver.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
), nil
|
||||
default:
|
||||
return xresolver.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var nameservers []xresolver.NameServer
|
||||
for _, server := range cfg.Nameservers {
|
||||
nameservers = append(nameservers, xresolver.NameServer{
|
||||
Addr: server.Addr,
|
||||
Chain: registry.ChainRegistry().Get(server.Chain),
|
||||
TTL: server.TTL,
|
||||
Timeout: server.Timeout,
|
||||
ClientIP: net.ParseIP(server.ClientIP),
|
||||
Prefer: server.Prefer,
|
||||
Hostname: server.Hostname,
|
||||
})
|
||||
}
|
||||
|
||||
return xresolver.NewResolver(
|
||||
nameservers,
|
||||
xresolver.LoggerOption(
|
||||
logger.Default().WithFields(map[string]any{
|
||||
"kind": "resolver",
|
||||
"resolver": cfg.Name,
|
||||
}),
|
||||
),
|
||||
)
|
||||
}
|
75
config/parsing/selector/parse.go
Normal file
75
config/parsing/selector/parse.go
Normal file
@ -0,0 +1,75 @@
|
||||
package selector
|
||||
|
||||
import (
|
||||
"github.com/go-gost/core/chain"
|
||||
"github.com/go-gost/core/selector"
|
||||
"github.com/go-gost/x/config"
|
||||
xs "github.com/go-gost/x/selector"
|
||||
)
|
||||
|
||||
func ParseChainSelector(cfg *config.SelectorConfig) selector.Selector[chain.Chainer] {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var strategy selector.Strategy[chain.Chainer]
|
||||
switch cfg.Strategy {
|
||||
case "round", "rr":
|
||||
strategy = xs.RoundRobinStrategy[chain.Chainer]()
|
||||
case "random", "rand":
|
||||
strategy = xs.RandomStrategy[chain.Chainer]()
|
||||
case "fifo", "ha":
|
||||
strategy = xs.FIFOStrategy[chain.Chainer]()
|
||||
case "hash":
|
||||
strategy = xs.HashStrategy[chain.Chainer]()
|
||||
default:
|
||||
strategy = xs.RoundRobinStrategy[chain.Chainer]()
|
||||
}
|
||||
return xs.NewSelector(
|
||||
strategy,
|
||||
xs.FailFilter[chain.Chainer](cfg.MaxFails, cfg.FailTimeout),
|
||||
xs.BackupFilter[chain.Chainer](),
|
||||
)
|
||||
}
|
||||
|
||||
func ParseNodeSelector(cfg *config.SelectorConfig) selector.Selector[*chain.Node] {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var strategy selector.Strategy[*chain.Node]
|
||||
switch cfg.Strategy {
|
||||
case "round", "rr":
|
||||
strategy = xs.RoundRobinStrategy[*chain.Node]()
|
||||
case "random", "rand":
|
||||
strategy = xs.RandomStrategy[*chain.Node]()
|
||||
case "fifo", "ha":
|
||||
strategy = xs.FIFOStrategy[*chain.Node]()
|
||||
case "hash":
|
||||
strategy = xs.HashStrategy[*chain.Node]()
|
||||
default:
|
||||
strategy = xs.RoundRobinStrategy[*chain.Node]()
|
||||
}
|
||||
|
||||
return xs.NewSelector(
|
||||
strategy,
|
||||
xs.FailFilter[*chain.Node](cfg.MaxFails, cfg.FailTimeout),
|
||||
xs.BackupFilter[*chain.Node](),
|
||||
)
|
||||
}
|
||||
|
||||
func DefaultNodeSelector() selector.Selector[*chain.Node] {
|
||||
return xs.NewSelector(
|
||||
xs.RoundRobinStrategy[*chain.Node](),
|
||||
xs.FailFilter[*chain.Node](xs.DefaultMaxFails, xs.DefaultFailTimeout),
|
||||
xs.BackupFilter[*chain.Node](),
|
||||
)
|
||||
}
|
||||
|
||||
func DefaultChainSelector() selector.Selector[chain.Chainer] {
|
||||
return xs.NewSelector(
|
||||
xs.RoundRobinStrategy[chain.Chainer](),
|
||||
xs.FailFilter[chain.Chainer](xs.DefaultMaxFails, xs.DefaultFailTimeout),
|
||||
xs.BackupFilter[chain.Chainer](),
|
||||
)
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
package parsing
|
||||
package service
|
||||
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -8,6 +9,7 @@ import (
|
||||
"github.com/go-gost/core/auth"
|
||||
"github.com/go-gost/core/bypass"
|
||||
"github.com/go-gost/core/chain"
|
||||
"github.com/go-gost/core/hop"
|
||||
"github.com/go-gost/core/handler"
|
||||
"github.com/go-gost/core/listener"
|
||||
"github.com/go-gost/core/logger"
|
||||
@ -17,6 +19,12 @@ import (
|
||||
"github.com/go-gost/core/service"
|
||||
xchain "github.com/go-gost/x/chain"
|
||||
"github.com/go-gost/x/config"
|
||||
"github.com/go-gost/x/config/parsing"
|
||||
auth_parser "github.com/go-gost/x/config/parsing/auth"
|
||||
hop_parser "github.com/go-gost/x/config/parsing/hop"
|
||||
bypass_parser "github.com/go-gost/x/config/parsing/bypass"
|
||||
selector_parser "github.com/go-gost/x/config/parsing/selector"
|
||||
admission_parser "github.com/go-gost/x/config/parsing/admission"
|
||||
tls_util "github.com/go-gost/x/internal/util/tls"
|
||||
"github.com/go-gost/x/metadata"
|
||||
"github.com/go-gost/x/registry"
|
||||
@ -56,12 +64,12 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
return nil, err
|
||||
}
|
||||
if tlsConfig == nil {
|
||||
tlsConfig = defaultTLSConfig.Clone()
|
||||
tlsConfig = parsing.DefaultTLSConfig().Clone()
|
||||
}
|
||||
|
||||
authers := autherList(cfg.Listener.Auther, cfg.Listener.Authers...)
|
||||
authers := auth_parser.List(cfg.Listener.Auther, cfg.Listener.Authers...)
|
||||
if len(authers) == 0 {
|
||||
if auther := ParseAutherFromAuth(cfg.Listener.Auth); auther != nil {
|
||||
if auther := auth_parser.ParseAutherFromAuth(cfg.Listener.Auth); auther != nil {
|
||||
authers = append(authers, auther)
|
||||
}
|
||||
}
|
||||
@ -70,7 +78,7 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
auther = auth.AuthenticatorGroup(authers...)
|
||||
}
|
||||
|
||||
admissions := admissionList(cfg.Admission, cfg.Admissions...)
|
||||
admissions := admission_parser.List(cfg.Admission, cfg.Admissions...)
|
||||
|
||||
var sockOpts *chain.SockOpts
|
||||
if cfg.SockOpts != nil {
|
||||
@ -85,26 +93,26 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
var ignoreChain bool
|
||||
if cfg.Metadata != nil {
|
||||
md := metadata.NewMetadata(cfg.Metadata)
|
||||
ppv = mdutil.GetInt(md, mdKeyProxyProtocol)
|
||||
if v := mdutil.GetString(md, mdKeyInterface); v != "" {
|
||||
ppv = mdutil.GetInt(md, parsing.MDKeyProxyProtocol)
|
||||
if v := mdutil.GetString(md, parsing.MDKeyInterface); v != "" {
|
||||
ifce = v
|
||||
}
|
||||
if v := mdutil.GetInt(md, mdKeySoMark); v > 0 {
|
||||
if v := mdutil.GetInt(md, parsing.MDKeySoMark); v > 0 {
|
||||
sockOpts = &chain.SockOpts{
|
||||
Mark: v,
|
||||
}
|
||||
}
|
||||
preUp = mdutil.GetStrings(md, mdKeyPreUp)
|
||||
preDown = mdutil.GetStrings(md, mdKeyPreDown)
|
||||
postUp = mdutil.GetStrings(md, mdKeyPostUp)
|
||||
postDown = mdutil.GetStrings(md, mdKeyPostDown)
|
||||
ignoreChain = mdutil.GetBool(md, mdKeyIgnoreChain)
|
||||
preUp = mdutil.GetStrings(md, parsing.MDKeyPreUp)
|
||||
preDown = mdutil.GetStrings(md, parsing.MDKeyPreDown)
|
||||
postUp = mdutil.GetStrings(md, parsing.MDKeyPostUp)
|
||||
postDown = mdutil.GetStrings(md, parsing.MDKeyPostDown)
|
||||
ignoreChain = mdutil.GetBool(md, parsing.MDKeyIgnoreChain)
|
||||
}
|
||||
|
||||
listenOpts := []listener.Option{
|
||||
listener.AddrOption(cfg.Addr),
|
||||
listener.AutherOption(auther),
|
||||
listener.AuthOption(parseAuth(cfg.Listener.Auth)),
|
||||
listener.AuthOption(auth_parser.Info(cfg.Listener.Auth)),
|
||||
listener.TLSConfigOption(tlsConfig),
|
||||
listener.AdmissionOption(admission.AdmissionGroup(admissions...)),
|
||||
listener.TrafficLimiterOption(registry.TrafficLimiterRegistry().Get(cfg.Limiter)),
|
||||
@ -150,12 +158,12 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
return nil, err
|
||||
}
|
||||
if tlsConfig == nil {
|
||||
tlsConfig = defaultTLSConfig.Clone()
|
||||
tlsConfig = parsing.DefaultTLSConfig().Clone()
|
||||
}
|
||||
|
||||
authers = autherList(cfg.Handler.Auther, cfg.Handler.Authers...)
|
||||
authers = auth_parser.List(cfg.Handler.Auther, cfg.Handler.Authers...)
|
||||
if len(authers) == 0 {
|
||||
if auther := ParseAutherFromAuth(cfg.Handler.Auth); auther != nil {
|
||||
if auther := auth_parser.ParseAutherFromAuth(cfg.Handler.Auth); auther != nil {
|
||||
authers = append(authers, auther)
|
||||
}
|
||||
}
|
||||
@ -172,9 +180,9 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
Recorder: registry.RecorderRegistry().Get(r.Name),
|
||||
Record: r.Record,
|
||||
Options: &recorder.Options{
|
||||
Direction: mdutil.GetBool(md, mdKeyRecorderDirection),
|
||||
TimestampFormat: mdutil.GetString(md, mdKeyRecorderTimestampFormat),
|
||||
Hexdump: mdutil.GetBool(md, mdKeyRecorderHexdump),
|
||||
Direction: mdutil.GetBool(md, parsing.MDKeyRecorderDirection),
|
||||
TimestampFormat: mdutil.GetString(md, parsing.MDKeyRecorderTimestampFormat),
|
||||
Hexdump: mdutil.GetBool(md, parsing.MDKeyRecorderHexdump),
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -201,8 +209,8 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
h = rf(
|
||||
handler.RouterOption(router),
|
||||
handler.AutherOption(auther),
|
||||
handler.AuthOption(parseAuth(cfg.Handler.Auth)),
|
||||
handler.BypassOption(bypass.BypassGroup(bypassList(cfg.Bypass, cfg.Bypasses...)...)),
|
||||
handler.AuthOption(auth_parser.Info(cfg.Handler.Auth)),
|
||||
handler.BypassOption(bypass.BypassGroup(bypass_parser.List(cfg.Bypass, cfg.Bypasses...)...)),
|
||||
handler.TLSConfigOption(tlsConfig),
|
||||
handler.RateLimiterOption(registry.RateLimiterRegistry().Get(cfg.RLimiter)),
|
||||
handler.LoggerOption(handlerLogger),
|
||||
@ -243,7 +251,7 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func parseForwarder(cfg *config.ForwarderConfig) (chain.Hop, error) {
|
||||
func parseForwarder(cfg *config.ForwarderConfig) (hop.Hop, error) {
|
||||
if cfg == nil {
|
||||
return nil, nil
|
||||
}
|
||||
@ -284,51 +292,11 @@ func parseForwarder(cfg *config.ForwarderConfig) (chain.Hop, error) {
|
||||
}
|
||||
|
||||
if len(hc.Nodes) > 0 {
|
||||
return ParseHop(&hc)
|
||||
return hop_parser.ParseHop(&hc)
|
||||
}
|
||||
return registry.HopRegistry().Get(hc.Name), nil
|
||||
}
|
||||
|
||||
func bypassList(name string, names ...string) []bypass.Bypass {
|
||||
var bypasses []bypass.Bypass
|
||||
if bp := registry.BypassRegistry().Get(name); bp != nil {
|
||||
bypasses = append(bypasses, bp)
|
||||
}
|
||||
for _, s := range names {
|
||||
if bp := registry.BypassRegistry().Get(s); bp != nil {
|
||||
bypasses = append(bypasses, bp)
|
||||
}
|
||||
}
|
||||
return bypasses
|
||||
}
|
||||
|
||||
func autherList(name string, names ...string) []auth.Authenticator {
|
||||
var authers []auth.Authenticator
|
||||
if auther := registry.AutherRegistry().Get(name); auther != nil {
|
||||
authers = append(authers, auther)
|
||||
}
|
||||
for _, s := range names {
|
||||
if auther := registry.AutherRegistry().Get(s); auther != nil {
|
||||
authers = append(authers, auther)
|
||||
}
|
||||
}
|
||||
return authers
|
||||
}
|
||||
|
||||
func admissionList(name string, names ...string) []admission.Admission {
|
||||
var admissions []admission.Admission
|
||||
if adm := registry.AdmissionRegistry().Get(name); adm != nil {
|
||||
admissions = append(admissions, adm)
|
||||
}
|
||||
for _, s := range names {
|
||||
if adm := registry.AdmissionRegistry().Get(s); adm != nil {
|
||||
admissions = append(admissions, adm)
|
||||
}
|
||||
}
|
||||
|
||||
return admissions
|
||||
}
|
||||
|
||||
func chainGroup(name string, group *config.ChainGroupConfig) chain.Chainer {
|
||||
var chains []chain.Chainer
|
||||
var sel selector.Selector[chain.Chainer]
|
||||
@ -342,14 +310,14 @@ func chainGroup(name string, group *config.ChainGroupConfig) chain.Chainer {
|
||||
chains = append(chains, c)
|
||||
}
|
||||
}
|
||||
sel = parseChainSelector(group.Selector)
|
||||
sel = selector_parser.ParseChainSelector(group.Selector)
|
||||
}
|
||||
if len(chains) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if sel == nil {
|
||||
sel = defaultChainSelector()
|
||||
sel = selector_parser.DefaultChainSelector()
|
||||
}
|
||||
|
||||
return xchain.NewChainGroup(chains...).
|
@ -23,6 +23,10 @@ var (
|
||||
defaultTLSConfig *tls.Config
|
||||
)
|
||||
|
||||
func DefaultTLSConfig() *tls.Config {
|
||||
return defaultTLSConfig
|
||||
}
|
||||
|
||||
func BuildDefaultTLSConfig(cfg *config.TLSConfig) {
|
||||
log := logger.Default()
|
||||
|
||||
|
Reference in New Issue
Block a user