add api & config

This commit is contained in:
ginuerzh
2022-03-17 22:54:57 +08:00
parent 2682c4d63b
commit 0f1f7790c5
20 changed files with 3456 additions and 18 deletions

136
config/parsing/chain.go Normal file
View File

@ -0,0 +1,136 @@
package parsing
import (
"github.com/go-gost/core/chain"
tls_util "github.com/go-gost/core/common/util/tls"
"github.com/go-gost/core/connector"
"github.com/go-gost/core/dialer"
"github.com/go-gost/core/logger"
"github.com/go-gost/core/metadata"
"github.com/go-gost/core/registry"
"github.com/go-gost/x/config"
)
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,
})
c := chain.NewChain(cfg.Name)
selector := parseSelector(cfg.Selector)
for _, hop := range cfg.Hops {
group := &chain.NodeGroup{}
for _, v := range hop.Nodes {
nodeLogger := chainLogger.WithFields(map[string]any{
"kind": "node",
"connector": v.Connector.Type,
"dialer": v.Dialer.Type,
"hop": hop.Name,
"node": v.Name,
})
connectorLogger := nodeLogger.WithFields(map[string]any{
"kind": "connector",
})
tlsCfg := v.Connector.TLS
if tlsCfg == nil {
tlsCfg = &config.TLSConfig{}
}
tlsConfig, err := tls_util.LoadClientConfig(
tlsCfg.CertFile, tlsCfg.KeyFile, tlsCfg.CAFile,
tlsCfg.Secure, tlsCfg.ServerName)
if err != nil {
chainLogger.Error(err)
return nil, err
}
cr := registry.ConnectorRegistry().Get(v.Connector.Type)(
connector.AuthOption(parseAuth(v.Connector.Auth)),
connector.TLSConfigOption(tlsConfig),
connector.LoggerOption(connectorLogger),
)
if v.Connector.Metadata == nil {
v.Connector.Metadata = make(map[string]any)
}
if err := cr.Init(metadata.MapMetadata(v.Connector.Metadata)); err != nil {
connectorLogger.Error("init: ", err)
return nil, err
}
dialerLogger := nodeLogger.WithFields(map[string]any{
"kind": "dialer",
})
tlsCfg = v.Dialer.TLS
if tlsCfg == nil {
tlsCfg = &config.TLSConfig{}
}
tlsConfig, err = tls_util.LoadClientConfig(
tlsCfg.CertFile, tlsCfg.KeyFile, tlsCfg.CAFile,
tlsCfg.Secure, tlsCfg.ServerName)
if err != nil {
chainLogger.Error(err)
return nil, err
}
d := registry.DialerRegistry().Get(v.Dialer.Type)(
dialer.AuthOption(parseAuth(v.Dialer.Auth)),
dialer.TLSConfigOption(tlsConfig),
dialer.LoggerOption(dialerLogger),
)
if v.Dialer.Metadata == nil {
v.Dialer.Metadata = make(map[string]any)
}
if err := d.Init(metadata.MapMetadata(v.Dialer.Metadata)); err != nil {
dialerLogger.Error("init: ", err)
return nil, err
}
if v.Bypass == "" {
v.Bypass = hop.Bypass
}
if v.Resolver == "" {
v.Resolver = hop.Resolver
}
if v.Hosts == "" {
v.Hosts = hop.Hosts
}
if v.Interface == "" {
v.Interface = hop.Interface
}
tr := (&chain.Transport{}).
WithConnector(cr).
WithDialer(d).
WithAddr(v.Addr).
WithInterface(v.Interface)
node := &chain.Node{
Name: v.Name,
Addr: v.Addr,
Bypass: registry.BypassRegistry().Get(v.Bypass),
Resolver: registry.ResolverRegistry().Get(v.Resolver),
Hosts: registry.HostsRegistry().Get(v.Hosts),
Marker: &chain.FailMarker{},
Transport: tr,
}
group.AddNode(node)
}
sel := selector
if s := parseSelector(hop.Selector); s != nil {
sel = s
}
group.WithSelector(sel)
c.AddNodeGroup(group)
}
return c, nil
}

161
config/parsing/parse.go Normal file
View File

@ -0,0 +1,161 @@
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"
hostspkg "github.com/go-gost/core/hosts"
"github.com/go-gost/core/logger"
"github.com/go-gost/core/registry"
"github.com/go-gost/core/resolver"
resolver_impl "github.com/go-gost/core/resolver/impl"
"github.com/go-gost/x/config"
)
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
}
if len(m) == 0 {
return nil
}
return auth.NewAuthenticator(m)
}
func ParseAutherFromAuth(au *config.AuthConfig) auth.Authenticator {
if au == nil || au.Username == "" {
return nil
}
return auth.NewAuthenticator(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
}
return admission.NewAdmissionPatterns(
cfg.Reverse,
cfg.Matchers,
admission.LoggerOption(logger.Default().WithFields(map[string]any{
"kind": "admission",
"admission": cfg.Name,
})),
)
}
func ParseBypass(cfg *config.BypassConfig) bypass.Bypass {
if cfg == nil {
return nil
}
return bypass.NewBypassPatterns(
cfg.Reverse,
cfg.Matchers,
bypass.LoggerOption(logger.Default().WithFields(map[string]any{
"kind": "bypass",
"bypass": cfg.Name,
})),
)
}
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) hostspkg.HostMapper {
if cfg == nil || len(cfg.Mappings) == 0 {
return nil
}
hosts := hostspkg.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
}

