add relay proxy

This commit is contained in:
ginuerzh
2021-11-18 22:54:23 +08:00
parent 1a1ee384b7
commit 8185d1124f
31 changed files with 747 additions and 106 deletions

88
cmd/gost/cmd.go Normal file
View File

@ -0,0 +1,88 @@
package main
import (
"errors"
"fmt"
"net/url"
"strings"
"github.com/go-gost/gost/pkg/config"
)
var (
ErrInvalidService = errors.New("invalid service")
ErrInvalidNode = errors.New("invalid node")
)
type stringList []string
func (l *stringList) String() string {
return fmt.Sprintf("%s", *l)
}
func (l *stringList) Set(value string) error {
*l = append(*l, value)
return nil
}
func buildConfigFromCmd(services, nodes stringList) (*config.Config, error) {
cfg := &config.Config{}
var chain *config.ChainConfig
if len(nodes) > 0 {
chain = &config.ChainConfig{
Name: "chain-0",
}
cfg.Chains = append(cfg.Chains, chain)
}
for i, node := range nodes {
url, err := checkCmd(node)
if err != nil {
return nil, err
}
chain.Hops = append(chain.Hops, &config.HopConfig{
Name: fmt.Sprintf("hop-%d", i),
Nodes: []*config.NodeConfig{
{
Name: "node-0",
URL: url,
},
},
})
}
for i, svc := range services {
url, err := checkCmd(svc)
if err != nil {
return nil, err
}
service := &config.ServiceConfig{
Name: fmt.Sprintf("service-%d", i),
URL: url,
}
if chain != nil {
service.Chain = chain.Name
}
cfg.Services = append(cfg.Services, service)
}
return cfg, nil
}
func checkCmd(s string) (string, error) {
s = strings.TrimSpace(s)
if s == "" {
return "", ErrInvalidService
}
if !strings.Contains(s, "://") {
s = "auto://" + s
}
u, err := url.Parse(s)
if err != nil {
return "", err
}
return u.String(), nil
}

View File

