update config

This commit is contained in:
ginuerzh
2022-01-03 23:45:49 +08:00
parent 14537d16ea
commit 566e930010
42 changed files with 412 additions and 521 deletions

View File

@ -7,11 +7,12 @@ import (
"strings"
"github.com/go-gost/gost/pkg/config"
"github.com/go-gost/gost/pkg/registry"
)
var (
ErrInvalidService = errors.New("invalid service")
ErrInvalidNode = errors.New("invalid node")
ErrInvalidCmd = errors.New("invalid cmd")
ErrInvalidNode = errors.New("invalid node")
)
type stringList []string
@ -36,32 +37,36 @@ func buildConfigFromCmd(services, nodes stringList) (*config.Config, error) {
}
for i, node := range nodes {
url, err := checkCmd(node)
url, err := normCmd(node)
if err != nil {
return nil, err
}
nodeConfig, err := buildNodeConfig(url)
if err != nil {
return nil, err
}
nodeConfig.Name = "node-0"
chain.Hops = append(chain.Hops, &config.HopConfig{
Name: fmt.Sprintf("hop-%d", i),
Nodes: []*config.NodeConfig{
{
Name: "node-0",
URL: url,
},
},
Name: fmt.Sprintf("hop-%d", i),
Nodes: []*config.NodeConfig{nodeConfig},
})
}
for i, svc := range services {
url, err := checkCmd(svc)
url, err := normCmd(svc)
if err != nil {
return nil, err
}
service := &config.ServiceConfig{
Name: fmt.Sprintf("service-%d", i),
URL: url,
service, err := buildServiceConfig(url)
if err != nil {
return nil, err
}
service.Name = fmt.Sprintf("service-%d", i)
if chain != nil {
service.Chain = chain.Name
service.Handler.Chain = chain.Name
}
cfg.Services = append(cfg.Services, service)
}
@ -69,20 +74,140 @@ func buildConfigFromCmd(services, nodes stringList) (*config.Config, error) {
return cfg, nil
}
func checkCmd(s string) (string, error) {
func buildServiceConfig(url *url.URL) (*config.ServiceConfig, error) {
var handler, listener string
schemes := strings.Split(url.Scheme, "+")
if len(schemes) == 1 {
handler = schemes[0]
listener = schemes[0]
}
if len(schemes) == 2 {
handler = schemes[0]
listener = schemes[1]
}
svc := &config.ServiceConfig{
Addr: url.Host,
}
if h := registry.GetHandler(handler); h == nil {
handler = "auto"
}
if ln := registry.GetListener(listener); ln == nil {
listener = "tcp"
if handler == "ssu" {
listener = "udp"
}
}
if remotes := strings.Trim(url.EscapedPath(), "/"); remotes != "" {
svc.Forwarder = &config.ForwarderConfig{
Targets: strings.Split(remotes, ","),
}
if handler != "relay" {
if listener == "tcp" || listener == "udp" ||
listener == "rtcp" || listener == "rudp" ||
listener == "tun" || listener == "tap" {
handler = listener
} else {
handler = "tcp"
}
}
}
md := make(map[string]interface{})
for k, v := range url.Query() {
if len(v) > 0 {
md[k] = v[0]
}
}
var auths []config.AuthConfig
if url.User != nil {
auth := config.AuthConfig{
Username: url.User.Username(),
}
auth.Password, _ = url.User.Password()
auths = append(auths, auth)
}
svc.Handler = &config.HandlerConfig{
Type: handler,
Auths: auths,
Metadata: md,
}
svc.Listener = &config.ListenerConfig{
Type: listener,
Metadata: md,
}
return svc, nil
}
func buildNodeConfig(url *url.URL) (*config.NodeConfig, error) {
var connector, dialer string
schemes := strings.Split(url.Scheme, "+")
if len(schemes) == 1 {
connector = schemes[0]
dialer = schemes[0]
}
if len(schemes) == 2 {
connector = schemes[0]
dialer = schemes[1]
}
node := &config.NodeConfig{
Addr: url.Host,
}
if c := registry.GetConnector(connector); c == nil {
connector = "http"
}
if d := registry.GetDialer(dialer); d == nil {
dialer = "tcp"
if connector == "ssu" {
dialer = "udp"
}
}
md := make(map[string]interface{})
for k, v := range url.Query() {
if len(v) > 0 {
md[k] = v[0]
}
}
md["serverName"] = url.Host
var auth *config.AuthConfig
if url.User != nil {
auth = &config.AuthConfig{
Username: url.User.Username(),
}
auth.Password, _ = url.User.Password()
}
node.Connector = &config.ConnectorConfig{
Type: connector,
Auth: auth,
Metadata: md,
}
node.Dialer = &config.DialerConfig{
Type: dialer,
Metadata: md,
}
return node, nil
}
func normCmd(s string) (*url.URL, error) {
s = strings.TrimSpace(s)
if s == "" {
return "", ErrInvalidService
return nil, ErrInvalidCmd
}
if !strings.Contains(s, "://") {
s = "auto://" + s
}
u, err := url.Parse(s)
if err != nil {
return "", err
}
return u.String(), nil
return url.Parse(s)
}

View File

@ -3,9 +3,11 @@ package main
import (
"io"
"net"
"net/url"
"os"
"strings"
"github.com/go-gost/gost/pkg/auth"
"github.com/go-gost/gost/pkg/bypass"
"github.com/go-gost/gost/pkg/chain"
"github.com/go-gost/gost/pkg/config"
@ -54,12 +56,14 @@ func buildService(cfg *config.Config) (services []*service.Service) {
}
for _, svc := range cfg.Services {
if svc.Listener == nil || svc.Handler == nil {
continue
}
serviceLogger := log.WithFields(map[string]interface{}{
"kind": "service",
"service": svc.Name,
"listener": svc.Listener.Type,
"handler": svc.Handler.Type,
"chain": svc.Chain,
})
listenerLogger := serviceLogger.WithFields(map[string]interface{}{
@ -67,11 +71,12 @@ func buildService(cfg *config.Config) (services []*service.Service) {
})
ln := registry.GetListener(svc.Listener.Type)(
listener.AddrOption(svc.Addr),
listener.AuthenticatorOption(authFromConfig(svc.Listener.Auths...)),
listener.LoggerOption(listenerLogger),
)
if chainable, ok := ln.(chain.Chainable); ok {
chainable.WithChain(chains[svc.Chain])
chainable.WithChain(chains[svc.Listener.Chain])
}
if svc.Listener.Metadata == nil {
@ -86,12 +91,13 @@ func buildService(cfg *config.Config) (services []*service.Service) {
})
h := registry.GetHandler(svc.Handler.Type)(
handler.BypassOption(bypasses[svc.Bypass]),
handler.LoggerOption(handlerLogger),
handler.BypassOption(bypasses[svc.Handler.Bypass]),
handler.AuthenticatorOption(authFromConfig(svc.Handler.Auths...)),
handler.RouterOption(&chain.Router{
Chain: chains[svc.Chain],
Resolver: resolvers[svc.Resolver],
Hosts: hosts[svc.Hosts],
Chain: chains[svc.Handler.Chain],
Resolver: resolvers[svc.Handler.Resolver],
Hosts: hosts[svc.Handler.Hosts],
Logger: handlerLogger,
}),
)
@ -134,14 +140,27 @@ func chainFromConfig(cfg *config.ChainConfig) *chain.Chain {
for _, hop := range cfg.Hops {
group := &chain.NodeGroup{}
for _, v := range hop.Nodes {
connectorLogger := chainLogger.WithFields(map[string]interface{}{
"kind": "connector",
nodeLogger := chainLogger.WithFields(map[string]interface{}{
"kind": "node",
"connector": v.Connector.Type,
"dialer": v.Dialer.Type,
"hop": hop.Name,
"node": v.Name,
})
connectorLogger := nodeLogger.WithFields(map[string]interface{}{
"kind": "connector",
})
var connectorUser *url.Userinfo
if auth := v.Connector.Auth; auth != nil && auth.Username != "" {
if auth.Password == "" {
connectorUser = url.User(auth.Username)
} else {
connectorUser = url.UserPassword(auth.Username, auth.Password)
}
}
cr := registry.GetConnector(v.Connector.Type)(
connector.UserOption(connectorUser),
connector.LoggerOption(connectorLogger),
)
@ -152,14 +171,20 @@ func chainFromConfig(cfg *config.ChainConfig) *chain.Chain {
connectorLogger.Fatal("init: ", err)
}
dialerLogger := chainLogger.WithFields(map[string]interface{}{
"kind": "dialer",
"connector": v.Connector.Type,
"dialer": v.Dialer.Type,
"hop": hop.Name,
"node": v.Name,
dialerLogger := nodeLogger.WithFields(map[string]interface{}{
"kind": "dialer",
})
var dialerUser *url.Userinfo
if auth := v.Dialer.Auth; auth != nil && auth.Username != "" {
if auth.Password == "" {
dialerUser = url.User(auth.Username)
} else {
dialerUser = url.UserPassword(auth.Username, auth.Password)
}
}
d := registry.GetDialer(v.Dialer.Type)(
dialer.UserOption(dialerUser),
dialer.LoggerOption(dialerLogger),
)
@ -305,3 +330,18 @@ func hostsFromConfig(cfg *config.HostsConfig) hostspkg.HostMapper {
}
return hosts
}
func authFromConfig(cfgs ...config.AuthConfig) auth.Authenticator {
auths := make(map[string]string)
for _, cfg := range cfgs {
if cfg.Username == "" {
continue
}
auths[cfg.Username] = cfg.Password
}
if len(auths) > 0 {
return auth.NewMapAuthenticator(auths)
}
return nil
}

View File

@ -63,8 +63,6 @@ func main() {
log.Fatal(err)
}
normConfig(cfg)
log = logFromConfig(cfg.Log)
if outputCfgFile != "" {

View File

@ -1,139 +0,0 @@
package main
import (
"net/url"
"strings"
"github.com/go-gost/gost/pkg/config"
"github.com/go-gost/gost/pkg/registry"
)
// normConfig normalizes the config.
func normConfig(cfg *config.Config) {
for _, svc := range cfg.Services {
normService(svc)
}
for _, chain := range cfg.Chains {
normChain(chain)
}
}
func normService(svc *config.ServiceConfig) {
if svc.URL == "" {
return
}
u, _ := url.Parse(svc.URL)
var handler, listener string
schemes := strings.Split(u.Scheme, "+")
if len(schemes) == 1 {
handler = schemes[0]
listener = schemes[0]
}
if len(schemes) == 2 {
handler = schemes[0]
listener = schemes[1]
}
md := make(map[string]interface{})
for k, v := range u.Query() {
if len(v) > 0 {
md[k] = v[0]
}
}
if u.User != nil {
md["users"] = []interface{}{u.User.String()}
}
svc.Addr = u.Host
if h := registry.GetHandler(handler); h == nil {
handler = "auto"
}
if ln := registry.GetListener(listener); ln == nil {
listener = "tcp"
if handler == "ssu" {
listener = "udp"
}
}
if remotes := strings.Trim(u.EscapedPath(), "/"); remotes != "" {
svc.Forwarder = &config.ForwarderConfig{
Targets: strings.Split(remotes, ","),
}
if handler != "relay" {
if listener == "tcp" || listener == "udp" ||
listener == "rtcp" || listener == "rudp" ||
listener == "tun" || listener == "tap" {
handler = listener
} else {
handler = "tcp"
}
}
}
svc.Handler = &config.HandlerConfig{
Type: handler,
Metadata: md,
}
svc.Listener = &config.ListenerConfig{
Type: listener,
Metadata: md,
}
}
func normChain(chain *config.ChainConfig) {
for _, hop := range chain.Hops {
for _, node := range hop.Nodes {
if node.URL == "" {
continue
}
u, _ := url.Parse(node.URL)
var connector, dialer string
schemes := strings.Split(u.Scheme, "+")
if len(schemes) == 1 {
connector = schemes[0]
dialer = schemes[0]
}
if len(schemes) == 2 {
connector = schemes[0]
dialer = schemes[1]
}
md := make(map[string]interface{})
for k, v := range u.Query() {
if len(v) > 0 {
md[k] = v[0]
}
}
if u.User != nil {
md["user"] = u.User.String()
}
md["serverName"] = u.Host
node.Addr = u.Host
if c := registry.GetConnector(connector); c == nil {
connector = "http"
}
if d := registry.GetDialer(dialer); d == nil {
dialer = "tcp"
if connector == "ssu" {
dialer = "udp"
}
}
node.Connector = &config.ConnectorConfig{
Type: connector,
Metadata: md,
}
node.Dialer = &config.DialerConfig{
Type: dialer,
Metadata: md,
}
}
}
}