149
config/parsing/service.go Normal file
View File

@ -0,0 +1,149 @@
package parsing
import (
"strings"
"github.com/go-gost/core/chain"
tls_util "github.com/go-gost/core/common/util/tls"
"github.com/go-gost/core/handler"
"github.com/go-gost/core/listener"
"github.com/go-gost/core/logger"
"github.com/go-gost/core/metadata"
"github.com/go-gost/core/registry"
"github.com/go-gost/core/service"
"github.com/go-gost/x/config"
)
func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
if cfg.Listener == nil {
cfg.Listener = &config.ListenerConfig{
Type: "tcp",
}
}
if cfg.Handler == nil {
cfg.Handler = &config.HandlerConfig{
Type: "auto",
}
}
serviceLogger := logger.Default().WithFields(map[string]any{
"kind": "service",
"service": cfg.Name,
"listener": cfg.Listener.Type,
"handler": cfg.Handler.Type,
})
listenerLogger := serviceLogger.WithFields(map[string]any{
"kind": "listener",
})
tlsCfg := cfg.Listener.TLS
if tlsCfg == nil {
tlsCfg = &config.TLSConfig{}
}
tlsConfig, err := tls_util.LoadServerConfig(
tlsCfg.CertFile, tlsCfg.KeyFile, tlsCfg.CAFile)
if err != nil {
listenerLogger.Error(err)
return nil, err
}
auther := ParseAutherFromAuth(cfg.Listener.Auth)
if cfg.Listener.Auther != "" {
auther = registry.AutherRegistry().Get(cfg.Listener.Auther)
}
ln := registry.ListenerRegistry().Get(cfg.Listener.Type)(
listener.AddrOption(cfg.Addr),
listener.AutherOption(auther),
listener.AuthOption(parseAuth(cfg.Listener.Auth)),
listener.TLSConfigOption(tlsConfig),
listener.AdmissionOption(registry.AdmissionRegistry().Get(cfg.Admission)),
listener.ChainOption(registry.ChainRegistry().Get(cfg.Listener.Chain)),
listener.LoggerOption(listenerLogger),
listener.ServiceOption(cfg.Name),
)
if cfg.Listener.Metadata == nil {
cfg.Listener.Metadata = make(map[string]any)
}
if err := ln.Init(metadata.MapMetadata(cfg.Listener.Metadata)); err != nil {
listenerLogger.Error("init: ", err)
return nil, err
}
handlerLogger := serviceLogger.WithFields(map[string]any{
"kind": "handler",
})
tlsCfg = cfg.Handler.TLS
if tlsCfg == nil {
tlsCfg = &config.TLSConfig{}
}
tlsConfig, err = tls_util.LoadServerConfig(
tlsCfg.CertFile, tlsCfg.KeyFile, tlsCfg.CAFile)
if err != nil {
handlerLogger.Error(err)
return nil, err
}
auther = ParseAutherFromAuth(cfg.Handler.Auth)
if cfg.Handler.Auther != "" {
auther = registry.AutherRegistry().Get(cfg.Handler.Auther)
}
router := (&chain.Router{}).
WithRetries(cfg.Handler.Retries).
// WithTimeout(timeout time.Duration).
WithInterface(cfg.Interface).
WithChain(registry.ChainRegistry().Get(cfg.Handler.Chain)).
WithResolver(registry.ResolverRegistry().Get(cfg.Resolver)).
WithHosts(registry.HostsRegistry().Get(cfg.Hosts)).
WithLogger(handlerLogger)
h := registry.HandlerRegistry().Get(cfg.Handler.Type)(
handler.RouterOption(router),
handler.AutherOption(auther),
handler.AuthOption(parseAuth(cfg.Handler.Auth)),
handler.BypassOption(registry.BypassRegistry().Get(cfg.Bypass)),
handler.TLSConfigOption(tlsConfig),
handler.LoggerOption(handlerLogger),
)
if forwarder, ok := h.(handler.Forwarder); ok {
forwarder.Forward(parseForwarder(cfg.Forwarder))
}
if cfg.Handler.Metadata == nil {
cfg.Handler.Metadata = make(map[string]any)
}
if err := h.Init(metadata.MapMetadata(cfg.Handler.Metadata)); err != nil {
handlerLogger.Error("init: ", err)
return nil, err
}
s := service.NewService(cfg.Name, ln, h,
service.AdmissionOption(registry.AdmissionRegistry().Get(cfg.Admission)),
service.LoggerOption(serviceLogger),
)
serviceLogger.Infof("listening on %s/%s", s.Addr().String(), s.Addr().Network())
return s, nil
}
func parseForwarder(cfg *config.ForwarderConfig) *chain.NodeGroup {
if cfg == nil || len(cfg.Targets) == 0 {
return nil
}
group := &chain.NodeGroup{}
for _, target := range cfg.Targets {
if v := strings.TrimSpace(target); v != "" {
group.AddNode(&chain.Node{
Name: target,
Addr: target,
Marker: &chain.FailMarker{},
})
}
}
return group.WithSelector(parseSelector(cfg.Selector))
}