From bdd239fb09e4fcdba8979ff608acb04791c3ee12 Mon Sep 17 00:00:00 2001 From: ginuerzh Date: Tue, 23 Aug 2022 21:49:49 +0800 Subject: [PATCH] add list support for auther, admission and bypass --- admission/admission.go | 13 ++++---- bypass/bypass.go | 12 ++++---- config/config.go | 58 ++++++++++++++++++++--------------- config/parsing/chain.go | 16 +++++++++- config/parsing/parse.go | 4 +-- config/parsing/service.go | 64 ++++++++++++++++++++++++++++++++------- go.mod | 2 +- go.sum | 4 +-- handler/dns/handler.go | 20 +++--------- handler/dns/metadata.go | 8 ++++- handler/tun/client.go | 4 +++ 11 files changed, 134 insertions(+), 71 deletions(-) diff --git a/admission/admission.go b/admission/admission.go index e2e914b..b040507 100644 --- a/admission/admission.go +++ b/admission/admission.go @@ -16,7 +16,7 @@ import ( ) type options struct { - reverse bool + whitelist bool matchers []string fileLoader loader.Loader redisLoader loader.Loader @@ -26,9 +26,9 @@ type options struct { type Option func(opts *options) -func ReverseOption(reverse bool) Option { +func WhitelistOption(whitelist bool) Option { return func(opts *options) { - opts.reverse = reverse + opts.whitelist = whitelist } } @@ -96,7 +96,7 @@ func NewAdmission(opts ...Option) admission_pkg.Admission { func (p *admission) Admit(addr string) bool { if addr == "" || p == nil { - return false + return true } // try to strip the port @@ -106,9 +106,8 @@ func (p *admission) Admit(addr string) bool { matched := p.matched(addr) - b := !p.options.reverse && matched || - p.options.reverse && !matched - return b + return !p.options.whitelist && !matched || + p.options.whitelist && matched } func (p *admission) periodReload(ctx context.Context) error { diff --git a/bypass/bypass.go b/bypass/bypass.go index af48164..a9af2a9 100644 --- a/bypass/bypass.go +++ b/bypass/bypass.go @@ -16,7 +16,7 @@ import ( ) type options struct { - reverse bool + whitelist bool matchers []string fileLoader loader.Loader redisLoader loader.Loader @@ -26,9 +26,9 @@ type options struct { type Option func(opts *options) -func ReverseOption(reverse bool) Option { +func WhitelistOption(whitelist bool) Option { return func(opts *options) { - opts.reverse = reverse + opts.whitelist = whitelist } } @@ -67,9 +67,9 @@ type bypass struct { cidrMatcher matcher.Matcher domainMatcher matcher.Matcher wildcardMatcher matcher.Matcher - mu sync.RWMutex cancelFunc context.CancelFunc options options + mu sync.RWMutex } // NewBypass creates and initializes a new Bypass. @@ -228,8 +228,8 @@ func (bp *bypass) Contains(addr string) bool { matched := bp.matched(addr) - b := !bp.options.reverse && matched || - bp.options.reverse && !matched + b := !bp.options.whitelist && matched || + bp.options.whitelist && !matched if b { bp.options.logger.Debugf("bypass: %s", addr) } diff --git a/config/config.go b/config/config.go index c619a28..c163eca 100644 --- a/config/config.go +++ b/config/config.go @@ -98,21 +98,25 @@ type SelectorConfig struct { } type AdmissionConfig struct { - Name string `json:"name"` - Reverse bool `yaml:",omitempty" json:"reverse,omitempty"` - Matchers []string `json:"matchers"` - Reload time.Duration `yaml:",omitempty" json:"reload,omitempty"` - File *FileLoader `yaml:",omitempty" json:"file,omitempty"` - Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"` + Name string `json:"name"` + // DEPRECATED by whitelist since beta.4 + Reverse bool `yaml:",omitempty" json:"reverse,omitempty"` + Whitelist bool `yaml:",omitempty" json:"whitelist,omitempty"` + Matchers []string `json:"matchers"` + Reload time.Duration `yaml:",omitempty" json:"reload,omitempty"` + File *FileLoader `yaml:",omitempty" json:"file,omitempty"` + Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"` } type BypassConfig struct { - Name string `json:"name"` - Reverse bool `yaml:",omitempty" json:"reverse,omitempty"` - Matchers []string `json:"matchers"` - Reload time.Duration `yaml:",omitempty" json:"reload,omitempty"` - File *FileLoader `yaml:",omitempty" json:"file,omitempty"` - Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"` + Name string `json:"name"` + // DEPRECATED by whitelist since beta.4 + Reverse bool `yaml:",omitempty" json:"reverse,omitempty"` + Whitelist bool `yaml:",omitempty" json:"whitelist,omitempty"` + Matchers []string `json:"matchers"` + Reload time.Duration `yaml:",omitempty" json:"reload,omitempty"` + File *FileLoader `yaml:",omitempty" json:"file,omitempty"` + Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"` } type FileLoader struct { @@ -184,6 +188,7 @@ type ListenerConfig struct { Type string `json:"type"` Chain string `yaml:",omitempty" json:"chain,omitempty"` Auther string `yaml:",omitempty" json:"auther,omitempty"` + Authers []string `yaml:",omitempty" json:"authers,omitempty"` Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"` TLS *TLSConfig `yaml:",omitempty" json:"tls,omitempty"` Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"` @@ -194,6 +199,7 @@ type HandlerConfig struct { Retries int `yaml:",omitempty" json:"retries,omitempty"` Chain string `yaml:",omitempty" json:"chain,omitempty"` Auther string `yaml:",omitempty" json:"auther,omitempty"` + Authers []string `yaml:",omitempty" json:"authers,omitempty"` Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"` TLS *TLSConfig `yaml:",omitempty" json:"tls,omitempty"` Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"` @@ -223,18 +229,20 @@ type SockOptsConfig struct { } type ServiceConfig struct { - Name string `json:"name"` - Addr string `yaml:",omitempty" json:"addr,omitempty"` - Interface string `yaml:",omitempty" json:"interface,omitempty"` - SockOpts *SockOptsConfig `yaml:"sockopts,omitempty" json:"sockopts,omitempty"` - Admission string `yaml:",omitempty" json:"admission,omitempty"` - Bypass string `yaml:",omitempty" json:"bypass,omitempty"` - Resolver string `yaml:",omitempty" json:"resolver,omitempty"` - Hosts string `yaml:",omitempty" json:"hosts,omitempty"` - Recorders []*RecorderObject `yaml:",omitempty" json:"recorders,omitempty"` - Handler *HandlerConfig `yaml:",omitempty" json:"handler,omitempty"` - Listener *ListenerConfig `yaml:",omitempty" json:"listener,omitempty"` - Forwarder *ForwarderConfig `yaml:",omitempty" json:"forwarder,omitempty"` + Name string `json:"name"` + Addr string `yaml:",omitempty" json:"addr,omitempty"` + Interface string `yaml:",omitempty" json:"interface,omitempty"` + SockOpts *SockOptsConfig `yaml:"sockopts,omitempty" json:"sockopts,omitempty"` + Admission string `yaml:",omitempty" json:"admission,omitempty"` + Admissions []string `yaml:",omitempty" json:"admissions,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"` + Recorders []*RecorderObject `yaml:",omitempty" json:"recorders,omitempty"` + Handler *HandlerConfig `yaml:",omitempty" json:"handler,omitempty"` + Listener *ListenerConfig `yaml:",omitempty" json:"listener,omitempty"` + Forwarder *ForwarderConfig `yaml:",omitempty" json:"forwarder,omitempty"` } type ChainConfig struct { @@ -249,6 +257,7 @@ type HopConfig struct { SockOpts *SockOptsConfig `yaml:"sockopts,omitempty" json:"sockopts,omitempty"` Selector *SelectorConfig `yaml:",omitempty" json:"selector,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"` Nodes []*NodeConfig `json:"nodes"` @@ -260,6 +269,7 @@ type NodeConfig struct { 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"` diff --git a/config/parsing/chain.go b/config/parsing/chain.go index 4bbe3cb..7b5a323 100644 --- a/config/parsing/chain.go +++ b/config/parsing/chain.go @@ -1,6 +1,7 @@ package parsing import ( + "github.com/go-gost/core/bypass" "github.com/go-gost/core/chain" "github.com/go-gost/core/connector" "github.com/go-gost/core/dialer" @@ -96,6 +97,9 @@ func ParseChain(cfg *config.ChainConfig) (chain.Chainer, error) { if v.Bypass == "" { v.Bypass = hop.Bypass } + if v.Bypasses == nil { + v.Bypasses = hop.Bypasses + } if v.Resolver == "" { v.Resolver = hop.Resolver } @@ -123,10 +127,20 @@ func ParseChain(cfg *config.ChainConfig) (chain.Chainer, error) { WithInterface(v.Interface). WithSockOpts(sockOpts) + var bypasses []bypass.Bypass + if bp := registry.BypassRegistry().Get(v.Bypass); bp != nil { + bypasses = append(bypasses, bp) + } + for _, s := range v.Bypasses { + if bp := registry.BypassRegistry().Get(s); bp != nil { + bypasses = append(bypasses, bp) + } + } + node := &chain.Node{ Name: v.Name, Addr: v.Addr, - Bypass: registry.BypassRegistry().Get(v.Bypass), + Bypass: bypass.BypassList(bypasses...), Resolver: registry.ResolverRegistry().Get(v.Resolver), Hosts: registry.HostsRegistry().Get(v.Hosts), Marker: &chain.FailMarker{}, diff --git a/config/parsing/parse.go b/config/parsing/parse.go index 832f636..8406238 100644 --- a/config/parsing/parse.go +++ b/config/parsing/parse.go @@ -113,7 +113,7 @@ func ParseAdmission(cfg *config.AdmissionConfig) admission.Admission { } opts := []admission_impl.Option{ admission_impl.MatchersOption(cfg.Matchers), - admission_impl.ReverseOption(cfg.Reverse), + admission_impl.WhitelistOption(cfg.Reverse || cfg.Whitelist), admission_impl.ReloadPeriodOption(cfg.Reload), admission_impl.LoggerOption(logger.Default().WithFields(map[string]any{ "kind": "admission", @@ -141,7 +141,7 @@ func ParseBypass(cfg *config.BypassConfig) bypass.Bypass { opts := []bypass_impl.Option{ bypass_impl.MatchersOption(cfg.Matchers), - bypass_impl.ReverseOption(cfg.Reverse), + bypass_impl.WhitelistOption(cfg.Reverse || cfg.Whitelist), bypass_impl.ReloadPeriodOption(cfg.Reload), bypass_impl.LoggerOption(logger.Default().WithFields(map[string]any{ "kind": "bypass", diff --git a/config/parsing/service.go b/config/parsing/service.go index 7927934..f6a081a 100644 --- a/config/parsing/service.go +++ b/config/parsing/service.go @@ -3,6 +3,9 @@ package parsing import ( "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/handler" "github.com/go-gost/core/listener" @@ -51,17 +54,37 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) { tlsConfig = defaultTLSConfig.Clone() } - auther := ParseAutherFromAuth(cfg.Listener.Auth) - if cfg.Listener.Auther != "" { - auther = registry.AutherRegistry().Get(cfg.Listener.Auther) + var authers []auth.Authenticator + if auther := registry.AutherRegistry().Get(cfg.Listener.Auther); auther != nil { + authers = append(authers, auther) + } + for _, s := range cfg.Listener.Authers { + if auther := registry.AutherRegistry().Get(s); auther != nil { + authers = append(authers, auther) + } + } + if len(authers) == 0 { + if auther := ParseAutherFromAuth(cfg.Listener.Auth); auther != nil { + authers = append(authers, auther) + } + } + + var admissions []admission.Admission + if adm := registry.AdmissionRegistry().Get(cfg.Admission); adm != nil { + admissions = append(admissions, adm) + } + for _, s := range cfg.Admissions { + if adm := registry.AdmissionRegistry().Get(s); adm != nil { + admissions = append(admissions, adm) + } } ln := registry.ListenerRegistry().Get(cfg.Listener.Type)( listener.AddrOption(cfg.Addr), - listener.AutherOption(auther), + listener.AutherOption(auth.AuthenticatorList(authers...)), listener.AuthOption(parseAuth(cfg.Listener.Auth)), listener.TLSConfigOption(tlsConfig), - listener.AdmissionOption(registry.AdmissionRegistry().Get(cfg.Admission)), + listener.AdmissionOption(admission.AdmissionList(admissions...)), listener.ChainOption(registry.ChainRegistry().Get(cfg.Listener.Chain)), listener.LoggerOption(listenerLogger), listener.ServiceOption(cfg.Name), @@ -93,9 +116,19 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) { tlsConfig = defaultTLSConfig.Clone() } - auther = ParseAutherFromAuth(cfg.Handler.Auth) - if cfg.Handler.Auther != "" { - auther = registry.AutherRegistry().Get(cfg.Handler.Auther) + authers = nil + if auther := registry.AutherRegistry().Get(cfg.Handler.Auther); auther != nil { + authers = append(authers, auther) + } + for _, s := range cfg.Handler.Authers { + if auther := registry.AutherRegistry().Get(s); auther != nil { + authers = append(authers, auther) + } + } + if len(authers) == 0 { + if auther := ParseAutherFromAuth(cfg.Handler.Auth); auther != nil { + authers = append(authers, auther) + } } var sockOpts *chain.SockOpts @@ -123,11 +156,20 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) { WithRecorder(recorders...). WithLogger(handlerLogger) + var bypasses []bypass.Bypass + if bp := registry.BypassRegistry().Get(cfg.Bypass); bp != nil { + bypasses = append(bypasses, bp) + } + for _, s := range cfg.Bypasses { + if bp := registry.BypassRegistry().Get(s); bp != nil { + bypasses = append(bypasses, bp) + } + } h := registry.HandlerRegistry().Get(cfg.Handler.Type)( handler.RouterOption(router), - handler.AutherOption(auther), + handler.AutherOption(auth.AuthenticatorList(authers...)), handler.AuthOption(parseAuth(cfg.Handler.Auth)), - handler.BypassOption(registry.BypassRegistry().Get(cfg.Bypass)), + handler.BypassOption(bypass.BypassList(bypasses...)), handler.TLSConfigOption(tlsConfig), handler.LoggerOption(handlerLogger), ) @@ -145,7 +187,7 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) { } s := service.NewService(cfg.Name, ln, h, - service.AdmissionOption(registry.AdmissionRegistry().Get(cfg.Admission)), + service.AdmissionOption(admission.AdmissionList(admissions...)), service.LoggerOption(serviceLogger), ) diff --git a/go.mod b/go.mod index e382112..e9deb77 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/gin-contrib/cors v1.3.1 github.com/gin-gonic/gin v1.7.7 - github.com/go-gost/core v0.0.0-20220818022848-2cc1d6f52c41 + github.com/go-gost/core v0.0.0-20220823134627-ff51aef51873 github.com/go-gost/gosocks4 v0.0.1 github.com/go-gost/gosocks5 v0.3.1-0.20211109033403-d894d75b7f09 github.com/go-gost/relay v0.1.1-0.20211123134818-8ef7fd81ffd7 diff --git a/go.sum b/go.sum index c1b5a07..152c8df 100644 --- a/go.sum +++ b/go.sum @@ -119,8 +119,8 @@ github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gost/core v0.0.0-20220818022848-2cc1d6f52c41 h1:HTp9LzqbWcZ0VyI0NKudOwweVfwXWbaM+WyNIjQUH74= -github.com/go-gost/core v0.0.0-20220818022848-2cc1d6f52c41/go.mod h1:bHVbCS9da6XtKNYMkMUVcck5UqDDUkyC37erVfs4GXQ= +github.com/go-gost/core v0.0.0-20220823134627-ff51aef51873 h1:e6bpEUHGywqZKcaHDcnZg/rg1nVsbVbGb8HRUKaRkdM= +github.com/go-gost/core v0.0.0-20220823134627-ff51aef51873/go.mod h1:bHVbCS9da6XtKNYMkMUVcck5UqDDUkyC37erVfs4GXQ= 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.3.1-0.20211109033403-d894d75b7f09 h1:A95M6UWcfZgOuJkQ7QLfG0Hs5peWIUSysCDNz4pfe04= diff --git a/handler/dns/handler.go b/handler/dns/handler.go index 5a1eb8c..b7aa3c5 100644 --- a/handler/dns/handler.go +++ b/handler/dns/handler.go @@ -1,12 +1,10 @@ package dns import ( - "bytes" "context" "errors" "fmt" "net" - "strconv" "strings" "time" @@ -114,7 +112,7 @@ func (h *dnsHandler) Handle(ctx context.Context, conn net.Conn, opts ...handler. }).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr()) }() - b := bufpool.Get(defaultBufferSize) + b := bufpool.Get(h.md.bufferSize) defer bufpool.Put(b) n, err := conn.Read(*b) @@ -165,7 +163,7 @@ func (h *dnsHandler) exchange(ctx context.Context, msg []byte, log logger.Logger mr = h.lookupHosts(&mq, log) if mr != nil { - b := bufpool.Get(defaultBufferSize) + b := bufpool.Get(h.md.bufferSize) return mr.PackBuffer(*b) } @@ -177,7 +175,7 @@ func (h *dnsHandler) exchange(ctx context.Context, msg []byte, log logger.Logger log.Debugf("exchange message %d (cached): %s", mq.Id, mq.Question[0].String()) mr.Id = mq.Id - b := bufpool.Get(defaultBufferSize) + b := bufpool.Get(h.md.bufferSize) return mr.PackBuffer(*b) } @@ -188,7 +186,7 @@ func (h *dnsHandler) exchange(ctx context.Context, msg []byte, log logger.Logger }() } - b := bufpool.Get(defaultBufferSize) + b := bufpool.Get(h.md.bufferSize) defer bufpool.Put(b) query, err := mq.PackBuffer(*b) @@ -268,13 +266,3 @@ func (h *dnsHandler) lookupHosts(r *dns.Msg, log logger.Logger) (m *dns.Msg) { return } - -func (h *dnsHandler) dumpMsgHeader(m *dns.Msg) string { - buf := new(bytes.Buffer) - buf.WriteString(m.MsgHdr.String() + " ") - buf.WriteString("QUERY: " + strconv.Itoa(len(m.Question)) + ", ") - buf.WriteString("ANSWER: " + strconv.Itoa(len(m.Answer)) + ", ") - buf.WriteString("AUTHORITY: " + strconv.Itoa(len(m.Ns)) + ", ") - buf.WriteString("ADDITIONAL: " + strconv.Itoa(len(m.Extra))) - return buf.String() -} diff --git a/handler/dns/metadata.go b/handler/dns/metadata.go index 75eed2b..edec461 100644 --- a/handler/dns/metadata.go +++ b/handler/dns/metadata.go @@ -19,7 +19,8 @@ type metadata struct { timeout time.Duration clientIP net.IP // nameservers - dns []string + dns []string + bufferSize int } func (h *dnsHandler) parseMetadata(md mdata.Metadata) (err error) { @@ -29,6 +30,7 @@ func (h *dnsHandler) parseMetadata(md mdata.Metadata) (err error) { timeout = "timeout" clientIP = "clientIP" dns = "dns" + bufferSize = "bufferSize" ) h.md.readTimeout = mdx.GetDuration(md, readTimeout) @@ -42,6 +44,10 @@ func (h *dnsHandler) parseMetadata(md mdata.Metadata) (err error) { h.md.clientIP = net.ParseIP(sip) } h.md.dns = mdx.GetStrings(md, dns) + h.md.bufferSize = mdx.GetInt(md, bufferSize) + if h.md.bufferSize <= 0 { + h.md.bufferSize = defaultBufferSize + } return } diff --git a/handler/tun/client.go b/handler/tun/client.go index 1c2db70..a3b6f40 100644 --- a/handler/tun/client.go +++ b/handler/tun/client.go @@ -50,6 +50,10 @@ func (h *tunHandler) keepAlive(ctx context.Context, conn net.Conn, ip net.IP) { copy(keepAliveData[:4], keepAliveHeader) // magic header copy(keepAliveData[4:], ip.To16()) + if _, err := conn.Write(keepAliveData[:]); err != nil { + return + } + ticker := time.NewTicker(h.md.keepAlivePeriod) defer ticker.Stop()