@ -29,11 +29,11 @@ func buildService(cfg *config.Config) (services []*service.Service) {
}
for _, bypassCfg := range cfg.Bypasses {
bypasses[bypassCfg.Name] = bypassFromConfig(&bypassCfg)
bypasses[bypassCfg.Name] = bypassFromConfig(bypassCfg)
}
for _, chainCfg := range cfg.Chains {
chains[chainCfg.Name] = chainFromConfig(&chainCfg)
chains[chainCfg.Name] = chainFromConfig(chainCfg)
}
for _, svc := range cfg.Services {
@ -47,9 +47,14 @@ func buildService(cfg *config.Config) (services []*service.Service) {
})
ln := registry.GetListener(svc.Listener.Type)(
listener.AddrOption(svc.Addr),
listener.ChainOption(chains[svc.Listener.Chain]),
listener.LoggerOption(listenerLogger),
)
cln, chainable := ln.(listener.Chainable)
if chainable {
cln.Chain(chains[svc.Chain])
}
if err := ln.Init(metadata.MapMetadata(svc.Listener.Metadata)); err != nil {
listenerLogger.Fatal("init: ", err)
}
@ -60,13 +65,17 @@ func buildService(cfg *config.Config) (services []*service.Service) {
})
h := registry.GetHandler(svc.Handler.Type)(
handler.ChainOption(chains[svc.Handler.Chain]),
handler.BypassOption(bypasses[svc.Handler.Bypass]),
handler.ChainOption(chains[svc.Chain]),
handler.BypassOption(bypasses[svc.Bypass]),
handler.LoggerOption(handlerLogger),
)
if forwarder, ok := h.(handler.Forwarder); ok {
forwarder.Forward(forwarderFromConfig(svc.Forwarder))
chain := chains[svc.Chain]
if chainable {
chain = nil
}
forwarder.Forward(forwarderFromConfig(svc.Forwarder), chain)
}
if err := h.Init(metadata.MapMetadata(svc.Handler.Metadata)); err != nil {
@ -145,6 +154,9 @@ func chainFromConfig(cfg *config.ChainConfig) *chain.Chain {
}
func logFromConfig(cfg *config.LogConfig) logger.Logger {
if cfg == nil {
cfg = &config.LogConfig{}
}
opts := []logger.LoggerOption{
logger.FormatLoggerOption(logger.LogFormat(cfg.Format)),
logger.LevelLoggerOption(logger.LogLevel(cfg.Level)),
@ -152,9 +164,9 @@ func logFromConfig(cfg *config.LogConfig) logger.Logger {
var out io.Writer = os.Stderr
switch cfg.Output {
case "stdout":
case "stdout", "":
out = os.Stdout
case "stderr", "":
case "stderr":
out = os.Stderr
default:
f, err := os.OpenFile(cfg.Output, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
@ -201,7 +213,7 @@ func bypassFromConfig(cfg *config.BypassConfig) bypass.Bypass {
}
func forwarderFromConfig(cfg *config.ForwarderConfig) *chain.NodeGroup {
if cfg == nil {
if cfg == nil || len(cfg.Targets) == 0 {
return nil
}

View File

@ -11,10 +11,10 @@ services:
- name: http+tcp
url: "http://gost:gost@:8000"
addr: ":28000"
chain: chain01
# bypass: bypass01
handler:
type: http
chain: chain01
# bypass: bypass01
metadata:
proxyAgent: "gost/3.0"
retry: 3
@ -30,10 +30,10 @@ services:
- name: ss
url: "ss://chacha20:gost@:8000"
addr: ":28338"
# chain: chain01
# bypass: bypass01
handler:
type: ss
# chain: chain01
# bypass: bypass01
metadata:
method: chacha20-ietf
password: gost
@ -48,10 +48,10 @@ services:
- name: socks5
url: "socks5://gost:gost@:1080"
addr: ":21080"
# chain: chain-ss
# bypass: bypass01
handler:
type: socks5
# chain: chain-ss
# bypass: bypass01
metadata:
auths:
- gost:gost
@ -121,6 +121,7 @@ services:
- name: rtcp
addr: ":28100"
# chain: chain-socks5
forwarder:
targets:
- 192.168.8.8:80
@ -131,7 +132,6 @@ services:
retry: 3
listener:
type: rtcp
# chain: chain-socks5
metadata:
keepAlive: 15s
mux: true

View File

@ -1,9 +1,12 @@
package main
import (
stdlog "log"
"flag"
"fmt"
"net/http"
_ "net/http/pprof"
"os"
"runtime"
"github.com/go-gost/gost/pkg/config"
"github.com/go-gost/gost/pkg/logger"
@ -11,14 +14,63 @@ import (
var (
log = logger.NewLogger()
cfgFile string
outputCfgFile string
services stringList
nodes stringList
debug bool
)
func init() {
var printVersion bool
flag.Var(&services, "L", "service list")
flag.Var(&nodes, "F", "chain node list")
flag.StringVar(&cfgFile, "C", "", "configure file")
flag.BoolVar(&printVersion, "V", false, "print version")
flag.BoolVar(&debug, "D", false, "debug mode")
flag.StringVar(&outputCfgFile, "O", "", "write config to FILE")
flag.Parse()
if printVersion {
fmt.Fprintf(os.Stdout, "gost %s (%s %s/%s)\n",
version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
os.Exit(0)
}
}
func main() {
stdlog.SetFlags(stdlog.LstdFlags | stdlog.Lshortfile)
cfg := &config.Config{}
if err := cfg.Load(); err != nil {
var err error
if len(services) > 0 {
cfg, err = buildConfigFromCmd(services, nodes)
if debug && cfg != nil {
if cfg.Log == nil {
cfg.Log = &config.LogConfig{}
}
cfg.Log.Level = string(logger.DebugLevel)
}
} else {
if cfgFile != "" {
err = cfg.ReadFile(cfgFile)
} else {
err = cfg.Load()
}
}
if err != nil {
log.Fatal(err)
}
normConfig(cfg)
if outputCfgFile != "" {
if err := cfg.WriteFile(outputCfgFile); err != nil {
log.Fatal(err)
}
os.Exit(0)
}
log = logFromConfig(cfg.Log)
if cfg.Profiling != nil && cfg.Profiling.Enabled {

100
cmd/gost/norm.go Normal file
View File

@ -0,0 +1,100 @@
package main
import (
"net/url"
"strings"
"github.com/go-gost/gost/pkg/config"
)
// 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]
}
}
svc.Addr = u.Host
svc.Handler = &config.HandlerConfig{
Type: handler,
Metadata: md,
}
svc.Listener = &config.ListenerConfig{
Type: listener,
Metadata: md,
}
if remotes := strings.Trim(u.EscapedPath(), "/"); remotes != "" {
svc.Forwarder = &config.ForwarderConfig{
Targets: strings.Split(remotes, ","),
}
}
}
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]
}
}
node.Addr = u.Host
node.Connector = &config.ConnectorConfig{
Type: connector,
Metadata: md,
}
node.Dialer = &config.DialerConfig{
Type: dialer,
Metadata: md,
}
}
}
}

View File

@ -14,6 +14,7 @@ import (
// Register handlers
_ "github.com/go-gost/gost/pkg/handler/forward"
_ "github.com/go-gost/gost/pkg/handler/http"
_ "github.com/go-gost/gost/pkg/handler/relay"
_ "github.com/go-gost/gost/pkg/handler/socks/v4"
_ "github.com/go-gost/gost/pkg/handler/socks/v5"
_ "github.com/go-gost/gost/pkg/handler/ss"

5
cmd/gost/version.go Normal file
View File

@ -0,0 +1,5 @@
package main
const (
version = "3.0.0-alpha"
)