x/config/parsing/parse.go
2022-09-02 10:57:40 +08:00

297 lines
8.1 KiB
Go

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 parseChainSelector(cfg *config.SelectorConfig) chain.Selector[chain.SelectableChainer] {
if cfg == nil {
return nil
}
var strategy chain.Strategy[chain.SelectableChainer]
switch cfg.Strategy {
case "round", "rr":
strategy = chain.RoundRobinStrategy[chain.SelectableChainer]()
case "random", "rand":
strategy = chain.RandomStrategy[chain.SelectableChainer]()
case "fifo", "ha":
strategy = chain.FIFOStrategy[chain.SelectableChainer]()
default:
strategy = chain.RoundRobinStrategy[chain.SelectableChainer]()
}
return chain.NewSelector(
strategy,
chain.FailFilter[chain.SelectableChainer](cfg.MaxFails, cfg.FailTimeout),
)
}
func parseNodeSelector(cfg *config.SelectorConfig) chain.Selector[*chain.Node] {
if cfg == nil {
return nil
}
var strategy chain.Strategy[*chain.Node]
switch cfg.Strategy {
case "round", "rr":
strategy = chain.RoundRobinStrategy[*chain.Node]()
case "random", "rand":
strategy = chain.RandomStrategy[*chain.Node]()
case "fifo", "ha":
strategy = chain.FIFOStrategy[*chain.Node]()
default:
strategy = chain.RoundRobinStrategy[*chain.Node]()
}
return chain.NewSelector(
strategy,
chain.FailFilter[*chain.Node](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.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),
)))
}
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.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),
)))
}
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 {
return nil
}
var mappings []hosts_impl.Mapping
for _, mapping := range cfg.Mappings {
if mapping.IP == "" || mapping.Hostname == "" {
continue
}
ip := net.ParseIP(mapping.IP)
if ip == nil {
continue
}
mappings = append(mappings, hosts_impl.Mapping{
Hostname: mapping.Hostname,
IP: ip,
})
}
opts := []hosts_impl.Option{
hosts_impl.MappingsOption(mappings),
hosts_impl.ReloadPeriodOption(cfg.Reload),
hosts_impl.LoggerOption(logger.Default().WithFields(map[string]any{
"kind": "hosts",
"hosts": cfg.Name,
})),
}
if cfg.File != nil && cfg.File.Path != "" {
opts = append(opts, hosts_impl.FileLoaderOption(loader.FileLoader(cfg.File.Path)))
}
if cfg.Redis != nil && cfg.Redis.Addr != "" {
switch cfg.Redis.Type {
case "list": // redis list
opts = append(opts, hosts_impl.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, hosts_impl.RedisLoaderOption(loader.RedisSetLoader(
cfg.Redis.Addr,
loader.DBRedisLoaderOption(cfg.Redis.DB),
loader.PasswordRedisLoaderOption(cfg.Redis.Password),
loader.KeyRedisLoaderOption(cfg.Redis.Key),
)))
}
}
return hosts_impl.NewHostMapper(opts...)
}
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
}