mirror of
https://github.com/go-gost/gost.git
synced 2026-10-09 12:35:45 +00:00
Compare commits
23
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4364190e6d | ||
|
|
be374b6488 | ||
|
|
ee72cea036 | ||
|
|
e587b4df7c | ||
|
|
8d8785f534 | ||
|
|
b96d37d4cc | ||
|
|
ffdf11e89e | ||
|
|
07132d8de7 | ||
|
|
0aee4f0ebd | ||
|
|
9db7137cd3 | ||
|
|
307a90c20e | ||
|
|
5daefb8e3c | ||
|
|
edca3e0a55 | ||
|
|
a8804ea02d | ||
|
|
f2d806886a | ||
|
|
fdd67a6086 | ||
|
|
345338d410 | ||
|
|
a8a6bbc3a3 | ||
|
|
c1bf501734 | ||
|
|
f1eaef8d69 | ||
|
|
0fba6d2500 | ||
|
|
1ec10ff7dd | ||
|
|
0983ecc52f |
@@ -36,7 +36,7 @@ jobs:
|
|||||||
# Set output parameters.
|
# Set output parameters.
|
||||||
echo ::set-output name=tags::${TAGS}
|
echo ::set-output name=tags::${TAGS}
|
||||||
echo ::set-output name=docker_image::${DOCKER_IMAGE}
|
echo ::set-output name=docker_image::${DOCKER_IMAGE}
|
||||||
echo ::set-output name=docker_platforms::linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8
|
echo ::set-output name=docker_platforms::linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/s390x
|
||||||
|
|
||||||
# https://github.com/crazy-max/ghaction-docker-buildx
|
# https://github.com/crazy-max/ghaction-docker-buildx
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
FROM --platform=$BUILDPLATFORM golang:1-alpine as builder
|
FROM --platform=$BUILDPLATFORM golang:1.18rc1-alpine as builder
|
||||||
|
|
||||||
# Convert TARGETPLATFORM to GOARCH format
|
# Convert TARGETPLATFORM to GOARCH format
|
||||||
# https://github.com/tonistiigi/xx
|
# https://github.com/tonistiigi/xx
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ NAME=gost
|
|||||||
BINDIR=bin
|
BINDIR=bin
|
||||||
VERSION=$(shell cat cmd/gost/version.go | grep 'version =' | sed 's/.*\"\(.*\)\".*/\1/g')
|
VERSION=$(shell cat cmd/gost/version.go | grep 'version =' | sed 's/.*\"\(.*\)\".*/\1/g')
|
||||||
GOBUILD=CGO_ENABLED=0 go build --ldflags="-s -w" -v -x -a
|
GOBUILD=CGO_ENABLED=0 go build --ldflags="-s -w" -v -x -a
|
||||||
GOFILES=cmd/gost/*
|
GOFILES=cmd/gost/*.go
|
||||||
|
|
||||||
PLATFORM_LIST = \
|
PLATFORM_LIST = \
|
||||||
darwin-amd64 \
|
darwin-amd64 \
|
||||||
@@ -19,6 +19,7 @@ PLATFORM_LIST = \
|
|||||||
linux-mipsle-hardfloat \
|
linux-mipsle-hardfloat \
|
||||||
linux-mips64 \
|
linux-mips64 \
|
||||||
linux-mips64le \
|
linux-mips64le \
|
||||||
|
linux-s390x \
|
||||||
freebsd-386 \
|
freebsd-386 \
|
||||||
freebsd-amd64
|
freebsd-amd64
|
||||||
|
|
||||||
@@ -26,7 +27,7 @@ WINDOWS_ARCH_LIST = \
|
|||||||
windows-386 \
|
windows-386 \
|
||||||
windows-amd64
|
windows-amd64
|
||||||
|
|
||||||
all: linux-amd64 darwin-amd64 windows-amd64 # Most used
|
all: linux-amd64 darwin-amd64 darwin-arm64 windows-amd64 # Most used
|
||||||
|
|
||||||
darwin-amd64:
|
darwin-amd64:
|
||||||
GOARCH=amd64 GOOS=darwin $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)
|
GOARCH=amd64 GOOS=darwin $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)
|
||||||
@@ -70,6 +71,9 @@ linux-mips64:
|
|||||||
linux-mips64le:
|
linux-mips64le:
|
||||||
GOARCH=mips64le GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)
|
GOARCH=mips64le GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)
|
||||||
|
|
||||||
|
linux-s390x:
|
||||||
|
GOARCH=s390x GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)
|
||||||
|
|
||||||
freebsd-386:
|
freebsd-386:
|
||||||
GOARCH=386 GOOS=freebsd $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)
|
GOARCH=386 GOOS=freebsd $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)
|
||||||
|
|
||||||
|
|||||||
+60
-17
@@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/go-gost/gost/pkg/config"
|
"github.com/go-gost/gost/pkg/config"
|
||||||
"github.com/go-gost/gost/pkg/metadata"
|
"github.com/go-gost/gost/pkg/metadata"
|
||||||
|
metrics "github.com/go-gost/gost/pkg/metrics/service"
|
||||||
"github.com/go-gost/gost/pkg/registry"
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,7 +36,19 @@ func buildConfigFromCmd(services, nodes stringList) (*config.Config, error) {
|
|||||||
if v := os.Getenv("GOST_PROFILING"); v != "" {
|
if v := os.Getenv("GOST_PROFILING"); v != "" {
|
||||||
cfg.Profiling = &config.ProfilingConfig{
|
cfg.Profiling = &config.ProfilingConfig{
|
||||||
Addr: v,
|
Addr: v,
|
||||||
Enabled: true,
|
Enable: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v := os.Getenv("GOST_METRICS"); v != "" {
|
||||||
|
cfg.Metrics = &config.MetricsConfig{
|
||||||
|
Addr: v,
|
||||||
|
Path: metrics.DefaultPath,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := os.Getenv("GOST_LOGGING_LEVEL"); v != "" {
|
||||||
|
cfg.Log = &config.LogConfig{
|
||||||
|
Level: v,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +120,7 @@ func buildConfigFromCmd(services, nodes stringList) (*config.Config, error) {
|
|||||||
}
|
}
|
||||||
resolverCfg.Nameservers = append(
|
resolverCfg.Nameservers = append(
|
||||||
resolverCfg.Nameservers,
|
resolverCfg.Nameservers,
|
||||||
config.NameserverConfig{
|
&config.NameserverConfig{
|
||||||
Addr: rs,
|
Addr: rs,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -127,7 +140,7 @@ func buildConfigFromCmd(services, nodes stringList) (*config.Config, error) {
|
|||||||
}
|
}
|
||||||
hostsCfg.Mappings = append(
|
hostsCfg.Mappings = append(
|
||||||
hostsCfg.Mappings,
|
hostsCfg.Mappings,
|
||||||
config.HostMappingConfig{
|
&config.HostMappingConfig{
|
||||||
Hostname: ss[0],
|
Hostname: ss[0],
|
||||||
IP: ss[1],
|
IP: ss[1],
|
||||||
},
|
},
|
||||||
@@ -138,6 +151,11 @@ func buildConfigFromCmd(services, nodes stringList) (*config.Config, error) {
|
|||||||
md.Del("hosts")
|
md.Del("hosts")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if v := metadata.GetString(md, "interface"); v != "" {
|
||||||
|
hopConfig.Interface = v
|
||||||
|
md.Del("interface")
|
||||||
|
}
|
||||||
|
|
||||||
chain.Hops = append(chain.Hops, hopConfig)
|
chain.Hops = append(chain.Hops, hopConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,6 +184,24 @@ func buildConfigFromCmd(services, nodes stringList) (*config.Config, error) {
|
|||||||
service.Handler.Retries = v
|
service.Handler.Retries = v
|
||||||
md.Del("retries")
|
md.Del("retries")
|
||||||
}
|
}
|
||||||
|
if v := metadata.GetString(md, "admission"); v != "" {
|
||||||
|
admCfg := &config.AdmissionConfig{
|
||||||
|
Name: fmt.Sprintf("admission-%d", len(cfg.Admissions)),
|
||||||
|
}
|
||||||
|
if v[0] == '~' {
|
||||||
|
admCfg.Reverse = true
|
||||||
|
v = v[1:]
|
||||||
|
}
|
||||||
|
for _, s := range strings.Split(v, ",") {
|
||||||
|
if s == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
admCfg.Matchers = append(admCfg.Matchers, s)
|
||||||
|
}
|
||||||
|
service.Admission = admCfg.Name
|
||||||
|
cfg.Admissions = append(cfg.Admissions, admCfg)
|
||||||
|
md.Del("admission")
|
||||||
|
}
|
||||||
if v := metadata.GetString(md, "bypass"); v != "" {
|
if v := metadata.GetString(md, "bypass"); v != "" {
|
||||||
bypassCfg := &config.BypassConfig{
|
bypassCfg := &config.BypassConfig{
|
||||||
Name: fmt.Sprintf("bypass-%d", len(cfg.Bypasses)),
|
Name: fmt.Sprintf("bypass-%d", len(cfg.Bypasses)),
|
||||||
@@ -194,7 +230,7 @@ func buildConfigFromCmd(services, nodes stringList) (*config.Config, error) {
|
|||||||
}
|
}
|
||||||
resolverCfg.Nameservers = append(
|
resolverCfg.Nameservers = append(
|
||||||
resolverCfg.Nameservers,
|
resolverCfg.Nameservers,
|
||||||
config.NameserverConfig{
|
&config.NameserverConfig{
|
||||||
Addr: rs,
|
Addr: rs,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -214,7 +250,7 @@ func buildConfigFromCmd(services, nodes stringList) (*config.Config, error) {
|
|||||||
}
|
}
|
||||||
hostsCfg.Mappings = append(
|
hostsCfg.Mappings = append(
|
||||||
hostsCfg.Mappings,
|
hostsCfg.Mappings,
|
||||||
config.HostMappingConfig{
|
&config.HostMappingConfig{
|
||||||
Hostname: ss[0],
|
Hostname: ss[0],
|
||||||
IP: ss[1],
|
IP: ss[1],
|
||||||
},
|
},
|
||||||
@@ -245,10 +281,10 @@ func buildServiceConfig(url *url.URL) (*config.ServiceConfig, error) {
|
|||||||
Addr: url.Host,
|
Addr: url.Host,
|
||||||
}
|
}
|
||||||
|
|
||||||
if h := registry.GetHandler(handler); h == nil {
|
if h := registry.HandlerRegistry().Get(handler); h == nil {
|
||||||
handler = "auto"
|
handler = "auto"
|
||||||
}
|
}
|
||||||
if ln := registry.GetListener(listener); ln == nil {
|
if ln := registry.ListenerRegistry().Get(listener); ln == nil {
|
||||||
listener = "tcp"
|
listener = "tcp"
|
||||||
if handler == "ssu" {
|
if handler == "ssu" {
|
||||||
listener = "udp"
|
listener = "udp"
|
||||||
@@ -271,13 +307,12 @@ func buildServiceConfig(url *url.URL) (*config.ServiceConfig, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var auths []*config.AuthConfig
|
var auth *config.AuthConfig
|
||||||
if url.User != nil {
|
if url.User != nil {
|
||||||
auth := &config.AuthConfig{
|
auth = &config.AuthConfig{
|
||||||
Username: url.User.Username(),
|
Username: url.User.Username(),
|
||||||
}
|
}
|
||||||
auth.Password, _ = url.User.Password()
|
auth.Password, _ = url.User.Password()
|
||||||
auths = append(auths, auth)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
md := metadata.MapMetadata{}
|
md := metadata.MapMetadata{}
|
||||||
@@ -292,7 +327,7 @@ func buildServiceConfig(url *url.URL) (*config.ServiceConfig, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
auths = append(auths, au)
|
auth = au
|
||||||
}
|
}
|
||||||
md.Del("auth")
|
md.Del("auth")
|
||||||
|
|
||||||
@@ -312,6 +347,10 @@ func buildServiceConfig(url *url.URL) (*config.ServiceConfig, error) {
|
|||||||
if v := metadata.GetString(md, "dns"); v != "" {
|
if v := metadata.GetString(md, "dns"); v != "" {
|
||||||
md.Set("dns", strings.Split(v, ","))
|
md.Set("dns", strings.Split(v, ","))
|
||||||
}
|
}
|
||||||
|
if v := metadata.GetString(md, "interface"); v != "" {
|
||||||
|
svc.Interface = v
|
||||||
|
md.Del("interface")
|
||||||
|
}
|
||||||
|
|
||||||
if svc.Forwarder != nil {
|
if svc.Forwarder != nil {
|
||||||
svc.Forwarder.Selector = parseSelector(md)
|
svc.Forwarder.Selector = parseSelector(md)
|
||||||
@@ -319,7 +358,7 @@ func buildServiceConfig(url *url.URL) (*config.ServiceConfig, error) {
|
|||||||
|
|
||||||
svc.Handler = &config.HandlerConfig{
|
svc.Handler = &config.HandlerConfig{
|
||||||
Type: handler,
|
Type: handler,
|
||||||
Auths: auths,
|
Auth: auth,
|
||||||
Metadata: md,
|
Metadata: md,
|
||||||
}
|
}
|
||||||
svc.Listener = &config.ListenerConfig{
|
svc.Listener = &config.ListenerConfig{
|
||||||
@@ -329,10 +368,10 @@ func buildServiceConfig(url *url.URL) (*config.ServiceConfig, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if svc.Handler.Type == "sshd" {
|
if svc.Handler.Type == "sshd" {
|
||||||
svc.Handler.Auths = nil
|
svc.Handler.Auth = nil
|
||||||
}
|
}
|
||||||
if svc.Listener.Type == "sshd" {
|
if svc.Listener.Type == "sshd" {
|
||||||
svc.Listener.Auths = auths
|
svc.Listener.Auth = auth
|
||||||
}
|
}
|
||||||
|
|
||||||
return svc, nil
|
return svc, nil
|
||||||
@@ -354,10 +393,10 @@ func buildNodeConfig(url *url.URL) (*config.NodeConfig, error) {
|
|||||||
Addr: url.Host,
|
Addr: url.Host,
|
||||||
}
|
}
|
||||||
|
|
||||||
if c := registry.GetConnector(connector); c == nil {
|
if c := registry.ConnectorRegistry().Get(connector); c == nil {
|
||||||
connector = "http"
|
connector = "http"
|
||||||
}
|
}
|
||||||
if d := registry.GetDialer(dialer); d == nil {
|
if d := registry.DialerRegistry().Get(dialer); d == nil {
|
||||||
dialer = "tcp"
|
dialer = "tcp"
|
||||||
if connector == "ssu" {
|
if connector == "ssu" {
|
||||||
dialer = "udp"
|
dialer = "udp"
|
||||||
@@ -389,6 +428,8 @@ func buildNodeConfig(url *url.URL) (*config.NodeConfig, error) {
|
|||||||
md.Del("auth")
|
md.Del("auth")
|
||||||
|
|
||||||
tlsConfig := &config.TLSConfig{
|
tlsConfig := &config.TLSConfig{
|
||||||
|
CertFile: metadata.GetString(md, "certFile"),
|
||||||
|
KeyFile: metadata.GetString(md, "keyFile"),
|
||||||
CAFile: metadata.GetString(md, "caFile"),
|
CAFile: metadata.GetString(md, "caFile"),
|
||||||
Secure: metadata.GetBool(md, "secure"),
|
Secure: metadata.GetBool(md, "secure"),
|
||||||
ServerName: metadata.GetString(md, "serverName"),
|
ServerName: metadata.GetString(md, "serverName"),
|
||||||
@@ -396,11 +437,13 @@ func buildNodeConfig(url *url.URL) (*config.NodeConfig, error) {
|
|||||||
if tlsConfig.ServerName == "" {
|
if tlsConfig.ServerName == "" {
|
||||||
tlsConfig.ServerName = url.Hostname()
|
tlsConfig.ServerName = url.Hostname()
|
||||||
}
|
}
|
||||||
|
md.Del("certFile")
|
||||||
|
md.Del("keyFile")
|
||||||
md.Del("caFile")
|
md.Del("caFile")
|
||||||
md.Del("secure")
|
md.Del("secure")
|
||||||
md.Del("serverName")
|
md.Del("serverName")
|
||||||
|
|
||||||
if !tlsConfig.Secure && tlsConfig.CAFile == "" {
|
if !tlsConfig.Secure && tlsConfig.CertFile == "" && tlsConfig.CAFile == "" {
|
||||||
tlsConfig = nil
|
tlsConfig = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+63
-358
@@ -1,308 +1,95 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"io"
|
"io"
|
||||||
"net"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/go-gost/gost/pkg/bypass"
|
"github.com/go-gost/gost/pkg/api"
|
||||||
"github.com/go-gost/gost/pkg/chain"
|
|
||||||
"github.com/go-gost/gost/pkg/config"
|
"github.com/go-gost/gost/pkg/config"
|
||||||
"github.com/go-gost/gost/pkg/connector"
|
"github.com/go-gost/gost/pkg/config/parsing"
|
||||||
"github.com/go-gost/gost/pkg/dialer"
|
|
||||||
"github.com/go-gost/gost/pkg/handler"
|
|
||||||
hostspkg "github.com/go-gost/gost/pkg/hosts"
|
|
||||||
"github.com/go-gost/gost/pkg/listener"
|
|
||||||
"github.com/go-gost/gost/pkg/logger"
|
"github.com/go-gost/gost/pkg/logger"
|
||||||
"github.com/go-gost/gost/pkg/metadata"
|
metrics "github.com/go-gost/gost/pkg/metrics/service"
|
||||||
"github.com/go-gost/gost/pkg/registry"
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
"github.com/go-gost/gost/pkg/resolver"
|
|
||||||
resolver_impl "github.com/go-gost/gost/pkg/resolver/impl"
|
|
||||||
"github.com/go-gost/gost/pkg/service"
|
"github.com/go-gost/gost/pkg/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func buildService(cfg *config.Config) (services []service.Service) {
|
||||||
chains = make(map[string]*chain.Chain)
|
if cfg == nil {
|
||||||
bypasses = make(map[string]bypass.Bypass)
|
|
||||||
resolvers = make(map[string]resolver.Resolver)
|
|
||||||
hosts = make(map[string]hostspkg.HostMapper)
|
|
||||||
)
|
|
||||||
|
|
||||||
func buildService(cfg *config.Config) (services []*service.Service) {
|
|
||||||
if cfg == nil || len(cfg.Services) == 0 {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, autherCfg := range cfg.Authers {
|
||||||
|
if auther := parsing.ParseAuther(autherCfg); auther != nil {
|
||||||
|
if err := registry.AutherRegistry().Register(autherCfg.Name, auther); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, admissionCfg := range cfg.Admissions {
|
||||||
|
if adm := parsing.ParseAdmission(admissionCfg); adm != nil {
|
||||||
|
if err := registry.AdmissionRegistry().Register(admissionCfg.Name, adm); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, bypassCfg := range cfg.Bypasses {
|
for _, bypassCfg := range cfg.Bypasses {
|
||||||
bypasses[bypassCfg.Name] = bypassFromConfig(bypassCfg)
|
if bp := parsing.ParseBypass(bypassCfg); bp != nil {
|
||||||
|
if err := registry.BypassRegistry().Register(bypassCfg.Name, bp); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, resolverCfg := range cfg.Resolvers {
|
for _, resolverCfg := range cfg.Resolvers {
|
||||||
r, err := resolverFromConfig(resolverCfg)
|
r, err := parsing.ParseResolver(resolverCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
resolvers[resolverCfg.Name] = r
|
if r != nil {
|
||||||
|
if err := registry.ResolverRegistry().Register(resolverCfg.Name, r); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, hostsCfg := range cfg.Hosts {
|
for _, hostsCfg := range cfg.Hosts {
|
||||||
hosts[hostsCfg.Name] = hostsFromConfig(hostsCfg)
|
if h := parsing.ParseHosts(hostsCfg); h != nil {
|
||||||
|
if err := registry.HostsRegistry().Register(hostsCfg.Name, h); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, chainCfg := range cfg.Chains {
|
for _, chainCfg := range cfg.Chains {
|
||||||
chains[chainCfg.Name] = chainFromConfig(chainCfg)
|
c, err := parsing.ParseChain(chainCfg)
|
||||||
}
|
|
||||||
|
|
||||||
for _, svc := range cfg.Services {
|
|
||||||
if svc.Listener == nil {
|
|
||||||
svc.Listener = &config.ListenerConfig{
|
|
||||||
Type: "tcp",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if svc.Handler == nil {
|
|
||||||
svc.Handler = &config.HandlerConfig{
|
|
||||||
Type: "auto",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
serviceLogger := log.WithFields(map[string]interface{}{
|
|
||||||
"kind": "service",
|
|
||||||
"service": svc.Name,
|
|
||||||
"listener": svc.Listener.Type,
|
|
||||||
"handler": svc.Handler.Type,
|
|
||||||
})
|
|
||||||
|
|
||||||
listenerLogger := serviceLogger.WithFields(map[string]interface{}{
|
|
||||||
"kind": "listener",
|
|
||||||
})
|
|
||||||
|
|
||||||
var tlsConfig *tls.Config
|
|
||||||
var err error
|
|
||||||
|
|
||||||
tlsCfg := svc.Listener.TLS
|
|
||||||
if tlsCfg == nil {
|
|
||||||
tlsCfg = &config.TLSConfig{}
|
|
||||||
}
|
|
||||||
tlsConfig, err = loadServerTLSConfig(tlsCfg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
if c != nil {
|
||||||
ln := registry.GetListener(svc.Listener.Type)(
|
if err := registry.ChainRegistry().Register(chainCfg.Name, c); err != nil {
|
||||||
listener.AddrOption(svc.Addr),
|
log.Fatal(err)
|
||||||
listener.ChainOption(chains[svc.Listener.Chain]),
|
}
|
||||||
listener.AuthsOption(authsFromConfig(svc.Listener.Auths...)...),
|
|
||||||
listener.TLSConfigOption(tlsConfig),
|
|
||||||
listener.LoggerOption(listenerLogger),
|
|
||||||
)
|
|
||||||
|
|
||||||
if svc.Listener.Metadata == nil {
|
|
||||||
svc.Listener.Metadata = make(map[string]interface{})
|
|
||||||
}
|
}
|
||||||
if err := ln.Init(metadata.MapMetadata(svc.Listener.Metadata)); err != nil {
|
|
||||||
listenerLogger.Fatal("init: ", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handlerLogger := serviceLogger.WithFields(map[string]interface{}{
|
for _, svcCfg := range cfg.Services {
|
||||||
"kind": "handler",
|
svc, err := parsing.ParseService(svcCfg)
|
||||||
})
|
|
||||||
|
|
||||||
tlsConfig = nil
|
|
||||||
tlsCfg = svc.Handler.TLS
|
|
||||||
if tlsCfg == nil {
|
|
||||||
tlsCfg = &config.TLSConfig{}
|
|
||||||
}
|
|
||||||
tlsConfig, err = loadServerTLSConfig(tlsCfg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
if svc != nil {
|
||||||
h := registry.GetHandler(svc.Handler.Type)(
|
if err := registry.ServiceRegistry().Register(svcCfg.Name, svc); err != nil {
|
||||||
handler.AuthsOption(authsFromConfig(svc.Handler.Auths...)...),
|
log.Fatal(err)
|
||||||
handler.RetriesOption(svc.Handler.Retries),
|
|
||||||
handler.ChainOption(chains[svc.Handler.Chain]),
|
|
||||||
handler.BypassOption(bypasses[svc.Bypass]),
|
|
||||||
handler.ResolverOption(resolvers[svc.Resolver]),
|
|
||||||
handler.HostsOption(hosts[svc.Hosts]),
|
|
||||||
handler.TLSConfigOption(tlsConfig),
|
|
||||||
handler.LoggerOption(handlerLogger),
|
|
||||||
)
|
|
||||||
|
|
||||||
if forwarder, ok := h.(handler.Forwarder); ok {
|
|
||||||
forwarder.Forward(forwarderFromConfig(svc.Forwarder))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if svc.Handler.Metadata == nil {
|
|
||||||
svc.Handler.Metadata = make(map[string]interface{})
|
|
||||||
}
|
}
|
||||||
if err := h.Init(metadata.MapMetadata(svc.Handler.Metadata)); err != nil {
|
services = append(services, svc)
|
||||||
handlerLogger.Fatal("init: ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
s := (&service.Service{}).
|
|
||||||
WithListener(ln).
|
|
||||||
WithHandler(h).
|
|
||||||
WithLogger(serviceLogger)
|
|
||||||
services = append(services, s)
|
|
||||||
|
|
||||||
serviceLogger.Infof("listening on %s/%s", s.Addr().String(), s.Addr().Network())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func chainFromConfig(cfg *config.ChainConfig) *chain.Chain {
|
|
||||||
if cfg == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
chainLogger := log.WithFields(map[string]interface{}{
|
|
||||||
"kind": "chain",
|
|
||||||
"chain": cfg.Name,
|
|
||||||
})
|
|
||||||
|
|
||||||
c := &chain.Chain{}
|
|
||||||
selector := selectorFromConfig(cfg.Selector)
|
|
||||||
for _, hop := range cfg.Hops {
|
|
||||||
group := &chain.NodeGroup{}
|
|
||||||
for _, v := range hop.Nodes {
|
|
||||||
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 user *url.Userinfo
|
|
||||||
if auth := v.Connector.Auth; auth != nil && auth.Username != "" {
|
|
||||||
if auth.Password == "" {
|
|
||||||
user = url.User(auth.Username)
|
|
||||||
} else {
|
|
||||||
user = url.UserPassword(auth.Username, auth.Password)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var tlsConfig *tls.Config
|
|
||||||
var err error
|
|
||||||
tlsCfg := v.Connector.TLS
|
|
||||||
if tlsCfg == nil {
|
|
||||||
tlsCfg = &config.TLSConfig{}
|
|
||||||
}
|
|
||||||
tlsConfig, err = loadClientTLSConfig(tlsCfg)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cr := registry.GetConnector(v.Connector.Type)(
|
|
||||||
connector.UserOption(user),
|
|
||||||
connector.TLSConfigOption(tlsConfig),
|
|
||||||
connector.LoggerOption(connectorLogger),
|
|
||||||
)
|
|
||||||
|
|
||||||
if v.Connector.Metadata == nil {
|
|
||||||
v.Connector.Metadata = make(map[string]interface{})
|
|
||||||
}
|
|
||||||
if err := cr.Init(metadata.MapMetadata(v.Connector.Metadata)); err != nil {
|
|
||||||
connectorLogger.Fatal("init: ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
dialerLogger := nodeLogger.WithFields(map[string]interface{}{
|
|
||||||
"kind": "dialer",
|
|
||||||
})
|
|
||||||
|
|
||||||
user = nil
|
|
||||||
if auth := v.Dialer.Auth; auth != nil && auth.Username != "" {
|
|
||||||
if auth.Password == "" {
|
|
||||||
user = url.User(auth.Username)
|
|
||||||
} else {
|
|
||||||
user = url.UserPassword(auth.Username, auth.Password)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tlsConfig = nil
|
|
||||||
tlsCfg = v.Dialer.TLS
|
|
||||||
if tlsCfg == nil {
|
|
||||||
tlsCfg = &config.TLSConfig{}
|
|
||||||
}
|
|
||||||
tlsConfig, err = loadClientTLSConfig(tlsCfg)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
d := registry.GetDialer(v.Dialer.Type)(
|
|
||||||
dialer.UserOption(user),
|
|
||||||
dialer.TLSConfigOption(tlsConfig),
|
|
||||||
dialer.LoggerOption(dialerLogger),
|
|
||||||
)
|
|
||||||
|
|
||||||
if v.Dialer.Metadata == nil {
|
|
||||||
v.Dialer.Metadata = make(map[string]interface{})
|
|
||||||
}
|
|
||||||
if err := d.Init(metadata.MapMetadata(v.Dialer.Metadata)); err != nil {
|
|
||||||
dialerLogger.Fatal("init: ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tr := (&chain.Transport{}).
|
|
||||||
WithConnector(cr).
|
|
||||||
WithDialer(d).
|
|
||||||
WithAddr(v.Addr)
|
|
||||||
|
|
||||||
if v.Bypass == "" {
|
|
||||||
v.Bypass = hop.Bypass
|
|
||||||
}
|
|
||||||
if v.Resolver == "" {
|
|
||||||
v.Resolver = hop.Resolver
|
|
||||||
}
|
|
||||||
if v.Hosts == "" {
|
|
||||||
v.Hosts = hop.Hosts
|
|
||||||
}
|
|
||||||
|
|
||||||
node := &chain.Node{
|
|
||||||
Name: v.Name,
|
|
||||||
Addr: v.Addr,
|
|
||||||
Transport: tr,
|
|
||||||
Bypass: bypasses[v.Bypass],
|
|
||||||
Resolver: resolvers[v.Resolver],
|
|
||||||
Hosts: hosts[v.Hosts],
|
|
||||||
Marker: &chain.FailMarker{},
|
|
||||||
}
|
|
||||||
group.AddNode(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
sel := selector
|
|
||||||
if s := selectorFromConfig(hop.Selector); s != nil {
|
|
||||||
sel = s
|
|
||||||
}
|
|
||||||
group.WithSelector(sel)
|
|
||||||
c.AddNodeGroup(group)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func forwarderFromConfig(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(selectorFromConfig(cfg.Selector))
|
|
||||||
}
|
|
||||||
|
|
||||||
func logFromConfig(cfg *config.LogConfig) logger.Logger {
|
func logFromConfig(cfg *config.LogConfig) logger.Logger {
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
cfg = &config.LogConfig{}
|
cfg = &config.LogConfig{}
|
||||||
@@ -314,7 +101,7 @@ func logFromConfig(cfg *config.LogConfig) logger.Logger {
|
|||||||
|
|
||||||
var out io.Writer = os.Stderr
|
var out io.Writer = os.Stderr
|
||||||
switch cfg.Output {
|
switch cfg.Output {
|
||||||
case "none":
|
case "none", "null":
|
||||||
return logger.Nop()
|
return logger.Nop()
|
||||||
case "stdout":
|
case "stdout":
|
||||||
out = os.Stdout
|
out = os.Stdout
|
||||||
@@ -333,104 +120,22 @@ func logFromConfig(cfg *config.LogConfig) logger.Logger {
|
|||||||
return logger.NewLogger(opts...)
|
return logger.NewLogger(opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectorFromConfig(cfg *config.SelectorConfig) chain.Selector {
|
func buildAPIService(cfg *config.APIConfig) (service.Service, error) {
|
||||||
if cfg == nil {
|
auther := parsing.ParseAutherFromAuth(cfg.Auth)
|
||||||
return nil
|
if cfg.Auther != "" {
|
||||||
|
auther = registry.AutherRegistry().Get(cfg.Auther)
|
||||||
}
|
}
|
||||||
|
return api.NewService(
|
||||||
var strategy chain.Strategy
|
cfg.Addr,
|
||||||
switch cfg.Strategy {
|
api.PathPrefixOption(cfg.PathPrefix),
|
||||||
case "round", "rr":
|
api.AccessLogOption(cfg.AccessLog),
|
||||||
strategy = chain.RoundRobinStrategy()
|
api.AutherOption(auther),
|
||||||
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 bypassFromConfig(cfg *config.BypassConfig) bypass.Bypass {
|
func buildMetricsService(cfg *config.MetricsConfig) (service.Service, error) {
|
||||||
if cfg == nil {
|
return metrics.NewService(
|
||||||
return nil
|
cfg.Addr,
|
||||||
}
|
metrics.PathOption(cfg.Path),
|
||||||
return bypass.NewBypassPatterns(
|
|
||||||
cfg.Reverse,
|
|
||||||
cfg.Matchers,
|
|
||||||
bypass.LoggerBypassOption(log.WithFields(map[string]interface{}{
|
|
||||||
"kind": "bypass",
|
|
||||||
"bypass": cfg.Name,
|
|
||||||
})),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolverFromConfig(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: chains[server.Chain],
|
|
||||||
TTL: server.TTL,
|
|
||||||
Timeout: server.Timeout,
|
|
||||||
ClientIP: net.ParseIP(server.ClientIP),
|
|
||||||
Prefer: server.Prefer,
|
|
||||||
Hostname: server.Hostname,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
logger := log.WithFields(map[string]interface{}{
|
|
||||||
"kind": "resolver",
|
|
||||||
"resolver": cfg.Name,
|
|
||||||
})
|
|
||||||
return resolver_impl.NewResolver(
|
|
||||||
nameservers,
|
|
||||||
resolver_impl.LoggerResolverOption(logger),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func hostsFromConfig(cfg *config.HostsConfig) hostspkg.HostMapper {
|
|
||||||
if cfg == nil || len(cfg.Mappings) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
hosts := hostspkg.NewHosts()
|
|
||||||
hosts.Logger = log.WithFields(map[string]interface{}{
|
|
||||||
"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 authsFromConfig(cfgs ...*config.AuthConfig) []*url.Userinfo {
|
|
||||||
var auths []*url.Userinfo
|
|
||||||
|
|
||||||
for _, cfg := range cfgs {
|
|
||||||
if cfg == nil || cfg.Username == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
auths = append(auths, url.UserPassword(cfg.Username, cfg.Password))
|
|
||||||
}
|
|
||||||
|
|
||||||
return auths
|
|
||||||
}
|
|
||||||
|
|||||||
+54
-20
@@ -3,7 +3,6 @@ package main
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
_ "net/http/pprof"
|
_ "net/http/pprof"
|
||||||
"os"
|
"os"
|
||||||
@@ -11,16 +10,19 @@ import (
|
|||||||
|
|
||||||
"github.com/go-gost/gost/pkg/config"
|
"github.com/go-gost/gost/pkg/config"
|
||||||
"github.com/go-gost/gost/pkg/logger"
|
"github.com/go-gost/gost/pkg/logger"
|
||||||
|
metrics "github.com/go-gost/gost/pkg/metrics/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
log = logger.Default()
|
log = logger.Default()
|
||||||
|
|
||||||
cfgFile string
|
cfgFile string
|
||||||
outputCfgFile string
|
outputFormat string
|
||||||
services stringList
|
services stringList
|
||||||
nodes stringList
|
nodes stringList
|
||||||
debug bool
|
debug bool
|
||||||
|
apiAddr string
|
||||||
|
metricsAddr string
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -30,8 +32,10 @@ func init() {
|
|||||||
flag.Var(&nodes, "F", "chain node list")
|
flag.Var(&nodes, "F", "chain node list")
|
||||||
flag.StringVar(&cfgFile, "C", "", "configure file")
|
flag.StringVar(&cfgFile, "C", "", "configure file")
|
||||||
flag.BoolVar(&printVersion, "V", false, "print version")
|
flag.BoolVar(&printVersion, "V", false, "print version")
|
||||||
|
flag.StringVar(&outputFormat, "O", "", "output format, one of yaml|json format")
|
||||||
flag.BoolVar(&debug, "D", false, "debug mode")
|
flag.BoolVar(&debug, "D", false, "debug mode")
|
||||||
flag.StringVar(&outputCfgFile, "O", "", "write config to FILE")
|
flag.StringVar(&apiAddr, "api", "", "api service address")
|
||||||
|
flag.StringVar(&metricsAddr, "metrics", "", "metrics service address")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if printVersion {
|
if printVersion {
|
||||||
@@ -44,7 +48,7 @@ func init() {
|
|||||||
func main() {
|
func main() {
|
||||||
cfg := &config.Config{}
|
cfg := &config.Config{}
|
||||||
var err error
|
var err error
|
||||||
if len(services) > 0 {
|
if len(services) > 0 || apiAddr != "" {
|
||||||
cfg, err = buildConfigFromCmd(services, nodes)
|
cfg, err = buildConfigFromCmd(services, nodes)
|
||||||
if debug && cfg != nil {
|
if debug && cfg != nil {
|
||||||
if cfg.Log == nil {
|
if cfg.Log == nil {
|
||||||
@@ -52,6 +56,17 @@ func main() {
|
|||||||
}
|
}
|
||||||
cfg.Log.Level = string(logger.DebugLevel)
|
cfg.Log.Level = string(logger.DebugLevel)
|
||||||
}
|
}
|
||||||
|
if apiAddr != "" {
|
||||||
|
cfg.API = &config.APIConfig{
|
||||||
|
Addr: apiAddr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if metricsAddr != "" {
|
||||||
|
cfg.Metrics = &config.MetricsConfig{
|
||||||
|
Addr: metricsAddr,
|
||||||
|
Path: metrics.DefaultPath,
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if cfgFile != "" {
|
if cfgFile != "" {
|
||||||
err = cfg.ReadFile(cfgFile)
|
err = cfg.ReadFile(cfgFile)
|
||||||
@@ -65,41 +80,60 @@ func main() {
|
|||||||
|
|
||||||
log = logFromConfig(cfg.Log)
|
log = logFromConfig(cfg.Log)
|
||||||
|
|
||||||
if outputCfgFile != "" {
|
logger.SetDefault(log)
|
||||||
var w io.Writer
|
|
||||||
if outputCfgFile == "-" {
|
if outputFormat != "" {
|
||||||
w = os.Stdout
|
if err := cfg.Write(os.Stdout, outputFormat); err != nil {
|
||||||
} else {
|
|
||||||
f, err := os.Create(outputCfgFile)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
w = f
|
|
||||||
}
|
|
||||||
if err := cfg.Write(w); err != nil {
|
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Profiling != nil && cfg.Profiling.Enabled {
|
if cfg.Profiling != nil && cfg.Profiling.Enable {
|
||||||
go func() {
|
go func() {
|
||||||
addr := cfg.Profiling.Addr
|
addr := cfg.Profiling.Addr
|
||||||
if addr == "" {
|
if addr == "" {
|
||||||
addr = ":6060"
|
addr = ":6060"
|
||||||
}
|
}
|
||||||
log.Info("profiling serve on ", addr)
|
log.Info("profiling server on ", addr)
|
||||||
log.Fatal(http.ListenAndServe(addr, nil))
|
log.Fatal(http.ListenAndServe(addr, nil))
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.API != nil {
|
||||||
|
s, err := buildAPIService(cfg.API)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
log.Info("api service on ", s.Addr())
|
||||||
|
log.Fatal(s.Serve())
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Metrics != nil {
|
||||||
|
s, err := buildMetricsService(cfg.Metrics)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
log.Info("metrics service on ", s.Addr())
|
||||||
|
log.Fatal(s.Serve())
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
buildDefaultTLSConfig(cfg.TLS)
|
buildDefaultTLSConfig(cfg.TLS)
|
||||||
|
|
||||||
services := buildService(cfg)
|
services := buildService(cfg)
|
||||||
for _, svc := range services {
|
for _, svc := range services {
|
||||||
go svc.Run()
|
go svc.Serve()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
select {}
|
select {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
_ "github.com/go-gost/gost/pkg/dialer/http2"
|
_ "github.com/go-gost/gost/pkg/dialer/http2"
|
||||||
_ "github.com/go-gost/gost/pkg/dialer/http2/h2"
|
_ "github.com/go-gost/gost/pkg/dialer/http2/h2"
|
||||||
_ "github.com/go-gost/gost/pkg/dialer/http3"
|
_ "github.com/go-gost/gost/pkg/dialer/http3"
|
||||||
|
_ "github.com/go-gost/gost/pkg/dialer/icmp"
|
||||||
_ "github.com/go-gost/gost/pkg/dialer/kcp"
|
_ "github.com/go-gost/gost/pkg/dialer/kcp"
|
||||||
_ "github.com/go-gost/gost/pkg/dialer/obfs/http"
|
_ "github.com/go-gost/gost/pkg/dialer/obfs/http"
|
||||||
_ "github.com/go-gost/gost/pkg/dialer/obfs/tls"
|
_ "github.com/go-gost/gost/pkg/dialer/obfs/tls"
|
||||||
@@ -58,6 +59,7 @@ import (
|
|||||||
_ "github.com/go-gost/gost/pkg/listener/http2"
|
_ "github.com/go-gost/gost/pkg/listener/http2"
|
||||||
_ "github.com/go-gost/gost/pkg/listener/http2/h2"
|
_ "github.com/go-gost/gost/pkg/listener/http2/h2"
|
||||||
_ "github.com/go-gost/gost/pkg/listener/http3"
|
_ "github.com/go-gost/gost/pkg/listener/http3"
|
||||||
|
_ "github.com/go-gost/gost/pkg/listener/icmp"
|
||||||
_ "github.com/go-gost/gost/pkg/listener/kcp"
|
_ "github.com/go-gost/gost/pkg/listener/kcp"
|
||||||
_ "github.com/go-gost/gost/pkg/listener/obfs/http"
|
_ "github.com/go-gost/gost/pkg/listener/obfs/http"
|
||||||
_ "github.com/go-gost/gost/pkg/listener/obfs/tls"
|
_ "github.com/go-gost/gost/pkg/listener/obfs/tls"
|
||||||
|
|||||||
+12
-11
@@ -14,14 +14,6 @@ import (
|
|||||||
"github.com/go-gost/gost/pkg/config"
|
"github.com/go-gost/gost/pkg/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func loadServerTLSConfig(cfg *config.TLSConfig) (*tls.Config, error) {
|
|
||||||
return tls_util.LoadServerConfig(cfg.CertFile, cfg.KeyFile, cfg.CAFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadClientTLSConfig(cfg *config.TLSConfig) (*tls.Config, error) {
|
|
||||||
return tls_util.LoadClientConfig(cfg.CertFile, cfg.KeyFile, cfg.CAFile, cfg.Secure, cfg.ServerName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildDefaultTLSConfig(cfg *config.TLSConfig) {
|
func buildDefaultTLSConfig(cfg *config.TLSConfig) {
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
cfg = &config.TLSConfig{
|
cfg = &config.TLSConfig{
|
||||||
@@ -80,12 +72,15 @@ func generateKeyPair() (rawCert, rawKey []byte, err error) {
|
|||||||
notBefore := time.Now()
|
notBefore := time.Now()
|
||||||
notAfter := notBefore.Add(validFor)
|
notAfter := notBefore.Add(validFor)
|
||||||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||||
serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)
|
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
template := x509.Certificate{
|
template := x509.Certificate{
|
||||||
SerialNumber: serialNumber,
|
SerialNumber: serialNumber,
|
||||||
Subject: pkix.Name{
|
Subject: pkix.Name{
|
||||||
Organization: []string{"gost"},
|
Organization: []string{"gost"},
|
||||||
CommonName: "gost.run",
|
|
||||||
},
|
},
|
||||||
NotBefore: notBefore,
|
NotBefore: notBefore,
|
||||||
NotAfter: notAfter,
|
NotAfter: notAfter,
|
||||||
@@ -94,13 +89,19 @@ func generateKeyPair() (rawCert, rawKey []byte, err error) {
|
|||||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||||
BasicConstraintsValid: true,
|
BasicConstraintsValid: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template.DNSNames = append(template.DNSNames, "gost.run")
|
||||||
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
|
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rawCert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
rawCert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
||||||
rawKey = pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
|
privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rawKey = pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privBytes})
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
const (
|
const (
|
||||||
version = "3.0.0-alpha.1"
|
version = "3.0.0-alpha.3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,73 +1,93 @@
|
|||||||
module github.com/go-gost/gost
|
module github.com/go-gost/gost
|
||||||
|
|
||||||
go 1.17
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed
|
github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed
|
||||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
|
|
||||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
|
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
|
||||||
github.com/cheekybits/genny v1.0.0 // indirect
|
|
||||||
github.com/coreos/go-iptables v0.5.0 // indirect
|
|
||||||
github.com/docker/libcontainer v2.2.1+incompatible
|
github.com/docker/libcontainer v2.2.1+incompatible
|
||||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
github.com/gin-contrib/cors v1.3.1
|
||||||
|
github.com/gin-gonic/gin v1.7.7
|
||||||
github.com/go-gost/gosocks4 v0.0.1
|
github.com/go-gost/gosocks4 v0.0.1
|
||||||
github.com/go-gost/gosocks5 v0.3.1-0.20211109033403-d894d75b7f09
|
github.com/go-gost/gosocks5 v0.3.1-0.20211109033403-d894d75b7f09
|
||||||
github.com/go-gost/relay v0.1.1-0.20211123134818-8ef7fd81ffd7
|
github.com/go-gost/relay v0.1.1-0.20211123134818-8ef7fd81ffd7
|
||||||
github.com/go-gost/tls-dissector v0.0.2-0.20211125135007-2b5d5bd9c07e
|
github.com/go-gost/tls-dissector v0.0.2-0.20211125135007-2b5d5bd9c07e
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
|
||||||
github.com/gobwas/glob v0.2.3
|
github.com/gobwas/glob v0.2.3
|
||||||
github.com/golang/snappy v0.0.3
|
github.com/golang/snappy v0.0.3
|
||||||
github.com/google/gopacket v1.1.19 // indirect
|
|
||||||
github.com/gorilla/websocket v1.4.2
|
github.com/gorilla/websocket v1.4.2
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/lucas-clemente/quic-go v0.25.0
|
||||||
github.com/klauspost/cpuid v1.3.1 // indirect
|
|
||||||
github.com/klauspost/reedsolomon v1.9.9 // indirect
|
|
||||||
github.com/lucas-clemente/quic-go v0.24.0
|
|
||||||
github.com/magiconair/properties v1.8.5 // indirect
|
|
||||||
github.com/marten-seemann/qtls-go1-16 v0.1.4 // indirect
|
|
||||||
github.com/marten-seemann/qtls-go1-17 v0.1.0 // indirect
|
|
||||||
github.com/miekg/dns v1.1.45
|
github.com/miekg/dns v1.1.45
|
||||||
github.com/milosgajdos/tenus v0.0.3
|
github.com/milosgajdos/tenus v0.0.3
|
||||||
github.com/mitchellh/mapstructure v1.4.2 // indirect
|
github.com/prometheus/client_golang v1.12.1
|
||||||
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104 // indirect
|
|
||||||
github.com/nxadm/tail v1.4.8 // indirect
|
|
||||||
github.com/onsi/ginkgo v1.16.4 // indirect
|
|
||||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
|
||||||
github.com/rs/xid v1.3.0
|
github.com/rs/xid v1.3.0
|
||||||
github.com/shadowsocks/go-shadowsocks2 v0.1.4
|
github.com/shadowsocks/go-shadowsocks2 v0.1.4
|
||||||
github.com/shadowsocks/shadowsocks-go v0.0.0-20200409064450-3e585ff90601
|
github.com/shadowsocks/shadowsocks-go v0.0.0-20200409064450-3e585ff90601
|
||||||
github.com/sirupsen/logrus v1.8.1
|
github.com/sirupsen/logrus v1.8.1
|
||||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
|
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
|
||||||
github.com/spf13/afero v1.6.0 // indirect
|
|
||||||
github.com/spf13/cast v1.4.1 // indirect
|
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
|
||||||
github.com/spf13/viper v1.9.0
|
github.com/spf13/viper v1.9.0
|
||||||
github.com/subosito/gotenv v1.2.0 // indirect
|
|
||||||
github.com/templexxx/cpu v0.0.7 // indirect
|
|
||||||
github.com/templexxx/xorsimd v0.4.1 // indirect
|
|
||||||
github.com/tjfoc/gmsm v1.3.2 // indirect
|
|
||||||
github.com/xtaci/kcp-go/v5 v5.6.1
|
github.com/xtaci/kcp-go/v5 v5.6.1
|
||||||
github.com/xtaci/smux v1.5.16
|
github.com/xtaci/smux v1.5.16
|
||||||
github.com/xtaci/tcpraw v1.2.25
|
github.com/xtaci/tcpraw v1.2.25
|
||||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
|
golang.org/x/crypto v0.0.0-20220214200702-86341886e292
|
||||||
golang.org/x/mod v0.4.2 // indirect
|
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
|
||||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
|
golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7
|
||||||
golang.org/x/text v0.3.7 // indirect
|
|
||||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 // indirect
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
|
||||||
google.golang.org/grpc v1.44.0
|
google.golang.org/grpc v1.44.0
|
||||||
gopkg.in/ini.v1 v1.63.2 // indirect
|
google.golang.org/protobuf v1.27.1
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||||
|
github.com/cheekybits/genny v1.0.0 // indirect
|
||||||
|
github.com/coreos/go-iptables v0.5.0 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||||
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
|
github.com/go-playground/locales v0.13.0 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.17.0 // indirect
|
||||||
|
github.com/go-playground/validator/v10 v10.4.1 // indirect
|
||||||
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
|
github.com/google/gopacket v1.1.19 // indirect
|
||||||
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/klauspost/cpuid v1.3.1 // indirect
|
||||||
|
github.com/klauspost/reedsolomon v1.9.9 // indirect
|
||||||
|
github.com/leodido/go-urn v1.2.0 // indirect
|
||||||
|
github.com/magiconair/properties v1.8.5 // indirect
|
||||||
github.com/marten-seemann/qpack v0.2.1 // indirect
|
github.com/marten-seemann/qpack v0.2.1 // indirect
|
||||||
|
github.com/marten-seemann/qtls-go1-16 v0.1.4 // indirect
|
||||||
|
github.com/marten-seemann/qtls-go1-17 v0.1.0 // indirect
|
||||||
|
github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.4.2 // indirect
|
||||||
|
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/nxadm/tail v1.4.8 // indirect
|
||||||
|
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||||
|
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/prometheus/client_model v0.2.0 // indirect
|
||||||
|
github.com/prometheus/common v0.32.1 // indirect
|
||||||
|
github.com/prometheus/procfs v0.7.3 // indirect
|
||||||
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||||
|
github.com/spf13/afero v1.6.0 // indirect
|
||||||
|
github.com/spf13/cast v1.4.1 // indirect
|
||||||
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/subosito/gotenv v1.2.0 // indirect
|
||||||
|
github.com/templexxx/cpu v0.0.7 // indirect
|
||||||
|
github.com/templexxx/xorsimd v0.4.1 // indirect
|
||||||
|
github.com/tjfoc/gmsm v1.3.2 // indirect
|
||||||
|
github.com/ugorji/go/codec v1.1.7 // indirect
|
||||||
|
golang.org/x/mod v0.5.1 // indirect
|
||||||
|
golang.org/x/text v0.3.7 // indirect
|
||||||
|
golang.org/x/tools v0.1.9 // indirect
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350 // indirect
|
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350 // indirect
|
||||||
google.golang.org/protobuf v1.27.1 // indirect
|
gopkg.in/ini.v1 v1.63.2 // indirect
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -56,6 +56,11 @@ github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed/go.mod h1:rA
|
|||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
|
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
|
||||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
|
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
|
||||||
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||||
@@ -65,12 +70,17 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI
|
|||||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ=
|
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
||||||
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
@@ -114,6 +124,13 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4
|
|||||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/gin-contrib/cors v1.3.1 h1:doAsuITavI4IOcd0Y19U4B+O0dNWihRyX//nn4sEmgA=
|
||||||
|
github.com/gin-contrib/cors v1.3.1/go.mod h1:jjEJ4268OPZUcU7k9Pm653S7lXUGcqMADzFA61xsmDk=
|
||||||
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
|
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
|
||||||
|
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
|
||||||
|
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
|
||||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
@@ -127,6 +144,23 @@ github.com/go-gost/relay v0.1.1-0.20211123134818-8ef7fd81ffd7 h1:itaaJhQJ19kUXEB
|
|||||||
github.com/go-gost/relay v0.1.1-0.20211123134818-8ef7fd81ffd7/go.mod h1:lcX+23LCQ3khIeASBo+tJ/WbwXFO32/N5YN6ucuYTG8=
|
github.com/go-gost/relay v0.1.1-0.20211123134818-8ef7fd81ffd7/go.mod h1:lcX+23LCQ3khIeASBo+tJ/WbwXFO32/N5YN6ucuYTG8=
|
||||||
github.com/go-gost/tls-dissector v0.0.2-0.20211125135007-2b5d5bd9c07e h1:73NGqAs22ey3wJkIYVD/ACEoovuIuOlEzQTEoqrO5+U=
|
github.com/go-gost/tls-dissector v0.0.2-0.20211125135007-2b5d5bd9c07e h1:73NGqAs22ey3wJkIYVD/ACEoovuIuOlEzQTEoqrO5+U=
|
||||||
github.com/go-gost/tls-dissector v0.0.2-0.20211125135007-2b5d5bd9c07e/go.mod h1:/9QfdewqmHdaE362Hv5nDaSWLx3pCmtD870d6GaquXs=
|
github.com/go-gost/tls-dissector v0.0.2-0.20211125135007-2b5d5bd9c07e/go.mod h1:/9QfdewqmHdaE362Hv5nDaSWLx3pCmtD870d6GaquXs=
|
||||||
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||||
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
|
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||||
|
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||||
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
|
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||||
|
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||||
|
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||||
|
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
|
||||||
|
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||||
|
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||||
|
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
|
||||||
|
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||||
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||||
@@ -246,10 +280,18 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
|
|||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
||||||
|
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
|
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/cpuid v1.2.4/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
github.com/klauspost/cpuid v1.2.4/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
@@ -257,7 +299,10 @@ github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s
|
|||||||
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
|
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
|
||||||
github.com/klauspost/reedsolomon v1.9.9 h1:qCL7LZlv17xMixl55nq2/Oa1Y86nfO8EqDfv2GHND54=
|
github.com/klauspost/reedsolomon v1.9.9 h1:qCL7LZlv17xMixl55nq2/Oa1Y86nfO8EqDfv2GHND54=
|
||||||
github.com/klauspost/reedsolomon v1.9.9/go.mod h1:O7yFFHiQwDR6b2t63KPUpccPtNdp5ADgh1gg4fd12wo=
|
github.com/klauspost/reedsolomon v1.9.9/go.mod h1:O7yFFHiQwDR6b2t63KPUpccPtNdp5ADgh1gg4fd12wo=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
@@ -265,8 +310,11 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|||||||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/lucas-clemente/quic-go v0.24.0 h1:ToR7SIIEdrgOhgVTHvPgdVRJfgVy+N0wQAagH7L4d5g=
|
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||||
github.com/lucas-clemente/quic-go v0.24.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0=
|
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||||
|
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||||
|
github.com/lucas-clemente/quic-go v0.25.0 h1:K+X9Gvd7JXsOHtU0N2icZ2Nw3rx82uBej3mP4CLgibc=
|
||||||
|
github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg=
|
||||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||||
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
|
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
|
||||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||||
@@ -278,14 +326,19 @@ github.com/marten-seemann/qtls-go1-16 v0.1.4 h1:xbHbOGGhrenVtII6Co8akhLEdrawwB2i
|
|||||||
github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
|
github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
|
||||||
github.com/marten-seemann/qtls-go1-17 v0.1.0 h1:P9ggrs5xtwiqXv/FHNwntmuLMNq3KaSIG93AtAZ48xk=
|
github.com/marten-seemann/qtls-go1-17 v0.1.0 h1:P9ggrs5xtwiqXv/FHNwntmuLMNq3KaSIG93AtAZ48xk=
|
||||||
github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8=
|
github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8=
|
||||||
|
github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1 h1:EnzzN9fPUkUck/1CuY1FlzBaIYMoiBsdwTNmNGkwUUM=
|
||||||
|
github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
|
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||||
|
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
@@ -304,9 +357,14 @@ github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
|
|||||||
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104 h1:ULR/QWMgcgRiZLUjSSJMU+fW+RDMstRdmnDWj9Q+AsA=
|
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104 h1:ULR/QWMgcgRiZLUjSSJMU+fW+RDMstRdmnDWj9Q+AsA=
|
||||||
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104/go.mod h1:wqKykBG2QzQDJEzvRkcS8x6MiSJkF52hXZsXcjaB3ls=
|
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104/go.mod h1:wqKykBG2QzQDJEzvRkcS8x6MiSJkF52hXZsXcjaB3ls=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
|
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
@@ -316,8 +374,9 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
|||||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||||
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
|
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
|
||||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
|
||||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||||
|
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||||
|
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
|
github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
|
||||||
@@ -326,6 +385,7 @@ github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTm
|
|||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
|
github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
|
||||||
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||||
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
@@ -335,10 +395,30 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
|||||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||||
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
||||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
|
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||||
|
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||||
|
github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk=
|
||||||
|
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||||
|
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||||
|
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||||
|
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
|
||||||
|
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||||
|
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||||
|
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
|
||||||
|
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
||||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||||
@@ -376,6 +456,9 @@ github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1l
|
|||||||
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
|
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
|
||||||
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
|
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
|
||||||
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8=
|
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8=
|
||||||
@@ -394,6 +477,7 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
|
|||||||
github.com/spf13/viper v1.9.0 h1:yR6EXjTp0y0cLN8OZg1CRZmOBdI88UcGkhgyJhu6nZk=
|
github.com/spf13/viper v1.9.0 h1:yR6EXjTp0y0cLN8OZg1CRZmOBdI88UcGkhgyJhu6nZk=
|
||||||
github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4=
|
github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
@@ -411,6 +495,9 @@ github.com/templexxx/xorsimd v0.4.1 h1:iUZcywbOYDRAZUasAs2eSCUW8eobuZDy0I9FJiORk
|
|||||||
github.com/templexxx/xorsimd v0.4.1/go.mod h1:W+ffZz8jJMH2SXwuKu9WhygqBMbFnp14G2fqEr8qaNo=
|
github.com/templexxx/xorsimd v0.4.1/go.mod h1:W+ffZz8jJMH2SXwuKu9WhygqBMbFnp14G2fqEr8qaNo=
|
||||||
github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM=
|
github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM=
|
||||||
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
|
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
|
||||||
|
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||||
|
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||||
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
||||||
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
|
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
|
||||||
github.com/xtaci/kcp-go/v5 v5.6.1 h1:Pwn0aoeNSPF9dTS7IgiPXn0HEtaIlVb6y5UKWPsx8bI=
|
github.com/xtaci/kcp-go/v5 v5.6.1 h1:Pwn0aoeNSPF9dTS7IgiPXn0HEtaIlVb6y5UKWPsx8bI=
|
||||||
@@ -444,6 +531,7 @@ go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
|||||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||||
golang.org/x/arch v0.0.0-20190909030613-46d78d1859ac/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
|
golang.org/x/arch v0.0.0-20190909030613-46d78d1859ac/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
|
||||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||||
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
@@ -459,8 +547,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
|
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE=
|
||||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@@ -496,14 +584,16 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
|
||||||
|
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
@@ -512,6 +602,7 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
|
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
@@ -541,10 +632,8 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
|
|||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY=
|
|
||||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
@@ -579,19 +668,23 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cO
|
|||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -602,6 +695,7 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -617,6 +711,8 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -626,6 +722,7 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -635,17 +732,17 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k=
|
|
||||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
|
|
||||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7 h1:BXxu8t6QN0G1uff4bzZzSkpsax8+ALqTGUtz08QrV00=
|
||||||
|
golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -655,7 +752,6 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
@@ -722,8 +818,9 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|||||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 h1:BonxutuHCTL0rBDnZlKjpGIQFTjyUVTexFOdWkB6Fg0=
|
|
||||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
|
golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8=
|
||||||
|
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -823,7 +920,6 @@ google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKr
|
|||||||
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||||
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
|
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
|
||||||
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||||
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71 h1:z+ErRPu0+KS02Td3fOAgdX+lnPDh/VyaABEJPD4JRQs=
|
|
||||||
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||||
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350 h1:YxHp5zqIcAShDEvRr5/0rVESVS+njYF68PSdazrNLJo=
|
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350 h1:YxHp5zqIcAShDEvRr5/0rVESVS+njYF68PSdazrNLJo=
|
||||||
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
@@ -854,7 +950,6 @@ google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ
|
|||||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||||
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||||
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||||
google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q=
|
|
||||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||||
google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg=
|
google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg=
|
||||||
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||||
@@ -873,12 +968,15 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
|||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
|
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||||
|
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
gopkg.in/ini.v1 v1.63.2 h1:tGK/CyBg7SMzb60vP1M03vNZ3VDu3wGQJwn7Sxi9r3c=
|
gopkg.in/ini.v1 v1.63.2 h1:tGK/CyBg7SMzb60vP1M03vNZ3VDu3wGQJwn7Sxi9r3c=
|
||||||
gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
@@ -888,6 +986,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package admission
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/go-gost/gost/pkg/common/matcher"
|
||||||
|
"github.com/go-gost/gost/pkg/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Admission interface {
|
||||||
|
Admit(addr string) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type options struct {
|
||||||
|
logger logger.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
type Option func(opts *options)
|
||||||
|
|
||||||
|
func LoggerOption(logger logger.Logger) Option {
|
||||||
|
return func(opts *options) {
|
||||||
|
opts.logger = logger
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type admission struct {
|
||||||
|
matchers []matcher.Matcher
|
||||||
|
reversed bool
|
||||||
|
options options
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAdmission creates and initializes a new Admission using matchers as its match rules.
|
||||||
|
// The rules will be reversed if the reversed is true.
|
||||||
|
func NewAdmission(reversed bool, matchers []matcher.Matcher, opts ...Option) Admission {
|
||||||
|
options := options{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
return &admission{
|
||||||
|
matchers: matchers,
|
||||||
|
reversed: reversed,
|
||||||
|
options: options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAdmissionPatterns creates and initializes a new Admission using matcher patterns as its match rules.
|
||||||
|
// The rules will be reversed if the reverse is true.
|
||||||
|
func NewAdmissionPatterns(reversed bool, patterns []string, opts ...Option) Admission {
|
||||||
|
var matchers []matcher.Matcher
|
||||||
|
for _, pattern := range patterns {
|
||||||
|
if m := matcher.NewMatcher(pattern); m != nil {
|
||||||
|
matchers = append(matchers, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NewAdmission(reversed, matchers, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *admission) Admit(addr string) bool {
|
||||||
|
if addr == "" || p == nil || len(p.matchers) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to strip the port
|
||||||
|
if host, port, _ := net.SplitHostPort(addr); host != "" && port != "" {
|
||||||
|
if p, _ := strconv.Atoi(port); p > 0 { // port is valid
|
||||||
|
addr = host
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var matched bool
|
||||||
|
for _, matcher := range p.matchers {
|
||||||
|
if matcher == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if matcher.Match(addr) {
|
||||||
|
matched = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b := !p.reversed && matched ||
|
||||||
|
p.reversed && !matched
|
||||||
|
return b
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
//go:embed swagger.yaml
|
||||||
|
swaggerDoc embed.FS
|
||||||
|
)
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
Code int `json:"code,omitempty"`
|
||||||
|
Msg string `json:"msg,omitempty"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-gost/gost/pkg/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// swagger:parameters getConfigRequest
|
||||||
|
type getConfigRequest struct {
|
||||||
|
// output format, one of yaml|json, default is json.
|
||||||
|
// in: query
|
||||||
|
Format string `form:"format" json:"format"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response getConfigResponse
|
||||||
|
type getConfigResponse struct {
|
||||||
|
Config *config.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func getConfig(ctx *gin.Context) {
|
||||||
|
// swagger:route GET /config ConfigManagement getConfigRequest
|
||||||
|
//
|
||||||
|
// Get current config.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: getConfigResponse
|
||||||
|
|
||||||
|
var req getConfigRequest
|
||||||
|
ctx.ShouldBindQuery(&req)
|
||||||
|
|
||||||
|
var resp getConfigResponse
|
||||||
|
resp.Config = config.Global()
|
||||||
|
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
switch req.Format {
|
||||||
|
case "yaml":
|
||||||
|
default:
|
||||||
|
req.Format = "json"
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.Config.Write(buf, req.Format)
|
||||||
|
|
||||||
|
contentType := "application/json"
|
||||||
|
if req.Format == "yaml" {
|
||||||
|
contentType = "text/x-yaml"
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data(http.StatusOK, contentType, buf.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters saveConfigRequest
|
||||||
|
type saveConfigRequest struct {
|
||||||
|
// output format, one of yaml|json, default is yaml.
|
||||||
|
// in: query
|
||||||
|
Format string `form:"format" json:"format"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response saveConfigResponse
|
||||||
|
type saveConfigResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveConfig(ctx *gin.Context) {
|
||||||
|
// swagger:route POST /config ConfigManagement saveConfigRequest
|
||||||
|
//
|
||||||
|
// Save current config to file (gost.yaml or gost.json).
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: saveConfigResponse
|
||||||
|
|
||||||
|
var req saveConfigRequest
|
||||||
|
ctx.ShouldBindQuery(&req)
|
||||||
|
|
||||||
|
file := "gost.yaml"
|
||||||
|
switch req.Format {
|
||||||
|
case "json":
|
||||||
|
file = "gost.json"
|
||||||
|
default:
|
||||||
|
req.Format = "yaml"
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Create(file)
|
||||||
|
if err != nil {
|
||||||
|
writeError(ctx, &Error{
|
||||||
|
statusCode: http.StatusInternalServerError,
|
||||||
|
Code: 40005,
|
||||||
|
Msg: fmt.Sprintf("create file: %s", err.Error()),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
if err := config.Global().Write(f, req.Format); err != nil {
|
||||||
|
writeError(ctx, &Error{
|
||||||
|
statusCode: http.StatusInternalServerError,
|
||||||
|
Code: 40006,
|
||||||
|
Msg: fmt.Sprintf("write: %s", err.Error()),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-gost/gost/pkg/config"
|
||||||
|
"github.com/go-gost/gost/pkg/config/parsing"
|
||||||
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// swagger:parameters createAdmissionRequest
|
||||||
|
type createAdmissionRequest struct {
|
||||||
|
// in: body
|
||||||
|
Data config.AdmissionConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response createAdmissionResponse
|
||||||
|
type createAdmissionResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func createAdmission(ctx *gin.Context) {
|
||||||
|
// swagger:route POST /config/admissions ConfigManagement createAdmissionRequest
|
||||||
|
//
|
||||||
|
// Create a new admission, the name of admission must be unique in admission list.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: createAdmissionResponse
|
||||||
|
|
||||||
|
var req createAdmissionRequest
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
if req.Data.Name == "" {
|
||||||
|
writeError(ctx, ErrInvalid)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v := parsing.ParseAdmission(&req.Data)
|
||||||
|
|
||||||
|
if err := registry.AdmissionRegistry().Register(req.Data.Name, v); err != nil {
|
||||||
|
writeError(ctx, ErrDup)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
cfg.Admissions = append(cfg.Admissions, &req.Data)
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters updateAdmissionRequest
|
||||||
|
type updateAdmissionRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
Admission string `uri:"admission" json:"admission"`
|
||||||
|
// in: body
|
||||||
|
Data config.AdmissionConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response updateAdmissionResponse
|
||||||
|
type updateAdmissionResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateAdmission(ctx *gin.Context) {
|
||||||
|
// swagger:route PUT /config/admissions/{admission} ConfigManagement updateAdmissionRequest
|
||||||
|
//
|
||||||
|
// Update admission by name, the admission must already exist.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: updateAdmissionResponse
|
||||||
|
|
||||||
|
var req updateAdmissionRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
if !registry.AdmissionRegistry().IsRegistered(req.Admission) {
|
||||||
|
writeError(ctx, ErrNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Data.Name = req.Admission
|
||||||
|
|
||||||
|
v := parsing.ParseAdmission(&req.Data)
|
||||||
|
|
||||||
|
registry.AdmissionRegistry().Unregister(req.Admission)
|
||||||
|
|
||||||
|
if err := registry.AdmissionRegistry().Register(req.Admission, v); err != nil {
|
||||||
|
writeError(ctx, ErrDup)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
for i := range cfg.Admissions {
|
||||||
|
if cfg.Admissions[i].Name == req.Admission {
|
||||||
|
cfg.Admissions[i] = &req.Data
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters deleteAdmissionRequest
|
||||||
|
type deleteAdmissionRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
Admission string `uri:"admission" json:"admission"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response deleteAdmissionResponse
|
||||||
|
type deleteAdmissionResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteAdmission(ctx *gin.Context) {
|
||||||
|
// swagger:route DELETE /config/admissions/{admission} ConfigManagement deleteAdmissionRequest
|
||||||
|
//
|
||||||
|
// Delete admission by name.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: deleteAdmissionResponse
|
||||||
|
|
||||||
|
var req deleteAdmissionRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
|
if !registry.AdmissionRegistry().IsRegistered(req.Admission) {
|
||||||
|
writeError(ctx, ErrNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
registry.AdmissionRegistry().Unregister(req.Admission)
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
admissiones := cfg.Admissions
|
||||||
|
cfg.Admissions = nil
|
||||||
|
for _, s := range admissiones {
|
||||||
|
if s.Name == req.Admission {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cfg.Admissions = append(cfg.Admissions, s)
|
||||||
|
}
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-gost/gost/pkg/config"
|
||||||
|
"github.com/go-gost/gost/pkg/config/parsing"
|
||||||
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// swagger:parameters createAutherRequest
|
||||||
|
type createAutherRequest struct {
|
||||||
|
// in: body
|
||||||
|
Data config.AutherConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response createAutherResponse
|
||||||
|
type createAutherResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func createAuther(ctx *gin.Context) {
|
||||||
|
// swagger:route POST /config/authers ConfigManagement createAutherRequest
|
||||||
|
//
|
||||||
|
// Create a new auther, the name of the auther must be unique in auther list.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: createAutherResponse
|
||||||
|
|
||||||
|
var req createAutherRequest
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
if req.Data.Name == "" {
|
||||||
|
writeError(ctx, ErrInvalid)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v := parsing.ParseAuther(&req.Data)
|
||||||
|
if err := registry.AutherRegistry().Register(req.Data.Name, v); err != nil {
|
||||||
|
writeError(ctx, ErrDup)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
cfg.Authers = append(cfg.Authers, &req.Data)
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters updateAutherRequest
|
||||||
|
type updateAutherRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
Auther string `uri:"auther" json:"auther"`
|
||||||
|
// in: body
|
||||||
|
Data config.AutherConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response updateAutherResponse
|
||||||
|
type updateAutherResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateAuther(ctx *gin.Context) {
|
||||||
|
// swagger:route PUT /config/authers/{auther} ConfigManagement updateAutherRequest
|
||||||
|
//
|
||||||
|
// Update auther by name, the auther must already exist.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: updateAutherResponse
|
||||||
|
|
||||||
|
var req updateAutherRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
if !registry.AutherRegistry().IsRegistered(req.Auther) {
|
||||||
|
writeError(ctx, ErrNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Data.Name = req.Auther
|
||||||
|
|
||||||
|
v := parsing.ParseAuther(&req.Data)
|
||||||
|
registry.AutherRegistry().Unregister(req.Auther)
|
||||||
|
|
||||||
|
if err := registry.AutherRegistry().Register(req.Auther, v); err != nil {
|
||||||
|
writeError(ctx, ErrDup)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
for i := range cfg.Authers {
|
||||||
|
if cfg.Authers[i].Name == req.Auther {
|
||||||
|
cfg.Authers[i] = &req.Data
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters deleteAutherRequest
|
||||||
|
type deleteAutherRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
Auther string `uri:"auther" json:"auther"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response deleteAutherResponse
|
||||||
|
type deleteAutherResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteAuther(ctx *gin.Context) {
|
||||||
|
// swagger:route DELETE /config/authers/{auther} ConfigManagement deleteAutherRequest
|
||||||
|
//
|
||||||
|
// Delete auther by name.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: deleteAutherResponse
|
||||||
|
|
||||||
|
var req deleteAutherRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
|
if !registry.AutherRegistry().IsRegistered(req.Auther) {
|
||||||
|
writeError(ctx, ErrNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
registry.AutherRegistry().Unregister(req.Auther)
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
authers := cfg.Authers
|
||||||
|
cfg.Authers = nil
|
||||||
|
for _, s := range authers {
|
||||||
|
if s.Name == req.Auther {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cfg.Authers = append(cfg.Authers, s)
|
||||||
|
}
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-gost/gost/pkg/config"
|
||||||
|
"github.com/go-gost/gost/pkg/config/parsing"
|
||||||
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// swagger:parameters createBypassRequest
|
||||||
|
type createBypassRequest struct {
|
||||||
|
// in: body
|
||||||
|
Data config.BypassConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response createBypassResponse
|
||||||
|
type createBypassResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func createBypass(ctx *gin.Context) {
|
||||||
|
// swagger:route POST /config/bypasses ConfigManagement createBypassRequest
|
||||||
|
//
|
||||||
|
// Create a new bypass, the name of bypass must be unique in bypass list.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: createBypassResponse
|
||||||
|
|
||||||
|
var req createBypassRequest
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
if req.Data.Name == "" {
|
||||||
|
writeError(ctx, ErrInvalid)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v := parsing.ParseBypass(&req.Data)
|
||||||
|
|
||||||
|
if err := registry.BypassRegistry().Register(req.Data.Name, v); err != nil {
|
||||||
|
writeError(ctx, ErrDup)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
cfg.Bypasses = append(cfg.Bypasses, &req.Data)
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters updateBypassRequest
|
||||||
|
type updateBypassRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
Bypass string `uri:"bypass" json:"bypass"`
|
||||||
|
// in: body
|
||||||
|
Data config.BypassConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response updateBypassResponse
|
||||||
|
type updateBypassResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateBypass(ctx *gin.Context) {
|
||||||
|
// swagger:route PUT /config/bypasses/{bypass} ConfigManagement updateBypassRequest
|
||||||
|
//
|
||||||
|
// Update bypass by name, the bypass must already exist.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: updateBypassResponse
|
||||||
|
|
||||||
|
var req updateBypassRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
if !registry.BypassRegistry().IsRegistered(req.Bypass) {
|
||||||
|
writeError(ctx, ErrNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Data.Name = req.Bypass
|
||||||
|
|
||||||
|
v := parsing.ParseBypass(&req.Data)
|
||||||
|
|
||||||
|
registry.BypassRegistry().Unregister(req.Bypass)
|
||||||
|
|
||||||
|
if err := registry.BypassRegistry().Register(req.Bypass, v); err != nil {
|
||||||
|
writeError(ctx, ErrDup)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
for i := range cfg.Bypasses {
|
||||||
|
if cfg.Bypasses[i].Name == req.Bypass {
|
||||||
|
cfg.Bypasses[i] = &req.Data
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters deleteBypassRequest
|
||||||
|
type deleteBypassRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
Bypass string `uri:"bypass" json:"bypass"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response deleteBypassResponse
|
||||||
|
type deleteBypassResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteBypass(ctx *gin.Context) {
|
||||||
|
// swagger:route DELETE /config/bypasses/{bypass} ConfigManagement deleteBypassRequest
|
||||||
|
//
|
||||||
|
// Delete bypass by name.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: deleteBypassResponse
|
||||||
|
|
||||||
|
var req deleteBypassRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
|
if !registry.BypassRegistry().IsRegistered(req.Bypass) {
|
||||||
|
writeError(ctx, ErrNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
registry.BypassRegistry().Unregister(req.Bypass)
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
bypasses := cfg.Bypasses
|
||||||
|
cfg.Bypasses = nil
|
||||||
|
for _, s := range bypasses {
|
||||||
|
if s.Name == req.Bypass {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cfg.Bypasses = append(cfg.Bypasses, s)
|
||||||
|
}
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-gost/gost/pkg/config"
|
||||||
|
"github.com/go-gost/gost/pkg/config/parsing"
|
||||||
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// swagger:parameters createChainRequest
|
||||||
|
type createChainRequest struct {
|
||||||
|
// in: body
|
||||||
|
Data config.ChainConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response createChainResponse
|
||||||
|
type createChainResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func createChain(ctx *gin.Context) {
|
||||||
|
// swagger:route POST /config/chains ConfigManagement createChainRequest
|
||||||
|
//
|
||||||
|
// Create a new chain, the name of chain must be unique in chain list.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: createChainResponse
|
||||||
|
|
||||||
|
var req createChainRequest
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
if req.Data.Name == "" {
|
||||||
|
writeError(ctx, ErrInvalid)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := parsing.ParseChain(&req.Data)
|
||||||
|
if err != nil {
|
||||||
|
writeError(ctx, ErrCreate)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := registry.ChainRegistry().Register(req.Data.Name, v); err != nil {
|
||||||
|
writeError(ctx, ErrDup)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
cfg.Chains = append(cfg.Chains, &req.Data)
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters updateChainRequest
|
||||||
|
type updateChainRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
// chain name
|
||||||
|
Chain string `uri:"chain" json:"chain"`
|
||||||
|
// in: body
|
||||||
|
Data config.ChainConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response updateChainResponse
|
||||||
|
type updateChainResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateChain(ctx *gin.Context) {
|
||||||
|
// swagger:route PUT /config/chains/{chain} ConfigManagement updateChainRequest
|
||||||
|
//
|
||||||
|
// Update chain by name, the chain must already exist.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: updateChainResponse
|
||||||
|
|
||||||
|
var req updateChainRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
if !registry.ChainRegistry().IsRegistered(req.Chain) {
|
||||||
|
writeError(ctx, ErrNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Data.Name = req.Chain
|
||||||
|
|
||||||
|
v, err := parsing.ParseChain(&req.Data)
|
||||||
|
if err != nil {
|
||||||
|
writeError(ctx, ErrCreate)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
registry.ChainRegistry().Unregister(req.Chain)
|
||||||
|
|
||||||
|
if err := registry.ChainRegistry().Register(req.Chain, v); err != nil {
|
||||||
|
writeError(ctx, ErrDup)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
for i := range cfg.Chains {
|
||||||
|
if cfg.Chains[i].Name == req.Chain {
|
||||||
|
cfg.Chains[i] = &req.Data
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters deleteChainRequest
|
||||||
|
type deleteChainRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
Chain string `uri:"chain" json:"chain"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response deleteChainResponse
|
||||||
|
type deleteChainResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteChain(ctx *gin.Context) {
|
||||||
|
// swagger:route DELETE /config/chains/{chain} ConfigManagement deleteChainRequest
|
||||||
|
//
|
||||||
|
// Delete chain by name.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: deleteChainResponse
|
||||||
|
|
||||||
|
var req deleteChainRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
|
if !registry.ChainRegistry().IsRegistered(req.Chain) {
|
||||||
|
writeError(ctx, ErrNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
registry.ChainRegistry().Unregister(req.Chain)
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
chains := cfg.Chains
|
||||||
|
cfg.Chains = nil
|
||||||
|
for _, s := range chains {
|
||||||
|
if s.Name == req.Chain {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cfg.Chains = append(cfg.Chains, s)
|
||||||
|
}
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-gost/gost/pkg/config"
|
||||||
|
"github.com/go-gost/gost/pkg/config/parsing"
|
||||||
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// swagger:parameters createHostsRequest
|
||||||
|
type createHostsRequest struct {
|
||||||
|
// in: body
|
||||||
|
Data config.HostsConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response createHostsResponse
|
||||||
|
type createHostsesponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func createHosts(ctx *gin.Context) {
|
||||||
|
// swagger:route POST /config/hosts ConfigManagement createHostsRequest
|
||||||
|
//
|
||||||
|
// Create a new hosts, the name of the hosts must be unique in hosts list.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: createHostsResponse
|
||||||
|
|
||||||
|
var req createHostsRequest
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
if req.Data.Name == "" {
|
||||||
|
writeError(ctx, ErrInvalid)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v := parsing.ParseHosts(&req.Data)
|
||||||
|
|
||||||
|
if err := registry.HostsRegistry().Register(req.Data.Name, v); err != nil {
|
||||||
|
writeError(ctx, ErrDup)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
cfg.Hosts = append(cfg.Hosts, &req.Data)
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters updateHostsRequest
|
||||||
|
type updateHostsRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
Hosts string `uri:"hosts" json:"hosts"`
|
||||||
|
// in: body
|
||||||
|
Data config.HostsConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response updateHostsResponse
|
||||||
|
type updateHostsResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateHosts(ctx *gin.Context) {
|
||||||
|
// swagger:route PUT /config/hosts/{hosts} ConfigManagement updateHostsRequest
|
||||||
|
//
|
||||||
|
// Update hosts by name, the hosts must already exist.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: updateHostsResponse
|
||||||
|
|
||||||
|
var req updateHostsRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
if !registry.HostsRegistry().IsRegistered(req.Hosts) {
|
||||||
|
writeError(ctx, ErrNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Data.Name = req.Hosts
|
||||||
|
|
||||||
|
v := parsing.ParseHosts(&req.Data)
|
||||||
|
|
||||||
|
registry.HostsRegistry().Unregister(req.Hosts)
|
||||||
|
|
||||||
|
if err := registry.HostsRegistry().Register(req.Hosts, v); err != nil {
|
||||||
|
writeError(ctx, ErrDup)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
for i := range cfg.Hosts {
|
||||||
|
if cfg.Hosts[i].Name == req.Hosts {
|
||||||
|
cfg.Hosts[i] = &req.Data
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters deleteHostsRequest
|
||||||
|
type deleteHostsRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
Hosts string `uri:"hosts" json:"hosts"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response deleteHostsResponse
|
||||||
|
type deleteHostsResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteHosts(ctx *gin.Context) {
|
||||||
|
// swagger:route DELETE /config/hosts/{hosts} ConfigManagement deleteHostsRequest
|
||||||
|
//
|
||||||
|
// Delete hosts by name.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: deleteHostsResponse
|
||||||
|
|
||||||
|
var req deleteHostsRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
|
if !registry.HostsRegistry().IsRegistered(req.Hosts) {
|
||||||
|
writeError(ctx, ErrNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
registry.HostsRegistry().Unregister(req.Hosts)
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
hosts := cfg.Hosts
|
||||||
|
cfg.Hosts = nil
|
||||||
|
for _, s := range hosts {
|
||||||
|
if s.Name == req.Hosts {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cfg.Hosts = append(cfg.Hosts, s)
|
||||||
|
}
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-gost/gost/pkg/config"
|
||||||
|
"github.com/go-gost/gost/pkg/config/parsing"
|
||||||
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// swagger:parameters createResolverRequest
|
||||||
|
type createResolverRequest struct {
|
||||||
|
// in: body
|
||||||
|
Data config.ResolverConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response createResolverResponse
|
||||||
|
type createResolverResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func createResolver(ctx *gin.Context) {
|
||||||
|
// swagger:route POST /config/resolvers ConfigManagement createResolverRequest
|
||||||
|
//
|
||||||
|
// Create a new resolver, the name of the resolver must be unique in resolver list.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: createResolverResponse
|
||||||
|
|
||||||
|
var req createResolverRequest
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
if req.Data.Name == "" {
|
||||||
|
writeError(ctx, ErrInvalid)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := parsing.ParseResolver(&req.Data)
|
||||||
|
if err != nil {
|
||||||
|
writeError(ctx, ErrCreate)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := registry.ResolverRegistry().Register(req.Data.Name, v); err != nil {
|
||||||
|
writeError(ctx, ErrDup)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
cfg.Resolvers = append(cfg.Resolvers, &req.Data)
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters updateResolverRequest
|
||||||
|
type updateResolverRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
Resolver string `uri:"resolver" json:"resolver"`
|
||||||
|
// in: body
|
||||||
|
Data config.ResolverConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response updateResolverResponse
|
||||||
|
type updateResolverResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateResolver(ctx *gin.Context) {
|
||||||
|
// swagger:route PUT /config/resolvers/{resolver} ConfigManagement updateResolverRequest
|
||||||
|
//
|
||||||
|
// Update resolver by name, the resolver must already exist.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: updateResolverResponse
|
||||||
|
|
||||||
|
var req updateResolverRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
if !registry.ResolverRegistry().IsRegistered(req.Resolver) {
|
||||||
|
writeError(ctx, ErrNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Data.Name = req.Resolver
|
||||||
|
|
||||||
|
v, err := parsing.ParseResolver(&req.Data)
|
||||||
|
if err != nil {
|
||||||
|
writeError(ctx, ErrCreate)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
registry.ResolverRegistry().Unregister(req.Resolver)
|
||||||
|
|
||||||
|
if err := registry.ResolverRegistry().Register(req.Resolver, v); err != nil {
|
||||||
|
writeError(ctx, ErrDup)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
for i := range cfg.Resolvers {
|
||||||
|
if cfg.Resolvers[i].Name == req.Resolver {
|
||||||
|
cfg.Resolvers[i] = &req.Data
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters deleteResolverRequest
|
||||||
|
type deleteResolverRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
Resolver string `uri:"resolver" json:"resolver"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response deleteResolverResponse
|
||||||
|
type deleteResolverResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteResolver(ctx *gin.Context) {
|
||||||
|
// swagger:route DELETE /config/resolvers/{resolver} ConfigManagement deleteResolverRequest
|
||||||
|
//
|
||||||
|
// Delete resolver by name.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: deleteResolverResponse
|
||||||
|
|
||||||
|
var req deleteResolverRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
|
if !registry.ResolverRegistry().IsRegistered(req.Resolver) {
|
||||||
|
writeError(ctx, ErrNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
registry.ResolverRegistry().Unregister(req.Resolver)
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
resolvers := cfg.Resolvers
|
||||||
|
cfg.Resolvers = nil
|
||||||
|
for _, s := range resolvers {
|
||||||
|
if s.Name == req.Resolver {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cfg.Resolvers = append(cfg.Resolvers, s)
|
||||||
|
}
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-gost/gost/pkg/config"
|
||||||
|
"github.com/go-gost/gost/pkg/config/parsing"
|
||||||
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// swagger:parameters createServiceRequest
|
||||||
|
type createServiceRequest struct {
|
||||||
|
// in: body
|
||||||
|
Data config.ServiceConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response createServiceResponse
|
||||||
|
type createServiceResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func createService(ctx *gin.Context) {
|
||||||
|
// swagger:route POST /config/services ConfigManagement createServiceRequest
|
||||||
|
//
|
||||||
|
// Create a new service, the name of the service must be unique in service list.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: createServiceResponse
|
||||||
|
|
||||||
|
var req createServiceRequest
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
if req.Data.Name == "" {
|
||||||
|
writeError(ctx, ErrInvalid)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if registry.ServiceRegistry().IsRegistered(req.Data.Name) {
|
||||||
|
writeError(ctx, ErrDup)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
svc, err := parsing.ParseService(&req.Data)
|
||||||
|
if err != nil {
|
||||||
|
writeError(ctx, ErrCreate)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := registry.ServiceRegistry().Register(req.Data.Name, svc); err != nil {
|
||||||
|
svc.Close()
|
||||||
|
writeError(ctx, ErrDup)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
go svc.Serve()
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
cfg.Services = append(cfg.Services, &req.Data)
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters updateServiceRequest
|
||||||
|
type updateServiceRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
Service string `uri:"service" json:"service"`
|
||||||
|
// in: body
|
||||||
|
Data config.ServiceConfig `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response updateServiceResponse
|
||||||
|
type updateServiceResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateService(ctx *gin.Context) {
|
||||||
|
// swagger:route PUT /config/services/{service} ConfigManagement updateServiceRequest
|
||||||
|
//
|
||||||
|
// Update service by name, the service must already exist.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: updateServiceResponse
|
||||||
|
|
||||||
|
var req updateServiceRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
ctx.ShouldBindJSON(&req.Data)
|
||||||
|
|
||||||
|
old := registry.ServiceRegistry().Get(req.Service)
|
||||||
|
if old == nil {
|
||||||
|
writeError(ctx, ErrNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
old.Close()
|
||||||
|
|
||||||
|
req.Data.Name = req.Service
|
||||||
|
|
||||||
|
svc, err := parsing.ParseService(&req.Data)
|
||||||
|
if err != nil {
|
||||||
|
writeError(ctx, ErrCreate)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
registry.ServiceRegistry().Unregister(req.Service)
|
||||||
|
|
||||||
|
if err := registry.ServiceRegistry().Register(req.Service, svc); err != nil {
|
||||||
|
svc.Close()
|
||||||
|
writeError(ctx, ErrDup)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
go svc.Serve()
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
for i := range cfg.Services {
|
||||||
|
if cfg.Services[i].Name == req.Service {
|
||||||
|
cfg.Services[i] = &req.Data
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:parameters deleteServiceRequest
|
||||||
|
type deleteServiceRequest struct {
|
||||||
|
// in: path
|
||||||
|
// required: true
|
||||||
|
Service string `uri:"service" json:"service"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful operation.
|
||||||
|
// swagger:response deleteServiceResponse
|
||||||
|
type deleteServiceResponse struct {
|
||||||
|
Data Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteService(ctx *gin.Context) {
|
||||||
|
// swagger:route DELETE /config/services/{service} ConfigManagement deleteServiceRequest
|
||||||
|
//
|
||||||
|
// Delete service by name.
|
||||||
|
//
|
||||||
|
// Security:
|
||||||
|
// basicAuth: []
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: deleteServiceResponse
|
||||||
|
|
||||||
|
var req deleteServiceRequest
|
||||||
|
ctx.ShouldBindUri(&req)
|
||||||
|
|
||||||
|
svc := registry.ServiceRegistry().Get(req.Service)
|
||||||
|
if svc == nil {
|
||||||
|
writeError(ctx, ErrNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
registry.ServiceRegistry().Unregister(req.Service)
|
||||||
|
svc.Close()
|
||||||
|
|
||||||
|
cfg := config.Global()
|
||||||
|
services := cfg.Services
|
||||||
|
cfg.Services = nil
|
||||||
|
for _, s := range services {
|
||||||
|
if s.Name == req.Service {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cfg.Services = append(cfg.Services, s)
|
||||||
|
}
|
||||||
|
config.SetGlobal(cfg)
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Response{
|
||||||
|
Msg: "OK",
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// Documentation of Web API.
|
||||||
|
//
|
||||||
|
// Schemes: https, http
|
||||||
|
// BasePath: /
|
||||||
|
// Version: 1.0.0
|
||||||
|
//
|
||||||
|
// Consumes:
|
||||||
|
// - application/json
|
||||||
|
//
|
||||||
|
// Produces:
|
||||||
|
// - application/json
|
||||||
|
//
|
||||||
|
// SecurityDefinitions:
|
||||||
|
// basicAuth:
|
||||||
|
// type: basic
|
||||||
|
//
|
||||||
|
// swagger:meta
|
||||||
|
package api
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalid = &Error{statusCode: http.StatusBadRequest, Code: 40001, Msg: "object invalid"}
|
||||||
|
ErrDup = &Error{statusCode: http.StatusBadRequest, Code: 40002, Msg: "object duplicated"}
|
||||||
|
ErrCreate = &Error{statusCode: http.StatusConflict, Code: 40003, Msg: "object creation failed"}
|
||||||
|
ErrNotFound = &Error{statusCode: http.StatusBadRequest, Code: 40004, Msg: "object not found"}
|
||||||
|
ErrSave = &Error{statusCode: http.StatusInternalServerError, Code: 40005, Msg: "save config failed"}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Error is an api error.
|
||||||
|
type Error struct {
|
||||||
|
statusCode int
|
||||||
|
Code int `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
b, _ := json.Marshal(e)
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeError(c *gin.Context, err error) {
|
||||||
|
// c.Set(HTTPResponseTag, err)
|
||||||
|
c.JSON(getStatusCode(err), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getStatusCode(err error) int {
|
||||||
|
if err == nil {
|
||||||
|
return http.StatusOK
|
||||||
|
}
|
||||||
|
if e, ok := err.(*Error); ok {
|
||||||
|
if e.statusCode >= http.StatusOK && e.statusCode < 600 {
|
||||||
|
return e.statusCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return http.StatusInternalServerError
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-gost/gost/pkg/auth"
|
||||||
|
"github.com/go-gost/gost/pkg/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mwLogger() gin.HandlerFunc {
|
||||||
|
return func(ctx *gin.Context) {
|
||||||
|
// start time
|
||||||
|
startTime := time.Now()
|
||||||
|
// Processing request
|
||||||
|
ctx.Next()
|
||||||
|
duration := time.Since(startTime)
|
||||||
|
|
||||||
|
logger.Default().WithFields(map[string]any{
|
||||||
|
"kind": "api",
|
||||||
|
"method": ctx.Request.Method,
|
||||||
|
"uri": ctx.Request.RequestURI,
|
||||||
|
"code": ctx.Writer.Status(),
|
||||||
|
"client": ctx.ClientIP(),
|
||||||
|
"duration": duration,
|
||||||
|
}).Infof("| %3d | %13v | %15s | %-7s %s",
|
||||||
|
ctx.Writer.Status(), duration, ctx.ClientIP(), ctx.Request.Method, ctx.Request.RequestURI)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mwBasicAuth(auther auth.Authenticator) gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
if auther == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u, p, _ := c.Request.BasicAuth()
|
||||||
|
if !auther.Authenticate(u, p) {
|
||||||
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-contrib/cors"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-gost/gost/pkg/auth"
|
||||||
|
"github.com/go-gost/gost/pkg/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
type options struct {
|
||||||
|
accessLog bool
|
||||||
|
pathPrefix string
|
||||||
|
auther auth.Authenticator
|
||||||
|
}
|
||||||
|
|
||||||
|
type Option func(*options)
|
||||||
|
|
||||||
|
func PathPrefixOption(pathPrefix string) Option {
|
||||||
|
return func(o *options) {
|
||||||
|
o.pathPrefix = pathPrefix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AccessLogOption(enable bool) Option {
|
||||||
|
return func(o *options) {
|
||||||
|
o.accessLog = enable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AutherOption(auther auth.Authenticator) Option {
|
||||||
|
return func(o *options) {
|
||||||
|
o.auther = auther
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type server struct {
|
||||||
|
s *http.Server
|
||||||
|
ln net.Listener
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(addr string, opts ...Option) (service.Service, error) {
|
||||||
|
ln, err := net.Listen("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var options options
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
gin.SetMode(gin.ReleaseMode)
|
||||||
|
|
||||||
|
r := gin.New()
|
||||||
|
r.Use(
|
||||||
|
cors.New((cors.Config{
|
||||||
|
AllowAllOrigins: true,
|
||||||
|
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
|
||||||
|
AllowHeaders: []string{"*"},
|
||||||
|
})),
|
||||||
|
gin.Recovery(),
|
||||||
|
)
|
||||||
|
if options.accessLog {
|
||||||
|
r.Use(mwLogger())
|
||||||
|
}
|
||||||
|
|
||||||
|
router := r.Group("")
|
||||||
|
if options.pathPrefix != "" {
|
||||||
|
router = router.Group(options.pathPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
router.StaticFS("/docs", http.FS(swaggerDoc))
|
||||||
|
|
||||||
|
config := router.Group("/config")
|
||||||
|
config.Use(mwBasicAuth(options.auther))
|
||||||
|
registerConfig(config)
|
||||||
|
|
||||||
|
return &server{
|
||||||
|
s: &http.Server{
|
||||||
|
Handler: r,
|
||||||
|
},
|
||||||
|
ln: ln,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) Serve() error {
|
||||||
|
return s.s.Serve(s.ln)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) Addr() net.Addr {
|
||||||
|
return s.ln.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) Close() error {
|
||||||
|
return s.s.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerConfig(config *gin.RouterGroup) {
|
||||||
|
config.GET("", getConfig)
|
||||||
|
config.POST("", saveConfig)
|
||||||
|
|
||||||
|
config.POST("/services", createService)
|
||||||
|
config.PUT("/services/:service", updateService)
|
||||||
|
config.DELETE("/services/:service", deleteService)
|
||||||
|
|
||||||
|
config.POST("/chains", createChain)
|
||||||
|
config.PUT("/chains/:chain", updateChain)
|
||||||
|
config.DELETE("/chains/:chain", deleteChain)
|
||||||
|
|
||||||
|
config.POST("/authers", createAuther)
|
||||||
|
config.PUT("/authers/:auther", updateAuther)
|
||||||
|
config.DELETE("/authers/:auther", deleteAuther)
|
||||||
|
|
||||||
|
config.POST("/admissions", createAdmission)
|
||||||
|
config.PUT("/admissions/:admission", updateAdmission)
|
||||||
|
config.DELETE("/admissions/:admission", deleteAdmission)
|
||||||
|
|
||||||
|
config.POST("/bypasses", createBypass)
|
||||||
|
config.PUT("/bypasses/:bypass", updateBypass)
|
||||||
|
config.DELETE("/bypasses/:bypass", deleteBypass)
|
||||||
|
|
||||||
|
config.POST("/resolvers", createResolver)
|
||||||
|
config.PUT("/resolvers/:resolver", updateResolver)
|
||||||
|
config.DELETE("/resolvers/:resolver", deleteResolver)
|
||||||
|
|
||||||
|
config.POST("/hosts", createHosts)
|
||||||
|
config.PUT("/hosts/:hosts", updateHosts)
|
||||||
|
config.DELETE("/hosts/:hosts", deleteHosts)
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
+12
-104
@@ -3,131 +3,39 @@ package bypass
|
|||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
|
"github.com/go-gost/gost/pkg/common/matcher"
|
||||||
"github.com/go-gost/gost/pkg/logger"
|
"github.com/go-gost/gost/pkg/logger"
|
||||||
glob "github.com/gobwas/glob"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Matcher is a generic pattern matcher,
|
|
||||||
// it gives the match result of the given pattern for specific v.
|
|
||||||
type Matcher interface {
|
|
||||||
Match(v string) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMatcher creates a Matcher for the given pattern.
|
|
||||||
// The acutal Matcher depends on the pattern:
|
|
||||||
// IP Matcher if pattern is a valid IP address.
|
|
||||||
// CIDR Matcher if pattern is a valid CIDR address.
|
|
||||||
// Domain Matcher if both of the above are not.
|
|
||||||
func NewMatcher(pattern string) Matcher {
|
|
||||||
if pattern == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if ip := net.ParseIP(pattern); ip != nil {
|
|
||||||
return IPMatcher(ip)
|
|
||||||
}
|
|
||||||
if _, inet, err := net.ParseCIDR(pattern); err == nil {
|
|
||||||
return CIDRMatcher(inet)
|
|
||||||
}
|
|
||||||
return DomainMatcher(pattern)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ipMatcher struct {
|
|
||||||
ip net.IP
|
|
||||||
}
|
|
||||||
|
|
||||||
// IPMatcher creates a Matcher for a specific IP address.
|
|
||||||
func IPMatcher(ip net.IP) Matcher {
|
|
||||||
return &ipMatcher{
|
|
||||||
ip: ip,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *ipMatcher) Match(ip string) bool {
|
|
||||||
if m == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return m.ip.Equal(net.ParseIP(ip))
|
|
||||||
}
|
|
||||||
|
|
||||||
type cidrMatcher struct {
|
|
||||||
ipNet *net.IPNet
|
|
||||||
}
|
|
||||||
|
|
||||||
// CIDRMatcher creates a Matcher for a specific CIDR notation IP address.
|
|
||||||
func CIDRMatcher(inet *net.IPNet) Matcher {
|
|
||||||
return &cidrMatcher{
|
|
||||||
ipNet: inet,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *cidrMatcher) Match(ip string) bool {
|
|
||||||
if m == nil || m.ipNet == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return m.ipNet.Contains(net.ParseIP(ip))
|
|
||||||
}
|
|
||||||
|
|
||||||
type domainMatcher struct {
|
|
||||||
pattern string
|
|
||||||
glob glob.Glob
|
|
||||||
}
|
|
||||||
|
|
||||||
// DomainMatcher creates a Matcher for a specific domain pattern,
|
|
||||||
// the pattern can be a plain domain such as 'example.com',
|
|
||||||
// a wildcard such as '*.exmaple.com' or a special wildcard '.example.com'.
|
|
||||||
func DomainMatcher(pattern string) Matcher {
|
|
||||||
p := pattern
|
|
||||||
if strings.HasPrefix(pattern, ".") {
|
|
||||||
p = pattern[1:] // trim the prefix '.'
|
|
||||||
pattern = "*" + p
|
|
||||||
}
|
|
||||||
return &domainMatcher{
|
|
||||||
pattern: p,
|
|
||||||
glob: glob.MustCompile(pattern),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *domainMatcher) Match(domain string) bool {
|
|
||||||
if m == nil || m.glob == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if domain == m.pattern {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return m.glob.Match(domain)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bypass is a filter of address (IP or domain).
|
// Bypass is a filter of address (IP or domain).
|
||||||
type Bypass interface {
|
type Bypass interface {
|
||||||
// Contains reports whether the bypass includes addr.
|
// Contains reports whether the bypass includes addr.
|
||||||
Contains(addr string) bool
|
Contains(addr string) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type bypassOptions struct {
|
type options struct {
|
||||||
logger logger.Logger
|
logger logger.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
type BypassOption func(opts *bypassOptions)
|
type Option func(opts *options)
|
||||||
|
|
||||||
func LoggerBypassOption(logger logger.Logger) BypassOption {
|
func LoggerOption(logger logger.Logger) Option {
|
||||||
return func(opts *bypassOptions) {
|
return func(opts *options) {
|
||||||
opts.logger = logger
|
opts.logger = logger
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type bypass struct {
|
type bypass struct {
|
||||||
matchers []Matcher
|
matchers []matcher.Matcher
|
||||||
reversed bool
|
reversed bool
|
||||||
options bypassOptions
|
options options
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBypass creates and initializes a new Bypass using matchers as its match rules.
|
// NewBypass creates and initializes a new Bypass using matchers as its match rules.
|
||||||
// The rules will be reversed if the reversed is true.
|
// The rules will be reversed if the reversed is true.
|
||||||
func NewBypass(reversed bool, matchers []Matcher, opts ...BypassOption) Bypass {
|
func NewBypass(reversed bool, matchers []matcher.Matcher, opts ...Option) Bypass {
|
||||||
options := bypassOptions{}
|
options := options{}
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(&options)
|
opt(&options)
|
||||||
}
|
}
|
||||||
@@ -140,10 +48,10 @@ func NewBypass(reversed bool, matchers []Matcher, opts ...BypassOption) Bypass {
|
|||||||
|
|
||||||
// NewBypassPatterns creates and initializes a new Bypass using matcher patterns as its match rules.
|
// NewBypassPatterns creates and initializes a new Bypass using matcher patterns as its match rules.
|
||||||
// The rules will be reversed if the reverse is true.
|
// The rules will be reversed if the reverse is true.
|
||||||
func NewBypassPatterns(reversed bool, patterns []string, opts ...BypassOption) Bypass {
|
func NewBypassPatterns(reversed bool, patterns []string, opts ...Option) Bypass {
|
||||||
var matchers []Matcher
|
var matchers []matcher.Matcher
|
||||||
for _, pattern := range patterns {
|
for _, pattern := range patterns {
|
||||||
if m := NewMatcher(pattern); m != nil {
|
if m := matcher.NewMatcher(pattern); m != nil {
|
||||||
matchers = append(matchers, m)
|
matchers = append(matchers, m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-12
@@ -1,5 +1,9 @@
|
|||||||
package chain
|
package chain
|
||||||
|
|
||||||
|
type Chainer interface {
|
||||||
|
Route(network, address string) *Route
|
||||||
|
}
|
||||||
|
|
||||||
type Chain struct {
|
type Chain struct {
|
||||||
groups []*NodeGroup
|
groups []*NodeGroup
|
||||||
}
|
}
|
||||||
@@ -8,16 +12,12 @@ func (c *Chain) AddNodeGroup(group *NodeGroup) {
|
|||||||
c.groups = append(c.groups, group)
|
c.groups = append(c.groups, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Chain) GetRoute() (r *route) {
|
func (c *Chain) Route(network, address string) (r *Route) {
|
||||||
return c.GetRouteFor("tcp", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Chain) GetRouteFor(network, address string) (r *route) {
|
|
||||||
if c == nil || len(c.groups) == 0 {
|
if c == nil || len(c.groups) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
r = &route{}
|
r = &Route{}
|
||||||
for _, group := range c.groups {
|
for _, group := range c.groups {
|
||||||
node := group.Next()
|
node := group.Next()
|
||||||
if node == nil {
|
if node == nil {
|
||||||
@@ -32,14 +32,10 @@ func (c *Chain) GetRouteFor(network, address string) (r *route) {
|
|||||||
WithRoute(r)
|
WithRoute(r)
|
||||||
node = node.Copy()
|
node = node.Copy()
|
||||||
node.Transport = tr
|
node.Transport = tr
|
||||||
r = &route{}
|
r = &Route{}
|
||||||
}
|
}
|
||||||
|
|
||||||
r.AddNode(node)
|
r.addNode(node)
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Chain) IsEmpty() bool {
|
|
||||||
return c == nil || len(c.groups) == 0
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/go-gost/gost/pkg/resolver"
|
"github.com/go-gost/gost/pkg/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
func resolve(ctx context.Context, addr string, resolver resolver.Resolver, hosts hosts.HostMapper, log logger.Logger) (string, error) {
|
func resolve(ctx context.Context, network, addr string, r resolver.Resolver, hosts hosts.HostMapper, log logger.Logger) (string, error) {
|
||||||
if addr == "" {
|
if addr == "" {
|
||||||
return addr, nil
|
return addr, nil
|
||||||
}
|
}
|
||||||
@@ -24,15 +24,18 @@ func resolve(ctx context.Context, addr string, resolver resolver.Resolver, hosts
|
|||||||
}
|
}
|
||||||
|
|
||||||
if hosts != nil {
|
if hosts != nil {
|
||||||
if ips, _ := hosts.Lookup("ip", host); len(ips) > 0 {
|
if ips, _ := hosts.Lookup(network, host); len(ips) > 0 {
|
||||||
log.Debugf("hit host mapper: %s -> %s", host, ips)
|
log.Debugf("hit host mapper: %s -> %s", host, ips)
|
||||||
return net.JoinHostPort(ips[0].String(), port), nil
|
return net.JoinHostPort(ips[0].String(), port), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if resolver != nil {
|
if r != nil {
|
||||||
ips, err := resolver.Resolve(ctx, host)
|
ips, err := r.Resolve(ctx, network, host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == resolver.ErrInvalid {
|
||||||
|
return addr, nil
|
||||||
|
}
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
if len(ips) == 0 {
|
if len(ips) == 0 {
|
||||||
|
|||||||
+34
-34
@@ -5,7 +5,9 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-gost/gost/pkg/common/net/dialer"
|
||||||
"github.com/go-gost/gost/pkg/common/util/udp"
|
"github.com/go-gost/gost/pkg/common/util/udp"
|
||||||
"github.com/go-gost/gost/pkg/connector"
|
"github.com/go-gost/gost/pkg/connector"
|
||||||
"github.com/go-gost/gost/pkg/logger"
|
"github.com/go-gost/gost/pkg/logger"
|
||||||
@@ -15,18 +17,25 @@ var (
|
|||||||
ErrEmptyRoute = errors.New("empty route")
|
ErrEmptyRoute = errors.New("empty route")
|
||||||
)
|
)
|
||||||
|
|
||||||
type route struct {
|
type Route struct {
|
||||||
nodes []*Node
|
nodes []*Node
|
||||||
|
ifceName string
|
||||||
logger logger.Logger
|
logger logger.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *route) AddNode(node *Node) {
|
func (r *Route) addNode(node *Node) {
|
||||||
r.nodes = append(r.nodes, node)
|
r.nodes = append(r.nodes, node)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *route) Dial(ctx context.Context, network, address string) (net.Conn, error) {
|
func (r *Route) Dial(ctx context.Context, network, address string) (net.Conn, error) {
|
||||||
if r.IsEmpty() {
|
if r.Len() == 0 {
|
||||||
return r.dialDirect(ctx, network, address)
|
netd := dialer.NetDialer{
|
||||||
|
Timeout: 30 * time.Second,
|
||||||
|
}
|
||||||
|
if r != nil {
|
||||||
|
netd.Interface = r.ifceName
|
||||||
|
}
|
||||||
|
return netd.Dial(ctx, network, address)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := r.connect(ctx)
|
conn, err := r.connect(ctx)
|
||||||
@@ -34,7 +43,7 @@ func (r *route) Dial(ctx context.Context, network, address string) (net.Conn, er
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cc, err := r.Last().Transport.Connect(ctx, conn, network, address)
|
cc, err := r.GetNode(r.Len()-1).Transport.Connect(ctx, conn, network, address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -42,21 +51,8 @@ func (r *route) Dial(ctx context.Context, network, address string) (net.Conn, er
|
|||||||
return cc, nil
|
return cc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *route) dialDirect(ctx context.Context, network, address string) (net.Conn, error) {
|
func (r *Route) Bind(ctx context.Context, network, address string, opts ...connector.BindOption) (net.Listener, error) {
|
||||||
switch network {
|
if r.Len() == 0 {
|
||||||
case "udp", "udp4", "udp6":
|
|
||||||
if address == "" {
|
|
||||||
return net.ListenUDP(network, nil)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
d := net.Dialer{}
|
|
||||||
return d.DialContext(ctx, network, address)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *route) Bind(ctx context.Context, network, address string, opts ...connector.BindOption) (net.Listener, error) {
|
|
||||||
if r.IsEmpty() {
|
|
||||||
return r.bindLocal(ctx, network, address, opts...)
|
return r.bindLocal(ctx, network, address, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +61,7 @@ func (r *route) Bind(ctx context.Context, network, address string, opts ...conne
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ln, err := r.Last().Transport.Bind(ctx, conn, network, address, opts...)
|
ln, err := r.GetNode(r.Len()-1).Transport.Bind(ctx, conn, network, address, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -74,14 +70,15 @@ func (r *route) Bind(ctx context.Context, network, address string, opts ...conne
|
|||||||
return ln, nil
|
return ln, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *route) connect(ctx context.Context) (conn net.Conn, err error) {
|
func (r *Route) connect(ctx context.Context) (conn net.Conn, err error) {
|
||||||
if r.IsEmpty() {
|
if r.Len() == 0 {
|
||||||
return nil, ErrEmptyRoute
|
return nil, ErrEmptyRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
|
network := "ip"
|
||||||
node := r.nodes[0]
|
node := r.nodes[0]
|
||||||
|
|
||||||
addr, err := resolve(ctx, node.Addr, node.Resolver, node.Hosts, r.logger)
|
addr, err := resolve(ctx, network, node.Addr, node.Resolver, node.Hosts, r.logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
node.Marker.Mark()
|
node.Marker.Mark()
|
||||||
return
|
return
|
||||||
@@ -102,7 +99,7 @@ func (r *route) connect(ctx context.Context) (conn net.Conn, err error) {
|
|||||||
|
|
||||||
preNode := node
|
preNode := node
|
||||||
for _, node := range r.nodes[1:] {
|
for _, node := range r.nodes[1:] {
|
||||||
addr, err = resolve(ctx, node.Addr, node.Resolver, node.Hosts, r.logger)
|
addr, err = resolve(ctx, network, node.Addr, node.Resolver, node.Hosts, r.logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cn.Close()
|
cn.Close()
|
||||||
node.Marker.Mark()
|
node.Marker.Mark()
|
||||||
@@ -130,18 +127,21 @@ func (r *route) connect(ctx context.Context) (conn net.Conn, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *route) IsEmpty() bool {
|
func (r *Route) Len() int {
|
||||||
return r == nil || len(r.nodes) == 0
|
if r == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return len(r.nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *route) Last() *Node {
|
func (r *Route) GetNode(index int) *Node {
|
||||||
if r.IsEmpty() {
|
if r.Len() == 0 || index < 0 || index >= len(r.nodes) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return r.nodes[len(r.nodes)-1]
|
return r.nodes[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *route) Path() (path []*Node) {
|
func (r *Route) Path() (path []*Node) {
|
||||||
if r == nil || len(r.nodes) == 0 {
|
if r == nil || len(r.nodes) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -155,7 +155,7 @@ func (r *route) Path() (path []*Node) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *route) bindLocal(ctx context.Context, network, address string, opts ...connector.BindOption) (net.Listener, error) {
|
func (r *Route) bindLocal(ctx context.Context, network, address string, opts ...connector.BindOption) (net.Listener, error) {
|
||||||
options := connector.BindOptions{}
|
options := connector.BindOptions{}
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(&options)
|
opt(&options)
|
||||||
@@ -177,7 +177,7 @@ func (r *route) bindLocal(ctx context.Context, network, address string, opts ...
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
logger := logger.Default().WithFields(map[string]interface{}{
|
logger := logger.Default().WithFields(map[string]any{
|
||||||
"network": network,
|
"network": network,
|
||||||
"address": address,
|
"address": address,
|
||||||
})
|
})
|
||||||
|
|||||||
+74
-21
@@ -5,6 +5,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/go-gost/gost/pkg/connector"
|
"github.com/go-gost/gost/pkg/connector"
|
||||||
"github.com/go-gost/gost/pkg/hosts"
|
"github.com/go-gost/gost/pkg/hosts"
|
||||||
@@ -13,11 +14,55 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Router struct {
|
type Router struct {
|
||||||
Retries int
|
timeout time.Duration
|
||||||
Chain *Chain
|
retries int
|
||||||
Hosts hosts.HostMapper
|
ifceName string
|
||||||
Resolver resolver.Resolver
|
chain Chainer
|
||||||
Logger logger.Logger
|
resolver resolver.Resolver
|
||||||
|
hosts hosts.HostMapper
|
||||||
|
logger logger.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Router) WithTimeout(timeout time.Duration) *Router {
|
||||||
|
r.timeout = timeout
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Router) WithRetries(retries int) *Router {
|
||||||
|
r.retries = retries
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Router) WithInterface(ifceName string) *Router {
|
||||||
|
r.ifceName = ifceName
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Router) WithChain(chain Chainer) *Router {
|
||||||
|
r.chain = chain
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Router) WithResolver(resolver resolver.Resolver) *Router {
|
||||||
|
r.resolver = resolver
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Router) WithHosts(hosts hosts.HostMapper) *Router {
|
||||||
|
r.hosts = hosts
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Router) Hosts() hosts.HostMapper {
|
||||||
|
if r != nil {
|
||||||
|
return r.hosts
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Router) WithLogger(logger logger.Logger) *Router {
|
||||||
|
r.logger = logger
|
||||||
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) Dial(ctx context.Context, network, address string) (conn net.Conn, err error) {
|
func (r *Router) Dial(ctx context.Context, network, address string) (conn net.Conn, err error) {
|
||||||
@@ -34,68 +79,76 @@ func (r *Router) Dial(ctx context.Context, network, address string) (conn net.Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) dial(ctx context.Context, network, address string) (conn net.Conn, err error) {
|
func (r *Router) dial(ctx context.Context, network, address string) (conn net.Conn, err error) {
|
||||||
count := r.Retries + 1
|
count := r.retries + 1
|
||||||
if count <= 0 {
|
if count <= 0 {
|
||||||
count = 1
|
count = 1
|
||||||
}
|
}
|
||||||
r.Logger.Debugf("dial %s/%s", address, network)
|
r.logger.Debugf("dial %s/%s", address, network)
|
||||||
|
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
route := r.Chain.GetRouteFor(network, address)
|
var route *Route
|
||||||
|
if r.chain != nil {
|
||||||
|
route = r.chain.Route(network, address)
|
||||||
|
}
|
||||||
|
|
||||||
if r.Logger.IsLevelEnabled(logger.DebugLevel) {
|
if r.logger.IsLevelEnabled(logger.DebugLevel) {
|
||||||
buf := bytes.Buffer{}
|
buf := bytes.Buffer{}
|
||||||
for _, node := range route.Path() {
|
for _, node := range route.Path() {
|
||||||
fmt.Fprintf(&buf, "%s@%s > ", node.Name, node.Addr)
|
fmt.Fprintf(&buf, "%s@%s > ", node.Name, node.Addr)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(&buf, "%s", address)
|
fmt.Fprintf(&buf, "%s", address)
|
||||||
r.Logger.Debugf("route(retry=%d) %s", i, buf.String())
|
r.logger.Debugf("route(retry=%d) %s", i, buf.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
address, err = resolve(ctx, address, r.Resolver, r.Hosts, r.Logger)
|
address, err = resolve(ctx, "ip", address, r.resolver, r.hosts, r.logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Logger.Error(err)
|
r.logger.Error(err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if route != nil {
|
if route == nil {
|
||||||
route.logger = r.Logger
|
route = &Route{}
|
||||||
}
|
}
|
||||||
|
route.ifceName = r.ifceName
|
||||||
|
route.logger = r.logger
|
||||||
|
|
||||||
conn, err = route.Dial(ctx, network, address)
|
conn, err = route.Dial(ctx, network, address)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
r.Logger.Errorf("route(retry=%d) %s", i, err)
|
r.logger.Errorf("route(retry=%d) %s", i, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) Bind(ctx context.Context, network, address string, opts ...connector.BindOption) (ln net.Listener, err error) {
|
func (r *Router) Bind(ctx context.Context, network, address string, opts ...connector.BindOption) (ln net.Listener, err error) {
|
||||||
count := r.Retries + 1
|
count := r.retries + 1
|
||||||
if count <= 0 {
|
if count <= 0 {
|
||||||
count = 1
|
count = 1
|
||||||
}
|
}
|
||||||
r.Logger.Debugf("bind on %s/%s", address, network)
|
r.logger.Debugf("bind on %s/%s", address, network)
|
||||||
|
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
route := r.Chain.GetRouteFor(network, address)
|
var route *Route
|
||||||
|
if r.chain != nil {
|
||||||
|
route = r.chain.Route(network, address)
|
||||||
|
}
|
||||||
|
|
||||||
if r.Logger.IsLevelEnabled(logger.DebugLevel) {
|
if r.logger.IsLevelEnabled(logger.DebugLevel) {
|
||||||
buf := bytes.Buffer{}
|
buf := bytes.Buffer{}
|
||||||
for _, node := range route.Path() {
|
for _, node := range route.Path() {
|
||||||
fmt.Fprintf(&buf, "%s@%s > ", node.Name, node.Addr)
|
fmt.Fprintf(&buf, "%s@%s > ", node.Name, node.Addr)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(&buf, "%s", address)
|
fmt.Fprintf(&buf, "%s", address)
|
||||||
r.Logger.Debugf("route(retry=%d) %s", i, buf.String())
|
r.logger.Debugf("route(retry=%d) %s", i, buf.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
ln, err = route.Bind(ctx, network, address, opts...)
|
ln, err = route.Bind(ctx, network, address, opts...)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
r.Logger.Errorf("route(retry=%d) %s", i, err)
|
r.logger.Errorf("route(retry=%d) %s", i, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|||||||
+21
-16
@@ -3,14 +3,17 @@ package chain
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
net_dialer "github.com/go-gost/gost/pkg/common/net/dialer"
|
||||||
"github.com/go-gost/gost/pkg/connector"
|
"github.com/go-gost/gost/pkg/connector"
|
||||||
"github.com/go-gost/gost/pkg/dialer"
|
"github.com/go-gost/gost/pkg/dialer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Transport struct {
|
type Transport struct {
|
||||||
addr string
|
addr string
|
||||||
route *route
|
ifceName string
|
||||||
|
route *Route
|
||||||
dialer dialer.Dialer
|
dialer dialer.Dialer
|
||||||
connector connector.Connector
|
connector connector.Connector
|
||||||
}
|
}
|
||||||
@@ -21,6 +24,11 @@ func (tr *Transport) Copy() *Transport {
|
|||||||
return tr
|
return tr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tr *Transport) WithInterface(ifceName string) *Transport {
|
||||||
|
tr.ifceName = ifceName
|
||||||
|
return tr
|
||||||
|
}
|
||||||
|
|
||||||
func (tr *Transport) WithDialer(dialer dialer.Dialer) *Transport {
|
func (tr *Transport) WithDialer(dialer dialer.Dialer) *Transport {
|
||||||
tr.dialer = dialer
|
tr.dialer = dialer
|
||||||
return tr
|
return tr
|
||||||
@@ -32,23 +40,20 @@ func (tr *Transport) WithConnector(connector connector.Connector) *Transport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tr *Transport) Dial(ctx context.Context, addr string) (net.Conn, error) {
|
func (tr *Transport) Dial(ctx context.Context, addr string) (net.Conn, error) {
|
||||||
return tr.dialer.Dial(ctx, addr, tr.dialOptions()...)
|
netd := &net_dialer.NetDialer{
|
||||||
}
|
Interface: tr.ifceName,
|
||||||
|
Timeout: 30 * time.Second,
|
||||||
func (tr *Transport) dialOptions() []dialer.DialOption {
|
}
|
||||||
|
if tr.route.Len() > 0 {
|
||||||
|
netd.DialFunc = func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
return tr.route.Dial(ctx, network, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
opts := []dialer.DialOption{
|
opts := []dialer.DialOption{
|
||||||
dialer.HostDialOption(tr.addr),
|
dialer.HostDialOption(tr.addr),
|
||||||
|
dialer.NetDialerDialOption(netd),
|
||||||
}
|
}
|
||||||
if !tr.route.IsEmpty() {
|
return tr.dialer.Dial(ctx, addr, opts...)
|
||||||
opts = append(opts,
|
|
||||||
dialer.DialFuncDialOption(
|
|
||||||
func(ctx context.Context, addr string) (net.Conn, error) {
|
|
||||||
return tr.route.Dial(ctx, "tcp", addr)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return opts
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr *Transport) Handshake(ctx context.Context, conn net.Conn) (net.Conn, error) {
|
func (tr *Transport) Handshake(ctx context.Context, conn net.Conn) (net.Conn, error) {
|
||||||
@@ -84,7 +89,7 @@ func (tr *Transport) Multiplex() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr *Transport) WithRoute(r *route) *Transport {
|
func (tr *Transport) WithRoute(r *Route) *Transport {
|
||||||
tr.route = r
|
tr.route = r
|
||||||
return tr
|
return tr
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ var (
|
|||||||
{
|
{
|
||||||
size: 128,
|
size: 128,
|
||||||
pool: sync.Pool{
|
pool: sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() any {
|
||||||
b := make([]byte, 128)
|
b := make([]byte, 128)
|
||||||
return &b
|
return &b
|
||||||
},
|
},
|
||||||
@@ -19,7 +19,7 @@ var (
|
|||||||
{
|
{
|
||||||
size: 512,
|
size: 512,
|
||||||
pool: sync.Pool{
|
pool: sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() any {
|
||||||
b := make([]byte, 512)
|
b := make([]byte, 512)
|
||||||
return &b
|
return &b
|
||||||
},
|
},
|
||||||
@@ -28,7 +28,7 @@ var (
|
|||||||
{
|
{
|
||||||
size: 1024,
|
size: 1024,
|
||||||
pool: sync.Pool{
|
pool: sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() any {
|
||||||
b := make([]byte, 1024)
|
b := make([]byte, 1024)
|
||||||
return &b
|
return &b
|
||||||
},
|
},
|
||||||
@@ -37,7 +37,7 @@ var (
|
|||||||
{
|
{
|
||||||
size: 4096,
|
size: 4096,
|
||||||
pool: sync.Pool{
|
pool: sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() any {
|
||||||
b := make([]byte, 4096)
|
b := make([]byte, 4096)
|
||||||
return &b
|
return &b
|
||||||
},
|
},
|
||||||
@@ -46,7 +46,7 @@ var (
|
|||||||
{
|
{
|
||||||
size: 8192,
|
size: 8192,
|
||||||
pool: sync.Pool{
|
pool: sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() any {
|
||||||
b := make([]byte, 8192)
|
b := make([]byte, 8192)
|
||||||
return &b
|
return &b
|
||||||
},
|
},
|
||||||
@@ -55,7 +55,7 @@ var (
|
|||||||
{
|
{
|
||||||
size: 16 * 1024,
|
size: 16 * 1024,
|
||||||
pool: sync.Pool{
|
pool: sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() any {
|
||||||
b := make([]byte, 16*1024)
|
b := make([]byte, 16*1024)
|
||||||
return &b
|
return &b
|
||||||
},
|
},
|
||||||
@@ -64,7 +64,7 @@ var (
|
|||||||
{
|
{
|
||||||
size: 32 * 1024,
|
size: 32 * 1024,
|
||||||
pool: sync.Pool{
|
pool: sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() any {
|
||||||
b := make([]byte, 32*1024)
|
b := make([]byte, 32*1024)
|
||||||
return &b
|
return &b
|
||||||
},
|
},
|
||||||
@@ -73,7 +73,7 @@ var (
|
|||||||
{
|
{
|
||||||
size: 64 * 1024,
|
size: 64 * 1024,
|
||||||
pool: sync.Pool{
|
pool: sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() any {
|
||||||
b := make([]byte, 64*1024)
|
b := make([]byte, 64*1024)
|
||||||
return &b
|
return &b
|
||||||
},
|
},
|
||||||
@@ -82,7 +82,7 @@ var (
|
|||||||
{
|
{
|
||||||
size: 65 * 1024,
|
size: 65 * 1024,
|
||||||
pool: sync.Pool{
|
pool: sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() any {
|
||||||
b := make([]byte, 65*1024)
|
b := make([]byte, 65*1024)
|
||||||
return &b
|
return &b
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
package matcher
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gobwas/glob"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Matcher is a generic pattern matcher,
|
||||||
|
// it gives the match result of the given pattern for specific v.
|
||||||
|
type Matcher interface {
|
||||||
|
Match(v string) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMatcher creates a Matcher for the given pattern.
|
||||||
|
// The acutal Matcher depends on the pattern:
|
||||||
|
// IP Matcher if pattern is a valid IP address.
|
||||||
|
// CIDR Matcher if pattern is a valid CIDR address.
|
||||||
|
// Domain Matcher if both of the above are not.
|
||||||
|
func NewMatcher(pattern string) Matcher {
|
||||||
|
if pattern == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if ip := net.ParseIP(pattern); ip != nil {
|
||||||
|
return IPMatcher(ip)
|
||||||
|
}
|
||||||
|
if _, inet, err := net.ParseCIDR(pattern); err == nil {
|
||||||
|
return CIDRMatcher(inet)
|
||||||
|
}
|
||||||
|
return DomainMatcher(pattern)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ipMatcher struct {
|
||||||
|
ip net.IP
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPMatcher creates a Matcher for a specific IP address.
|
||||||
|
func IPMatcher(ip net.IP) Matcher {
|
||||||
|
return &ipMatcher{
|
||||||
|
ip: ip,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ipMatcher) Match(ip string) bool {
|
||||||
|
if m == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return m.ip.Equal(net.ParseIP(ip))
|
||||||
|
}
|
||||||
|
|
||||||
|
type cidrMatcher struct {
|
||||||
|
ipNet *net.IPNet
|
||||||
|
}
|
||||||
|
|
||||||
|
// CIDRMatcher creates a Matcher for a specific CIDR notation IP address.
|
||||||
|
func CIDRMatcher(inet *net.IPNet) Matcher {
|
||||||
|
return &cidrMatcher{
|
||||||
|
ipNet: inet,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *cidrMatcher) Match(ip string) bool {
|
||||||
|
if m == nil || m.ipNet == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return m.ipNet.Contains(net.ParseIP(ip))
|
||||||
|
}
|
||||||
|
|
||||||
|
type domainMatcher struct {
|
||||||
|
pattern string
|
||||||
|
glob glob.Glob
|
||||||
|
}
|
||||||
|
|
||||||
|
// DomainMatcher creates a Matcher for a specific domain pattern,
|
||||||
|
// the pattern can be a plain domain such as 'example.com',
|
||||||
|
// a wildcard such as '*.exmaple.com' or a special wildcard '.example.com'.
|
||||||
|
func DomainMatcher(pattern string) Matcher {
|
||||||
|
p := pattern
|
||||||
|
if strings.HasPrefix(pattern, ".") {
|
||||||
|
p = pattern[1:] // trim the prefix '.'
|
||||||
|
pattern = "*" + p
|
||||||
|
}
|
||||||
|
return &domainMatcher{
|
||||||
|
pattern: p,
|
||||||
|
glob: glob.MustCompile(pattern),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *domainMatcher) Match(domain string) bool {
|
||||||
|
if m == nil || m.glob == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if domain == m.pattern {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return m.glob.Match(domain)
|
||||||
|
}
|
||||||
@@ -0,0 +1,222 @@
|
|||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/go-gost/gost/pkg/metrics"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errUnsupport = errors.New("unsupported operation")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ServerConn is a server side Conn with metrics supported.
|
||||||
|
type serverConn struct {
|
||||||
|
net.Conn
|
||||||
|
service string
|
||||||
|
}
|
||||||
|
|
||||||
|
func WrapConn(service string, c net.Conn) net.Conn {
|
||||||
|
return &serverConn{
|
||||||
|
service: service,
|
||||||
|
Conn: c,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *serverConn) Read(b []byte) (n int, err error) {
|
||||||
|
n, err = c.Conn.Read(b)
|
||||||
|
metrics.InputBytes(c.service).Add(float64(n))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *serverConn) Write(b []byte) (n int, err error) {
|
||||||
|
n, err = c.Conn.Write(b)
|
||||||
|
metrics.OutputBytes(c.service).Add(float64(n))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type packetConn struct {
|
||||||
|
net.PacketConn
|
||||||
|
service string
|
||||||
|
}
|
||||||
|
|
||||||
|
func WrapPacketConn(service string, pc net.PacketConn) net.PacketConn {
|
||||||
|
return &packetConn{
|
||||||
|
PacketConn: pc,
|
||||||
|
service: service,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *packetConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||||
|
n, addr, err = c.PacketConn.ReadFrom(p)
|
||||||
|
metrics.InputBytes(c.service).Add(float64(n))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *packetConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||||
|
n, err = c.PacketConn.WriteTo(p, addr)
|
||||||
|
metrics.OutputBytes(c.service).Add(float64(n))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type udpConn struct {
|
||||||
|
net.PacketConn
|
||||||
|
service string
|
||||||
|
}
|
||||||
|
|
||||||
|
func WrapUDPConn(service string, pc net.PacketConn) UDPConn {
|
||||||
|
return &udpConn{
|
||||||
|
PacketConn: pc,
|
||||||
|
service: service,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpConn) RemoteAddr() net.Addr {
|
||||||
|
if nc, ok := c.PacketConn.(remoteAddr); ok {
|
||||||
|
return nc.RemoteAddr()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpConn) SetReadBuffer(n int) error {
|
||||||
|
if nc, ok := c.PacketConn.(setBuffer); ok {
|
||||||
|
return nc.SetReadBuffer(n)
|
||||||
|
}
|
||||||
|
return errUnsupport
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpConn) SetWriteBuffer(n int) error {
|
||||||
|
if nc, ok := c.PacketConn.(setBuffer); ok {
|
||||||
|
return nc.SetWriteBuffer(n)
|
||||||
|
}
|
||||||
|
return errUnsupport
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpConn) Read(b []byte) (n int, err error) {
|
||||||
|
if nc, ok := c.PacketConn.(io.Reader); ok {
|
||||||
|
n, err = nc.Read(b)
|
||||||
|
metrics.InputBytes(c.service).Add(float64(n))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = errUnsupport
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||||
|
n, addr, err = c.PacketConn.ReadFrom(p)
|
||||||
|
metrics.InputBytes(c.service).Add(float64(n))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpConn) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) {
|
||||||
|
if nc, ok := c.PacketConn.(readUDP); ok {
|
||||||
|
n, addr, err = nc.ReadFromUDP(b)
|
||||||
|
metrics.InputBytes(c.service).Add(float64(n))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = errUnsupport
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error) {
|
||||||
|
if nc, ok := c.PacketConn.(readUDP); ok {
|
||||||
|
n, oobn, flags, addr, err = nc.ReadMsgUDP(b, oob)
|
||||||
|
metrics.InputBytes(c.service).Add(float64(n + oobn))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = errUnsupport
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpConn) Write(b []byte) (n int, err error) {
|
||||||
|
if nc, ok := c.PacketConn.(io.Writer); ok {
|
||||||
|
n, err = nc.Write(b)
|
||||||
|
metrics.OutputBytes(c.service).Add(float64(n))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = errUnsupport
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||||
|
n, err = c.PacketConn.WriteTo(p, addr)
|
||||||
|
metrics.OutputBytes(c.service).Add(float64(n))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpConn) WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error) {
|
||||||
|
if nc, ok := c.PacketConn.(writeUDP); ok {
|
||||||
|
n, err = nc.WriteToUDP(b, addr)
|
||||||
|
metrics.OutputBytes(c.service).Add(float64(n))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = errUnsupport
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpConn) WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error) {
|
||||||
|
if nc, ok := c.PacketConn.(writeUDP); ok {
|
||||||
|
n, oobn, err = nc.WriteMsgUDP(b, oob, addr)
|
||||||
|
metrics.OutputBytes(c.service).Add(float64(n + oobn))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = errUnsupport
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpConn) SyscallConn() (rc syscall.RawConn, err error) {
|
||||||
|
if nc, ok := c.PacketConn.(syscallConn); ok {
|
||||||
|
return nc.SyscallConn()
|
||||||
|
}
|
||||||
|
err = errUnsupport
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpConn) SetDSCP(n int) error {
|
||||||
|
if nc, ok := c.PacketConn.(setDSCP); ok {
|
||||||
|
return nc.SetDSCP(n)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type UDPConn interface {
|
||||||
|
net.PacketConn
|
||||||
|
io.Reader
|
||||||
|
io.Writer
|
||||||
|
readUDP
|
||||||
|
writeUDP
|
||||||
|
setBuffer
|
||||||
|
syscallConn
|
||||||
|
remoteAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
type setBuffer interface {
|
||||||
|
SetReadBuffer(bytes int) error
|
||||||
|
SetWriteBuffer(bytes int) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type readUDP interface {
|
||||||
|
ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error)
|
||||||
|
ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type writeUDP interface {
|
||||||
|
WriteToUDP(b []byte, addr *net.UDPAddr) (int, error)
|
||||||
|
WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type syscallConn interface {
|
||||||
|
SyscallConn() (syscall.RawConn, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type remoteAddr interface {
|
||||||
|
RemoteAddr() net.Addr
|
||||||
|
}
|
||||||
|
|
||||||
|
// tcpraw.TCPConn
|
||||||
|
type setDSCP interface {
|
||||||
|
SetDSCP(int) error
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package metrics
|
||||||
|
|
||||||
|
import "net"
|
||||||
|
|
||||||
|
type listener struct {
|
||||||
|
service string
|
||||||
|
net.Listener
|
||||||
|
}
|
||||||
|
|
||||||
|
func WrapListener(service string, ln net.Listener) net.Listener {
|
||||||
|
return &listener{
|
||||||
|
service: service,
|
||||||
|
Listener: ln,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ln *listener) Accept() (net.Conn, error) {
|
||||||
|
c, err := ln.Listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return WrapConn(ln.service, c), nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
package dialer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-gost/gost/pkg/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
DefaultNetDialer = &NetDialer{
|
||||||
|
Timeout: 30 * time.Second,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type NetDialer struct {
|
||||||
|
Interface string
|
||||||
|
Timeout time.Duration
|
||||||
|
DialFunc func(ctx context.Context, network, addr string) (net.Conn, error)
|
||||||
|
Logger logger.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *NetDialer) Dial(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
if d == nil {
|
||||||
|
d = DefaultNetDialer
|
||||||
|
}
|
||||||
|
log := d.Logger
|
||||||
|
if log == nil {
|
||||||
|
log = logger.Default()
|
||||||
|
}
|
||||||
|
|
||||||
|
ifceName, ifAddr, err := parseInterfaceAddr(d.Interface, network)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if d.DialFunc != nil {
|
||||||
|
return d.DialFunc(ctx, network, addr)
|
||||||
|
}
|
||||||
|
logger.Default().Infof("interface: %s %v/%s", ifceName, ifAddr, network)
|
||||||
|
|
||||||
|
switch network {
|
||||||
|
case "udp", "udp4", "udp6":
|
||||||
|
if addr == "" {
|
||||||
|
var laddr *net.UDPAddr
|
||||||
|
if ifAddr != nil {
|
||||||
|
laddr, _ = ifAddr.(*net.UDPAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return net.ListenUDP(network, laddr)
|
||||||
|
}
|
||||||
|
case "tcp", "tcp4", "tcp6":
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("dial: unsupported network %s", network)
|
||||||
|
}
|
||||||
|
netd := net.Dialer{
|
||||||
|
Timeout: d.Timeout,
|
||||||
|
LocalAddr: ifAddr,
|
||||||
|
Control: func(network, address string, c syscall.RawConn) error {
|
||||||
|
var cerr error
|
||||||
|
err := c.Control(func(fd uintptr) {
|
||||||
|
cerr = bindDevice(fd, ifceName)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if cerr != nil {
|
||||||
|
return cerr
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return netd.DialContext(ctx, network, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseInterfaceAddr(ifceName, network string) (ifce string, addr net.Addr, err error) {
|
||||||
|
if ifceName == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ip := net.ParseIP(ifceName)
|
||||||
|
if ip == nil {
|
||||||
|
var ife *net.Interface
|
||||||
|
ife, err = net.InterfaceByName(ifceName)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var addrs []net.Addr
|
||||||
|
addrs, err = ife.Addrs()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(addrs) == 0 {
|
||||||
|
err = fmt.Errorf("addr not found for interface %s", ifceName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ip = addrs[0].(*net.IPNet).IP
|
||||||
|
ifce = ifceName
|
||||||
|
} else {
|
||||||
|
ifce, err = findInterfaceByIP(ip)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
port := 0
|
||||||
|
switch network {
|
||||||
|
case "tcp", "tcp4", "tcp6":
|
||||||
|
addr = &net.TCPAddr{IP: ip, Port: port}
|
||||||
|
return
|
||||||
|
case "udp", "udp4", "udp6":
|
||||||
|
addr = &net.UDPAddr{IP: ip, Port: port}
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
addr = &net.IPAddr{IP: ip}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func findInterfaceByIP(ip net.IP) (string, error) {
|
||||||
|
ifces, err := net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
for _, ifce := range ifces {
|
||||||
|
addrs, _ := ifce.Addrs()
|
||||||
|
if len(addrs) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, addr := range addrs {
|
||||||
|
ipAddr, _ := addr.(*net.IPNet)
|
||||||
|
if ipAddr == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// logger.Default().Infof("%s-%s", ipAddr, ip)
|
||||||
|
if ipAddr.IP.Equal(ip) {
|
||||||
|
return ifce.Name, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package dialer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func bindDevice(fd uintptr, ifceName string) error {
|
||||||
|
// unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
|
||||||
|
// unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
|
||||||
|
if ifceName == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return unix.BindToDevice(int(fd), ifceName)
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
//go:build !linux
|
||||||
|
|
||||||
|
package dialer
|
||||||
|
|
||||||
|
func bindDevice(fd uintptr, ifceName string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package handler
|
package relay
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package handler
|
package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package auth
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
"github.com/go-gost/gost/pkg/auth"
|
|
||||||
)
|
|
||||||
|
|
||||||
func AuthFromUsers(users ...*url.Userinfo) auth.Authenticator {
|
|
||||||
kvs := make(map[string]string)
|
|
||||||
for _, v := range users {
|
|
||||||
if v == nil || v.Username() == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
kvs[v.Username()], _ = v.Password()
|
|
||||||
}
|
|
||||||
|
|
||||||
var authenticator auth.Authenticator
|
|
||||||
if len(kvs) > 0 {
|
|
||||||
authenticator = auth.NewMapAuthenticator(kvs)
|
|
||||||
}
|
|
||||||
|
|
||||||
return authenticator
|
|
||||||
}
|
|
||||||
@@ -95,7 +95,7 @@ func file_gost_proto_rawDescGZIP() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var file_gost_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
var file_gost_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||||
var file_gost_proto_goTypes = []interface{}{
|
var file_gost_proto_goTypes = []any{
|
||||||
(*Chunk)(nil), // 0: Chunk
|
(*Chunk)(nil), // 0: Chunk
|
||||||
}
|
}
|
||||||
var file_gost_proto_depIdxs = []int32{
|
var file_gost_proto_depIdxs = []int32{
|
||||||
@@ -114,7 +114,7 @@ func file_gost_proto_init() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !protoimpl.UnsafeEnabled {
|
if !protoimpl.UnsafeEnabled {
|
||||||
file_gost_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
file_gost_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
||||||
switch v := v.(*Chunk); i {
|
switch v := v.(*Chunk); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ func RegisterGostTunelServer(s grpc.ServiceRegistrar, srv GostTunelServer) {
|
|||||||
s.RegisterService(&GostTunel_ServiceDesc, srv)
|
s.RegisterService(&GostTunel_ServiceDesc, srv)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _GostTunel_Tunnel_Handler(srv interface{}, stream grpc.ServerStream) error {
|
func _GostTunel_Tunnel_Handler(srv any, stream grpc.ServerStream) error {
|
||||||
return srv.(GostTunelServer).Tunnel(&gostTunelTunnelServer{stream})
|
return srv.(GostTunelServer).Tunnel(&gostTunelTunnelServer{stream})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ func (session *Session) GetConn() (net.Conn, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &StreamConn{Conn: session.conn, stream: stream}, nil
|
return &streamConn{Conn: session.conn, stream: stream}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *Session) Accept() (net.Conn, error) {
|
func (session *Session) Accept() (net.Conn, error) {
|
||||||
@@ -46,7 +46,7 @@ func (session *Session) Accept() (net.Conn, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &StreamConn{Conn: session.conn, stream: stream}, nil
|
return &streamConn{Conn: session.conn, stream: stream}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *Session) Close() error {
|
func (session *Session) Close() error {
|
||||||
@@ -67,19 +67,19 @@ func (session *Session) NumStreams() int {
|
|||||||
return session.session.NumStreams()
|
return session.session.NumStreams()
|
||||||
}
|
}
|
||||||
|
|
||||||
type StreamConn struct {
|
type streamConn struct {
|
||||||
net.Conn
|
net.Conn
|
||||||
stream *smux.Stream
|
stream *smux.Stream
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StreamConn) Read(b []byte) (n int, err error) {
|
func (c *streamConn) Read(b []byte) (n int, err error) {
|
||||||
return c.stream.Read(b)
|
return c.stream.Read(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StreamConn) Write(b []byte) (n int, err error) {
|
func (c *streamConn) Write(b []byte) (n int, err error) {
|
||||||
return c.stream.Write(b)
|
return c.stream.Write(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StreamConn) Close() error {
|
func (c *streamConn) Close() error {
|
||||||
return c.stream.Close()
|
return c.stream.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ func (p *ConnPool) WithLogger(logger logger.Logger) *ConnPool {
|
|||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ConnPool) Get(key interface{}) (c *Conn, ok bool) {
|
func (p *ConnPool) Get(key any) (c *Conn, ok bool) {
|
||||||
v, ok := p.m.Load(key)
|
v, ok := p.m.Load(key)
|
||||||
if ok {
|
if ok {
|
||||||
c, ok = v.(*Conn)
|
c, ok = v.(*Conn)
|
||||||
@@ -36,11 +36,11 @@ func (p *ConnPool) Get(key interface{}) (c *Conn, ok bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ConnPool) Set(key interface{}, c *Conn) {
|
func (p *ConnPool) Set(key any, c *Conn) {
|
||||||
p.m.Store(key, c)
|
p.m.Store(key, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ConnPool) Delete(key interface{}) {
|
func (p *ConnPool) Delete(key any) {
|
||||||
p.m.Delete(key)
|
p.m.Delete(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ func (p *ConnPool) Close() {
|
|||||||
|
|
||||||
close(p.closed)
|
close(p.closed)
|
||||||
|
|
||||||
p.m.Range(func(k, v interface{}) bool {
|
p.m.Range(func(k, v any) bool {
|
||||||
if c, ok := v.(*Conn); ok && c != nil {
|
if c, ok := v.(*Conn); ok && c != nil {
|
||||||
c.Close()
|
c.Close()
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,7 @@ func (p *ConnPool) idleCheck() {
|
|||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
size := 0
|
size := 0
|
||||||
idles := 0
|
idles := 0
|
||||||
p.m.Range(func(key, value interface{}) bool {
|
p.m.Range(func(key, value any) bool {
|
||||||
c, ok := value.(*Conn)
|
c, ok := value.(*Conn)
|
||||||
if !ok || c == nil {
|
if !ok || c == nil {
|
||||||
p.Delete(key)
|
p.Delete(key)
|
||||||
|
|||||||
+164
-86
@@ -1,7 +1,9 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
@@ -19,149 +21,215 @@ func init() {
|
|||||||
v.AddConfigPath(".")
|
v.AddConfigPath(".")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
global = &Config{}
|
||||||
|
globalMux sync.RWMutex
|
||||||
|
)
|
||||||
|
|
||||||
|
func Global() *Config {
|
||||||
|
globalMux.RLock()
|
||||||
|
defer globalMux.RUnlock()
|
||||||
|
|
||||||
|
cfg := &Config{}
|
||||||
|
*cfg = *global
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetGlobal(c *Config) {
|
||||||
|
globalMux.Lock()
|
||||||
|
defer globalMux.Unlock()
|
||||||
|
|
||||||
|
global = c
|
||||||
|
}
|
||||||
|
|
||||||
type LogConfig struct {
|
type LogConfig struct {
|
||||||
Output string `yaml:",omitempty"`
|
Output string `yaml:",omitempty" json:"output,omitempty"`
|
||||||
Level string `yaml:",omitempty"`
|
Level string `yaml:",omitempty" json:"level,omitempty"`
|
||||||
Format string `yaml:",omitempty"`
|
Format string `yaml:",omitempty" json:"format,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProfilingConfig struct {
|
type ProfilingConfig struct {
|
||||||
Addr string
|
Addr string `json:"addr"`
|
||||||
Enabled bool
|
Enable bool `json:"enable"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type APIConfig struct {
|
||||||
|
Addr string `json:"addr"`
|
||||||
|
PathPrefix string `yaml:"pathPrefix,omitempty" json:"pathPrefix,omitempty"`
|
||||||
|
AccessLog bool `yaml:"accesslog,omitempty" json:"accesslog,omitempty"`
|
||||||
|
Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"`
|
||||||
|
Auther string `yaml:",omitempty" json:"auther,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MetricsConfig struct {
|
||||||
|
Addr string `json:"addr"`
|
||||||
|
Path string `json:"path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TLSConfig struct {
|
type TLSConfig struct {
|
||||||
CertFile string `yaml:"certFile,omitempty"`
|
CertFile string `yaml:"certFile,omitempty" json:"certFile,omitempty"`
|
||||||
KeyFile string `yaml:"keyFile,omitempty"`
|
KeyFile string `yaml:"keyFile,omitempty" json:"keyFile,omitempty"`
|
||||||
CAFile string `yaml:"caFile,omitempty"`
|
CAFile string `yaml:"caFile,omitempty" json:"caFile,omitempty"`
|
||||||
Secure bool `yaml:",omitempty"`
|
Secure bool `yaml:",omitempty" json:"secure,omitempty"`
|
||||||
ServerName string `yaml:"serverName,omitempty"`
|
ServerName string `yaml:"serverName,omitempty" json:"serverName,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AutherConfig struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
// inline, file, redis, etc.
|
||||||
|
Type string `yaml:",omitempty" json:"type,omitempty"`
|
||||||
|
Auths []*AuthConfig `yaml:",omitempty" json:"auths"`
|
||||||
|
// File string `yaml:",omitempty" json:"file"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthConfig struct {
|
type AuthConfig struct {
|
||||||
Username string
|
Username string `json:"username"`
|
||||||
Password string
|
Password string `yaml:",omitempty" json:"password,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SelectorConfig struct {
|
type SelectorConfig struct {
|
||||||
Strategy string
|
Strategy string `json:"strategy"`
|
||||||
MaxFails int `yaml:"maxFails"`
|
MaxFails int `yaml:"maxFails" json:"maxFails"`
|
||||||
FailTimeout time.Duration `yaml:"failTimeout"`
|
FailTimeout time.Duration `yaml:"failTimeout" json:"failTimeout"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AdmissionConfig struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
// inline, file, etc.
|
||||||
|
Type string `yaml:",omitempty" json:"type,omitempty"`
|
||||||
|
Reverse bool `yaml:",omitempty" json:"reverse,omitempty"`
|
||||||
|
Matchers []string `json:"matchers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BypassConfig struct {
|
type BypassConfig struct {
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
Reverse bool `yaml:",omitempty"`
|
// inline, file, etc.
|
||||||
Matchers []string
|
Type string `yaml:",omitempty" json:"type,omitempty"`
|
||||||
|
Reverse bool `yaml:",omitempty" json:"reverse,omitempty"`
|
||||||
|
Matchers []string `json:"matchers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type NameserverConfig struct {
|
type NameserverConfig struct {
|
||||||
Addr string
|
Addr string `json:"addr"`
|
||||||
Chain string `yaml:",omitempty"`
|
Chain string `yaml:",omitempty" json:"chain,omitempty"`
|
||||||
Prefer string `yaml:",omitempty"`
|
Prefer string `yaml:",omitempty" json:"prefer,omitempty"`
|
||||||
ClientIP string `yaml:"clientIP,omitempty"`
|
ClientIP string `yaml:"clientIP,omitempty" json:"clientIP,omitempty"`
|
||||||
Hostname string `yaml:",omitempty"`
|
Hostname string `yaml:",omitempty" json:"hostname,omitempty"`
|
||||||
TTL time.Duration `yaml:",omitempty"`
|
TTL time.Duration `yaml:",omitempty" json:"ttl,omitempty"`
|
||||||
Timeout time.Duration `yaml:",omitempty"`
|
Timeout time.Duration `yaml:",omitempty" json:"timeout,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResolverConfig struct {
|
type ResolverConfig struct {
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
Nameservers []NameserverConfig
|
// inline, file, etc.
|
||||||
|
Type string `yaml:",omitempty" json:"type,omitempty"`
|
||||||
|
Nameservers []*NameserverConfig `json:"nameservers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type HostMappingConfig struct {
|
type HostMappingConfig struct {
|
||||||
IP string
|
IP string `json:"ip"`
|
||||||
Hostname string
|
Hostname string `json:"hostname"`
|
||||||
Aliases []string `yaml:",omitempty"`
|
Aliases []string `yaml:",omitempty" json:"aliases,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type HostsConfig struct {
|
type HostsConfig struct {
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
Mappings []HostMappingConfig
|
// inline, file, etc.
|
||||||
|
Type string `yaml:",omitempty" json:"type,omitempty"`
|
||||||
|
Mappings []*HostMappingConfig `json:"mappings"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListenerConfig struct {
|
type ListenerConfig struct {
|
||||||
Type string
|
Type string `json:"type"`
|
||||||
Chain string `yaml:",omitempty"`
|
Chain string `yaml:",omitempty" json:"chain,omitempty"`
|
||||||
Auths []*AuthConfig `yaml:",omitempty"`
|
Auther string `yaml:",omitempty" json:"auther,omitempty"`
|
||||||
TLS *TLSConfig `yaml:",omitempty"`
|
Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"`
|
||||||
Metadata map[string]interface{} `yaml:",omitempty"`
|
TLS *TLSConfig `yaml:",omitempty" json:"tls,omitempty"`
|
||||||
|
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type HandlerConfig struct {
|
type HandlerConfig struct {
|
||||||
Type string
|
Type string `json:"type"`
|
||||||
Retries int `yaml:",omitempty"`
|
Retries int `yaml:",omitempty" json:"retries,omitempty"`
|
||||||
Chain string `yaml:",omitempty"`
|
Chain string `yaml:",omitempty" json:"chain,omitempty"`
|
||||||
Auths []*AuthConfig `yaml:",omitempty"`
|
Auther string `yaml:",omitempty" json:"auther,omitempty"`
|
||||||
TLS *TLSConfig `yaml:",omitempty"`
|
Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"`
|
||||||
Metadata map[string]interface{} `yaml:",omitempty"`
|
TLS *TLSConfig `yaml:",omitempty" json:"tls,omitempty"`
|
||||||
|
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ForwarderConfig struct {
|
type ForwarderConfig struct {
|
||||||
Targets []string
|
Targets []string `json:"targets"`
|
||||||
Selector *SelectorConfig `yaml:",omitempty"`
|
Selector *SelectorConfig `yaml:",omitempty" json:"selector,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DialerConfig struct {
|
type DialerConfig struct {
|
||||||
Type string
|
Type string `json:"type"`
|
||||||
Auth *AuthConfig `yaml:",omitempty"`
|
Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"`
|
||||||
TLS *TLSConfig `yaml:",omitempty"`
|
TLS *TLSConfig `yaml:",omitempty" json:"tls,omitempty"`
|
||||||
Metadata map[string]interface{} `yaml:",omitempty"`
|
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConnectorConfig struct {
|
type ConnectorConfig struct {
|
||||||
Type string
|
Type string `json:"type"`
|
||||||
Auth *AuthConfig `yaml:",omitempty"`
|
Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"`
|
||||||
TLS *TLSConfig `yaml:",omitempty"`
|
TLS *TLSConfig `yaml:",omitempty" json:"tls,omitempty"`
|
||||||
Metadata map[string]interface{} `yaml:",omitempty"`
|
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServiceConfig struct {
|
type ServiceConfig struct {
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
Addr string `yaml:",omitempty"`
|
Addr string `yaml:",omitempty" json:"addr,omitempty"`
|
||||||
Bypass string `yaml:",omitempty"`
|
Interface string `yaml:",omitempty" json:"interface,omitempty"`
|
||||||
Resolver string `yaml:",omitempty"`
|
Admission string `yaml:",omitempty" json:"admission,omitempty"`
|
||||||
Hosts string `yaml:",omitempty"`
|
Bypass string `yaml:",omitempty" json:"bypass,omitempty"`
|
||||||
Handler *HandlerConfig `yaml:",omitempty"`
|
Resolver string `yaml:",omitempty" json:"resolver,omitempty"`
|
||||||
Listener *ListenerConfig `yaml:",omitempty"`
|
Hosts string `yaml:",omitempty" json:"hosts,omitempty"`
|
||||||
Forwarder *ForwarderConfig `yaml:",omitempty"`
|
Handler *HandlerConfig `yaml:",omitempty" json:"handler,omitempty"`
|
||||||
|
Listener *ListenerConfig `yaml:",omitempty" json:"listener,omitempty"`
|
||||||
|
Forwarder *ForwarderConfig `yaml:",omitempty" json:"forwarder,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChainConfig struct {
|
type ChainConfig struct {
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
Selector *SelectorConfig `yaml:",omitempty"`
|
Selector *SelectorConfig `yaml:",omitempty" json:"selector,omitempty"`
|
||||||
Hops []*HopConfig
|
Hops []*HopConfig `json:"hops"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type HopConfig struct {
|
type HopConfig struct {
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
Selector *SelectorConfig `yaml:",omitempty"`
|
Interface string `yaml:",omitempty" json:"interface,omitempty"`
|
||||||
Bypass string `yaml:",omitempty"`
|
Selector *SelectorConfig `yaml:",omitempty" json:"selector,omitempty"`
|
||||||
Resolver string `yaml:",omitempty"`
|
Bypass string `yaml:",omitempty" json:"bypass,omitempty"`
|
||||||
Hosts string `yaml:",omitempty"`
|
Resolver string `yaml:",omitempty" json:"resolver,omitempty"`
|
||||||
Nodes []*NodeConfig
|
Hosts string `yaml:",omitempty" json:"hosts,omitempty"`
|
||||||
|
Nodes []*NodeConfig `json:"nodes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type NodeConfig struct {
|
type NodeConfig struct {
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
Addr string `yaml:",omitempty"`
|
Addr string `yaml:",omitempty" json:"addr,omitempty"`
|
||||||
Bypass string `yaml:",omitempty"`
|
Interface string `yaml:",omitempty" json:"interface,omitempty"`
|
||||||
Resolver string `yaml:",omitempty"`
|
Bypass string `yaml:",omitempty" json:"bypass,omitempty"`
|
||||||
Hosts string `yaml:",omitempty"`
|
Resolver string `yaml:",omitempty" json:"resolver,omitempty"`
|
||||||
Connector *ConnectorConfig `yaml:",omitempty"`
|
Hosts string `yaml:",omitempty" json:"hosts,omitempty"`
|
||||||
Dialer *DialerConfig `yaml:",omitempty"`
|
Connector *ConnectorConfig `yaml:",omitempty" json:"connector,omitempty"`
|
||||||
|
Dialer *DialerConfig `yaml:",omitempty" json:"dialer,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Services []*ServiceConfig
|
Services []*ServiceConfig `json:"services"`
|
||||||
Chains []*ChainConfig `yaml:",omitempty"`
|
Chains []*ChainConfig `yaml:",omitempty" json:"chains,omitempty"`
|
||||||
Bypasses []*BypassConfig `yaml:",omitempty"`
|
Authers []*AutherConfig `yaml:",omitempty" json:"authers,omitempty"`
|
||||||
Resolvers []*ResolverConfig `yaml:",omitempty"`
|
Admissions []*AdmissionConfig `yaml:",omitempty" json:"admissions,omitempty"`
|
||||||
Hosts []*HostsConfig `yaml:",omitempty"`
|
Bypasses []*BypassConfig `yaml:",omitempty" json:"bypasses,omitempty"`
|
||||||
TLS *TLSConfig `yaml:",omitempty"`
|
Resolvers []*ResolverConfig `yaml:",omitempty" json:"resolvers,omitempty"`
|
||||||
Log *LogConfig `yaml:",omitempty"`
|
Hosts []*HostsConfig `yaml:",omitempty" json:"hosts,omitempty"`
|
||||||
Profiling *ProfilingConfig `yaml:",omitempty"`
|
TLS *TLSConfig `yaml:",omitempty" json:"tls,omitempty"`
|
||||||
|
Log *LogConfig `yaml:",omitempty" json:"log,omitempty"`
|
||||||
|
Profiling *ProfilingConfig `yaml:",omitempty" json:"profiling,omitempty"`
|
||||||
|
API *APIConfig `yaml:",omitempty" json:"api,omitempty"`
|
||||||
|
Metrics *MetricsConfig `yaml:",omitempty" json:"metrics,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Load() error {
|
func (c *Config) Load() error {
|
||||||
@@ -188,9 +256,19 @@ func (c *Config) ReadFile(file string) error {
|
|||||||
return v.Unmarshal(c)
|
return v.Unmarshal(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Write(w io.Writer) error {
|
func (c *Config) Write(w io.Writer, format string) error {
|
||||||
|
switch format {
|
||||||
|
case "json":
|
||||||
|
enc := json.NewEncoder(w)
|
||||||
|
enc.SetIndent("", " ")
|
||||||
|
enc.Encode(c)
|
||||||
|
return nil
|
||||||
|
case "yaml":
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
enc := yaml.NewEncoder(w)
|
enc := yaml.NewEncoder(w)
|
||||||
defer enc.Close()
|
defer enc.Close()
|
||||||
|
|
||||||
return enc.Encode(c)
|
return enc.Encode(c)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
package parsing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-gost/gost/pkg/chain"
|
||||||
|
tls_util "github.com/go-gost/gost/pkg/common/util/tls"
|
||||||
|
"github.com/go-gost/gost/pkg/config"
|
||||||
|
"github.com/go-gost/gost/pkg/connector"
|
||||||
|
"github.com/go-gost/gost/pkg/dialer"
|
||||||
|
"github.com/go-gost/gost/pkg/logger"
|
||||||
|
"github.com/go-gost/gost/pkg/metadata"
|
||||||
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
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.Chain{}
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
package parsing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/go-gost/gost/pkg/admission"
|
||||||
|
"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"
|
||||||
|
hostspkg "github.com/go-gost/gost/pkg/hosts"
|
||||||
|
"github.com/go-gost/gost/pkg/logger"
|
||||||
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
|
"github.com/go-gost/gost/pkg/resolver"
|
||||||
|
resolver_impl "github.com/go-gost/gost/pkg/resolver/impl"
|
||||||
|
)
|
||||||
|
|
||||||
|
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.NewMapAuthenticator(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseAutherFromAuth(au *config.AuthConfig) auth.Authenticator {
|
||||||
|
if au == nil || au.Username == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return auth.NewMapAuthenticator(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
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
package parsing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-gost/gost/pkg/chain"
|
||||||
|
tls_util "github.com/go-gost/gost/pkg/common/util/tls"
|
||||||
|
"github.com/go-gost/gost/pkg/config"
|
||||||
|
"github.com/go-gost/gost/pkg/handler"
|
||||||
|
"github.com/go-gost/gost/pkg/listener"
|
||||||
|
"github.com/go-gost/gost/pkg/logger"
|
||||||
|
"github.com/go-gost/gost/pkg/metadata"
|
||||||
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
|
"github.com/go-gost/gost/pkg/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
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.ChainOption(registry.ChainRegistry().Get(cfg.Listener.Chain)),
|
||||||
|
listener.AutherOption(auther),
|
||||||
|
listener.AuthOption(parseAuth(cfg.Listener.Auth)),
|
||||||
|
listener.TLSConfigOption(tlsConfig),
|
||||||
|
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))
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegiserConnector("forward", NewConnector)
|
registry.ConnectorRegistry().Register("forward", NewConnector)
|
||||||
}
|
}
|
||||||
|
|
||||||
type forwardConnector struct {
|
type forwardConnector struct {
|
||||||
@@ -33,7 +33,7 @@ func (c *forwardConnector) Init(md md.Metadata) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *forwardConnector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
func (c *forwardConnector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
||||||
log := c.options.Logger.WithFields(map[string]interface{}{
|
log := c.options.Logger.WithFields(map[string]any{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
"network": network,
|
"network": network,
|
||||||
|
|||||||
@@ -19,11 +19,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegiserConnector("http", NewConnector)
|
registry.ConnectorRegistry().Register("http", NewConnector)
|
||||||
}
|
}
|
||||||
|
|
||||||
type httpConnector struct {
|
type httpConnector struct {
|
||||||
user *url.Userinfo
|
|
||||||
md metadata
|
md metadata
|
||||||
options connector.Options
|
options connector.Options
|
||||||
}
|
}
|
||||||
@@ -35,7 +34,6 @@ func NewConnector(opts ...connector.Option) connector.Connector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &httpConnector{
|
return &httpConnector{
|
||||||
user: options.User,
|
|
||||||
options: options,
|
options: options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -45,7 +43,7 @@ func (c *httpConnector) Init(md md.Metadata) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *httpConnector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
func (c *httpConnector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
||||||
log := c.options.Logger.WithFields(map[string]interface{}{
|
log := c.options.Logger.WithFields(map[string]any{
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"network": network,
|
"network": network,
|
||||||
@@ -67,7 +65,7 @@ func (c *httpConnector) Connect(ctx context.Context, conn net.Conn, network, add
|
|||||||
}
|
}
|
||||||
req.Header.Set("Proxy-Connection", "keep-alive")
|
req.Header.Set("Proxy-Connection", "keep-alive")
|
||||||
|
|
||||||
if user := c.user; user != nil {
|
if user := c.options.Auth; user != nil {
|
||||||
u := user.Username()
|
u := user.Username()
|
||||||
p, _ := user.Password()
|
p, _ := user.Password()
|
||||||
req.Header.Set("Proxy-Authorization",
|
req.Header.Set("Proxy-Authorization",
|
||||||
|
|||||||
@@ -20,11 +20,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegiserConnector("http2", NewConnector)
|
registry.ConnectorRegistry().Register("http2", NewConnector)
|
||||||
}
|
}
|
||||||
|
|
||||||
type http2Connector struct {
|
type http2Connector struct {
|
||||||
user *url.Userinfo
|
|
||||||
md metadata
|
md metadata
|
||||||
options connector.Options
|
options connector.Options
|
||||||
}
|
}
|
||||||
@@ -36,7 +35,6 @@ func NewConnector(opts ...connector.Option) connector.Connector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &http2Connector{
|
return &http2Connector{
|
||||||
user: options.User,
|
|
||||||
options: options,
|
options: options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,7 +44,7 @@ func (c *http2Connector) Init(md md.Metadata) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *http2Connector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
func (c *http2Connector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
||||||
log := c.options.Logger.WithFields(map[string]interface{}{
|
log := c.options.Logger.WithFields(map[string]any{
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"network": network,
|
"network": network,
|
||||||
@@ -76,7 +74,7 @@ func (c *http2Connector) Connect(ctx context.Context, conn net.Conn, network, ad
|
|||||||
req.Header.Set("User-Agent", c.md.UserAgent)
|
req.Header.Set("User-Agent", c.md.UserAgent)
|
||||||
}
|
}
|
||||||
|
|
||||||
if user := c.user; user != nil {
|
if user := c.options.Auth; user != nil {
|
||||||
u := user.Username()
|
u := user.Username()
|
||||||
p, _ := user.Password()
|
p, _ := user.Password()
|
||||||
req.Header.Set("Proxy-Authorization",
|
req.Header.Set("Proxy-Authorization",
|
||||||
|
|||||||
@@ -9,16 +9,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
User *url.Userinfo
|
Auth *url.Userinfo
|
||||||
TLSConfig *tls.Config
|
TLSConfig *tls.Config
|
||||||
Logger logger.Logger
|
Logger logger.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
type Option func(opts *Options)
|
type Option func(opts *Options)
|
||||||
|
|
||||||
func UserOption(user *url.Userinfo) Option {
|
func AuthOption(auth *url.Userinfo) Option {
|
||||||
return func(opts *Options) {
|
return func(opts *Options) {
|
||||||
opts.User = user
|
opts.Auth = auth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import (
|
|||||||
|
|
||||||
// Bind implements connector.Binder.
|
// Bind implements connector.Binder.
|
||||||
func (c *relayConnector) Bind(ctx context.Context, conn net.Conn, network, address string, opts ...connector.BindOption) (net.Listener, error) {
|
func (c *relayConnector) Bind(ctx context.Context, conn net.Conn, network, address string, opts ...connector.BindOption) (net.Listener, error) {
|
||||||
log := c.options.Logger.WithFields(map[string]interface{}{
|
log := c.options.Logger.WithFields(map[string]any{
|
||||||
"network": network,
|
"network": network,
|
||||||
"address": address,
|
"address": address,
|
||||||
})
|
})
|
||||||
@@ -82,10 +82,10 @@ func (c *relayConnector) bind(conn net.Conn, cmd uint8, network, address string)
|
|||||||
Flags: cmd,
|
Flags: cmd,
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.user != nil {
|
if c.options.Auth != nil {
|
||||||
pwd, _ := c.user.Password()
|
pwd, _ := c.options.Auth.Password()
|
||||||
req.Features = append(req.Features, &relay.UserAuthFeature{
|
req.Features = append(req.Features, &relay.UserAuthFeature{
|
||||||
Username: c.user.Username(),
|
Username: c.options.Auth.Username(),
|
||||||
Password: pwd,
|
Password: pwd,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-gost/gost/pkg/common/util/socks"
|
"github.com/go-gost/gost/pkg/common/util/socks"
|
||||||
@@ -15,11 +14,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegiserConnector("relay", NewConnector)
|
registry.ConnectorRegistry().Register("relay", NewConnector)
|
||||||
}
|
}
|
||||||
|
|
||||||
type relayConnector struct {
|
type relayConnector struct {
|
||||||
user *url.Userinfo
|
|
||||||
md metadata
|
md metadata
|
||||||
options connector.Options
|
options connector.Options
|
||||||
}
|
}
|
||||||
@@ -31,7 +29,6 @@ func NewConnector(opts ...connector.Option) connector.Connector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &relayConnector{
|
return &relayConnector{
|
||||||
user: options.User,
|
|
||||||
options: options,
|
options: options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -41,7 +38,7 @@ func (c *relayConnector) Init(md md.Metadata) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *relayConnector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
func (c *relayConnector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
||||||
log := c.options.Logger.WithFields(map[string]interface{}{
|
log := c.options.Logger.WithFields(map[string]any{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
"network": network,
|
"network": network,
|
||||||
@@ -73,10 +70,10 @@ func (c *relayConnector) Connect(ctx context.Context, conn net.Conn, network, ad
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.user != nil {
|
if c.options.Auth != nil {
|
||||||
pwd, _ := c.user.Password()
|
pwd, _ := c.options.Auth.Password()
|
||||||
req.Features = append(req.Features, &relay.UserAuthFeature{
|
req.Features = append(req.Features, &relay.UserAuthFeature{
|
||||||
Username: c.user.Username(),
|
Username: c.options.Auth.Username(),
|
||||||
Password: pwd,
|
Password: pwd,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegiserConnector("sni", NewConnector)
|
registry.ConnectorRegistry().Register("sni", NewConnector)
|
||||||
}
|
}
|
||||||
|
|
||||||
type sniConnector struct {
|
type sniConnector struct {
|
||||||
@@ -34,7 +34,7 @@ func (c *sniConnector) Init(md md.Metadata) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *sniConnector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
func (c *sniConnector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
||||||
log := c.options.Logger.WithFields(map[string]interface{}{
|
log := c.options.Logger.WithFields(map[string]any{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
"network": network,
|
"network": network,
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -16,12 +15,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegiserConnector("socks4", NewConnector)
|
registry.ConnectorRegistry().Register("socks4", NewConnector)
|
||||||
registry.RegiserConnector("socks4a", NewConnector)
|
registry.ConnectorRegistry().Register("socks4a", NewConnector)
|
||||||
}
|
}
|
||||||
|
|
||||||
type socks4Connector struct {
|
type socks4Connector struct {
|
||||||
user *url.Userinfo
|
|
||||||
md metadata
|
md metadata
|
||||||
options connector.Options
|
options connector.Options
|
||||||
}
|
}
|
||||||
@@ -33,7 +31,6 @@ func NewConnector(opts ...connector.Option) connector.Connector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &socks4Connector{
|
return &socks4Connector{
|
||||||
user: options.User,
|
|
||||||
options: options,
|
options: options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,7 +40,7 @@ func (c *socks4Connector) Init(md md.Metadata) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *socks4Connector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
func (c *socks4Connector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
||||||
log := c.options.Logger.WithFields(map[string]interface{}{
|
log := c.options.Logger.WithFields(map[string]any{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
"network": network,
|
"network": network,
|
||||||
@@ -99,8 +96,8 @@ func (c *socks4Connector) Connect(ctx context.Context, conn net.Conn, network, a
|
|||||||
}
|
}
|
||||||
|
|
||||||
var userid []byte
|
var userid []byte
|
||||||
if c.user != nil && c.user.Username() != "" {
|
if c.options.Auth != nil {
|
||||||
userid = []byte(c.user.Username())
|
userid = []byte(c.options.Auth.Username())
|
||||||
}
|
}
|
||||||
req := gosocks4.NewRequest(gosocks4.CmdConnect, addr, userid)
|
req := gosocks4.NewRequest(gosocks4.CmdConnect, addr, userid)
|
||||||
if err := req.Write(conn); err != nil {
|
if err := req.Write(conn); err != nil {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
|
|
||||||
// Bind implements connector.Binder.
|
// Bind implements connector.Binder.
|
||||||
func (c *socks5Connector) Bind(ctx context.Context, conn net.Conn, network, address string, opts ...connector.BindOption) (net.Listener, error) {
|
func (c *socks5Connector) Bind(ctx context.Context, conn net.Conn, network, address string, opts ...connector.BindOption) (net.Listener, error) {
|
||||||
log := c.options.Logger.WithFields(map[string]interface{}{
|
log := c.options.Logger.WithFields(map[string]any{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
"network": network,
|
"network": network,
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegiserConnector("socks5", NewConnector)
|
registry.ConnectorRegistry().Register("socks5", NewConnector)
|
||||||
registry.RegiserConnector("socks", NewConnector)
|
registry.ConnectorRegistry().Register("socks", NewConnector)
|
||||||
}
|
}
|
||||||
|
|
||||||
type socks5Connector struct {
|
type socks5Connector struct {
|
||||||
@@ -48,7 +48,7 @@ func (c *socks5Connector) Init(md md.Metadata) (err error) {
|
|||||||
gosocks5.MethodNoAuth,
|
gosocks5.MethodNoAuth,
|
||||||
gosocks5.MethodUserPass,
|
gosocks5.MethodUserPass,
|
||||||
},
|
},
|
||||||
User: c.options.User,
|
User: c.options.Auth,
|
||||||
TLSConfig: c.options.TLSConfig,
|
TLSConfig: c.options.TLSConfig,
|
||||||
logger: c.options.Logger,
|
logger: c.options.Logger,
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ func (c *socks5Connector) Init(md md.Metadata) (err error) {
|
|||||||
|
|
||||||
// Handshake implements connector.Handshaker.
|
// Handshake implements connector.Handshaker.
|
||||||
func (c *socks5Connector) Handshake(ctx context.Context, conn net.Conn) (net.Conn, error) {
|
func (c *socks5Connector) Handshake(ctx context.Context, conn net.Conn) (net.Conn, error) {
|
||||||
log := c.options.Logger.WithFields(map[string]interface{}{
|
log := c.options.Logger.WithFields(map[string]any{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
})
|
})
|
||||||
@@ -87,7 +87,7 @@ func (c *socks5Connector) Handshake(ctx context.Context, conn net.Conn) (net.Con
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *socks5Connector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
func (c *socks5Connector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
||||||
log := c.options.Logger.WithFields(map[string]interface{}{
|
log := c.options.Logger.WithFields(map[string]any{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
"network": network,
|
"network": network,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegiserConnector("ss", NewConnector)
|
registry.ConnectorRegistry().Register("ss", NewConnector)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ssConnector struct {
|
type ssConnector struct {
|
||||||
@@ -41,9 +41,9 @@ func (c *ssConnector) Init(md md.Metadata) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.options.User != nil {
|
if c.options.Auth != nil {
|
||||||
method := c.options.User.Username()
|
method := c.options.Auth.Username()
|
||||||
password, _ := c.options.User.Password()
|
password, _ := c.options.Auth.Password()
|
||||||
c.cipher, err = ss.ShadowCipher(method, password, c.md.key)
|
c.cipher, err = ss.ShadowCipher(method, password, c.md.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ func (c *ssConnector) Init(md md.Metadata) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ssConnector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
func (c *ssConnector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
||||||
log := c.options.Logger.WithFields(map[string]interface{}{
|
log := c.options.Logger.WithFields(map[string]any{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
"network": network,
|
"network": network,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegiserConnector("ssu", NewConnector)
|
registry.ConnectorRegistry().Register("ssu", NewConnector)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ssuConnector struct {
|
type ssuConnector struct {
|
||||||
@@ -40,9 +40,9 @@ func (c *ssuConnector) Init(md md.Metadata) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.options.User != nil {
|
if c.options.Auth != nil {
|
||||||
method := c.options.User.Username()
|
method := c.options.Auth.Username()
|
||||||
password, _ := c.options.User.Password()
|
password, _ := c.options.Auth.Password()
|
||||||
c.cipher, err = ss.ShadowCipher(method, password, c.md.key)
|
c.cipher, err = ss.ShadowCipher(method, password, c.md.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ func (c *ssuConnector) Init(md md.Metadata) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ssuConnector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
func (c *ssuConnector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
||||||
log := c.options.Logger.WithFields(map[string]interface{}{
|
log := c.options.Logger.WithFields(map[string]any{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
"network": network,
|
"network": network,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegiserConnector("sshd", NewConnector)
|
registry.ConnectorRegistry().Register("sshd", NewConnector)
|
||||||
}
|
}
|
||||||
|
|
||||||
type sshdConnector struct {
|
type sshdConnector struct {
|
||||||
@@ -35,7 +35,7 @@ func (c *sshdConnector) Init(md md.Metadata) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *sshdConnector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
func (c *sshdConnector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
|
||||||
log := c.options.Logger.WithFields(map[string]interface{}{
|
log := c.options.Logger.WithFields(map[string]any{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
"network": network,
|
"network": network,
|
||||||
@@ -59,7 +59,7 @@ func (c *sshdConnector) Connect(ctx context.Context, conn net.Conn, network, add
|
|||||||
|
|
||||||
// Bind implements connector.Binder.
|
// Bind implements connector.Binder.
|
||||||
func (c *sshdConnector) Bind(ctx context.Context, conn net.Conn, network, address string, opts ...connector.BindOption) (net.Listener, error) {
|
func (c *sshdConnector) Bind(ctx context.Context, conn net.Conn, network, address string, opts ...connector.BindOption) (net.Listener, error) {
|
||||||
log := c.options.Logger.WithFields(map[string]interface{}{
|
log := c.options.Logger.WithFields(map[string]any{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
"network": network,
|
"network": network,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterDialer("ftcp", NewDialer)
|
registry.DialerRegistry().Register("ftcp", NewDialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ftcpDialer struct {
|
type ftcpDialer struct {
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
|
|
||||||
pb "github.com/go-gost/gost/pkg/common/util/grpc/proto"
|
pb "github.com/go-gost/gost/pkg/common/util/grpc/proto"
|
||||||
"github.com/go-gost/gost/pkg/dialer"
|
"github.com/go-gost/gost/pkg/dialer"
|
||||||
"github.com/go-gost/gost/pkg/logger"
|
|
||||||
md "github.com/go-gost/gost/pkg/metadata"
|
md "github.com/go-gost/gost/pkg/metadata"
|
||||||
"github.com/go-gost/gost/pkg/registry"
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
@@ -18,13 +17,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterDialer("grpc", NewDialer)
|
registry.DialerRegistry().Register("grpc", NewDialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type grpcDialer struct {
|
type grpcDialer struct {
|
||||||
clients map[string]pb.GostTunelClient
|
clients map[string]pb.GostTunelClient
|
||||||
clientMutex sync.Mutex
|
clientMutex sync.Mutex
|
||||||
logger logger.Logger
|
|
||||||
md metadata
|
md metadata
|
||||||
options dialer.Options
|
options dialer.Options
|
||||||
}
|
}
|
||||||
@@ -37,7 +35,6 @@ func NewDialer(opts ...dialer.Option) dialer.Dialer {
|
|||||||
|
|
||||||
return &grpcDialer{
|
return &grpcDialer{
|
||||||
clients: make(map[string]pb.GostTunelClient),
|
clients: make(map[string]pb.GostTunelClient),
|
||||||
logger: options.Logger,
|
|
||||||
options: options,
|
options: options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,17 +68,21 @@ func (d *grpcDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO
|
|||||||
if host == "" {
|
if host == "" {
|
||||||
host = options.Host
|
host = options.Host
|
||||||
}
|
}
|
||||||
|
if h, _, _ := net.SplitHostPort(host); h != "" {
|
||||||
|
host = h
|
||||||
|
}
|
||||||
|
|
||||||
grpcOpts := []grpc.DialOption{
|
grpcOpts := []grpc.DialOption{
|
||||||
grpc.WithBlock(),
|
// grpc.WithBlock(),
|
||||||
grpc.WithContextDialer(func(c context.Context, s string) (net.Conn, error) {
|
grpc.WithContextDialer(func(c context.Context, s string) (net.Conn, error) {
|
||||||
return d.dial(ctx, "tcp", s, &options)
|
return options.NetDialer.Dial(c, "tcp", s)
|
||||||
}),
|
}),
|
||||||
grpc.WithAuthority(host),
|
grpc.WithAuthority(host),
|
||||||
grpc.WithConnectParams(grpc.ConnectParams{
|
grpc.WithConnectParams(grpc.ConnectParams{
|
||||||
Backoff: backoff.DefaultConfig,
|
Backoff: backoff.DefaultConfig,
|
||||||
MinConnectTimeout: 10 * time.Second,
|
MinConnectTimeout: 10 * time.Second,
|
||||||
}),
|
}),
|
||||||
|
grpc.FailOnNonTempDialError(true),
|
||||||
}
|
}
|
||||||
if !d.md.insecure {
|
if !d.md.insecure {
|
||||||
grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(credentials.NewTLS(d.options.TLSConfig)))
|
grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(credentials.NewTLS(d.options.TLSConfig)))
|
||||||
@@ -91,7 +92,7 @@ func (d *grpcDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO
|
|||||||
|
|
||||||
cc, err := grpc.DialContext(ctx, addr, grpcOpts...)
|
cc, err := grpc.DialContext(ctx, addr, grpcOpts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.logger.Error(err)
|
d.options.Logger.Error(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
client = pb.NewGostTunelClient(cc)
|
client = pb.NewGostTunelClient(cc)
|
||||||
@@ -110,31 +111,3 @@ func (d *grpcDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO
|
|||||||
closed: make(chan struct{}),
|
closed: make(chan struct{}),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *grpcDialer) dial(ctx context.Context, network, addr string, opts *dialer.DialOptions) (net.Conn, error) {
|
|
||||||
dial := opts.DialFunc
|
|
||||||
if dial != nil {
|
|
||||||
conn, err := dial(ctx, addr)
|
|
||||||
if err != nil {
|
|
||||||
d.logger.Error(err)
|
|
||||||
} else {
|
|
||||||
d.logger.WithFields(map[string]interface{}{
|
|
||||||
"src": conn.LocalAddr().String(),
|
|
||||||
"dst": addr,
|
|
||||||
}).Debug("dial with dial func")
|
|
||||||
}
|
|
||||||
return conn, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var netd net.Dialer
|
|
||||||
conn, err := netd.DialContext(ctx, network, addr)
|
|
||||||
if err != nil {
|
|
||||||
d.logger.Error(err)
|
|
||||||
} else {
|
|
||||||
d.logger.WithFields(map[string]interface{}{
|
|
||||||
"src": conn.LocalAddr().String(),
|
|
||||||
"dst": addr,
|
|
||||||
}).Debugf("dial direct %s/%s", addr, network)
|
|
||||||
}
|
|
||||||
return conn, err
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
net_dialer "github.com/go-gost/gost/pkg/common/net/dialer"
|
||||||
"github.com/go-gost/gost/pkg/dialer"
|
"github.com/go-gost/gost/pkg/dialer"
|
||||||
http2_util "github.com/go-gost/gost/pkg/internal/util/http2"
|
http2_util "github.com/go-gost/gost/pkg/internal/util/http2"
|
||||||
"github.com/go-gost/gost/pkg/logger"
|
"github.com/go-gost/gost/pkg/logger"
|
||||||
@@ -15,7 +16,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterDialer("http2", NewDialer)
|
registry.DialerRegistry().Register("http2", NewDialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type http2Dialer struct {
|
type http2Dialer struct {
|
||||||
@@ -73,7 +74,11 @@ func (d *http2Dialer) Dial(ctx context.Context, address string, opts ...dialer.D
|
|||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
TLSClientConfig: d.options.TLSConfig,
|
TLSClientConfig: d.options.TLSConfig,
|
||||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
return d.dial(ctx, network, addr, &options)
|
netd := options.NetDialer
|
||||||
|
if netd == nil {
|
||||||
|
netd = net_dialer.DefaultNetDialer
|
||||||
|
}
|
||||||
|
return netd.Dial(ctx, network, addr)
|
||||||
},
|
},
|
||||||
ForceAttemptHTTP2: true,
|
ForceAttemptHTTP2: true,
|
||||||
MaxIdleConns: 100,
|
MaxIdleConns: 100,
|
||||||
@@ -94,31 +99,3 @@ func (d *http2Dialer) Dial(ctx context.Context, address string, opts ...dialer.D
|
|||||||
delete(d.clients, address)
|
delete(d.clients, address)
|
||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *http2Dialer) dial(ctx context.Context, network, addr string, opts *dialer.DialOptions) (net.Conn, error) {
|
|
||||||
dial := opts.DialFunc
|
|
||||||
if dial != nil {
|
|
||||||
conn, err := dial(ctx, addr)
|
|
||||||
if err != nil {
|
|
||||||
d.logger.Error(err)
|
|
||||||
} else {
|
|
||||||
d.logger.WithFields(map[string]interface{}{
|
|
||||||
"src": conn.LocalAddr().String(),
|
|
||||||
"dst": addr,
|
|
||||||
}).Debug("dial with dial func")
|
|
||||||
}
|
|
||||||
return conn, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var netd net.Dialer
|
|
||||||
conn, err := netd.DialContext(ctx, network, addr)
|
|
||||||
if err != nil {
|
|
||||||
d.logger.Error(err)
|
|
||||||
} else {
|
|
||||||
d.logger.WithFields(map[string]interface{}{
|
|
||||||
"src": conn.LocalAddr().String(),
|
|
||||||
"dst": addr,
|
|
||||||
}).Debugf("dial direct %s/%s", addr, network)
|
|
||||||
}
|
|
||||||
return conn, err
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterDialer("h2", NewTLSDialer)
|
registry.DialerRegistry().Register("h2", NewTLSDialer)
|
||||||
registry.RegisterDialer("h2c", NewDialer)
|
registry.DialerRegistry().Register("h2c", NewDialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type h2Dialer struct {
|
type h2Dialer struct {
|
||||||
@@ -93,14 +93,14 @@ func (d *h2Dialer) Dial(ctx context.Context, address string, opts ...dialer.Dial
|
|||||||
if d.h2c {
|
if d.h2c {
|
||||||
client.Transport = &http2.Transport{
|
client.Transport = &http2.Transport{
|
||||||
DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
|
DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||||
return d.dial(ctx, network, addr, options)
|
return options.NetDialer.Dial(ctx, network, addr)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
client.Transport = &http.Transport{
|
client.Transport = &http.Transport{
|
||||||
TLSClientConfig: d.options.TLSConfig,
|
TLSClientConfig: d.options.TLSConfig,
|
||||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
return d.dial(ctx, network, addr, options)
|
return options.NetDialer.Dial(ctx, network, addr)
|
||||||
},
|
},
|
||||||
ForceAttemptHTTP2: true,
|
ForceAttemptHTTP2: true,
|
||||||
MaxIdleConns: 100,
|
MaxIdleConns: 100,
|
||||||
@@ -163,31 +163,3 @@ func (d *h2Dialer) Dial(ctx context.Context, address string, opts ...dialer.Dial
|
|||||||
}
|
}
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *h2Dialer) dial(ctx context.Context, network, addr string, opts *dialer.DialOptions) (net.Conn, error) {
|
|
||||||
dial := opts.DialFunc
|
|
||||||
if dial != nil {
|
|
||||||
conn, err := dial(ctx, addr)
|
|
||||||
if err != nil {
|
|
||||||
d.logger.Error(err)
|
|
||||||
} else {
|
|
||||||
d.logger.WithFields(map[string]interface{}{
|
|
||||||
"src": conn.LocalAddr().String(),
|
|
||||||
"dst": addr,
|
|
||||||
}).Debug("dial with dial func")
|
|
||||||
}
|
|
||||||
return conn, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var netd net.Dialer
|
|
||||||
conn, err := netd.DialContext(ctx, network, addr)
|
|
||||||
if err != nil {
|
|
||||||
d.logger.Error(err)
|
|
||||||
} else {
|
|
||||||
d.logger.WithFields(map[string]interface{}{
|
|
||||||
"src": conn.LocalAddr().String(),
|
|
||||||
"dst": addr,
|
|
||||||
}).Debugf("dial direct %s/%s", addr, network)
|
|
||||||
}
|
|
||||||
return conn, err
|
|
||||||
}
|
|
||||||
|
|||||||
+56
-13
@@ -2,26 +2,28 @@ package http3
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/go-gost/gost/pkg/dialer"
|
"github.com/go-gost/gost/pkg/dialer"
|
||||||
pht_util "github.com/go-gost/gost/pkg/internal/util/pht"
|
pht_util "github.com/go-gost/gost/pkg/internal/util/pht"
|
||||||
"github.com/go-gost/gost/pkg/logger"
|
|
||||||
md "github.com/go-gost/gost/pkg/metadata"
|
md "github.com/go-gost/gost/pkg/metadata"
|
||||||
"github.com/go-gost/gost/pkg/registry"
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
|
"github.com/lucas-clemente/quic-go"
|
||||||
"github.com/lucas-clemente/quic-go/http3"
|
"github.com/lucas-clemente/quic-go/http3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterDialer("http3", NewDialer)
|
registry.DialerRegistry().Register("http3", NewDialer)
|
||||||
registry.RegisterDialer("h3", NewDialer)
|
registry.DialerRegistry().Register("h3", NewDialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type http3Dialer struct {
|
type http3Dialer struct {
|
||||||
client *pht_util.Client
|
clients map[string]*pht_util.Client
|
||||||
|
clientMutex sync.Mutex
|
||||||
md metadata
|
md metadata
|
||||||
logger logger.Logger
|
|
||||||
options dialer.Options
|
options dialer.Options
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +34,7 @@ func NewDialer(opts ...dialer.Option) dialer.Dialer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &http3Dialer{
|
return &http3Dialer{
|
||||||
logger: options.Logger,
|
clients: make(map[string]*pht_util.Client),
|
||||||
options: options,
|
options: options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,13 +44,49 @@ func (d *http3Dialer) Init(md md.Metadata) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tr := &http3.RoundTripper{
|
return nil
|
||||||
TLSClientConfig: d.options.TLSConfig,
|
}
|
||||||
|
|
||||||
|
func (d *http3Dialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (net.Conn, error) {
|
||||||
|
d.clientMutex.Lock()
|
||||||
|
defer d.clientMutex.Unlock()
|
||||||
|
|
||||||
|
client, ok := d.clients[addr]
|
||||||
|
if !ok {
|
||||||
|
var options dialer.DialOptions
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
}
|
}
|
||||||
d.client = &pht_util.Client{
|
|
||||||
|
host := d.md.host
|
||||||
|
if host == "" {
|
||||||
|
host = options.Host
|
||||||
|
}
|
||||||
|
if h, _, _ := net.SplitHostPort(host); h != "" {
|
||||||
|
host = h
|
||||||
|
}
|
||||||
|
|
||||||
|
client = &pht_util.Client{
|
||||||
|
Host: host,
|
||||||
Client: &http.Client{
|
Client: &http.Client{
|
||||||
// Timeout: 60 * time.Second,
|
// Timeout: 60 * time.Second,
|
||||||
Transport: tr,
|
Transport: &http3.RoundTripper{
|
||||||
|
TLSClientConfig: d.options.TLSConfig,
|
||||||
|
Dial: func(network, adr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlySession, error) {
|
||||||
|
// d.options.Logger.Infof("dial: %s/%s, %s", addr, network, host)
|
||||||
|
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
udpConn, err := options.NetDialer.Dial(context.Background(), "udp", "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return quic.DialEarly(udpConn.(net.PacketConn), udpAddr, host, tlsCfg, cfg)
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
AuthorizePath: d.md.authorizePath,
|
AuthorizePath: d.md.authorizePath,
|
||||||
PushPath: d.md.pushPath,
|
PushPath: d.md.pushPath,
|
||||||
@@ -56,9 +94,14 @@ func (d *http3Dialer) Init(md md.Metadata) (err error) {
|
|||||||
TLSEnabled: true,
|
TLSEnabled: true,
|
||||||
Logger: d.options.Logger,
|
Logger: d.options.Logger,
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
d.clients[addr] = client
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.Dial(ctx, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *http3Dialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (net.Conn, error) {
|
// Multiplex implements dialer.Multiplexer interface.
|
||||||
return d.client.Dial(ctx, addr)
|
func (d *http3Dialer) Multiplex() bool {
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ type metadata struct {
|
|||||||
authorizePath string
|
authorizePath string
|
||||||
pushPath string
|
pushPath string
|
||||||
pullPath string
|
pullPath string
|
||||||
|
host string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *http3Dialer) parseMetadata(md mdata.Metadata) (err error) {
|
func (d *http3Dialer) parseMetadata(md mdata.Metadata) (err error) {
|
||||||
@@ -30,6 +31,7 @@ func (d *http3Dialer) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
authorizePath = "authorizePath"
|
authorizePath = "authorizePath"
|
||||||
pushPath = "pushPath"
|
pushPath = "pushPath"
|
||||||
pullPath = "pullPath"
|
pullPath = "pullPath"
|
||||||
|
host = "host"
|
||||||
)
|
)
|
||||||
|
|
||||||
d.md.authorizePath = mdata.GetString(md, authorizePath)
|
d.md.authorizePath = mdata.GetString(md, authorizePath)
|
||||||
@@ -44,5 +46,7 @@ func (d *http3Dialer) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
if !strings.HasPrefix(d.md.pullPath, "/") {
|
if !strings.HasPrefix(d.md.pullPath, "/") {
|
||||||
d.md.pullPath = defaultPullPath
|
d.md.pullPath = defaultPullPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d.md.host = mdata.GetString(md, host)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package quic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/lucas-clemente/quic-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
type quicSession struct {
|
||||||
|
session quic.Session
|
||||||
|
}
|
||||||
|
|
||||||
|
func (session *quicSession) GetConn() (*quicConn, error) {
|
||||||
|
stream, err := session.session.OpenStreamSync(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &quicConn{
|
||||||
|
Stream: stream,
|
||||||
|
laddr: session.session.LocalAddr(),
|
||||||
|
raddr: session.session.RemoteAddr(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (session *quicSession) Close() error {
|
||||||
|
return session.session.CloseWithError(quic.ApplicationErrorCode(0), "closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
type quicConn struct {
|
||||||
|
quic.Stream
|
||||||
|
laddr net.Addr
|
||||||
|
raddr net.Addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *quicConn) LocalAddr() net.Addr {
|
||||||
|
return c.laddr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *quicConn) RemoteAddr() net.Addr {
|
||||||
|
return c.raddr
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
package quic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"math"
|
||||||
|
"math/rand"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-gost/gost/pkg/dialer"
|
||||||
|
icmp_pkg "github.com/go-gost/gost/pkg/internal/util/icmp"
|
||||||
|
"github.com/go-gost/gost/pkg/logger"
|
||||||
|
md "github.com/go-gost/gost/pkg/metadata"
|
||||||
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
|
"github.com/lucas-clemente/quic-go"
|
||||||
|
"golang.org/x/net/icmp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.DialerRegistry().Register("icmp", NewDialer)
|
||||||
|
}
|
||||||
|
|
||||||
|
type icmpDialer struct {
|
||||||
|
sessions map[string]*quicSession
|
||||||
|
sessionMutex sync.Mutex
|
||||||
|
logger logger.Logger
|
||||||
|
md metadata
|
||||||
|
options dialer.Options
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDialer(opts ...dialer.Option) dialer.Dialer {
|
||||||
|
options := dialer.Options{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &icmpDialer{
|
||||||
|
sessions: make(map[string]*quicSession),
|
||||||
|
logger: options.Logger,
|
||||||
|
options: options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *icmpDialer) Init(md md.Metadata) (err error) {
|
||||||
|
if err = d.parseMetadata(md); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *icmpDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (conn net.Conn, err error) {
|
||||||
|
if _, _, err := net.SplitHostPort(addr); err != nil {
|
||||||
|
addr = net.JoinHostPort(addr, "0")
|
||||||
|
}
|
||||||
|
|
||||||
|
raddr, err := net.ResolveUDPAddr("udp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.sessionMutex.Lock()
|
||||||
|
defer d.sessionMutex.Unlock()
|
||||||
|
|
||||||
|
session, ok := d.sessions[addr]
|
||||||
|
if !ok {
|
||||||
|
options := &dialer.DialOptions{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
var pc net.PacketConn
|
||||||
|
pc, err = icmp.ListenPacket("ip4:icmp", "")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
id := raddr.Port
|
||||||
|
if id == 0 {
|
||||||
|
id = rand.New(rand.NewSource(time.Now().UnixNano())).Intn(math.MaxUint16) + 1
|
||||||
|
raddr.Port = id
|
||||||
|
}
|
||||||
|
pc = icmp_pkg.ClientConn(pc, id)
|
||||||
|
|
||||||
|
session, err = d.initSession(ctx, raddr, pc)
|
||||||
|
if err != nil {
|
||||||
|
d.logger.Error(err)
|
||||||
|
pc.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.sessions[addr] = session
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err = session.GetConn()
|
||||||
|
if err != nil {
|
||||||
|
session.Close()
|
||||||
|
delete(d.sessions, addr)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *icmpDialer) initSession(ctx context.Context, addr net.Addr, conn net.PacketConn) (*quicSession, error) {
|
||||||
|
quicConfig := &quic.Config{
|
||||||
|
KeepAlive: d.md.keepAlive,
|
||||||
|
HandshakeIdleTimeout: d.md.handshakeTimeout,
|
||||||
|
MaxIdleTimeout: d.md.maxIdleTimeout,
|
||||||
|
Versions: []quic.VersionNumber{
|
||||||
|
quic.Version1,
|
||||||
|
quic.VersionDraft29,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsCfg := d.options.TLSConfig
|
||||||
|
tlsCfg.NextProtos = []string{"http/3", "quic/v1"}
|
||||||
|
|
||||||
|
session, err := quic.DialContext(ctx, conn, addr, addr.String(), tlsCfg, quicConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &quicSession{session: session}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiplex implements dialer.Multiplexer interface.
|
||||||
|
func (d *icmpDialer) Multiplex() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package quic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
mdata "github.com/go-gost/gost/pkg/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
type metadata struct {
|
||||||
|
keepAlive bool
|
||||||
|
maxIdleTimeout time.Duration
|
||||||
|
handshakeTimeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *icmpDialer) parseMetadata(md mdata.Metadata) (err error) {
|
||||||
|
const (
|
||||||
|
keepAlive = "keepAlive"
|
||||||
|
handshakeTimeout = "handshakeTimeout"
|
||||||
|
maxIdleTimeout = "maxIdleTimeout"
|
||||||
|
)
|
||||||
|
|
||||||
|
d.md.handshakeTimeout = mdata.GetDuration(md, handshakeTimeout)
|
||||||
|
|
||||||
|
d.md.keepAlive = mdata.GetBool(md, keepAlive)
|
||||||
|
d.md.handshakeTimeout = mdata.GetDuration(md, handshakeTimeout)
|
||||||
|
d.md.maxIdleTimeout = mdata.GetDuration(md, maxIdleTimeout)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type muxSession struct {
|
type muxSession struct {
|
||||||
conn net.Conn
|
|
||||||
session *smux.Session
|
session *smux.Session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+47
-71
@@ -18,7 +18,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterDialer("kcp", NewDialer)
|
registry.DialerRegistry().Register("kcp", NewDialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type kcpDialer struct {
|
type kcpDialer struct {
|
||||||
@@ -26,17 +26,19 @@ type kcpDialer struct {
|
|||||||
sessionMutex sync.Mutex
|
sessionMutex sync.Mutex
|
||||||
logger logger.Logger
|
logger logger.Logger
|
||||||
md metadata
|
md metadata
|
||||||
|
options dialer.Options
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDialer(opts ...dialer.Option) dialer.Dialer {
|
func NewDialer(opts ...dialer.Option) dialer.Dialer {
|
||||||
options := &dialer.Options{}
|
options := dialer.Options{}
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(options)
|
opt(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &kcpDialer{
|
return &kcpDialer{
|
||||||
sessions: make(map[string]*muxSession),
|
sessions: make(map[string]*muxSession),
|
||||||
logger: options.Logger,
|
logger: options.Logger,
|
||||||
|
options: options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,15 +52,10 @@ func (d *kcpDialer) Init(md md.Metadata) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multiplex implements dialer.Multiplexer interface.
|
|
||||||
func (d *kcpDialer) Multiplex() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *kcpDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (conn net.Conn, err error) {
|
func (d *kcpDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (conn net.Conn, err error) {
|
||||||
var options dialer.DialOptions
|
raddr, err := net.ResolveUDPAddr("udp", addr)
|
||||||
for _, opt := range opts {
|
if err != nil {
|
||||||
opt(&options)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
d.sessionMutex.Lock()
|
d.sessionMutex.Lock()
|
||||||
@@ -70,86 +67,60 @@ func (d *kcpDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOp
|
|||||||
ok = false
|
ok = false
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
raddr, err := net.ResolveUDPAddr("udp", addr)
|
var options dialer.DialOptions
|
||||||
if err != nil {
|
for _, opt := range opts {
|
||||||
return nil, err
|
opt(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var pc net.PacketConn
|
||||||
if d.md.config.TCP {
|
if d.md.config.TCP {
|
||||||
pc, err := tcpraw.Dial("tcp", addr)
|
pc, err = tcpraw.Dial("tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
conn = &fakeTCPConn{
|
pc = &fakeTCPConn{
|
||||||
raddr: raddr,
|
raddr: raddr,
|
||||||
PacketConn: pc,
|
PacketConn: pc,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
conn, err = net.ListenUDP("udp", nil)
|
c, err := options.NetDialer.Dial(ctx, "udp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
pc, ok = c.(net.PacketConn)
|
||||||
|
if !ok {
|
||||||
|
c.Close()
|
||||||
|
return nil, errors.New("quic: wrong connection type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
session, err = d.initSession(ctx, raddr, pc)
|
||||||
|
if err != nil {
|
||||||
|
d.logger.Error(err)
|
||||||
|
pc.Close()
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
session = &muxSession{conn: conn}
|
|
||||||
d.sessions[addr] = session
|
d.sessions[addr] = session
|
||||||
}
|
}
|
||||||
|
|
||||||
return session.conn, err
|
conn, err = session.GetConn()
|
||||||
}
|
|
||||||
|
|
||||||
// Handshake implements dialer.Handshaker
|
|
||||||
func (d *kcpDialer) Handshake(ctx context.Context, conn net.Conn, options ...dialer.HandshakeOption) (net.Conn, error) {
|
|
||||||
opts := &dialer.HandshakeOptions{}
|
|
||||||
for _, option := range options {
|
|
||||||
option(opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
d.sessionMutex.Lock()
|
|
||||||
defer d.sessionMutex.Unlock()
|
|
||||||
|
|
||||||
if d.md.handshakeTimeout > 0 {
|
|
||||||
conn.SetDeadline(time.Now().Add(d.md.handshakeTimeout))
|
|
||||||
defer conn.SetDeadline(time.Time{})
|
|
||||||
}
|
|
||||||
|
|
||||||
session, ok := d.sessions[opts.Addr]
|
|
||||||
if session != nil && session.conn != conn {
|
|
||||||
conn.Close()
|
|
||||||
return nil, errors.New("kcp: unrecognized connection")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ok || session.session == nil {
|
|
||||||
s, err := d.initSession(ctx, opts.Addr, conn)
|
|
||||||
if err != nil {
|
|
||||||
d.logger.Error(err)
|
|
||||||
conn.Close()
|
|
||||||
delete(d.sessions, opts.Addr)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
session = s
|
|
||||||
d.sessions[opts.Addr] = session
|
|
||||||
}
|
|
||||||
cc, err := session.GetConn()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
session.Close()
|
session.Close()
|
||||||
delete(d.sessions, opts.Addr)
|
delete(d.sessions, addr)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return cc, nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *kcpDialer) initSession(ctx context.Context, addr string, conn net.Conn) (*muxSession, error) {
|
func (d *kcpDialer) initSession(ctx context.Context, addr net.Addr, conn net.PacketConn) (*muxSession, error) {
|
||||||
pc, ok := conn.(net.PacketConn)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("kcp: wrong connection type")
|
|
||||||
}
|
|
||||||
|
|
||||||
config := d.md.config
|
config := d.md.config
|
||||||
|
|
||||||
kcpconn, err := kcp.NewConn(addr,
|
kcpconn, err := kcp.NewConn(addr.String(),
|
||||||
kcp_util.BlockCrypt(config.Key, config.Crypt, kcp_util.DefaultSalt),
|
kcp_util.BlockCrypt(config.Key, config.Crypt, kcp_util.DefaultSalt),
|
||||||
config.DataShard, config.ParityShard, pc)
|
config.DataShard, config.ParityShard, conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -162,15 +133,15 @@ func (d *kcpDialer) initSession(ctx context.Context, addr string, conn net.Conn)
|
|||||||
kcpconn.SetACKNoDelay(config.AckNodelay)
|
kcpconn.SetACKNoDelay(config.AckNodelay)
|
||||||
|
|
||||||
if config.DSCP > 0 {
|
if config.DSCP > 0 {
|
||||||
if err := kcpconn.SetDSCP(config.DSCP); err != nil {
|
if er := kcpconn.SetDSCP(config.DSCP); er != nil {
|
||||||
d.logger.Warn("SetDSCP: ", err)
|
d.logger.Warn("SetDSCP: ", er)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := kcpconn.SetReadBuffer(config.SockBuf); err != nil {
|
if er := kcpconn.SetReadBuffer(config.SockBuf); er != nil {
|
||||||
d.logger.Warn("SetReadBuffer: ", err)
|
d.logger.Warn("SetReadBuffer: ", er)
|
||||||
}
|
}
|
||||||
if err := kcpconn.SetWriteBuffer(config.SockBuf); err != nil {
|
if er := kcpconn.SetWriteBuffer(config.SockBuf); er != nil {
|
||||||
d.logger.Warn("SetWriteBuffer: ", err)
|
d.logger.Warn("SetWriteBuffer: ", er)
|
||||||
}
|
}
|
||||||
|
|
||||||
// stream multiplex
|
// stream multiplex
|
||||||
@@ -185,5 +156,10 @@ func (d *kcpDialer) initSession(ctx context.Context, addr string, conn net.Conn)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &muxSession{conn: conn, session: session}, nil
|
return &muxSession{session: session}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiplex implements dialer.Multiplexer interface.
|
||||||
|
func (d *kcpDialer) Multiplex() bool {
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterDialer("ohttp", NewDialer)
|
registry.DialerRegistry().Register("ohttp", NewDialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type obfsHTTPDialer struct {
|
type obfsHTTPDialer struct {
|
||||||
@@ -35,8 +35,12 @@ func (d *obfsHTTPDialer) Init(md md.Metadata) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *obfsHTTPDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (net.Conn, error) {
|
func (d *obfsHTTPDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (net.Conn, error) {
|
||||||
var netd net.Dialer
|
options := &dialer.DialOptions{}
|
||||||
conn, err := netd.DialContext(ctx, "tcp", addr)
|
for _, opt := range opts {
|
||||||
|
opt(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := options.NetDialer.Dial(ctx, "tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.logger.Error(err)
|
d.logger.Error(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterDialer("otls", NewDialer)
|
registry.DialerRegistry().Register("otls", NewDialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type obfsTLSDialer struct {
|
type obfsTLSDialer struct {
|
||||||
@@ -35,8 +35,12 @@ func (d *obfsTLSDialer) Init(md md.Metadata) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *obfsTLSDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (net.Conn, error) {
|
func (d *obfsTLSDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (net.Conn, error) {
|
||||||
var netd net.Dialer
|
options := &dialer.DialOptions{}
|
||||||
conn, err := netd.DialContext(ctx, "tcp", addr)
|
for _, opt := range opts {
|
||||||
|
opt(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := options.NetDialer.Dial(ctx, "tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.logger.Error(err)
|
d.logger.Error(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,24 @@
|
|||||||
package dialer
|
package dialer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"net"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/go-gost/gost/pkg/common/net/dialer"
|
||||||
"github.com/go-gost/gost/pkg/logger"
|
"github.com/go-gost/gost/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
User *url.Userinfo
|
Auth *url.Userinfo
|
||||||
TLSConfig *tls.Config
|
TLSConfig *tls.Config
|
||||||
Logger logger.Logger
|
Logger logger.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
type Option func(opts *Options)
|
type Option func(opts *Options)
|
||||||
|
|
||||||
func UserOption(user *url.Userinfo) Option {
|
func AuthOption(auth *url.Userinfo) Option {
|
||||||
return func(opts *Options) {
|
return func(opts *Options) {
|
||||||
opts.User = user
|
opts.Auth = auth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +36,7 @@ func LoggerOption(logger logger.Logger) Option {
|
|||||||
|
|
||||||
type DialOptions struct {
|
type DialOptions struct {
|
||||||
Host string
|
Host string
|
||||||
DialFunc func(ctx context.Context, addr string) (net.Conn, error)
|
NetDialer *dialer.NetDialer
|
||||||
}
|
}
|
||||||
|
|
||||||
type DialOption func(opts *DialOptions)
|
type DialOption func(opts *DialOptions)
|
||||||
@@ -48,9 +47,9 @@ func HostDialOption(host string) DialOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DialFuncDialOption(dialf func(ctx context.Context, addr string) (net.Conn, error)) DialOption {
|
func NetDialerDialOption(netd *dialer.NetDialer) DialOption {
|
||||||
return func(opts *DialOptions) {
|
return func(opts *DialOptions) {
|
||||||
opts.DialFunc = dialf
|
opts.NetDialer = netd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+37
-14
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-gost/gost/pkg/dialer"
|
"github.com/go-gost/gost/pkg/dialer"
|
||||||
@@ -14,13 +15,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterDialer("pht", NewDialer)
|
registry.DialerRegistry().Register("pht", NewDialer)
|
||||||
registry.RegisterDialer("phts", NewTLSDialer)
|
registry.DialerRegistry().Register("phts", NewTLSDialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type phtDialer struct {
|
type phtDialer struct {
|
||||||
|
clients map[string]*pht_util.Client
|
||||||
|
clientMutex sync.Mutex
|
||||||
tlsEnabled bool
|
tlsEnabled bool
|
||||||
client *pht_util.Client
|
|
||||||
md metadata
|
md metadata
|
||||||
logger logger.Logger
|
logger logger.Logger
|
||||||
options dialer.Options
|
options dialer.Options
|
||||||
@@ -33,7 +35,7 @@ func NewDialer(opts ...dialer.Option) dialer.Dialer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &phtDialer{
|
return &phtDialer{
|
||||||
logger: options.Logger,
|
clients: make(map[string]*pht_util.Client),
|
||||||
options: options,
|
options: options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,7 +48,7 @@ func NewTLSDialer(opts ...dialer.Option) dialer.Dialer {
|
|||||||
|
|
||||||
return &phtDialer{
|
return &phtDialer{
|
||||||
tlsEnabled: true,
|
tlsEnabled: true,
|
||||||
logger: options.Logger,
|
clients: make(map[string]*pht_util.Client),
|
||||||
options: options,
|
options: options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,12 +58,33 @@ func (d *phtDialer) Init(md md.Metadata) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *phtDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (net.Conn, error) {
|
||||||
|
d.clientMutex.Lock()
|
||||||
|
defer d.clientMutex.Unlock()
|
||||||
|
|
||||||
|
client, ok := d.clients[addr]
|
||||||
|
if !ok {
|
||||||
|
var options dialer.DialOptions
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
host := d.md.host
|
||||||
|
if host == "" {
|
||||||
|
host = options.Host
|
||||||
|
}
|
||||||
|
if h, _, _ := net.SplitHostPort(host); h != "" {
|
||||||
|
host = h
|
||||||
|
}
|
||||||
|
|
||||||
tr := &http.Transport{
|
tr := &http.Transport{
|
||||||
// Proxy: http.ProxyFromEnvironment,
|
// Proxy: http.ProxyFromEnvironment,
|
||||||
DialContext: (&net.Dialer{
|
DialContext: func(ctx context.Context, network, adr string) (net.Conn, error) {
|
||||||
Timeout: 30 * time.Second,
|
return options.NetDialer.Dial(ctx, network, addr)
|
||||||
KeepAlive: 30 * time.Second,
|
},
|
||||||
}).DialContext,
|
|
||||||
ForceAttemptHTTP2: true,
|
ForceAttemptHTTP2: true,
|
||||||
MaxIdleConns: 100,
|
MaxIdleConns: 100,
|
||||||
IdleConnTimeout: 90 * time.Second,
|
IdleConnTimeout: 90 * time.Second,
|
||||||
@@ -72,7 +95,8 @@ func (d *phtDialer) Init(md md.Metadata) (err error) {
|
|||||||
tr.TLSClientConfig = d.options.TLSConfig
|
tr.TLSClientConfig = d.options.TLSConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
d.client = &pht_util.Client{
|
client = &pht_util.Client{
|
||||||
|
Host: host,
|
||||||
Client: &http.Client{
|
Client: &http.Client{
|
||||||
// Timeout: 60 * time.Second,
|
// Timeout: 60 * time.Second,
|
||||||
Transport: tr,
|
Transport: tr,
|
||||||
@@ -83,9 +107,8 @@ func (d *phtDialer) Init(md md.Metadata) (err error) {
|
|||||||
TLSEnabled: d.tlsEnabled,
|
TLSEnabled: d.tlsEnabled,
|
||||||
Logger: d.options.Logger,
|
Logger: d.options.Logger,
|
||||||
}
|
}
|
||||||
return nil
|
d.clients[addr] = client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *phtDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (net.Conn, error) {
|
return client.Dial(ctx, addr)
|
||||||
return d.client.Dial(ctx, addr)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ type metadata struct {
|
|||||||
authorizePath string
|
authorizePath string
|
||||||
pushPath string
|
pushPath string
|
||||||
pullPath string
|
pullPath string
|
||||||
|
host string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *phtDialer) parseMetadata(md mdata.Metadata) (err error) {
|
func (d *phtDialer) parseMetadata(md mdata.Metadata) (err error) {
|
||||||
@@ -30,6 +31,7 @@ func (d *phtDialer) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
authorizePath = "authorizePath"
|
authorizePath = "authorizePath"
|
||||||
pushPath = "pushPath"
|
pushPath = "pushPath"
|
||||||
pullPath = "pullPath"
|
pullPath = "pullPath"
|
||||||
|
host = "host"
|
||||||
)
|
)
|
||||||
|
|
||||||
d.md.authorizePath = mdata.GetString(md, authorizePath)
|
d.md.authorizePath = mdata.GetString(md, authorizePath)
|
||||||
@@ -44,5 +46,7 @@ func (d *phtDialer) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
if !strings.HasPrefix(d.md.pullPath, "/") {
|
if !strings.HasPrefix(d.md.pullPath, "/") {
|
||||||
d.md.pullPath = defaultPullPath
|
d.md.pullPath = defaultPullPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d.md.host = mdata.GetString(md, host)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type quicSession struct {
|
type quicSession struct {
|
||||||
conn net.Conn
|
|
||||||
session quic.Session
|
session quic.Session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+45
-72
@@ -5,7 +5,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-gost/gost/pkg/dialer"
|
"github.com/go-gost/gost/pkg/dialer"
|
||||||
quic_util "github.com/go-gost/gost/pkg/internal/util/quic"
|
quic_util "github.com/go-gost/gost/pkg/internal/util/quic"
|
||||||
@@ -16,7 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterDialer("quic", NewDialer)
|
registry.DialerRegistry().Register("quic", NewDialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type quicDialer struct {
|
type quicDialer struct {
|
||||||
@@ -48,15 +47,14 @@ func (d *quicDialer) Init(md md.Metadata) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multiplex implements dialer.Multiplexer interface.
|
|
||||||
func (d *quicDialer) Multiplex() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *quicDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (conn net.Conn, err error) {
|
func (d *quicDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (conn net.Conn, err error) {
|
||||||
var options dialer.DialOptions
|
if _, _, err := net.SplitHostPort(addr); err != nil {
|
||||||
for _, opt := range opts {
|
addr = net.JoinHostPort(addr, "0")
|
||||||
opt(&options)
|
}
|
||||||
|
|
||||||
|
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
d.sessionMutex.Lock()
|
d.sessionMutex.Lock()
|
||||||
@@ -64,75 +62,46 @@ func (d *quicDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO
|
|||||||
|
|
||||||
session, ok := d.sessions[addr]
|
session, ok := d.sessions[addr]
|
||||||
if !ok {
|
if !ok {
|
||||||
var cc *net.UDPConn
|
options := &dialer.DialOptions{}
|
||||||
cc, err = net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
|
for _, opt := range opts {
|
||||||
|
opt(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := options.NetDialer.Dial(ctx, "udp", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
|
||||||
}
|
|
||||||
conn = cc
|
|
||||||
|
|
||||||
if d.md.cipherKey != nil {
|
|
||||||
conn = quic_util.CipherConn(cc, d.md.cipherKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
session = &quicSession{conn: conn}
|
|
||||||
d.sessions[addr] = session
|
|
||||||
}
|
|
||||||
|
|
||||||
return session.conn, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handshake implements dialer.Handshaker
|
|
||||||
func (d *quicDialer) Handshake(ctx context.Context, conn net.Conn, options ...dialer.HandshakeOption) (net.Conn, error) {
|
|
||||||
opts := &dialer.HandshakeOptions{}
|
|
||||||
for _, option := range options {
|
|
||||||
option(opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
d.sessionMutex.Lock()
|
|
||||||
defer d.sessionMutex.Unlock()
|
|
||||||
|
|
||||||
if d.md.handshakeTimeout > 0 {
|
|
||||||
conn.SetDeadline(time.Now().Add(d.md.handshakeTimeout))
|
|
||||||
defer conn.SetDeadline(time.Time{})
|
|
||||||
}
|
|
||||||
|
|
||||||
session, ok := d.sessions[opts.Addr]
|
|
||||||
if session != nil && session.conn != conn {
|
|
||||||
conn.Close()
|
|
||||||
return nil, errors.New("quic: unrecognized connection")
|
|
||||||
}
|
|
||||||
if !ok || session.session == nil {
|
|
||||||
s, err := d.initSession(ctx, opts.Addr, conn)
|
|
||||||
if err != nil {
|
|
||||||
d.logger.Error(err)
|
|
||||||
conn.Close()
|
|
||||||
delete(d.sessions, opts.Addr)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
session = s
|
pc, ok := c.(net.PacketConn)
|
||||||
d.sessions[opts.Addr] = session
|
|
||||||
}
|
|
||||||
cc, err := session.GetConn()
|
|
||||||
if err != nil {
|
|
||||||
session.Close()
|
|
||||||
delete(d.sessions, opts.Addr)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return cc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *quicDialer) initSession(ctx context.Context, addr string, conn net.Conn) (*quicSession, error) {
|
|
||||||
pc, ok := conn.(net.PacketConn)
|
|
||||||
if !ok {
|
if !ok {
|
||||||
|
c.Close()
|
||||||
return nil, errors.New("quic: wrong connection type")
|
return nil, errors.New("quic: wrong connection type")
|
||||||
}
|
}
|
||||||
|
|
||||||
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
if d.md.cipherKey != nil {
|
||||||
|
pc = quic_util.CipherPacketConn(pc, d.md.cipherKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
session, err = d.initSession(ctx, udpAddr, pc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
d.logger.Error(err)
|
||||||
|
pc.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d.sessions[addr] = session
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err = session.GetConn()
|
||||||
|
if err != nil {
|
||||||
|
session.Close()
|
||||||
|
delete(d.sessions, addr)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *quicDialer) initSession(ctx context.Context, addr net.Addr, conn net.PacketConn) (*quicSession, error) {
|
||||||
quicConfig := &quic.Config{
|
quicConfig := &quic.Config{
|
||||||
KeepAlive: d.md.keepAlive,
|
KeepAlive: d.md.keepAlive,
|
||||||
HandshakeIdleTimeout: d.md.handshakeTimeout,
|
HandshakeIdleTimeout: d.md.handshakeTimeout,
|
||||||
@@ -146,10 +115,14 @@ func (d *quicDialer) initSession(ctx context.Context, addr string, conn net.Conn
|
|||||||
tlsCfg := d.options.TLSConfig
|
tlsCfg := d.options.TLSConfig
|
||||||
tlsCfg.NextProtos = []string{"http/3", "quic/v1"}
|
tlsCfg.NextProtos = []string{"http/3", "quic/v1"}
|
||||||
|
|
||||||
session, err := quic.DialContext(ctx, pc, udpAddr, addr, tlsCfg, quicConfig)
|
session, err := quic.DialContext(ctx, conn, addr, addr.String(), tlsCfg, quicConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.logger.Error(err)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &quicSession{conn: conn, session: session}, nil
|
return &quicSession{session: session}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiplex implements dialer.Multiplexer interface.
|
||||||
|
func (d *quicDialer) Multiplex() bool {
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ type metadata struct {
|
|||||||
handshakeTimeout time.Duration
|
handshakeTimeout time.Duration
|
||||||
|
|
||||||
cipherKey []byte
|
cipherKey []byte
|
||||||
|
host string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *quicDialer) parseMetadata(md mdata.Metadata) (err error) {
|
func (d *quicDialer) parseMetadata(md mdata.Metadata) (err error) {
|
||||||
@@ -21,6 +22,7 @@ func (d *quicDialer) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
maxIdleTimeout = "maxIdleTimeout"
|
maxIdleTimeout = "maxIdleTimeout"
|
||||||
|
|
||||||
cipherKey = "cipherKey"
|
cipherKey = "cipherKey"
|
||||||
|
host = "host"
|
||||||
)
|
)
|
||||||
|
|
||||||
d.md.handshakeTimeout = mdata.GetDuration(md, handshakeTimeout)
|
d.md.handshakeTimeout = mdata.GetDuration(md, handshakeTimeout)
|
||||||
@@ -32,5 +34,7 @@ func (d *quicDialer) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
d.md.keepAlive = mdata.GetBool(md, keepAlive)
|
d.md.keepAlive = mdata.GetBool(md, keepAlive)
|
||||||
d.md.handshakeTimeout = mdata.GetDuration(md, handshakeTimeout)
|
d.md.handshakeTimeout = mdata.GetDuration(md, handshakeTimeout)
|
||||||
d.md.maxIdleTimeout = mdata.GetDuration(md, maxIdleTimeout)
|
d.md.maxIdleTimeout = mdata.GetDuration(md, maxIdleTimeout)
|
||||||
|
|
||||||
|
d.md.host = mdata.GetString(md, host)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterDialer("ssh", NewDialer)
|
registry.DialerRegistry().Register("ssh", NewDialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type sshDialer struct {
|
type sshDialer struct {
|
||||||
@@ -52,11 +52,6 @@ func (d *sshDialer) Multiplex() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *sshDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (conn net.Conn, err error) {
|
func (d *sshDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (conn net.Conn, err error) {
|
||||||
var options dialer.DialOptions
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(&options)
|
|
||||||
}
|
|
||||||
|
|
||||||
d.sessionMutex.Lock()
|
d.sessionMutex.Lock()
|
||||||
defer d.sessionMutex.Unlock()
|
defer d.sessionMutex.Unlock()
|
||||||
|
|
||||||
@@ -66,7 +61,12 @@ func (d *sshDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOp
|
|||||||
ok = false
|
ok = false
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
conn, err = d.dial(ctx, "tcp", addr, &options)
|
var options dialer.DialOptions
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err = options.NetDialer.Dial(ctx, "tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -134,34 +134,6 @@ func (d *sshDialer) Handshake(ctx context.Context, conn net.Conn, options ...dia
|
|||||||
return ssh_util.NewConn(conn, channel), nil
|
return ssh_util.NewConn(conn, channel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *sshDialer) dial(ctx context.Context, network, addr string, opts *dialer.DialOptions) (net.Conn, error) {
|
|
||||||
dial := opts.DialFunc
|
|
||||||
if dial != nil {
|
|
||||||
conn, err := dial(ctx, addr)
|
|
||||||
if err != nil {
|
|
||||||
d.logger.Error(err)
|
|
||||||
} else {
|
|
||||||
d.logger.WithFields(map[string]interface{}{
|
|
||||||
"src": conn.LocalAddr().String(),
|
|
||||||
"dst": addr,
|
|
||||||
}).Debug("dial with dial func")
|
|
||||||
}
|
|
||||||
return conn, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var netd net.Dialer
|
|
||||||
conn, err := netd.DialContext(ctx, network, addr)
|
|
||||||
if err != nil {
|
|
||||||
d.logger.Error(err)
|
|
||||||
} else {
|
|
||||||
d.logger.WithFields(map[string]interface{}{
|
|
||||||
"src": conn.LocalAddr().String(),
|
|
||||||
"dst": addr,
|
|
||||||
}).Debugf("dial direct %s/%s", addr, network)
|
|
||||||
}
|
|
||||||
return conn, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *sshDialer) initSession(ctx context.Context, addr string, conn net.Conn) (*sshSession, error) {
|
func (d *sshDialer) initSession(ctx context.Context, addr string, conn net.Conn) (*sshSession, error) {
|
||||||
config := ssh.ClientConfig{
|
config := ssh.ClientConfig{
|
||||||
Timeout: 30 * time.Second,
|
Timeout: 30 * time.Second,
|
||||||
|
|||||||
+10
-43
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -16,11 +15,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterDialer("sshd", NewDialer)
|
registry.DialerRegistry().Register("sshd", NewDialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type sshdDialer struct {
|
type sshdDialer struct {
|
||||||
user *url.Userinfo
|
|
||||||
sessions map[string]*sshSession
|
sessions map[string]*sshSession
|
||||||
sessionMutex sync.Mutex
|
sessionMutex sync.Mutex
|
||||||
md metadata
|
md metadata
|
||||||
@@ -34,7 +32,6 @@ func NewDialer(opts ...dialer.Option) dialer.Dialer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &sshdDialer{
|
return &sshdDialer{
|
||||||
user: options.User,
|
|
||||||
sessions: make(map[string]*sshSession),
|
sessions: make(map[string]*sshSession),
|
||||||
options: options,
|
options: options,
|
||||||
}
|
}
|
||||||
@@ -54,11 +51,6 @@ func (d *sshdDialer) Multiplex() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *sshdDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (conn net.Conn, err error) {
|
func (d *sshdDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (conn net.Conn, err error) {
|
||||||
var options dialer.DialOptions
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(&options)
|
|
||||||
}
|
|
||||||
|
|
||||||
d.sessionMutex.Lock()
|
d.sessionMutex.Lock()
|
||||||
defer d.sessionMutex.Unlock()
|
defer d.sessionMutex.Unlock()
|
||||||
|
|
||||||
@@ -68,7 +60,12 @@ func (d *sshdDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO
|
|||||||
ok = false
|
ok = false
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
conn, err = d.dial(ctx, "tcp", addr, &options)
|
var options dialer.DialOptions
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err = options.NetDialer.Dial(ctx, "tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -132,44 +129,14 @@ func (d *sshdDialer) Handshake(ctx context.Context, conn net.Conn, options ...di
|
|||||||
return ssh_util.NewClientConn(session.conn, session.client), nil
|
return ssh_util.NewClientConn(session.conn, session.client), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *sshdDialer) dial(ctx context.Context, network, addr string, opts *dialer.DialOptions) (net.Conn, error) {
|
|
||||||
log := d.options.Logger
|
|
||||||
|
|
||||||
dial := opts.DialFunc
|
|
||||||
if dial != nil {
|
|
||||||
conn, err := dial(ctx, addr)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
} else {
|
|
||||||
log.WithFields(map[string]interface{}{
|
|
||||||
"src": conn.LocalAddr().String(),
|
|
||||||
"dst": addr,
|
|
||||||
}).Debug("dial with dial func")
|
|
||||||
}
|
|
||||||
return conn, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var netd net.Dialer
|
|
||||||
conn, err := netd.DialContext(ctx, network, addr)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
} else {
|
|
||||||
log.WithFields(map[string]interface{}{
|
|
||||||
"src": conn.LocalAddr().String(),
|
|
||||||
"dst": addr,
|
|
||||||
}).Debugf("dial direct %s/%s", addr, network)
|
|
||||||
}
|
|
||||||
return conn, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *sshdDialer) initSession(ctx context.Context, addr string, conn net.Conn) (*sshSession, error) {
|
func (d *sshdDialer) initSession(ctx context.Context, addr string, conn net.Conn) (*sshSession, error) {
|
||||||
config := ssh.ClientConfig{
|
config := ssh.ClientConfig{
|
||||||
// Timeout: timeout,
|
// Timeout: timeout,
|
||||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||||
}
|
}
|
||||||
if d.user != nil {
|
if d.options.Auth != nil {
|
||||||
config.User = d.user.Username()
|
config.User = d.options.Auth.Username()
|
||||||
if password, _ := d.user.Password(); password != "" {
|
if password, _ := d.options.Auth.Password(); password != "" {
|
||||||
config.Auth = []ssh.AuthMethod{
|
config.Auth = []ssh.AuthMethod{
|
||||||
ssh.Password(password),
|
ssh.Password(password),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterDialer("tcp", NewDialer)
|
registry.DialerRegistry().Register("tcp", NewDialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type tcpDialer struct {
|
type tcpDialer struct {
|
||||||
@@ -40,8 +40,7 @@ func (d *tcpDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOp
|
|||||||
opt(&options)
|
opt(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
var netd net.Dialer
|
conn, err := options.NetDialer.Dial(ctx, "tcp", addr)
|
||||||
conn, err := netd.DialContext(ctx, "tcp", addr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.logger.Error(err)
|
d.logger.Error(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterDialer("tls", NewDialer)
|
registry.DialerRegistry().Register("tls", NewDialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type tlsDialer struct {
|
type tlsDialer struct {
|
||||||
@@ -44,8 +44,7 @@ func (d *tlsDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOp
|
|||||||
opt(&options)
|
opt(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
var netd net.Dialer
|
conn, err := options.NetDialer.Dial(ctx, "tcp", addr)
|
||||||
conn, err := netd.DialContext(ctx, "tcp", addr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.logger.Error(err)
|
d.logger.Error(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterDialer("mtls", NewDialer)
|
registry.DialerRegistry().Register("mtls", NewDialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type mtlsDialer struct {
|
type mtlsDialer struct {
|
||||||
@@ -54,11 +54,6 @@ func (d *mtlsDialer) Multiplex() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *mtlsDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (conn net.Conn, err error) {
|
func (d *mtlsDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (conn net.Conn, err error) {
|
||||||
var options dialer.DialOptions
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(&options)
|
|
||||||
}
|
|
||||||
|
|
||||||
d.sessionMutex.Lock()
|
d.sessionMutex.Lock()
|
||||||
defer d.sessionMutex.Unlock()
|
defer d.sessionMutex.Unlock()
|
||||||
|
|
||||||
@@ -68,7 +63,12 @@ func (d *mtlsDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO
|
|||||||
ok = false
|
ok = false
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
conn, err = d.dial(ctx, "tcp", addr, &options)
|
var options dialer.DialOptions
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err = options.NetDialer.Dial(ctx, "tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -122,34 +122,6 @@ func (d *mtlsDialer) Handshake(ctx context.Context, conn net.Conn, options ...di
|
|||||||
return cc, nil
|
return cc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *mtlsDialer) dial(ctx context.Context, network, addr string, opts *dialer.DialOptions) (net.Conn, error) {
|
|
||||||
dial := opts.DialFunc
|
|
||||||
if dial != nil {
|
|
||||||
conn, err := dial(ctx, addr)
|
|
||||||
if err != nil {
|
|
||||||
d.logger.Error(err)
|
|
||||||
} else {
|
|
||||||
d.logger.WithFields(map[string]interface{}{
|
|
||||||
"src": conn.LocalAddr().String(),
|
|
||||||
"dst": addr,
|
|
||||||
}).Debug("dial with dial func")
|
|
||||||
}
|
|
||||||
return conn, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var netd net.Dialer
|
|
||||||
conn, err := netd.DialContext(ctx, network, addr)
|
|
||||||
if err != nil {
|
|
||||||
d.logger.Error(err)
|
|
||||||
} else {
|
|
||||||
d.logger.WithFields(map[string]interface{}{
|
|
||||||
"src": conn.LocalAddr().String(),
|
|
||||||
"dst": addr,
|
|
||||||
}).Debugf("dial direct %s/%s", addr, network)
|
|
||||||
}
|
|
||||||
return conn, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *mtlsDialer) initSession(ctx context.Context, conn net.Conn) (*muxSession, error) {
|
func (d *mtlsDialer) initSession(ctx context.Context, conn net.Conn) (*muxSession, error) {
|
||||||
tlsConn := tls.Client(conn, d.options.TLSConfig)
|
tlsConn := tls.Client(conn, d.options.TLSConfig)
|
||||||
if err := tlsConn.HandshakeContext(ctx); err != nil {
|
if err := tlsConn.HandshakeContext(ctx); err != nil {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterDialer("udp", NewDialer)
|
registry.DialerRegistry().Register("udp", NewDialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type udpDialer struct {
|
type udpDialer struct {
|
||||||
@@ -35,16 +35,16 @@ func (d *udpDialer) Init(md md.Metadata) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *udpDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (net.Conn, error) {
|
func (d *udpDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (net.Conn, error) {
|
||||||
taddr, err := net.ResolveUDPAddr("udp", addr)
|
var options dialer.DialOptions
|
||||||
if err != nil {
|
for _, opt := range opts {
|
||||||
return nil, err
|
opt(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := net.DialUDP("udp", nil, taddr)
|
c, err := options.NetDialer.Dial(ctx, "udp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &conn{
|
return &conn{
|
||||||
UDPConn: c,
|
UDPConn: c.(*net.UDPConn),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-13
@@ -8,20 +8,18 @@ import (
|
|||||||
|
|
||||||
"github.com/go-gost/gost/pkg/dialer"
|
"github.com/go-gost/gost/pkg/dialer"
|
||||||
ws_util "github.com/go-gost/gost/pkg/internal/util/ws"
|
ws_util "github.com/go-gost/gost/pkg/internal/util/ws"
|
||||||
"github.com/go-gost/gost/pkg/logger"
|
|
||||||
md "github.com/go-gost/gost/pkg/metadata"
|
md "github.com/go-gost/gost/pkg/metadata"
|
||||||
"github.com/go-gost/gost/pkg/registry"
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterDialer("ws", NewDialer)
|
registry.DialerRegistry().Register("ws", NewDialer)
|
||||||
registry.RegisterDialer("wss", NewTLSDialer)
|
registry.DialerRegistry().Register("wss", NewTLSDialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type wsDialer struct {
|
type wsDialer struct {
|
||||||
tlsEnabled bool
|
tlsEnabled bool
|
||||||
logger logger.Logger
|
|
||||||
md metadata
|
md metadata
|
||||||
options dialer.Options
|
options dialer.Options
|
||||||
}
|
}
|
||||||
@@ -33,7 +31,6 @@ func NewDialer(opts ...dialer.Option) dialer.Dialer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &wsDialer{
|
return &wsDialer{
|
||||||
logger: options.Logger,
|
|
||||||
options: options,
|
options: options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,7 +43,6 @@ func NewTLSDialer(opts ...dialer.Option) dialer.Dialer {
|
|||||||
|
|
||||||
return &wsDialer{
|
return &wsDialer{
|
||||||
tlsEnabled: true,
|
tlsEnabled: true,
|
||||||
logger: options.Logger,
|
|
||||||
options: options,
|
options: options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,10 +57,9 @@ func (d *wsDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOpt
|
|||||||
opt(&options)
|
opt(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
var netd net.Dialer
|
conn, err := options.NetDialer.Dial(ctx, "tcp", addr)
|
||||||
conn, err := netd.DialContext(ctx, "tcp", addr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.logger.Error(err)
|
d.options.Logger.Error(err)
|
||||||
}
|
}
|
||||||
return conn, err
|
return conn, err
|
||||||
}
|
}
|
||||||
@@ -77,8 +72,8 @@ func (d *wsDialer) Handshake(ctx context.Context, conn net.Conn, options ...dial
|
|||||||
}
|
}
|
||||||
|
|
||||||
if d.md.handshakeTimeout > 0 {
|
if d.md.handshakeTimeout > 0 {
|
||||||
conn.SetDeadline(time.Now().Add(d.md.handshakeTimeout))
|
conn.SetReadDeadline(time.Now().Add(d.md.handshakeTimeout))
|
||||||
defer conn.SetDeadline(time.Time{})
|
defer conn.SetReadDeadline(time.Time{})
|
||||||
}
|
}
|
||||||
|
|
||||||
host := d.md.host
|
host := d.md.host
|
||||||
@@ -102,11 +97,36 @@ func (d *wsDialer) Handshake(ctx context.Context, conn net.Conn, options ...dial
|
|||||||
dialer.TLSClientConfig = d.options.TLSConfig
|
dialer.TLSClientConfig = d.options.TLSConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
c, resp, err := dialer.Dial(url.String(), d.md.header)
|
c, resp, err := dialer.DialContext(ctx, url.String(), d.md.header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
|
|
||||||
return ws_util.Conn(c), nil
|
cc := ws_util.Conn(c)
|
||||||
|
|
||||||
|
if d.md.keepAlive > 0 {
|
||||||
|
c.SetReadDeadline(time.Now().Add(d.md.keepAlive * 2))
|
||||||
|
c.SetPongHandler(func(string) error {
|
||||||
|
c.SetReadDeadline(time.Now().Add(d.md.keepAlive * 2))
|
||||||
|
d.options.Logger.Infof("pong: set read deadline: %v", d.md.keepAlive*2)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
go d.keepAlive(cc)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *wsDialer) keepAlive(conn ws_util.WebsocketConn) {
|
||||||
|
ticker := time.NewTicker(d.md.keepAlive)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for range ticker.C {
|
||||||
|
conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
|
||||||
|
if err := conn.WriteMessage(websocket.PingMessage, nil); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.options.Logger.Infof("send ping")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ type metadata struct {
|
|||||||
enableCompression bool
|
enableCompression bool
|
||||||
|
|
||||||
header http.Header
|
header http.Header
|
||||||
|
keepAlive time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *wsDialer) parseMetadata(md mdata.Metadata) (err error) {
|
func (d *wsDialer) parseMetadata(md mdata.Metadata) (err error) {
|
||||||
@@ -36,6 +37,7 @@ func (d *wsDialer) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
enableCompression = "enableCompression"
|
enableCompression = "enableCompression"
|
||||||
|
|
||||||
header = "header"
|
header = "header"
|
||||||
|
keepAlive = "keepAlive"
|
||||||
)
|
)
|
||||||
|
|
||||||
d.md.host = mdata.GetString(md, host)
|
d.md.host = mdata.GetString(md, host)
|
||||||
@@ -58,6 +60,7 @@ func (d *wsDialer) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
}
|
}
|
||||||
d.md.header = h
|
d.md.header = h
|
||||||
}
|
}
|
||||||
|
d.md.keepAlive = mdata.GetDuration(md, keepAlive)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-50
@@ -10,7 +10,6 @@ import (
|
|||||||
|
|
||||||
"github.com/go-gost/gost/pkg/dialer"
|
"github.com/go-gost/gost/pkg/dialer"
|
||||||
ws_util "github.com/go-gost/gost/pkg/internal/util/ws"
|
ws_util "github.com/go-gost/gost/pkg/internal/util/ws"
|
||||||
"github.com/go-gost/gost/pkg/logger"
|
|
||||||
md "github.com/go-gost/gost/pkg/metadata"
|
md "github.com/go-gost/gost/pkg/metadata"
|
||||||
"github.com/go-gost/gost/pkg/registry"
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
@@ -18,15 +17,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterDialer("mws", NewDialer)
|
registry.DialerRegistry().Register("mws", NewDialer)
|
||||||
registry.RegisterDialer("mwss", NewTLSDialer)
|
registry.DialerRegistry().Register("mwss", NewTLSDialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type mwsDialer struct {
|
type mwsDialer struct {
|
||||||
sessions map[string]*muxSession
|
sessions map[string]*muxSession
|
||||||
sessionMutex sync.Mutex
|
sessionMutex sync.Mutex
|
||||||
tlsEnabled bool
|
tlsEnabled bool
|
||||||
logger logger.Logger
|
|
||||||
md metadata
|
md metadata
|
||||||
options dialer.Options
|
options dialer.Options
|
||||||
}
|
}
|
||||||
@@ -39,7 +37,6 @@ func NewDialer(opts ...dialer.Option) dialer.Dialer {
|
|||||||
|
|
||||||
return &mwsDialer{
|
return &mwsDialer{
|
||||||
sessions: make(map[string]*muxSession),
|
sessions: make(map[string]*muxSession),
|
||||||
logger: options.Logger,
|
|
||||||
options: options,
|
options: options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,7 +50,6 @@ func NewTLSDialer(opts ...dialer.Option) dialer.Dialer {
|
|||||||
return &mwsDialer{
|
return &mwsDialer{
|
||||||
tlsEnabled: true,
|
tlsEnabled: true,
|
||||||
sessions: make(map[string]*muxSession),
|
sessions: make(map[string]*muxSession),
|
||||||
logger: options.Logger,
|
|
||||||
options: options,
|
options: options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,11 +67,6 @@ func (d *mwsDialer) Multiplex() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *mwsDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (conn net.Conn, err error) {
|
func (d *mwsDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (conn net.Conn, err error) {
|
||||||
var options dialer.DialOptions
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(&options)
|
|
||||||
}
|
|
||||||
|
|
||||||
d.sessionMutex.Lock()
|
d.sessionMutex.Lock()
|
||||||
defer d.sessionMutex.Unlock()
|
defer d.sessionMutex.Unlock()
|
||||||
|
|
||||||
@@ -85,7 +76,12 @@ func (d *mwsDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOp
|
|||||||
ok = false
|
ok = false
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
conn, err = d.dial(ctx, "tcp", addr, &options)
|
var options dialer.DialOptions
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err = options.NetDialer.Dial(ctx, "tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -107,11 +103,6 @@ func (d *mwsDialer) Handshake(ctx context.Context, conn net.Conn, options ...dia
|
|||||||
d.sessionMutex.Lock()
|
d.sessionMutex.Lock()
|
||||||
defer d.sessionMutex.Unlock()
|
defer d.sessionMutex.Unlock()
|
||||||
|
|
||||||
if d.md.handshakeTimeout > 0 {
|
|
||||||
conn.SetDeadline(time.Now().Add(d.md.handshakeTimeout))
|
|
||||||
defer conn.SetDeadline(time.Time{})
|
|
||||||
}
|
|
||||||
|
|
||||||
session, ok := d.sessions[opts.Addr]
|
session, ok := d.sessions[opts.Addr]
|
||||||
if session != nil && session.conn != conn {
|
if session != nil && session.conn != conn {
|
||||||
conn.Close()
|
conn.Close()
|
||||||
@@ -125,7 +116,7 @@ func (d *mwsDialer) Handshake(ctx context.Context, conn net.Conn, options ...dia
|
|||||||
}
|
}
|
||||||
s, err := d.initSession(ctx, host, conn)
|
s, err := d.initSession(ctx, host, conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.logger.Error(err)
|
d.options.Logger.Error(err)
|
||||||
conn.Close()
|
conn.Close()
|
||||||
delete(d.sessions, opts.Addr)
|
delete(d.sessions, opts.Addr)
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -143,34 +134,6 @@ func (d *mwsDialer) Handshake(ctx context.Context, conn net.Conn, options ...dia
|
|||||||
return cc, nil
|
return cc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *mwsDialer) dial(ctx context.Context, network, addr string, opts *dialer.DialOptions) (net.Conn, error) {
|
|
||||||
dial := opts.DialFunc
|
|
||||||
if dial != nil {
|
|
||||||
conn, err := dial(ctx, addr)
|
|
||||||
if err != nil {
|
|
||||||
d.logger.Error(err)
|
|
||||||
} else {
|
|
||||||
d.logger.WithFields(map[string]interface{}{
|
|
||||||
"src": conn.LocalAddr().String(),
|
|
||||||
"dst": addr,
|
|
||||||
}).Debug("dial with dial func")
|
|
||||||
}
|
|
||||||
return conn, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var netd net.Dialer
|
|
||||||
conn, err := netd.DialContext(ctx, network, addr)
|
|
||||||
if err != nil {
|
|
||||||
d.logger.Error(err)
|
|
||||||
} else {
|
|
||||||
d.logger.WithFields(map[string]interface{}{
|
|
||||||
"src": conn.LocalAddr().String(),
|
|
||||||
"dst": addr,
|
|
||||||
}).Debugf("dial direct %s/%s", addr, network)
|
|
||||||
}
|
|
||||||
return conn, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *mwsDialer) initSession(ctx context.Context, host string, conn net.Conn) (*muxSession, error) {
|
func (d *mwsDialer) initSession(ctx context.Context, host string, conn net.Conn) (*muxSession, error) {
|
||||||
dialer := websocket.Dialer{
|
dialer := websocket.Dialer{
|
||||||
HandshakeTimeout: d.md.handshakeTimeout,
|
HandshakeTimeout: d.md.handshakeTimeout,
|
||||||
@@ -188,13 +151,30 @@ func (d *mwsDialer) initSession(ctx context.Context, host string, conn net.Conn)
|
|||||||
dialer.TLSClientConfig = d.options.TLSConfig
|
dialer.TLSClientConfig = d.options.TLSConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
c, resp, err := dialer.Dial(url.String(), d.md.header)
|
if d.md.handshakeTimeout > 0 {
|
||||||
|
conn.SetReadDeadline(time.Now().Add(d.md.handshakeTimeout))
|
||||||
|
}
|
||||||
|
|
||||||
|
c, resp, err := dialer.DialContext(ctx, url.String(), d.md.header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
|
|
||||||
conn = ws_util.Conn(c)
|
if d.md.handshakeTimeout > 0 {
|
||||||
|
conn.SetReadDeadline(time.Time{})
|
||||||
|
}
|
||||||
|
|
||||||
|
cc := ws_util.Conn(c)
|
||||||
|
|
||||||
|
if d.md.keepAlive > 0 {
|
||||||
|
c.SetReadDeadline(time.Now().Add(d.md.keepAlive * 2))
|
||||||
|
c.SetPongHandler(func(string) error {
|
||||||
|
c.SetReadDeadline(time.Now().Add(d.md.keepAlive * 2))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
go d.keepAlive(cc)
|
||||||
|
}
|
||||||
|
|
||||||
// stream multiplex
|
// stream multiplex
|
||||||
smuxConfig := smux.DefaultConfig()
|
smuxConfig := smux.DefaultConfig()
|
||||||
@@ -215,9 +195,21 @@ func (d *mwsDialer) initSession(ctx context.Context, host string, conn net.Conn)
|
|||||||
smuxConfig.MaxStreamBuffer = d.md.muxMaxStreamBuffer
|
smuxConfig.MaxStreamBuffer = d.md.muxMaxStreamBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
session, err := smux.Client(conn, smuxConfig)
|
session, err := smux.Client(cc, smuxConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &muxSession{conn: conn, session: session}, nil
|
return &muxSession{conn: cc, session: session}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *mwsDialer) keepAlive(conn ws_util.WebsocketConn) {
|
||||||
|
ticker := time.NewTicker(d.md.keepAlive)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for range ticker.C {
|
||||||
|
conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
|
||||||
|
if err := conn.WriteMessage(websocket.PingMessage, nil); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ type metadata struct {
|
|||||||
muxMaxStreamBuffer int
|
muxMaxStreamBuffer int
|
||||||
|
|
||||||
header http.Header
|
header http.Header
|
||||||
|
keepAlive time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *mwsDialer) parseMetadata(md mdata.Metadata) (err error) {
|
func (d *mwsDialer) parseMetadata(md mdata.Metadata) (err error) {
|
||||||
@@ -43,6 +44,7 @@ func (d *mwsDialer) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
enableCompression = "enableCompression"
|
enableCompression = "enableCompression"
|
||||||
|
|
||||||
header = "header"
|
header = "header"
|
||||||
|
keepAlive = "keepAlive"
|
||||||
|
|
||||||
muxKeepAliveDisabled = "muxKeepAliveDisabled"
|
muxKeepAliveDisabled = "muxKeepAliveDisabled"
|
||||||
muxKeepAliveInterval = "muxKeepAliveInterval"
|
muxKeepAliveInterval = "muxKeepAliveInterval"
|
||||||
@@ -79,5 +81,7 @@ func (d *mwsDialer) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
}
|
}
|
||||||
d.md.header = h
|
d.md.header = h
|
||||||
}
|
}
|
||||||
|
d.md.keepAlive = mdata.GetDuration(md, keepAlive)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-18
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/go-gost/gosocks4"
|
"github.com/go-gost/gosocks4"
|
||||||
"github.com/go-gost/gosocks5"
|
"github.com/go-gost/gosocks5"
|
||||||
|
netpkg "github.com/go-gost/gost/pkg/common/net"
|
||||||
"github.com/go-gost/gost/pkg/handler"
|
"github.com/go-gost/gost/pkg/handler"
|
||||||
md "github.com/go-gost/gost/pkg/metadata"
|
md "github.com/go-gost/gost/pkg/metadata"
|
||||||
"github.com/go-gost/gost/pkg/registry"
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
@@ -15,7 +16,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterHandler("auto", NewHandler)
|
registry.HandlerRegistry().Register("auto", NewHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
type autoHandler struct {
|
type autoHandler struct {
|
||||||
@@ -36,24 +37,24 @@ func NewHandler(opts ...handler.Option) handler.Handler {
|
|||||||
options: options,
|
options: options,
|
||||||
}
|
}
|
||||||
|
|
||||||
if f := registry.GetHandler("http"); f != nil {
|
if f := registry.HandlerRegistry().Get("http"); f != nil {
|
||||||
v := append(opts,
|
v := append(opts,
|
||||||
handler.LoggerOption(options.Logger.WithFields(map[string]interface{}{"type": "http"})))
|
handler.LoggerOption(options.Logger.WithFields(map[string]any{"type": "http"})))
|
||||||
h.httpHandler = f(v...)
|
h.httpHandler = f(v...)
|
||||||
}
|
}
|
||||||
if f := registry.GetHandler("socks4"); f != nil {
|
if f := registry.HandlerRegistry().Get("socks4"); f != nil {
|
||||||
v := append(opts,
|
v := append(opts,
|
||||||
handler.LoggerOption(options.Logger.WithFields(map[string]interface{}{"type": "socks4"})))
|
handler.LoggerOption(options.Logger.WithFields(map[string]any{"type": "socks4"})))
|
||||||
h.socks4Handler = f(v...)
|
h.socks4Handler = f(v...)
|
||||||
}
|
}
|
||||||
if f := registry.GetHandler("socks5"); f != nil {
|
if f := registry.HandlerRegistry().Get("socks5"); f != nil {
|
||||||
v := append(opts,
|
v := append(opts,
|
||||||
handler.LoggerOption(options.Logger.WithFields(map[string]interface{}{"type": "socks5"})))
|
handler.LoggerOption(options.Logger.WithFields(map[string]any{"type": "socks5"})))
|
||||||
h.socks5Handler = f(v...)
|
h.socks5Handler = f(v...)
|
||||||
}
|
}
|
||||||
if f := registry.GetHandler("relay"); f != nil {
|
if f := registry.HandlerRegistry().Get("relay"); f != nil {
|
||||||
v := append(opts,
|
v := append(opts,
|
||||||
handler.LoggerOption(options.Logger.WithFields(map[string]interface{}{"type": "relay"})))
|
handler.LoggerOption(options.Logger.WithFields(map[string]any{"type": "relay"})))
|
||||||
h.relayHandler = f(v...)
|
h.relayHandler = f(v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,8 +86,8 @@ func (h *autoHandler) Init(md md.Metadata) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *autoHandler) Handle(ctx context.Context, conn net.Conn) {
|
func (h *autoHandler) Handle(ctx context.Context, conn net.Conn) error {
|
||||||
log := h.options.Logger.WithFields(map[string]interface{}{
|
log := h.options.Logger.WithFields(map[string]any{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
})
|
})
|
||||||
@@ -94,7 +95,7 @@ func (h *autoHandler) Handle(ctx context.Context, conn net.Conn) {
|
|||||||
start := time.Now()
|
start := time.Now()
|
||||||
log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr())
|
log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr())
|
||||||
defer func() {
|
defer func() {
|
||||||
log.WithFields(map[string]interface{}{
|
log.WithFields(map[string]any{
|
||||||
"duration": time.Since(start),
|
"duration": time.Since(start),
|
||||||
}).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr())
|
}).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr())
|
||||||
}()
|
}()
|
||||||
@@ -104,26 +105,27 @@ func (h *autoHandler) Handle(ctx context.Context, conn net.Conn) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
conn = handler.NewBufferReaderConn(conn, br)
|
conn = netpkg.NewBufferReaderConn(conn, br)
|
||||||
switch b[0] {
|
switch b[0] {
|
||||||
case gosocks4.Ver4: // socks4
|
case gosocks4.Ver4: // socks4
|
||||||
if h.socks4Handler != nil {
|
if h.socks4Handler != nil {
|
||||||
h.socks4Handler.Handle(ctx, conn)
|
return h.socks4Handler.Handle(ctx, conn)
|
||||||
}
|
}
|
||||||
case gosocks5.Ver5: // socks5
|
case gosocks5.Ver5: // socks5
|
||||||
if h.socks5Handler != nil {
|
if h.socks5Handler != nil {
|
||||||
h.socks5Handler.Handle(ctx, conn)
|
return h.socks5Handler.Handle(ctx, conn)
|
||||||
}
|
}
|
||||||
case relay.Version1: // relay
|
case relay.Version1: // relay
|
||||||
if h.relayHandler != nil {
|
if h.relayHandler != nil {
|
||||||
h.relayHandler.Handle(ctx, conn)
|
return h.relayHandler.Handle(ctx, conn)
|
||||||
}
|
}
|
||||||
default: // http
|
default: // http
|
||||||
if h.httpHandler != nil {
|
if h.httpHandler != nil {
|
||||||
h.httpHandler.Handle(ctx, conn)
|
return h.httpHandler.Handle(ctx, conn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-15
@@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/go-gost/gost/pkg/chain"
|
"github.com/go-gost/gost/pkg/chain"
|
||||||
"github.com/go-gost/gost/pkg/common/bufpool"
|
"github.com/go-gost/gost/pkg/common/bufpool"
|
||||||
"github.com/go-gost/gost/pkg/handler"
|
"github.com/go-gost/gost/pkg/handler"
|
||||||
|
"github.com/go-gost/gost/pkg/hosts"
|
||||||
resolver_util "github.com/go-gost/gost/pkg/internal/util/resolver"
|
resolver_util "github.com/go-gost/gost/pkg/internal/util/resolver"
|
||||||
"github.com/go-gost/gost/pkg/logger"
|
"github.com/go-gost/gost/pkg/logger"
|
||||||
md "github.com/go-gost/gost/pkg/metadata"
|
md "github.com/go-gost/gost/pkg/metadata"
|
||||||
@@ -26,13 +27,14 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterHandler("dns", NewHandler)
|
registry.HandlerRegistry().Register("dns", NewHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
type dnsHandler struct {
|
type dnsHandler struct {
|
||||||
exchangers []exchanger.Exchanger
|
exchangers []exchanger.Exchanger
|
||||||
cache *resolver_util.Cache
|
cache *resolver_util.Cache
|
||||||
router *chain.Router
|
router *chain.Router
|
||||||
|
hosts hosts.HostMapper
|
||||||
md metadata
|
md metadata
|
||||||
options handler.Options
|
options handler.Options
|
||||||
}
|
}
|
||||||
@@ -55,13 +57,12 @@ func (h *dnsHandler) Init(md md.Metadata) (err error) {
|
|||||||
log := h.options.Logger
|
log := h.options.Logger
|
||||||
|
|
||||||
h.cache = resolver_util.NewCache().WithLogger(log)
|
h.cache = resolver_util.NewCache().WithLogger(log)
|
||||||
h.router = &chain.Router{
|
|
||||||
Retries: h.options.Retries,
|
h.router = h.options.Router
|
||||||
Chain: h.options.Chain,
|
if h.router == nil {
|
||||||
Resolver: h.options.Resolver,
|
h.router = (&chain.Router{}).WithLogger(log)
|
||||||
// Hosts: h.options.Hosts,
|
|
||||||
Logger: log,
|
|
||||||
}
|
}
|
||||||
|
h.hosts = h.router.Hosts()
|
||||||
|
|
||||||
for _, server := range h.md.dns {
|
for _, server := range h.md.dns {
|
||||||
server = strings.TrimSpace(server)
|
server = strings.TrimSpace(server)
|
||||||
@@ -97,18 +98,18 @@ func (h *dnsHandler) Init(md md.Metadata) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *dnsHandler) Handle(ctx context.Context, conn net.Conn) {
|
func (h *dnsHandler) Handle(ctx context.Context, conn net.Conn) error {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
log := h.options.Logger.WithFields(map[string]interface{}{
|
log := h.options.Logger.WithFields(map[string]any{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
})
|
})
|
||||||
|
|
||||||
log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr())
|
log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr())
|
||||||
defer func() {
|
defer func() {
|
||||||
log.WithFields(map[string]interface{}{
|
log.WithFields(map[string]any{
|
||||||
"duration": time.Since(start),
|
"duration": time.Since(start),
|
||||||
}).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr())
|
}).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr())
|
||||||
}()
|
}()
|
||||||
@@ -119,18 +120,20 @@ func (h *dnsHandler) Handle(ctx context.Context, conn net.Conn) {
|
|||||||
n, err := conn.Read(*b)
|
n, err := conn.Read(*b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
reply, err := h.exchange(ctx, (*b)[:n], log)
|
reply, err := h.exchange(ctx, (*b)[:n], log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
defer bufpool.Put(&reply)
|
defer bufpool.Put(&reply)
|
||||||
|
|
||||||
if _, err = conn.Write(reply); err != nil {
|
if _, err = conn.Write(reply); err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *dnsHandler) exchange(ctx context.Context, msg []byte, log logger.Logger) ([]byte, error) {
|
func (h *dnsHandler) exchange(ctx context.Context, msg []byte, log logger.Logger) ([]byte, error) {
|
||||||
@@ -218,7 +221,7 @@ func (h *dnsHandler) exchange(ctx context.Context, msg []byte, log logger.Logger
|
|||||||
|
|
||||||
// lookup host mapper
|
// lookup host mapper
|
||||||
func (h *dnsHandler) lookupHosts(r *dns.Msg, log logger.Logger) (m *dns.Msg) {
|
func (h *dnsHandler) lookupHosts(r *dns.Msg, log logger.Logger) (m *dns.Msg) {
|
||||||
if h.options.Hosts == nil ||
|
if h.hosts == nil ||
|
||||||
r.Question[0].Qclass != dns.ClassINET ||
|
r.Question[0].Qclass != dns.ClassINET ||
|
||||||
(r.Question[0].Qtype != dns.TypeA && r.Question[0].Qtype != dns.TypeAAAA) {
|
(r.Question[0].Qtype != dns.TypeA && r.Question[0].Qtype != dns.TypeAAAA) {
|
||||||
return nil
|
return nil
|
||||||
@@ -231,7 +234,7 @@ func (h *dnsHandler) lookupHosts(r *dns.Msg, log logger.Logger) (m *dns.Msg) {
|
|||||||
|
|
||||||
switch r.Question[0].Qtype {
|
switch r.Question[0].Qtype {
|
||||||
case dns.TypeA:
|
case dns.TypeA:
|
||||||
ips, _ := h.options.Hosts.Lookup("ip4", host)
|
ips, _ := h.hosts.Lookup("ip4", host)
|
||||||
if len(ips) == 0 {
|
if len(ips) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -247,7 +250,7 @@ func (h *dnsHandler) lookupHosts(r *dns.Msg, log logger.Logger) (m *dns.Msg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case dns.TypeAAAA:
|
case dns.TypeAAAA:
|
||||||
ips, _ := h.options.Hosts.Lookup("ip6", host)
|
ips, _ := h.hosts.Lookup("ip6", host)
|
||||||
if len(ips) == 0 {
|
if len(ips) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,20 +2,22 @@ package local
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-gost/gost/pkg/chain"
|
"github.com/go-gost/gost/pkg/chain"
|
||||||
|
netpkg "github.com/go-gost/gost/pkg/common/net"
|
||||||
"github.com/go-gost/gost/pkg/handler"
|
"github.com/go-gost/gost/pkg/handler"
|
||||||
md "github.com/go-gost/gost/pkg/metadata"
|
md "github.com/go-gost/gost/pkg/metadata"
|
||||||
"github.com/go-gost/gost/pkg/registry"
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterHandler("tcp", NewHandler)
|
registry.HandlerRegistry().Register("tcp", NewHandler)
|
||||||
registry.RegisterHandler("udp", NewHandler)
|
registry.HandlerRegistry().Register("udp", NewHandler)
|
||||||
registry.RegisterHandler("forward", NewHandler)
|
registry.HandlerRegistry().Register("forward", NewHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
type forwardHandler struct {
|
type forwardHandler struct {
|
||||||
@@ -46,12 +48,9 @@ func (h *forwardHandler) Init(md md.Metadata) (err error) {
|
|||||||
h.group = chain.NewNodeGroup(&chain.Node{Name: "dummy", Addr: ":0"})
|
h.group = chain.NewNodeGroup(&chain.Node{Name: "dummy", Addr: ":0"})
|
||||||
}
|
}
|
||||||
|
|
||||||
h.router = &chain.Router{
|
h.router = h.options.Router
|
||||||
Retries: h.options.Retries,
|
if h.router == nil {
|
||||||
Chain: h.options.Chain,
|
h.router = (&chain.Router{}).WithLogger(h.options.Logger)
|
||||||
Resolver: h.options.Resolver,
|
|
||||||
Hosts: h.options.Hosts,
|
|
||||||
Logger: h.options.Logger,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -62,26 +61,27 @@ func (h *forwardHandler) Forward(group *chain.NodeGroup) {
|
|||||||
h.group = group
|
h.group = group
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn) {
|
func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn) error {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
log := h.options.Logger.WithFields(map[string]interface{}{
|
log := h.options.Logger.WithFields(map[string]any{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
})
|
})
|
||||||
|
|
||||||
log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr())
|
log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr())
|
||||||
defer func() {
|
defer func() {
|
||||||
log.WithFields(map[string]interface{}{
|
log.WithFields(map[string]any{
|
||||||
"duration": time.Since(start),
|
"duration": time.Since(start),
|
||||||
}).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr())
|
}).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
target := h.group.Next()
|
target := h.group.Next()
|
||||||
if target == nil {
|
if target == nil {
|
||||||
log.Error("no target available")
|
err := errors.New("target not available")
|
||||||
return
|
log.Error(err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
network := "tcp"
|
network := "tcp"
|
||||||
@@ -89,7 +89,7 @@ func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn) {
|
|||||||
network = "udp"
|
network = "udp"
|
||||||
}
|
}
|
||||||
|
|
||||||
log = log.WithFields(map[string]interface{}{
|
log = log.WithFields(map[string]any{
|
||||||
"dst": fmt.Sprintf("%s/%s", target.Addr, network),
|
"dst": fmt.Sprintf("%s/%s", target.Addr, network),
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -101,15 +101,17 @@ func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn) {
|
|||||||
// TODO: the router itself may be failed due to the failed node in the router,
|
// TODO: the router itself may be failed due to the failed node in the router,
|
||||||
// the dead marker may be a wrong operation.
|
// the dead marker may be a wrong operation.
|
||||||
target.Marker.Mark()
|
target.Marker.Mark()
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
defer cc.Close()
|
defer cc.Close()
|
||||||
target.Marker.Reset()
|
target.Marker.Reset()
|
||||||
|
|
||||||
t := time.Now()
|
t := time.Now()
|
||||||
log.Infof("%s <-> %s", conn.RemoteAddr(), target.Addr)
|
log.Infof("%s <-> %s", conn.RemoteAddr(), target.Addr)
|
||||||
handler.Transport(conn, cc)
|
netpkg.Transport(conn, cc)
|
||||||
log.WithFields(map[string]interface{}{
|
log.WithFields(map[string]any{
|
||||||
"duration": time.Since(t),
|
"duration": time.Since(t),
|
||||||
}).Infof("%s >-< %s", conn.RemoteAddr(), target.Addr)
|
}).Infof("%s >-< %s", conn.RemoteAddr(), target.Addr)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,19 +2,21 @@ package remote
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-gost/gost/pkg/chain"
|
"github.com/go-gost/gost/pkg/chain"
|
||||||
|
netpkg "github.com/go-gost/gost/pkg/common/net"
|
||||||
"github.com/go-gost/gost/pkg/handler"
|
"github.com/go-gost/gost/pkg/handler"
|
||||||
md "github.com/go-gost/gost/pkg/metadata"
|
md "github.com/go-gost/gost/pkg/metadata"
|
||||||
"github.com/go-gost/gost/pkg/registry"
|
"github.com/go-gost/gost/pkg/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterHandler("rtcp", NewHandler)
|
registry.HandlerRegistry().Register("rtcp", NewHandler)
|
||||||
registry.RegisterHandler("rudp", NewHandler)
|
registry.HandlerRegistry().Register("rudp", NewHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
type forwardHandler struct {
|
type forwardHandler struct {
|
||||||
@@ -40,12 +42,9 @@ func (h *forwardHandler) Init(md md.Metadata) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.router = &chain.Router{
|
h.router = h.options.Router
|
||||||
Retries: h.options.Retries,
|
if h.router == nil {
|
||||||
Chain: h.options.Chain,
|
h.router = (&chain.Router{}).WithLogger(h.options.Logger)
|
||||||
Resolver: h.options.Resolver,
|
|
||||||
Hosts: h.options.Hosts,
|
|
||||||
Logger: h.options.Logger,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -56,26 +55,27 @@ func (h *forwardHandler) Forward(group *chain.NodeGroup) {
|
|||||||
h.group = group
|
h.group = group
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn) {
|
func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn) error {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
log := h.options.Logger.WithFields(map[string]interface{}{
|
log := h.options.Logger.WithFields(map[string]any{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
})
|
})
|
||||||
|
|
||||||
log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr())
|
log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr())
|
||||||
defer func() {
|
defer func() {
|
||||||
log.WithFields(map[string]interface{}{
|
log.WithFields(map[string]any{
|
||||||
"duration": time.Since(start),
|
"duration": time.Since(start),
|
||||||
}).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr())
|
}).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
target := h.group.Next()
|
target := h.group.Next()
|
||||||
if target == nil {
|
if target == nil {
|
||||||
log.Error("no target available")
|
err := errors.New("target not available")
|
||||||
return
|
log.Error(err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
network := "tcp"
|
network := "tcp"
|
||||||
@@ -83,7 +83,7 @@ func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn) {
|
|||||||
network = "udp"
|
network = "udp"
|
||||||
}
|
}
|
||||||
|
|
||||||
log = log.WithFields(map[string]interface{}{
|
log = log.WithFields(map[string]any{
|
||||||
"dst": fmt.Sprintf("%s/%s", target.Addr, network),
|
"dst": fmt.Sprintf("%s/%s", target.Addr, network),
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -95,15 +95,17 @@ func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn) {
|
|||||||
// TODO: the router itself may be failed due to the failed node in the router,
|
// TODO: the router itself may be failed due to the failed node in the router,
|
||||||
// the dead marker may be a wrong operation.
|
// the dead marker may be a wrong operation.
|
||||||
target.Marker.Mark()
|
target.Marker.Mark()
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
defer cc.Close()
|
defer cc.Close()
|
||||||
target.Marker.Reset()
|
target.Marker.Reset()
|
||||||
|
|
||||||
t := time.Now()
|
t := time.Now()
|
||||||
log.Infof("%s <-> %s", conn.RemoteAddr(), target.Addr)
|
log.Infof("%s <-> %s", conn.RemoteAddr(), target.Addr)
|
||||||
handler.Transport(conn, cc)
|
netpkg.Transport(conn, cc)
|
||||||
log.WithFields(map[string]interface{}{
|
log.WithFields(map[string]any{
|
||||||
"duration": time.Since(t),
|
"duration": time.Since(t),
|
||||||
}).Infof("%s >-< %s", conn.RemoteAddr(), target.Addr)
|
}).Infof("%s >-< %s", conn.RemoteAddr(), target.Addr)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
type Handler interface {
|
type Handler interface {
|
||||||
Init(metadata.Metadata) error
|
Init(metadata.Metadata) error
|
||||||
Handle(context.Context, net.Conn)
|
Handle(context.Context, net.Conn) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Forwarder interface {
|
type Forwarder interface {
|
||||||
|
|||||||
+25
-37
@@ -16,9 +16,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
"github.com/asaskevich/govalidator"
|
||||||
"github.com/go-gost/gost/pkg/auth"
|
|
||||||
"github.com/go-gost/gost/pkg/chain"
|
"github.com/go-gost/gost/pkg/chain"
|
||||||
auth_util "github.com/go-gost/gost/pkg/common/util/auth"
|
netpkg "github.com/go-gost/gost/pkg/common/net"
|
||||||
"github.com/go-gost/gost/pkg/handler"
|
"github.com/go-gost/gost/pkg/handler"
|
||||||
"github.com/go-gost/gost/pkg/logger"
|
"github.com/go-gost/gost/pkg/logger"
|
||||||
md "github.com/go-gost/gost/pkg/metadata"
|
md "github.com/go-gost/gost/pkg/metadata"
|
||||||
@@ -26,12 +25,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterHandler("http", NewHandler)
|
registry.HandlerRegistry().Register("http", NewHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
type httpHandler struct {
|
type httpHandler struct {
|
||||||
router *chain.Router
|
router *chain.Router
|
||||||
authenticator auth.Authenticator
|
|
||||||
md metadata
|
md metadata
|
||||||
options handler.Options
|
options handler.Options
|
||||||
}
|
}
|
||||||
@@ -52,29 +50,25 @@ func (h *httpHandler) Init(md md.Metadata) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
h.authenticator = auth_util.AuthFromUsers(h.options.Auths...)
|
h.router = h.options.Router
|
||||||
h.router = &chain.Router{
|
if h.router == nil {
|
||||||
Retries: h.options.Retries,
|
h.router = (&chain.Router{}).WithLogger(h.options.Logger)
|
||||||
Chain: h.options.Chain,
|
|
||||||
Resolver: h.options.Resolver,
|
|
||||||
Hosts: h.options.Hosts,
|
|
||||||
Logger: h.options.Logger,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpHandler) Handle(ctx context.Context, conn net.Conn) {
|
func (h *httpHandler) Handle(ctx context.Context, conn net.Conn) error {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
log := h.options.Logger.WithFields(map[string]interface{}{
|
log := h.options.Logger.WithFields(map[string]any{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
})
|
})
|
||||||
log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr())
|
log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr())
|
||||||
defer func() {
|
defer func() {
|
||||||
log.WithFields(map[string]interface{}{
|
log.WithFields(map[string]any{
|
||||||
"duration": time.Since(start),
|
"duration": time.Since(start),
|
||||||
}).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr())
|
}).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr())
|
||||||
}()
|
}()
|
||||||
@@ -82,18 +76,14 @@ func (h *httpHandler) Handle(ctx context.Context, conn net.Conn) {
|
|||||||
req, err := http.ReadRequest(bufio.NewReader(conn))
|
req, err := http.ReadRequest(bufio.NewReader(conn))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
defer req.Body.Close()
|
defer req.Body.Close()
|
||||||
|
|
||||||
h.handleRequest(ctx, conn, req, log)
|
return h.handleRequest(ctx, conn, req, log)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *http.Request, log logger.Logger) {
|
func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *http.Request, log logger.Logger) error {
|
||||||
if req == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if h.md.sni && !req.URL.IsAbs() && govalidator.IsDNSName(req.Host) {
|
if h.md.sni && !req.URL.IsAbs() && govalidator.IsDNSName(req.Host) {
|
||||||
req.URL.Scheme = "http"
|
req.URL.Scheme = "http"
|
||||||
}
|
}
|
||||||
@@ -124,7 +114,7 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt
|
|||||||
addr = net.JoinHostPort(addr, "80")
|
addr = net.JoinHostPort(addr, "80")
|
||||||
}
|
}
|
||||||
|
|
||||||
fields := map[string]interface{}{
|
fields := map[string]any{
|
||||||
"dst": addr,
|
"dst": addr,
|
||||||
}
|
}
|
||||||
if u, _, _ := h.basicProxyAuth(req.Header.Get("Proxy-Authorization"), log); u != "" {
|
if u, _, _ := h.basicProxyAuth(req.Header.Get("Proxy-Authorization"), log); u != "" {
|
||||||
@@ -156,30 +146,27 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt
|
|||||||
}
|
}
|
||||||
log.Info("bypass: ", addr)
|
log.Info("bypass: ", addr)
|
||||||
|
|
||||||
resp.Write(conn)
|
return resp.Write(conn)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !h.authenticate(conn, req, resp, log) {
|
if !h.authenticate(conn, req, resp, log) {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if network == "udp" {
|
if network == "udp" {
|
||||||
h.handleUDP(ctx, conn, network, req.Host, log)
|
return h.handleUDP(ctx, conn, network, req.Host, log)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Method == "PRI" ||
|
if req.Method == "PRI" ||
|
||||||
(req.Method != http.MethodConnect && req.URL.Scheme != "http") {
|
(req.Method != http.MethodConnect && req.URL.Scheme != "http") {
|
||||||
resp.StatusCode = http.StatusBadRequest
|
resp.StatusCode = http.StatusBadRequest
|
||||||
resp.Write(conn)
|
|
||||||
|
|
||||||
if log.IsLevelEnabled(logger.DebugLevel) {
|
if log.IsLevelEnabled(logger.DebugLevel) {
|
||||||
dump, _ := httputil.DumpResponse(resp, false)
|
dump, _ := httputil.DumpResponse(resp, false)
|
||||||
log.Debug(string(dump))
|
log.Debug(string(dump))
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return resp.Write(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Del("Proxy-Authorization")
|
req.Header.Del("Proxy-Authorization")
|
||||||
@@ -187,13 +174,12 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt
|
|||||||
cc, err := h.router.Dial(ctx, network, addr)
|
cc, err := h.router.Dial(ctx, network, addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.StatusCode = http.StatusServiceUnavailable
|
resp.StatusCode = http.StatusServiceUnavailable
|
||||||
resp.Write(conn)
|
|
||||||
|
|
||||||
if log.IsLevelEnabled(logger.DebugLevel) {
|
if log.IsLevelEnabled(logger.DebugLevel) {
|
||||||
dump, _ := httputil.DumpResponse(resp, false)
|
dump, _ := httputil.DumpResponse(resp, false)
|
||||||
log.Debug(string(dump))
|
log.Debug(string(dump))
|
||||||
}
|
}
|
||||||
return
|
return resp.Write(conn)
|
||||||
}
|
}
|
||||||
defer cc.Close()
|
defer cc.Close()
|
||||||
|
|
||||||
@@ -207,22 +193,24 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt
|
|||||||
}
|
}
|
||||||
if err = resp.Write(conn); err != nil {
|
if err = resp.Write(conn); err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
req.Header.Del("Proxy-Connection")
|
req.Header.Del("Proxy-Connection")
|
||||||
if err = req.Write(cc); err != nil {
|
if err = req.Write(cc); err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
log.Infof("%s <-> %s", conn.RemoteAddr(), addr)
|
log.Infof("%s <-> %s", conn.RemoteAddr(), addr)
|
||||||
handler.Transport(conn, cc)
|
netpkg.Transport(conn, cc)
|
||||||
log.WithFields(map[string]interface{}{
|
log.WithFields(map[string]any{
|
||||||
"duration": time.Since(start),
|
"duration": time.Since(start),
|
||||||
}).Infof("%s >-< %s", conn.RemoteAddr(), addr)
|
}).Infof("%s >-< %s", conn.RemoteAddr(), addr)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpHandler) decodeServerName(s string) (string, error) {
|
func (h *httpHandler) decodeServerName(s string) (string, error) {
|
||||||
@@ -266,7 +254,7 @@ func (h *httpHandler) basicProxyAuth(proxyAuth string, log logger.Logger) (usern
|
|||||||
|
|
||||||
func (h *httpHandler) authenticate(conn net.Conn, req *http.Request, resp *http.Response, log logger.Logger) (ok bool) {
|
func (h *httpHandler) authenticate(conn net.Conn, req *http.Request, resp *http.Response, log logger.Logger) (ok bool) {
|
||||||
u, p, _ := h.basicProxyAuth(req.Header.Get("Proxy-Authorization"), log)
|
u, p, _ := h.basicProxyAuth(req.Header.Get("Proxy-Authorization"), log)
|
||||||
if h.authenticator == nil || h.authenticator.Authenticate(u, p) {
|
if h.options.Auther == nil || h.options.Auther.Authenticate(u, p) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +287,7 @@ func (h *httpHandler) authenticate(conn net.Conn, req *http.Request, resp *http.
|
|||||||
defer cc.Close()
|
defer cc.Close()
|
||||||
|
|
||||||
req.Write(cc)
|
req.Write(cc)
|
||||||
handler.Transport(conn, cc)
|
netpkg.Transport(conn, cc)
|
||||||
return
|
return
|
||||||
case "file":
|
case "file":
|
||||||
f, _ := os.Open(pr.Value)
|
f, _ := os.Open(pr.Value)
|
||||||
|
|||||||
+16
-12
@@ -2,18 +2,19 @@ package http
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-gost/gost/pkg/common/net/relay"
|
||||||
"github.com/go-gost/gost/pkg/common/util/socks"
|
"github.com/go-gost/gost/pkg/common/util/socks"
|
||||||
"github.com/go-gost/gost/pkg/handler"
|
|
||||||
"github.com/go-gost/gost/pkg/logger"
|
"github.com/go-gost/gost/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *httpHandler) handleUDP(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) {
|
func (h *httpHandler) handleUDP(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) error {
|
||||||
log = log.WithFields(map[string]interface{}{
|
log = log.WithFields(map[string]any{
|
||||||
"cmd": "udp",
|
"cmd": "udp",
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -28,15 +29,15 @@ func (h *httpHandler) handleUDP(ctx context.Context, conn net.Conn, network, add
|
|||||||
|
|
||||||
if !h.md.enableUDP {
|
if !h.md.enableUDP {
|
||||||
resp.StatusCode = http.StatusForbidden
|
resp.StatusCode = http.StatusForbidden
|
||||||
resp.Write(conn)
|
|
||||||
|
|
||||||
if log.IsLevelEnabled(logger.DebugLevel) {
|
if log.IsLevelEnabled(logger.DebugLevel) {
|
||||||
dump, _ := httputil.DumpResponse(resp, false)
|
dump, _ := httputil.DumpResponse(resp, false)
|
||||||
log.Debug(string(dump))
|
log.Debug(string(dump))
|
||||||
}
|
}
|
||||||
log.Error("UDP relay is diabled")
|
|
||||||
|
|
||||||
return
|
log.Error("http: UDP relay is disabled")
|
||||||
|
|
||||||
|
return resp.Write(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.StatusCode = http.StatusOK
|
resp.StatusCode = http.StatusOK
|
||||||
@@ -46,31 +47,34 @@ func (h *httpHandler) handleUDP(ctx context.Context, conn net.Conn, network, add
|
|||||||
}
|
}
|
||||||
if err := resp.Write(conn); err != nil {
|
if err := resp.Write(conn); err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// obtain a udp connection
|
// obtain a udp connection
|
||||||
c, err := h.router.Dial(ctx, "udp", "") // UDP association
|
c, err := h.router.Dial(ctx, "udp", "") // UDP association
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
|
|
||||||
pc, ok := c.(net.PacketConn)
|
pc, ok := c.(net.PacketConn)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Errorf("wrong connection type")
|
err = errors.New("wrong connection type")
|
||||||
return
|
log.Error(err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
relay := handler.NewUDPRelay(socks.UDPTunServerConn(conn), pc).
|
relay := relay.NewUDPRelay(socks.UDPTunServerConn(conn), pc).
|
||||||
WithBypass(h.options.Bypass).
|
WithBypass(h.options.Bypass).
|
||||||
WithLogger(log)
|
WithLogger(log)
|
||||||
|
|
||||||
t := time.Now()
|
t := time.Now()
|
||||||
log.Infof("%s <-> %s", conn.RemoteAddr(), pc.LocalAddr())
|
log.Infof("%s <-> %s", conn.RemoteAddr(), pc.LocalAddr())
|
||||||
relay.Run()
|
relay.Run()
|
||||||
log.WithFields(map[string]interface{}{
|
log.WithFields(map[string]any{
|
||||||
"duration": time.Since(t),
|
"duration": time.Since(t),
|
||||||
}).Infof("%s >-< %s", conn.RemoteAddr(), pc.LocalAddr())
|
}).Infof("%s >-< %s", conn.RemoteAddr(), pc.LocalAddr())
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-gost/gost/pkg/auth"
|
|
||||||
"github.com/go-gost/gost/pkg/chain"
|
"github.com/go-gost/gost/pkg/chain"
|
||||||
auth_util "github.com/go-gost/gost/pkg/common/util/auth"
|
netpkg "github.com/go-gost/gost/pkg/common/net"
|
||||||
"github.com/go-gost/gost/pkg/handler"
|
"github.com/go-gost/gost/pkg/handler"
|
||||||
http2_util "github.com/go-gost/gost/pkg/internal/util/http2"
|
http2_util "github.com/go-gost/gost/pkg/internal/util/http2"
|
||||||
"github.com/go-gost/gost/pkg/logger"
|
"github.com/go-gost/gost/pkg/logger"
|
||||||
@@ -29,12 +28,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.RegisterHandler("http2", NewHandler)
|
registry.HandlerRegistry().Register("http2", NewHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
type http2Handler struct {
|
type http2Handler struct {
|
||||||
router *chain.Router
|
router *chain.Router
|
||||||
authenticator auth.Authenticator
|
|
||||||
md metadata
|
md metadata
|
||||||
options handler.Options
|
options handler.Options
|
||||||
}
|
}
|
||||||
@@ -55,44 +53,42 @@ func (h *http2Handler) Init(md md.Metadata) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
h.authenticator = auth_util.AuthFromUsers(h.options.Auths...)
|
h.router = h.options.Router
|
||||||
h.router = &chain.Router{
|
if h.router == nil {
|
||||||
Retries: h.options.Retries,
|
h.router = (&chain.Router{}).WithLogger(h.options.Logger)
|
||||||
Chain: h.options.Chain,
|
|
||||||
Resolver: h.options.Resolver,
|
|
||||||
Hosts: h.options.Hosts,
|
|
||||||
Logger: h.options.Logger,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *http2Handler) Handle(ctx context.Context, conn net.Conn) {
|
func (h *http2Handler) Handle(ctx context.Context, conn net.Conn) error {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
log := h.options.Logger.WithFields(map[string]interface{}{
|
log := h.options.Logger.WithFields(map[string]any{
|
||||||
"remote": conn.RemoteAddr().String(),
|
"remote": conn.RemoteAddr().String(),
|
||||||
"local": conn.LocalAddr().String(),
|
"local": conn.LocalAddr().String(),
|
||||||
})
|
})
|
||||||
log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr())
|
log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr())
|
||||||
defer func() {
|
defer func() {
|
||||||
log.WithFields(map[string]interface{}{
|
log.WithFields(map[string]any{
|
||||||
"duration": time.Since(start),
|
"duration": time.Since(start),
|
||||||
}).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr())
|
}).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
cc, ok := conn.(*http2_util.ServerConn)
|
cc, ok := conn.(*http2_util.ServerConn)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Error("wrong connection type")
|
err := errors.New("wrong connection type")
|
||||||
return
|
log.Error(err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
h.roundTrip(ctx, cc.Writer(), cc.Request(), log)
|
return h.roundTrip(ctx, cc.Writer(), cc.Request(), log)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: there is an issue (golang/go#43989) will cause the client hangs
|
// NOTE: there is an issue (golang/go#43989) will cause the client hangs
|
||||||
// when server returns an non-200 status code,
|
// when server returns an non-200 status code,
|
||||||
// May be fixed in go1.18.
|
// May be fixed in go1.18.
|
||||||
func (h *http2Handler) roundTrip(ctx context.Context, w http.ResponseWriter, req *http.Request, log logger.Logger) {
|
func (h *http2Handler) roundTrip(ctx context.Context, w http.ResponseWriter, req *http.Request, log logger.Logger) error {
|
||||||
// Try to get the actual host.
|
// Try to get the actual host.
|
||||||
// Compatible with GOST 2.x.
|
// Compatible with GOST 2.x.
|
||||||
if v := req.Header.Get("Gost-Target"); v != "" {
|
if v := req.Header.Get("Gost-Target"); v != "" {
|
||||||
@@ -114,7 +110,7 @@ func (h *http2Handler) roundTrip(ctx context.Context, w http.ResponseWriter, req
|
|||||||
addr = net.JoinHostPort(addr, "80")
|
addr = net.JoinHostPort(addr, "80")
|
||||||
}
|
}
|
||||||
|
|
||||||
fields := map[string]interface{}{
|
fields := map[string]any{
|
||||||
"dst": addr,
|
"dst": addr,
|
||||||
}
|
}
|
||||||
if u, _, _ := h.basicProxyAuth(req.Header.Get("Proxy-Authorization")); u != "" {
|
if u, _, _ := h.basicProxyAuth(req.Header.Get("Proxy-Authorization")); u != "" {
|
||||||
@@ -135,7 +131,7 @@ func (h *http2Handler) roundTrip(ctx context.Context, w http.ResponseWriter, req
|
|||||||
if h.options.Bypass != nil && h.options.Bypass.Contains(addr) {
|
if h.options.Bypass != nil && h.options.Bypass.Contains(addr) {
|
||||||
w.WriteHeader(http.StatusForbidden)
|
w.WriteHeader(http.StatusForbidden)
|
||||||
log.Info("bypass: ", addr)
|
log.Info("bypass: ", addr)
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
resp := &http.Response{
|
resp := &http.Response{
|
||||||
@@ -146,7 +142,7 @@ func (h *http2Handler) roundTrip(ctx context.Context, w http.ResponseWriter, req
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !h.authenticate(w, req, resp, log) {
|
if !h.authenticate(w, req, resp, log) {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete the proxy related headers.
|
// delete the proxy related headers.
|
||||||
@@ -157,7 +153,7 @@ func (h *http2Handler) roundTrip(ctx context.Context, w http.ResponseWriter, req
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
w.WriteHeader(http.StatusServiceUnavailable)
|
w.WriteHeader(http.StatusServiceUnavailable)
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
defer cc.Close()
|
defer cc.Close()
|
||||||
|
|
||||||
@@ -174,28 +170,31 @@ func (h *http2Handler) roundTrip(ctx context.Context, w http.ResponseWriter, req
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
log.Infof("%s <-> %s", conn.RemoteAddr(), addr)
|
log.Infof("%s <-> %s", conn.RemoteAddr(), addr)
|
||||||
handler.Transport(conn, cc)
|
netpkg.Transport(conn, cc)
|
||||||
log.WithFields(map[string]interface{}{
|
log.WithFields(map[string]any{
|
||||||
"duration": time.Since(start),
|
"duration": time.Since(start),
|
||||||
}).Infof("%s >-< %s", conn.RemoteAddr(), addr)
|
}).Infof("%s >-< %s", conn.RemoteAddr(), addr)
|
||||||
|
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
log.Infof("%s <-> %s", req.RemoteAddr, addr)
|
log.Infof("%s <-> %s", req.RemoteAddr, addr)
|
||||||
handler.Transport(&readWriter{r: req.Body, w: flushWriter{w}}, cc)
|
netpkg.Transport(&readWriter{r: req.Body, w: flushWriter{w}}, cc)
|
||||||
log.WithFields(map[string]interface{}{
|
log.WithFields(map[string]any{
|
||||||
"duration": time.Since(start),
|
"duration": time.Since(start),
|
||||||
}).Infof("%s >-< %s", req.RemoteAddr, addr)
|
}).Infof("%s >-< %s", req.RemoteAddr, addr)
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: forward request
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *http2Handler) decodeServerName(s string) (string, error) {
|
func (h *http2Handler) decodeServerName(s string) (string, error) {
|
||||||
@@ -239,7 +238,7 @@ func (h *http2Handler) basicProxyAuth(proxyAuth string) (username, password stri
|
|||||||
|
|
||||||
func (h *http2Handler) authenticate(w http.ResponseWriter, r *http.Request, resp *http.Response, log logger.Logger) (ok bool) {
|
func (h *http2Handler) authenticate(w http.ResponseWriter, r *http.Request, resp *http.Response, log logger.Logger) (ok bool) {
|
||||||
u, p, _ := h.basicProxyAuth(r.Header.Get("Proxy-Authorization"))
|
u, p, _ := h.basicProxyAuth(r.Header.Get("Proxy-Authorization"))
|
||||||
if h.authenticator == nil || h.authenticator.Authenticate(u, p) {
|
if h.options.Auther == nil || h.options.Auther.Authenticate(u, p) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user