package parsing import ( "net" "net/url" "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/logger" "github.com/go-gost/core/recorder" "github.com/go-gost/core/resolver" 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" hosts_impl "github.com/go-gost/x/hosts" "github.com/go-gost/x/internal/loader" recorder_impl "github.com/go-gost/x/recorder" "github.com/go-gost/x/registry" resolver_impl "github.com/go-gost/x/resolver" ) func ParseAuther(cfg *config.AutherConfig) auth.Authenticator { if cfg == nil { return nil } 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.AuthsPeriodOption(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), ))) } 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.AuthsPeriodOption( map[string]string{ au.Username: au.Password, }, )) } 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 parseSelector(cfg *config.SelectorConfig) chain.Selector { if cfg == nil { return nil } var strategy chain.Strategy switch cfg.Strategy { case "round", "rr": strategy = chain.RoundRobinStrategy() case "random", "rand": strategy = chain.RandomStrategy() case "fifo", "ha": strategy = chain.FIFOStrategy() default: strategy = chain.RoundRobinStrategy() } return chain.NewSelector( strategy, chain.InvalidFilter(), chain.FailFilter(cfg.MaxFails, cfg.FailTimeout), ) } func ParseAdmission(cfg *config.AdmissionConfig) admission.Admission { if cfg == nil { return nil } opts := []admission_impl.Option{ admission_impl.MatchersOption(cfg.Matchers), admission_impl.ReverseOption(cfg.Reverse), 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), ))) } return admission_impl.NewAdmission(opts...) } func ParseBypass(cfg *config.BypassConfig) bypass.Bypass { if cfg == nil { return nil } opts := []bypass_impl.Option{ bypass_impl.MatchersOption(cfg.Matchers), bypass_impl.ReverseOption(cfg.Reverse), 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), ))) } return bypass_impl.NewBypass(opts...) } func ParseResolver(cfg *config.ResolverConfig) (resolver.Resolver, error) { if cfg == nil { return nil, nil } 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.LoggerResolverOption( logger.Default().WithFields(map[string]any{ "kind": "resolver", "resolver": cfg.Name, }), ), ) } func ParseHosts(cfg *config.HostsConfig) hosts.HostMapper { if cfg == nil || len(cfg.Mappings) == 0 { return nil } hosts := hosts_impl.NewHosts() hosts.Logger = logger.Default().WithFields(map[string]any{ "kind": "hosts", "hosts": cfg.Name, }) for _, host := range cfg.Mappings { if host.IP == "" || host.Hostname == "" { continue } ip := net.ParseIP(host.IP) if ip == nil { continue } hosts.Map(ip, host.Hostname, host.Aliases...) } return hosts } func ParseRecorder(cfg *config.RecorderConfig) (r recorder.Recorder) { if cfg == nil { return nil } if cfg.File != nil && cfg.File.Path != "" { return recorder_impl.FileRecorder(cfg.File.Path, recorder_impl.SepRecorderOption(cfg.File.Sep)) } if cfg.Redis != nil && cfg.Redis.Addr != "" && cfg.Redis.Key != "" { switch cfg.Redis.Type { case "list": // redis list return recorder_impl.RedisListRecorder(cfg.Redis.Addr, recorder_impl.DBRedisRecorderOption(cfg.Redis.DB), recorder_impl.KeyRedisRecorderOption(cfg.Redis.Key), recorder_impl.PasswordRedisRecorderOption(cfg.Redis.Password), ) default: // redis set return recorder_impl.RedisSetRecorder(cfg.Redis.Addr, recorder_impl.DBRedisRecorderOption(cfg.Redis.DB), recorder_impl.KeyRedisRecorderOption(cfg.Redis.Key), recorder_impl.PasswordRedisRecorderOption(cfg.Redis.Password), ) } } return }