From 40f709880d119f76e6b71f1c2e2e9983cbfc03ae Mon Sep 17 00:00:00 2001 From: ginuerzh Date: Wed, 8 May 2024 21:25:14 +0800 Subject: [PATCH] add node filter config --- config/config.go | 76 +++++++++++++++++++-------------- config/parsing/hop/parse.go | 2 +- config/parsing/node/parse.go | 48 +++++++++++---------- config/parsing/service/parse.go | 41 ++++++++++++++---- go.mod | 2 +- go.sum | 4 ++ internal/plugin/plugin.go | 5 +++ 7 files changed, 111 insertions(+), 67 deletions(-) diff --git a/config/config.go b/config/config.go index 389bc95..312aca0 100644 --- a/config/config.go +++ b/config/config.go @@ -343,25 +343,32 @@ type HandlerConfig struct { } type ForwarderConfig struct { - Name string `yaml:",omitempty" json:"name,omitempty"` + // DEPRECATED by hop field + Name string `yaml:",omitempty" json:"name,omitempty"` + // the referenced hop name + Hop string `yaml:",omitempty" json:"hop,omitempty"` Selector *SelectorConfig `yaml:",omitempty" json:"selector,omitempty"` Nodes []*ForwardNodeConfig `json:"nodes"` } type ForwardNodeConfig struct { - Name string `yaml:",omitempty" json:"name,omitempty"` - Addr string `yaml:",omitempty" json:"addr,omitempty"` - Host string `yaml:",omitempty" json:"host,omitempty"` - Network string `yaml:",omitempty" json:"network,omitempty"` - Protocol string `yaml:",omitempty" json:"protocol,omitempty"` - Path string `yaml:",omitempty" json:"path,omitempty"` - Bypass string `yaml:",omitempty" json:"bypass,omitempty"` - Bypasses []string `yaml:",omitempty" json:"bypasses,omitempty"` - HTTP *HTTPNodeConfig `yaml:",omitempty" json:"http,omitempty"` - TLS *TLSNodeConfig `yaml:",omitempty" json:"tls,omitempty"` - // DEPRECATED by HTTP.Auth - Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"` - Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"` + Name string `yaml:",omitempty" json:"name,omitempty"` + Addr string `yaml:",omitempty" json:"addr,omitempty"` + Network string `yaml:",omitempty" json:"network,omitempty"` + Bypass string `yaml:",omitempty" json:"bypass,omitempty"` + Bypasses []string `yaml:",omitempty" json:"bypasses,omitempty"` + // DEPRECATED by filter.protocol + Protocol string `yaml:",omitempty" json:"protocol,omitempty"` + // DEPRECATED by filter.host + Host string `yaml:",omitempty" json:"host,omitempty"` + // DEPRECATED by filter.path + Path string `yaml:",omitempty" json:"path,omitempty"` + // DEPRECATED by http.auth + Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"` + Filter *NodeFilterConfig `yaml:",omitempty" json:"filter,omitempty"` + HTTP *HTTPNodeConfig `yaml:",omitempty" json:"http,omitempty"` + TLS *TLSNodeConfig `yaml:",omitempty" json:"tls,omitempty"` + Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"` } type HTTPURLRewriteConfig struct { @@ -369,11 +376,17 @@ type HTTPURLRewriteConfig struct { Replacement string } +type NodeFilterConfig struct { + Host string `yaml:",omitempty" json:"host,omitempty"` + Protocol string `yaml:",omitempty" json:"protocol,omitempty"` + Path string `yaml:",omitempty" json:"path,omitempty"` +} + type HTTPNodeConfig struct { Host string `yaml:",omitempty" json:"host,omitempty"` Header map[string]string `yaml:",omitempty" json:"header,omitempty"` - Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"` Rewrite []HTTPURLRewriteConfig `yaml:",omitempty" json:"rewrite,omitempty"` + Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"` } type TLSNodeConfig struct { @@ -477,24 +490,21 @@ type HopConfig struct { } type NodeConfig struct { - Name string `json:"name"` - Addr string `yaml:",omitempty" json:"addr,omitempty"` - Host string `yaml:",omitempty" json:"host,omitempty"` - Network string `yaml:",omitempty" json:"network,omitempty"` - Protocol string `yaml:",omitempty" json:"protocol,omitempty"` - Path string `yaml:",omitempty" json:"path,omitempty"` - Interface string `yaml:",omitempty" json:"interface,omitempty"` - SockOpts *SockOptsConfig `yaml:"sockopts,omitempty" json:"sockopts,omitempty"` - Bypass string `yaml:",omitempty" json:"bypass,omitempty"` - Bypasses []string `yaml:",omitempty" json:"bypasses,omitempty"` - Resolver string `yaml:",omitempty" json:"resolver,omitempty"` - Hosts string `yaml:",omitempty" json:"hosts,omitempty"` - Connector *ConnectorConfig `yaml:",omitempty" json:"connector,omitempty"` - Dialer *DialerConfig `yaml:",omitempty" json:"dialer,omitempty"` - HTTP *HTTPNodeConfig `yaml:",omitempty" json:"http,omitempty"` - TLS *TLSNodeConfig `yaml:",omitempty" json:"tls,omitempty"` - Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"` - Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"` + Name string `json:"name"` + Addr string `yaml:",omitempty" json:"addr,omitempty"` + Network string `yaml:",omitempty" json:"network,omitempty"` + Bypass string `yaml:",omitempty" json:"bypass,omitempty"` + Bypasses []string `yaml:",omitempty" json:"bypasses,omitempty"` + Resolver string `yaml:",omitempty" json:"resolver,omitempty"` + Hosts string `yaml:",omitempty" json:"hosts,omitempty"` + Connector *ConnectorConfig `yaml:",omitempty" json:"connector,omitempty"` + Dialer *DialerConfig `yaml:",omitempty" json:"dialer,omitempty"` + Interface string `yaml:",omitempty" json:"interface,omitempty"` + SockOpts *SockOptsConfig `yaml:"sockopts,omitempty" json:"sockopts,omitempty"` + Filter *NodeFilterConfig `yaml:",omitempty" json:"filter,omitempty"` + HTTP *HTTPNodeConfig `yaml:",omitempty" json:"http,omitempty"` + TLS *TLSNodeConfig `yaml:",omitempty" json:"tls,omitempty"` + Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"` } type Config struct { diff --git a/config/parsing/hop/parse.go b/config/parsing/hop/parse.go index fadd088..6bab821 100644 --- a/config/parsing/hop/parse.go +++ b/config/parsing/hop/parse.go @@ -32,7 +32,7 @@ func ParseHop(cfg *config.HopConfig, log logger.Logger) (hop.Hop, error) { } } switch strings.ToLower(cfg.Plugin.Type) { - case "http": + case plugin.HTTP: return hop_plugin.NewHTTPPlugin( cfg.Name, cfg.Plugin.Addr, plugin.TLSConfigOption(tlsCfg), diff --git a/config/parsing/node/parse.go b/config/parsing/node/parse.go index b1eb9c2..e91df94 100644 --- a/config/parsing/node/parse.go +++ b/config/parsing/node/parse.go @@ -147,46 +147,47 @@ func ParseNode(hop string, cfg *config.NodeConfig, log logger.Logger) (*chain.No 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), - chain.PathNodeOption(cfg.Path), chain.NetworkNodeOption(cfg.Network), } + + if filter := cfg.Filter; filter != nil { + // convert *.example.com to .example.com + // convert *example.com to example.com + host := filter.Host + if strings.HasPrefix(host, "*") { + host = host[1:] + if !strings.HasPrefix(host, ".") { + host = "." + host + } + } + + settings := &chain.NodeFilterSettings{ + Protocol: filter.Protocol, + Host: host, + Path: filter.Path, + } + opts = append(opts, chain.NodeFilterOption(settings)) + } + if cfg.HTTP != nil { settings := &chain.HTTPNodeSettings{ Host: cfg.HTTP.Host, Header: cfg.HTTP.Header, } - auth := cfg.HTTP.Auth - if auth == nil { - auth = cfg.Auth - } - if auth != nil { + if auth := cfg.HTTP.Auth; auth != nil && auth.Username != "" { settings.Auther = xauth.NewAuthenticator( xauth.AuthsOption(map[string]string{auth.Username: auth.Password}), xauth.LoggerOption(log.WithFields(map[string]any{ - "kind": "node", - "node": cfg.Name, - "addr": cfg.Addr, - "host": cfg.Host, - "protocol": cfg.Protocol, + "kind": "node", + "node": cfg.Name, + "addr": cfg.Addr, })), ) } @@ -200,6 +201,7 @@ func ParseNode(hop string, cfg *config.NodeConfig, log logger.Logger) (*chain.No } opts = append(opts, chain.HTTPNodeOption(settings)) } + if cfg.TLS != nil { tlsCfg := &chain.TLSNodeSettings{ ServerName: cfg.TLS.ServerName, diff --git a/config/parsing/service/parse.go b/config/parsing/service/parse.go index 4c54487..572e1e3 100644 --- a/config/parsing/service/parse.go +++ b/config/parsing/service/parse.go @@ -275,6 +275,14 @@ func parseForwarder(cfg *config.ForwarderConfig, log logger.Logger) (hop.Hop, er return nil, nil } + hopName := cfg.Hop + if hopName == "" { + hopName = cfg.Name + } + if hopName != "" { + return registry.HopRegistry().Get(hopName), nil + } + hc := config.HopConfig{ Name: cfg.Name, Selector: cfg.Selector, @@ -290,27 +298,42 @@ func parseForwarder(cfg *config.ForwarderConfig, log logger.Logger) (hop.Hop, er if i > 0 { name = fmt.Sprintf("%s-%d", node.Name, i) } + + filter := node.Filter + if filter == nil { + if node.Protocol != "" || node.Host != "" || node.Path != "" { + filter = &config.NodeFilterConfig{ + Protocol: node.Protocol, + Host: node.Host, + Path: node.Path, + } + } + } + + httpCfg := node.HTTP + if node.Auth != nil { + if httpCfg == nil { + httpCfg = &config.HTTPNodeConfig{} + } + if httpCfg.Auth == nil { + httpCfg.Auth = node.Auth + } + } hc.Nodes = append(hc.Nodes, &config.NodeConfig{ Name: name, Addr: addr, - Host: node.Host, Network: node.Network, - Protocol: node.Protocol, - Path: node.Path, Bypass: node.Bypass, Bypasses: node.Bypasses, - HTTP: node.HTTP, + Filter: filter, + HTTP: httpCfg, TLS: node.TLS, - Auth: node.Auth, Metadata: node.Metadata, }) } } } - if len(hc.Nodes) > 0 { - return hop_parser.ParseHop(&hc, log) - } - return registry.HopRegistry().Get(hc.Name), nil + return hop_parser.ParseHop(&hc, log) } func chainGroup(name string, group *config.ChainGroupConfig) chain.Chainer { diff --git a/go.mod b/go.mod index 353893f..8c046e4 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/gin-contrib/cors v1.5.0 github.com/gin-gonic/gin v1.9.1 - github.com/go-gost/core v0.0.0-20240424153155-5d6c2115fa15 + github.com/go-gost/core v0.0.0-20240508132029-8d554ddcf77c github.com/go-gost/gosocks4 v0.0.1 github.com/go-gost/gosocks5 v0.4.0 github.com/go-gost/plugin v0.0.0-20240103125338-9c84e29cb81a diff --git a/go.sum b/go.sum index e314386..250a74c 100644 --- a/go.sum +++ b/go.sum @@ -53,8 +53,12 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-gost/core v0.0.0-20220914115321-50d443049f3b h1:fWUPYFp0W/6GEhL0wrURGPQN2AQHhf4IZKiALJJOJh8= +github.com/go-gost/core v0.0.0-20220914115321-50d443049f3b/go.mod h1:bHVbCS9da6XtKNYMkMUVcck5UqDDUkyC37erVfs4GXQ= github.com/go-gost/core v0.0.0-20240424153155-5d6c2115fa15 h1:X7rvyLzslfgA+A7VKlUr//l798na8ZywuFyGcGfDUl8= github.com/go-gost/core v0.0.0-20240424153155-5d6c2115fa15/go.mod h1:j08tDHkFzk7dfOeLhl3RWsASdf9YWWRfWBUQqbQvx3A= +github.com/go-gost/core v0.0.0-20240508132029-8d554ddcf77c h1:1ahtn+3bQB50at5ubWDOrA4yja8vWpWNrGSRaCztNWg= +github.com/go-gost/core v0.0.0-20240508132029-8d554ddcf77c/go.mod h1:j08tDHkFzk7dfOeLhl3RWsASdf9YWWRfWBUQqbQvx3A= github.com/go-gost/gosocks4 v0.0.1 h1:+k1sec8HlELuQV7rWftIkmy8UijzUt2I6t+iMPlGB2s= github.com/go-gost/gosocks4 v0.0.1/go.mod h1:3B6L47HbU/qugDg4JnoFPHgJXE43Inz8Bah1QaN9qCc= github.com/go-gost/gosocks5 v0.4.0 h1:EIrOEkpJez4gwHrMa33frA+hHXJyevjp47thpMQsJzI= diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go index 56a7428..a7043c3 100644 --- a/internal/plugin/plugin.go +++ b/internal/plugin/plugin.go @@ -12,6 +12,11 @@ import ( "google.golang.org/grpc/credentials/insecure" ) +const ( + GRPC string = "grpc" + HTTP string = "http" +) + type Options struct { Token string TLSConfig *tls.Config