From 28644802964ed66ea862d95f4026ecc0dee8a727 Mon Sep 17 00:00:00 2001 From: ginuerzh Date: Wed, 16 Mar 2022 20:38:26 +0800 Subject: [PATCH] move pkg to github.com/go-gost/core --- Dockerfile | 2 +- cmd/gost/cmd.go | 10 +- cmd/gost/config.go | 6 +- cmd/gost/main.go | 9 +- cmd/gost/register.go | 36 +-- cmd/gost/tls.go | 2 +- go.mod | 48 ++-- go.sum | 84 +++--- pkg/admission/admission.go | 89 ------- pkg/admission/wrapper/conn.go | 223 ---------------- pkg/admission/wrapper/listener.go | 37 --- pkg/auth/auth.go | 28 -- pkg/bypass/bypass.go | 90 ------- pkg/chain/chain.go | 41 --- pkg/chain/node.go | 97 ------- pkg/chain/resovle.go | 47 ---- pkg/chain/route.go | 192 -------------- pkg/chain/router.go | 169 ------------- pkg/chain/selector.go | 170 ------------- pkg/chain/transport.go | 100 -------- pkg/common/bufpool/pool.go | 113 --------- pkg/common/matcher/matcher.go | 99 -------- pkg/common/net/dialer/dialer.go | 144 ----------- pkg/common/net/dialer/dialer_linux.go | 14 - pkg/common/net/dialer/dialer_other.go | 7 - pkg/common/net/relay/relay.go | 126 --------- pkg/common/net/transport.go | 50 ---- pkg/common/net/udp.go | 41 --- pkg/common/util/resolver/cache.go | 88 ------- pkg/common/util/resolver/resolver.go | 30 --- pkg/common/util/tls/tls.go | 178 ------------- pkg/common/util/udp/conn.go | 102 -------- pkg/common/util/udp/listener.go | 120 --------- pkg/common/util/udp/pool.go | 100 -------- pkg/connector/binder.go | 15 -- pkg/connector/connector.go | 18 -- pkg/connector/forward/connector.go | 45 ---- pkg/connector/http/connector.go | 129 ---------- pkg/connector/http/metadata.go | 32 --- pkg/connector/option.go | 80 ------ pkg/connector/socks/v4/connector.go | 123 --------- pkg/connector/socks/v4/metadata.go | 24 -- pkg/connector/socks/v5/bind.go | 130 ---------- pkg/connector/socks/v5/conn.go | 17 -- pkg/connector/socks/v5/connector.go | 173 ------------- pkg/connector/socks/v5/listener.go | 102 -------- pkg/connector/socks/v5/metadata.go | 24 -- pkg/connector/socks/v5/selector.go | 73 ------ pkg/dialer/dialer.go | 22 -- pkg/dialer/option.go | 66 ----- pkg/dialer/tcp/dialer.go | 48 ---- pkg/dialer/tcp/metadata.go | 23 -- pkg/dialer/tls/dialer.go | 68 ----- pkg/dialer/tls/metadata.go | 21 -- pkg/dialer/udp/conn.go | 17 -- pkg/dialer/udp/dialer.go | 50 ---- pkg/dialer/udp/metadata.go | 23 -- pkg/handler/auto/handler.go | 115 --------- pkg/handler/forward/local/handler.go | 117 --------- pkg/handler/forward/local/metadata.go | 20 -- pkg/handler/forward/remote/handler.go | 111 -------- pkg/handler/forward/remote/metadata.go | 20 -- pkg/handler/handler.go | 18 -- pkg/handler/http/handler.go | 337 ------------------------- pkg/handler/http/metadata.go | 53 ---- pkg/handler/http/udp.go | 80 ------ pkg/handler/option.go | 71 ------ pkg/handler/socks/v4/handler.go | 152 ----------- pkg/handler/socks/v4/metadata.go | 20 -- pkg/handler/socks/v5/bind.go | 149 ----------- pkg/handler/socks/v5/connect.go | 53 ---- pkg/handler/socks/v5/handler.go | 115 --------- pkg/handler/socks/v5/mbind.go | 133 ---------- pkg/handler/socks/v5/metadata.go | 43 ---- pkg/handler/socks/v5/selector.go | 90 ------- pkg/handler/socks/v5/udp.go | 85 ------- pkg/handler/socks/v5/udp_tun.go | 72 ------ pkg/hosts/hosts.go | 132 ---------- pkg/internal/util/mux/mux.go | 85 ------- pkg/internal/util/socks/conn.go | 172 ------------- pkg/internal/util/socks/socks.go | 18 -- pkg/internal/util/tcp.go | 32 --- pkg/listener/listener.go | 44 ---- pkg/listener/option.go | 72 ------ pkg/listener/rtcp/listener.go | 102 -------- pkg/listener/rtcp/metadata.go | 19 -- pkg/listener/rudp/listener.go | 109 -------- pkg/listener/rudp/metadata.go | 54 ---- pkg/listener/tcp/listener.go | 60 ----- pkg/listener/tcp/metadata.go | 12 - pkg/listener/tls/listener.go | 64 ----- pkg/listener/tls/metadata.go | 12 - pkg/listener/udp/listener.go | 73 ------ pkg/listener/udp/metadata.go | 52 ---- pkg/logger/gost_logger.go | 155 ------------ pkg/logger/logger.go | 71 ------ pkg/logger/nop_logger.go | 53 ---- pkg/metadata/metadata.go | 156 ------------ pkg/registry/admission.go | 40 --- pkg/registry/auther.go | 40 --- pkg/registry/bypass.go | 40 --- pkg/registry/chain.go | 40 --- pkg/registry/connector.go | 26 -- pkg/registry/dialer.go | 26 -- pkg/registry/handler.go | 26 -- pkg/registry/hosts.go | 42 --- pkg/registry/listener.go | 26 -- pkg/registry/registry.go | 116 --------- pkg/registry/resolver.go | 43 ---- pkg/registry/service.go | 20 -- pkg/resolver/exchanger/exchanger.go | 220 ---------------- pkg/resolver/impl/resolver.go | 178 ------------- pkg/resolver/resolver.go | 17 -- pkg/service/service.go | 120 --------- 114 files changed, 106 insertions(+), 8330 deletions(-) delete mode 100644 pkg/admission/admission.go delete mode 100644 pkg/admission/wrapper/conn.go delete mode 100644 pkg/admission/wrapper/listener.go delete mode 100644 pkg/auth/auth.go delete mode 100644 pkg/bypass/bypass.go delete mode 100644 pkg/chain/chain.go delete mode 100644 pkg/chain/node.go delete mode 100644 pkg/chain/resovle.go delete mode 100644 pkg/chain/route.go delete mode 100644 pkg/chain/router.go delete mode 100644 pkg/chain/selector.go delete mode 100644 pkg/chain/transport.go delete mode 100644 pkg/common/bufpool/pool.go delete mode 100644 pkg/common/matcher/matcher.go delete mode 100644 pkg/common/net/dialer/dialer.go delete mode 100644 pkg/common/net/dialer/dialer_linux.go delete mode 100644 pkg/common/net/dialer/dialer_other.go delete mode 100644 pkg/common/net/relay/relay.go delete mode 100644 pkg/common/net/transport.go delete mode 100644 pkg/common/net/udp.go delete mode 100644 pkg/common/util/resolver/cache.go delete mode 100644 pkg/common/util/resolver/resolver.go delete mode 100644 pkg/common/util/tls/tls.go delete mode 100644 pkg/common/util/udp/conn.go delete mode 100644 pkg/common/util/udp/listener.go delete mode 100644 pkg/common/util/udp/pool.go delete mode 100644 pkg/connector/binder.go delete mode 100644 pkg/connector/connector.go delete mode 100644 pkg/connector/forward/connector.go delete mode 100644 pkg/connector/http/connector.go delete mode 100644 pkg/connector/http/metadata.go delete mode 100644 pkg/connector/option.go delete mode 100644 pkg/connector/socks/v4/connector.go delete mode 100644 pkg/connector/socks/v4/metadata.go delete mode 100644 pkg/connector/socks/v5/bind.go delete mode 100644 pkg/connector/socks/v5/conn.go delete mode 100644 pkg/connector/socks/v5/connector.go delete mode 100644 pkg/connector/socks/v5/listener.go delete mode 100644 pkg/connector/socks/v5/metadata.go delete mode 100644 pkg/connector/socks/v5/selector.go delete mode 100644 pkg/dialer/dialer.go delete mode 100644 pkg/dialer/option.go delete mode 100644 pkg/dialer/tcp/dialer.go delete mode 100644 pkg/dialer/tcp/metadata.go delete mode 100644 pkg/dialer/tls/dialer.go delete mode 100644 pkg/dialer/tls/metadata.go delete mode 100644 pkg/dialer/udp/conn.go delete mode 100644 pkg/dialer/udp/dialer.go delete mode 100644 pkg/dialer/udp/metadata.go delete mode 100644 pkg/handler/auto/handler.go delete mode 100644 pkg/handler/forward/local/handler.go delete mode 100644 pkg/handler/forward/local/metadata.go delete mode 100644 pkg/handler/forward/remote/handler.go delete mode 100644 pkg/handler/forward/remote/metadata.go delete mode 100644 pkg/handler/handler.go delete mode 100644 pkg/handler/http/handler.go delete mode 100644 pkg/handler/http/metadata.go delete mode 100644 pkg/handler/http/udp.go delete mode 100644 pkg/handler/option.go delete mode 100644 pkg/handler/socks/v4/handler.go delete mode 100644 pkg/handler/socks/v4/metadata.go delete mode 100644 pkg/handler/socks/v5/bind.go delete mode 100644 pkg/handler/socks/v5/connect.go delete mode 100644 pkg/handler/socks/v5/handler.go delete mode 100644 pkg/handler/socks/v5/mbind.go delete mode 100644 pkg/handler/socks/v5/metadata.go delete mode 100644 pkg/handler/socks/v5/selector.go delete mode 100644 pkg/handler/socks/v5/udp.go delete mode 100644 pkg/handler/socks/v5/udp_tun.go delete mode 100644 pkg/hosts/hosts.go delete mode 100644 pkg/internal/util/mux/mux.go delete mode 100644 pkg/internal/util/socks/conn.go delete mode 100644 pkg/internal/util/socks/socks.go delete mode 100644 pkg/internal/util/tcp.go delete mode 100644 pkg/listener/listener.go delete mode 100644 pkg/listener/option.go delete mode 100644 pkg/listener/rtcp/listener.go delete mode 100644 pkg/listener/rtcp/metadata.go delete mode 100644 pkg/listener/rudp/listener.go delete mode 100644 pkg/listener/rudp/metadata.go delete mode 100644 pkg/listener/tcp/listener.go delete mode 100644 pkg/listener/tcp/metadata.go delete mode 100644 pkg/listener/tls/listener.go delete mode 100644 pkg/listener/tls/metadata.go delete mode 100644 pkg/listener/udp/listener.go delete mode 100644 pkg/listener/udp/metadata.go delete mode 100644 pkg/logger/gost_logger.go delete mode 100644 pkg/logger/logger.go delete mode 100644 pkg/logger/nop_logger.go delete mode 100644 pkg/metadata/metadata.go delete mode 100644 pkg/registry/admission.go delete mode 100644 pkg/registry/auther.go delete mode 100644 pkg/registry/bypass.go delete mode 100644 pkg/registry/chain.go delete mode 100644 pkg/registry/connector.go delete mode 100644 pkg/registry/dialer.go delete mode 100644 pkg/registry/handler.go delete mode 100644 pkg/registry/hosts.go delete mode 100644 pkg/registry/listener.go delete mode 100644 pkg/registry/registry.go delete mode 100644 pkg/registry/resolver.go delete mode 100644 pkg/registry/service.go delete mode 100644 pkg/resolver/exchanger/exchanger.go delete mode 100644 pkg/resolver/impl/resolver.go delete mode 100644 pkg/resolver/resolver.go delete mode 100644 pkg/service/service.go diff --git a/Dockerfile b/Dockerfile index 30cf2fd..3bca520 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=$BUILDPLATFORM golang:1.18rc1-alpine as builder +FROM --platform=$BUILDPLATFORM golang:1.18-alpine as builder # Convert TARGETPLATFORM to GOARCH format # https://github.com/tonistiigi/xx diff --git a/cmd/gost/cmd.go b/cmd/gost/cmd.go index 255d5ce..1d11429 100644 --- a/cmd/gost/cmd.go +++ b/cmd/gost/cmd.go @@ -10,8 +10,8 @@ import ( "time" "github.com/go-gost/config" - "github.com/go-gost/gost/v3/pkg/metadata" - "github.com/go-gost/gost/v3/pkg/registry" + "github.com/go-gost/core/metadata" + "github.com/go-gost/core/registry" ) var ( @@ -34,14 +34,12 @@ func buildConfigFromCmd(services, nodes stringList) (*config.Config, error) { if v := os.Getenv("GOST_PROFILING"); v != "" { cfg.Profiling = &config.ProfilingConfig{ - Enable: true, - Addr: v, + Addr: v, } } if v := os.Getenv("GOST_METRICS"); v != "" { cfg.Metrics = &config.MetricsConfig{ - Enable: true, - Addr: v, + Addr: v, } } diff --git a/cmd/gost/config.go b/cmd/gost/config.go index bc8da44..607e84f 100644 --- a/cmd/gost/config.go +++ b/cmd/gost/config.go @@ -7,9 +7,9 @@ import ( "github.com/go-gost/api" "github.com/go-gost/config" "github.com/go-gost/config/parsing" - "github.com/go-gost/gost/v3/pkg/logger" - "github.com/go-gost/gost/v3/pkg/registry" - "github.com/go-gost/gost/v3/pkg/service" + "github.com/go-gost/core/logger" + "github.com/go-gost/core/registry" + "github.com/go-gost/core/service" metrics "github.com/go-gost/metrics/service" ) diff --git a/cmd/gost/main.go b/cmd/gost/main.go index 6f34d6d..4615964 100644 --- a/cmd/gost/main.go +++ b/cmd/gost/main.go @@ -9,7 +9,7 @@ import ( "runtime" "github.com/go-gost/config" - "github.com/go-gost/gost/v3/pkg/logger" + "github.com/go-gost/core/logger" "github.com/go-gost/metrics" ) @@ -63,8 +63,7 @@ func main() { } if metricsAddr != "" { cfg.Metrics = &config.MetricsConfig{ - Enable: true, - Addr: metricsAddr, + Addr: metricsAddr, } } } else { @@ -89,7 +88,7 @@ func main() { os.Exit(0) } - if cfg.Profiling != nil && cfg.Profiling.Enable { + if cfg.Profiling != nil { go func() { addr := cfg.Profiling.Addr if addr == "" { @@ -113,7 +112,7 @@ func main() { }() } - if cfg.Metrics != nil && cfg.Metrics.Enable { + if cfg.Metrics != nil { metrics.SetGlobal(metrics.NewMetrics()) if cfg.Metrics.Addr != "" { s, err := buildMetricsService(cfg.Metrics) diff --git a/cmd/gost/register.go b/cmd/gost/register.go index 6dbf419..6d57fc4 100644 --- a/cmd/gost/register.go +++ b/cmd/gost/register.go @@ -2,27 +2,27 @@ package main import ( // core components - _ "github.com/go-gost/gost/v3/pkg/connector/forward" - _ "github.com/go-gost/gost/v3/pkg/connector/http" - _ "github.com/go-gost/gost/v3/pkg/connector/socks/v4" - _ "github.com/go-gost/gost/v3/pkg/connector/socks/v5" + _ "github.com/go-gost/core/connector/forward" + _ "github.com/go-gost/core/connector/http" + _ "github.com/go-gost/core/connector/socks/v4" + _ "github.com/go-gost/core/connector/socks/v5" - _ "github.com/go-gost/gost/v3/pkg/dialer/tcp" - _ "github.com/go-gost/gost/v3/pkg/dialer/tls" - _ "github.com/go-gost/gost/v3/pkg/dialer/udp" + _ "github.com/go-gost/core/dialer/tcp" + _ "github.com/go-gost/core/dialer/tls" + _ "github.com/go-gost/core/dialer/udp" - _ "github.com/go-gost/gost/v3/pkg/handler/auto" - _ "github.com/go-gost/gost/v3/pkg/handler/forward/local" - _ "github.com/go-gost/gost/v3/pkg/handler/forward/remote" - _ "github.com/go-gost/gost/v3/pkg/handler/http" - _ "github.com/go-gost/gost/v3/pkg/handler/socks/v4" - _ "github.com/go-gost/gost/v3/pkg/handler/socks/v5" + _ "github.com/go-gost/core/handler/auto" + _ "github.com/go-gost/core/handler/forward/local" + _ "github.com/go-gost/core/handler/forward/remote" + _ "github.com/go-gost/core/handler/http" + _ "github.com/go-gost/core/handler/socks/v4" + _ "github.com/go-gost/core/handler/socks/v5" - _ "github.com/go-gost/gost/v3/pkg/listener/rtcp" - _ "github.com/go-gost/gost/v3/pkg/listener/rudp" - _ "github.com/go-gost/gost/v3/pkg/listener/tcp" - _ "github.com/go-gost/gost/v3/pkg/listener/tls" - _ "github.com/go-gost/gost/v3/pkg/listener/udp" + _ "github.com/go-gost/core/listener/rtcp" + _ "github.com/go-gost/core/listener/rudp" + _ "github.com/go-gost/core/listener/tcp" + _ "github.com/go-gost/core/listener/tls" + _ "github.com/go-gost/core/listener/udp" // extended components _ "github.com/go-gost/x/connector/http2" diff --git a/cmd/gost/tls.go b/cmd/gost/tls.go index be35d57..3fe7dff 100644 --- a/cmd/gost/tls.go +++ b/cmd/gost/tls.go @@ -11,7 +11,7 @@ import ( "time" "github.com/go-gost/config" - tls_util "github.com/go-gost/gost/v3/pkg/common/util/tls" + tls_util "github.com/go-gost/core/common/util/tls" ) func buildDefaultTLSConfig(cfg *config.TLSConfig) { diff --git a/go.mod b/go.mod index 7150908..e13274e 100644 --- a/go.mod +++ b/go.mod @@ -4,24 +4,20 @@ go 1.18 replace github.com/templexxx/cpu v0.0.7 => github.com/templexxx/cpu v0.0.10-0.20211111114238-98168dcec14a +replace github.com/go-gost/metrics => /home/gerry/code/go-gost/metrics + require ( - github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d - github.com/go-gost/api v0.0.0-20220314132010-fb9f62042a6a - github.com/go-gost/config v0.0.0-20220314131548-69ef8eeb9733 - github.com/go-gost/gosocks4 v0.0.1 - github.com/go-gost/gosocks5 v0.3.1-0.20211109033403-d894d75b7f09 - github.com/go-gost/metrics v0.0.0-20220314135054-2263ae431a5f - github.com/go-gost/x v0.0.0-20220315075737-506142fd0b72 - github.com/gobwas/glob v0.2.3 - github.com/miekg/dns v1.1.45 - github.com/sirupsen/logrus v1.8.1 - github.com/xtaci/smux v1.5.16 - golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 + github.com/go-gost/api v0.0.0-20220316115521-ab4ad0f12488 + github.com/go-gost/config v0.0.0-20220316114445-04016a392b1e + github.com/go-gost/core v0.0.0-20220316114029-7db81fcfeb66 + github.com/go-gost/metrics v0.0.0-20220316114656-e95ab1c62ea8 + github.com/go-gost/x v0.0.0-20220316120634-36947bcbd9f3 ) require ( github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed // indirect github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect + github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // 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 @@ -31,13 +27,15 @@ require ( github.com/gin-contrib/cors v1.3.1 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.7.7 // indirect - github.com/go-gost/gost v0.0.0-20220312160816-bfc1f8472cc2 // indirect + github.com/go-gost/gosocks4 v0.0.1 // indirect + github.com/go-gost/gosocks5 v0.3.1-0.20211109033403-d894d75b7f09 // indirect github.com/go-gost/relay v0.1.1-0.20211123134818-8ef7fd81ffd7 // indirect github.com/go-gost/tls-dissector v0.0.2-0.20211125135007-2b5d5bd9c07e // 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-playground/locales v0.14.0 // indirect + github.com/go-playground/universal-translator v0.18.0 // indirect + github.com/go-playground/validator/v10 v10.10.1 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect + github.com/gobwas/glob v0.2.3 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/gopacket v1.1.19 // indirect @@ -46,7 +44,7 @@ require ( 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/leodido/go-urn v1.2.1 // indirect github.com/lucas-clemente/quic-go v0.25.0 // indirect github.com/magiconair/properties v1.8.6 // indirect github.com/marten-seemann/qpack v0.2.1 // indirect @@ -55,6 +53,7 @@ require ( github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/miekg/dns v1.1.47 // indirect github.com/milosgajdos/tenus v0.0.3 // indirect github.com/mitchellh/mapstructure v1.4.3 // indirect github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104 // indirect @@ -72,24 +71,27 @@ require ( github.com/rs/xid v1.3.0 // indirect github.com/shadowsocks/go-shadowsocks2 v0.1.5 // indirect github.com/shadowsocks/shadowsocks-go v0.0.0-20200409064450-3e585ff90601 // indirect + github.com/sirupsen/logrus v1.8.1 // indirect github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 // indirect github.com/spf13/afero v1.8.2 // 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.10.0 // indirect + github.com/spf13/viper v1.10.1 // 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 + github.com/ugorji/go/codec v1.2.7 // indirect github.com/xtaci/kcp-go/v5 v5.6.1 // indirect + github.com/xtaci/smux v1.5.16 // indirect github.com/xtaci/tcpraw v1.2.25 // indirect - golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 // indirect - golang.org/x/mod v0.5.1 // indirect - golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect + golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect + golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect + golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect + golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 // indirect golang.org/x/text v0.3.7 // indirect - golang.org/x/tools v0.1.9 // indirect + golang.org/x/tools v0.1.10 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350 // indirect google.golang.org/grpc v1.45.0 // indirect diff --git a/go.sum b/go.sum index 7bff9b0..3436d3b 100644 --- a/go.sum +++ b/go.sum @@ -66,6 +66,7 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r 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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= 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.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= @@ -87,6 +88,7 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH github.com/coreos/go-iptables v0.5.0 h1:mw6SAibtHKZcNzAsOxjoHIG0gy5YFHhypWSSNc6EjbQ= github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -120,26 +122,22 @@ github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gost/api v0.0.0-20220314132010-fb9f62042a6a h1:omtLcSi8zs+Bi5eFZt16S364qnzADN0XaRlXysbjuek= -github.com/go-gost/api v0.0.0-20220314132010-fb9f62042a6a/go.mod h1:KSqpPSLY4nzNKU1iitZsGghXECh+afmexaCOUWewgT4= -github.com/go-gost/config v0.0.0-20220314131548-69ef8eeb9733 h1:TrBS1GYkM0WZBEMBlzHzB5lwp/VEosB4JwyhAApVnYY= -github.com/go-gost/config v0.0.0-20220314131548-69ef8eeb9733/go.mod h1:bz3HBlZwBiyiRmHcEgrxls6c824tubyw7FcSVgs75z8= +github.com/go-gost/api v0.0.0-20220316115521-ab4ad0f12488 h1:c1hthEceq5yiXwZEdX73e4dj4BRxNxFQfSXXDR1wL2Y= +github.com/go-gost/api v0.0.0-20220316115521-ab4ad0f12488/go.mod h1:TfLdWhO3b86fPiVOOtorOqhhZVSYwNS8C0BmarYaHtg= +github.com/go-gost/config v0.0.0-20220316114445-04016a392b1e h1:0tQmXLljIgBxA1ghQ80HoF6RGlzLdkOirHjAgvGU4NA= +github.com/go-gost/config v0.0.0-20220316114445-04016a392b1e/go.mod h1:TcXyaEcav8QK85dnpt+2piewCGLsUQ3W0D8SFTcRdAA= +github.com/go-gost/core v0.0.0-20220316114029-7db81fcfeb66 h1:c2xJRqXxys5FSi66dK5xSxuz8IeoYy2N+uOPse4OooE= +github.com/go-gost/core v0.0.0-20220316114029-7db81fcfeb66/go.mod h1:WyaY3XWXX0SHgao6DP8/YnSnzyMTJEWdyzegDWNSQFY= github.com/go-gost/gosocks4 v0.0.1 h1:+k1sec8HlELuQV7rWftIkmy8UijzUt2I6t+iMPlGB2s= github.com/go-gost/gosocks4 v0.0.1/go.mod h1:3B6L47HbU/qugDg4JnoFPHgJXE43Inz8Bah1QaN9qCc= github.com/go-gost/gosocks5 v0.3.1-0.20211109033403-d894d75b7f09 h1:A95M6UWcfZgOuJkQ7QLfG0Hs5peWIUSysCDNz4pfe04= github.com/go-gost/gosocks5 v0.3.1-0.20211109033403-d894d75b7f09/go.mod h1:1G6I7HP7VFVxveGkoK8mnprnJqSqJjdcASKsdUn4Pp4= -github.com/go-gost/gost v0.0.0-20220312160816-bfc1f8472cc2 h1:yTxlvQ99SsSylNHv7A7v739k0gKbW9sqquXPlJX/EGE= -github.com/go-gost/gost v0.0.0-20220312160816-bfc1f8472cc2/go.mod h1:d7OMWKlZWgWarOEqYEsicSOjplSPMpoOpC8wCqMkBjI= -github.com/go-gost/metrics v0.0.0-20220314135054-2263ae431a5f h1:gNquUvOvPXUpq4Xk7ed7motbVN5t0HMqImf96k+pzlU= -github.com/go-gost/metrics v0.0.0-20220314135054-2263ae431a5f/go.mod h1:Ac2Pigx5GMJEznkP9wLdBJ36+rYwWiJPqWk7lrg3FKg= github.com/go-gost/relay v0.1.1-0.20211123134818-8ef7fd81ffd7 h1:itaaJhQJ19kUXEB4Igb0EbY8m+1Py2AaNNSBds/9gk4= 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/go.mod h1:/9QfdewqmHdaE362Hv5nDaSWLx3pCmtD870d6GaquXs= -github.com/go-gost/x v0.0.0-20220315074522-073ad80ce42d h1:WBw+yVkD5GTu30Cz5l4spRJxQJajo+DRzCQWPaI6h08= -github.com/go-gost/x v0.0.0-20220315074522-073ad80ce42d/go.mod h1:9yCS6ulkZHRgYe5yjih0Tn0wo+2kXy4tjABfQFTOius= -github.com/go-gost/x v0.0.0-20220315075737-506142fd0b72 h1:2gj6BwCUpn+5FJsV+xxGUY60HXCQO6eVU6leEcY1rts= -github.com/go-gost/x v0.0.0-20220315075737-506142fd0b72/go.mod h1:9yCS6ulkZHRgYe5yjih0Tn0wo+2kXy4tjABfQFTOius= +github.com/go-gost/x v0.0.0-20220316120634-36947bcbd9f3 h1:rweJPJBr3k6wqzUgLbEMeoJq/AUa5koaUaqjp+rvk6I= +github.com/go-gost/x v0.0.0-20220316120634-36947bcbd9f3/go.mod h1:CEpilNHCLNGQO2sGEJMxTqPJIj1zJ7q3BuzSQU4CyG8= 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= @@ -149,13 +147,16 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG 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/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= 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/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-playground/validator/v10 v10.10.1 h1:uA0+amWMiglNZKZ9FJRKUAe9U3RX91eVn1JYXMWt7ig= +github.com/go-playground/validator/v10 v10.10.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= 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/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= @@ -269,15 +270,19 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv 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/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 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/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.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= -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/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= 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= @@ -300,8 +305,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k 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/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= -github.com/miekg/dns v1.1.45 h1:g5fRIhm9nx7g8osrAvgb16QJfmyMsyOCb+J7LSv+Qzk= -github.com/miekg/dns v1.1.45/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/miekg/dns v1.1.47 h1:J9bWiXbqMbnZPcY8Qi2E3EWIBsIm6MZzzJB9VRg5gL8= +github.com/miekg/dns v1.1.47/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/milosgajdos/tenus v0.0.3 h1:jmaJzwaY1DUyYVD0lM4U+uvP2kkEg1VahDqRFxIkVBE= github.com/milosgajdos/tenus v0.0.3/go.mod h1:eIjx29vNeDOYWJuCnaHY2r4fq5egetV26ry3on7p8qY= github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= @@ -336,6 +341,7 @@ github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je4 github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= 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/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 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.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -372,6 +378,9 @@ github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr 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/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -420,8 +429,8 @@ github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmq github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.10.0 h1:mXH0UwHS4D2HwWZa75im4xIQynLfblmWV7qcWpfv0yk= -github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= +github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= +github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= 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= @@ -442,8 +451,10 @@ github.com/templexxx/xorsimd v0.4.1/go.mod h1:W+ffZz8jJMH2SXwuKu9WhygqBMbFnp14G2 github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM= 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 v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= 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/xtaci/kcp-go/v5 v5.6.1 h1:Pwn0aoeNSPF9dTS7IgiPXn0HEtaIlVb6y5UKWPsx8bI= @@ -484,8 +495,9 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 h1:syTAU9FwmvzEoIYMqcPHOcVm4H3U5u90WsvuYgwpETU= -golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/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-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -521,8 +533,8 @@ 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.1/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/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= 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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -565,8 +577,9 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= 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-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-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/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-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -650,9 +663,10 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/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-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-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng= -golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 h1:A9i04dxx7Cribqbs8jf3FQLogkL/CV2YN7hj9KWJCkc= +golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/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-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= @@ -724,8 +738,8 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/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/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= 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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -846,8 +860,9 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ 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 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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= @@ -868,6 +883,7 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/admission/admission.go b/pkg/admission/admission.go deleted file mode 100644 index 2934645..0000000 --- a/pkg/admission/admission.go +++ /dev/null @@ -1,89 +0,0 @@ -package admission - -import ( - "net" - "strconv" - - "github.com/go-gost/gost/v3/pkg/common/matcher" - "github.com/go-gost/gost/v3/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 { - p.options.logger.Debugf("admission: %v is denied", addr) - 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 - if !b { - p.options.logger.Debugf("admission: %v is denied", addr) - } - return b -} diff --git a/pkg/admission/wrapper/conn.go b/pkg/admission/wrapper/conn.go deleted file mode 100644 index 673ee3e..0000000 --- a/pkg/admission/wrapper/conn.go +++ /dev/null @@ -1,223 +0,0 @@ -package wrapper - -import ( - "errors" - "io" - "net" - "syscall" - - "github.com/go-gost/gost/v3/pkg/admission" -) - -var ( - errUnsupport = errors.New("unsupported operation") -) - -type packetConn struct { - net.PacketConn - admission admission.Admission -} - -func WrapPacketConn(admission admission.Admission, pc net.PacketConn) net.PacketConn { - if admission == nil { - return pc - } - return &packetConn{ - PacketConn: pc, - admission: admission, - } -} - -func (c *packetConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { - for { - n, addr, err = c.PacketConn.ReadFrom(p) - if err != nil { - return - } - - if c.admission != nil && - !c.admission.Admit(addr.String()) { - continue - } - - return - } -} - -type udpConn struct { - net.PacketConn - admission admission.Admission -} - -func WrapUDPConn(admission admission.Admission, pc net.PacketConn) UDPConn { - return &udpConn{ - PacketConn: pc, - admission: admission, - } -} - -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) - return - } - err = errUnsupport - return -} - -func (c *udpConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { - for { - n, addr, err = c.PacketConn.ReadFrom(p) - if err != nil { - return - } - if c.admission != nil && - !c.admission.Admit(addr.String()) { - continue - } - return - } -} - -func (c *udpConn) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) { - if nc, ok := c.PacketConn.(readUDP); ok { - for { - n, addr, err = nc.ReadFromUDP(b) - if err != nil { - return - } - if c.admission != nil && - !c.admission.Admit(addr.String()) { - continue - } - 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 { - for { - n, oobn, flags, addr, err = nc.ReadMsgUDP(b, oob) - if err != nil { - return - } - if c.admission != nil && - !c.admission.Admit(addr.String()) { - continue - } - 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) - return - } - err = errUnsupport - return -} - -func (c *udpConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { - n, err = c.PacketConn.WriteTo(p, addr) - 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) - 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) - 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 -} diff --git a/pkg/admission/wrapper/listener.go b/pkg/admission/wrapper/listener.go deleted file mode 100644 index eb411bb..0000000 --- a/pkg/admission/wrapper/listener.go +++ /dev/null @@ -1,37 +0,0 @@ -package wrapper - -import ( - "net" - - "github.com/go-gost/gost/v3/pkg/admission" -) - -type listener struct { - net.Listener - admission admission.Admission -} - -func WrapListener(admission admission.Admission, ln net.Listener) net.Listener { - if admission == nil { - return ln - } - return &listener{ - Listener: ln, - admission: admission, - } -} - -func (ln *listener) Accept() (net.Conn, error) { - for { - c, err := ln.Listener.Accept() - if err != nil { - return nil, err - } - if ln.admission != nil && - !ln.admission.Admit(c.RemoteAddr().String()) { - c.Close() - continue - } - return c, err - } -} diff --git a/pkg/auth/auth.go b/pkg/auth/auth.go deleted file mode 100644 index 6bdf54d..0000000 --- a/pkg/auth/auth.go +++ /dev/null @@ -1,28 +0,0 @@ -package auth - -// Authenticator is an interface for user authentication. -type Authenticator interface { - Authenticate(user, password string) bool -} - -// authenticator is an Authenticator that authenticates client by key-value pairs. -type authenticator struct { - kvs map[string]string -} - -// NewAuthenticator creates an Authenticator that authenticates client by pre-defined user mapping. -func NewAuthenticator(kvs map[string]string) Authenticator { - return &authenticator{ - kvs: kvs, - } -} - -// Authenticate checks the validity of the provided user-password pair. -func (au *authenticator) Authenticate(user, password string) bool { - if au == nil || len(au.kvs) == 0 { - return true - } - - v, ok := au.kvs[user] - return ok && (v == "" || password == v) -} diff --git a/pkg/bypass/bypass.go b/pkg/bypass/bypass.go deleted file mode 100644 index d183eaa..0000000 --- a/pkg/bypass/bypass.go +++ /dev/null @@ -1,90 +0,0 @@ -package bypass - -import ( - "net" - "strconv" - - "github.com/go-gost/gost/v3/pkg/common/matcher" - "github.com/go-gost/gost/v3/pkg/logger" -) - -// Bypass is a filter of address (IP or domain). -type Bypass interface { - // Contains reports whether the bypass includes addr. - Contains(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 bypass struct { - matchers []matcher.Matcher - reversed bool - options options -} - -// NewBypass creates and initializes a new Bypass using matchers as its match rules. -// The rules will be reversed if the reversed is true. -func NewBypass(reversed bool, matchers []matcher.Matcher, opts ...Option) Bypass { - options := options{} - for _, opt := range opts { - opt(&options) - } - return &bypass{ - matchers: matchers, - reversed: reversed, - options: options, - } -} - -// NewBypassPatterns creates and initializes a new Bypass using matcher patterns as its match rules. -// The rules will be reversed if the reverse is true. -func NewBypassPatterns(reversed bool, patterns []string, opts ...Option) Bypass { - var matchers []matcher.Matcher - for _, pattern := range patterns { - if m := matcher.NewMatcher(pattern); m != nil { - matchers = append(matchers, m) - } - } - return NewBypass(reversed, matchers, opts...) -} - -func (bp *bypass) Contains(addr string) bool { - if addr == "" || bp == nil || len(bp.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 bp.matchers { - if matcher == nil { - continue - } - if matcher.Match(addr) { - matched = true - break - } - } - - b := !bp.reversed && matched || - bp.reversed && !matched - if b { - bp.options.logger.Debugf("bypass: %s", addr) - } - return b -} diff --git a/pkg/chain/chain.go b/pkg/chain/chain.go deleted file mode 100644 index 90c3ba6..0000000 --- a/pkg/chain/chain.go +++ /dev/null @@ -1,41 +0,0 @@ -package chain - -type Chainer interface { - Route(network, address string) *Route -} - -type Chain struct { - groups []*NodeGroup -} - -func (c *Chain) AddNodeGroup(group *NodeGroup) { - c.groups = append(c.groups, group) -} - -func (c *Chain) Route(network, address string) (r *Route) { - if c == nil || len(c.groups) == 0 { - return - } - - r = &Route{} - for _, group := range c.groups { - node := group.Next() - if node == nil { - return - } - if node.Bypass != nil && node.Bypass.Contains(address) { - break - } - - if node.Transport.Multiplex() { - tr := node.Transport.Copy(). - WithRoute(r) - node = node.Copy() - node.Transport = tr - r = &Route{} - } - - r.addNode(node) - } - return r -} diff --git a/pkg/chain/node.go b/pkg/chain/node.go deleted file mode 100644 index 38e00ff..0000000 --- a/pkg/chain/node.go +++ /dev/null @@ -1,97 +0,0 @@ -package chain - -import ( - "sync/atomic" - "time" - - "github.com/go-gost/gost/v3/pkg/bypass" - "github.com/go-gost/gost/v3/pkg/hosts" - "github.com/go-gost/gost/v3/pkg/resolver" -) - -type Node struct { - Name string - Addr string - Transport *Transport - Bypass bypass.Bypass - Resolver resolver.Resolver - Hosts hosts.HostMapper - Marker *FailMarker -} - -func (node *Node) Copy() *Node { - n := &Node{} - *n = *node - return n -} - -type NodeGroup struct { - nodes []*Node - selector Selector -} - -func NewNodeGroup(nodes ...*Node) *NodeGroup { - return &NodeGroup{ - nodes: nodes, - } -} - -func (g *NodeGroup) AddNode(node *Node) { - g.nodes = append(g.nodes, node) -} - -func (g *NodeGroup) WithSelector(selector Selector) *NodeGroup { - g.selector = selector - return g -} - -func (g *NodeGroup) Next() *Node { - if g == nil || len(g.nodes) == 0 { - return nil - } - - s := g.selector - if s == nil { - s = DefaultSelector - } - - return s.Select(g.nodes...) -} - -type FailMarker struct { - failTime int64 - failCount int64 -} - -func (m *FailMarker) FailTime() int64 { - if m == nil { - return 0 - } - - return atomic.LoadInt64(&m.failTime) -} - -func (m *FailMarker) FailCount() int64 { - if m == nil { - return 0 - } - - return atomic.LoadInt64(&m.failCount) -} - -func (m *FailMarker) Mark() { - if m == nil { - return - } - - atomic.AddInt64(&m.failCount, 1) - atomic.StoreInt64(&m.failTime, time.Now().Unix()) -} - -func (m *FailMarker) Reset() { - if m == nil { - return - } - - atomic.StoreInt64(&m.failCount, 0) -} diff --git a/pkg/chain/resovle.go b/pkg/chain/resovle.go deleted file mode 100644 index 542457e..0000000 --- a/pkg/chain/resovle.go +++ /dev/null @@ -1,47 +0,0 @@ -package chain - -import ( - "context" - "fmt" - "net" - - "github.com/go-gost/gost/v3/pkg/hosts" - "github.com/go-gost/gost/v3/pkg/logger" - "github.com/go-gost/gost/v3/pkg/resolver" -) - -func resolve(ctx context.Context, network, addr string, r resolver.Resolver, hosts hosts.HostMapper, log logger.Logger) (string, error) { - if addr == "" { - return addr, nil - } - - host, port, err := net.SplitHostPort(addr) - if err != nil { - return "", err - } - if host == "" { - return addr, nil - } - - if hosts != nil { - if ips, _ := hosts.Lookup(network, host); len(ips) > 0 { - log.Debugf("hit host mapper: %s -> %s", host, ips) - return net.JoinHostPort(ips[0].String(), port), nil - } - } - - if r != nil { - ips, err := r.Resolve(ctx, network, host) - if err != nil { - if err == resolver.ErrInvalid { - return addr, nil - } - log.Error(err) - } - if len(ips) == 0 { - return "", fmt.Errorf("resolver: domain %s does not exists", host) - } - return net.JoinHostPort(ips[0].String(), port), nil - } - return addr, nil -} diff --git a/pkg/chain/route.go b/pkg/chain/route.go deleted file mode 100644 index 033d4e9..0000000 --- a/pkg/chain/route.go +++ /dev/null @@ -1,192 +0,0 @@ -package chain - -import ( - "context" - "errors" - "fmt" - "net" - "time" - - "github.com/go-gost/gost/v3/pkg/common/net/dialer" - "github.com/go-gost/gost/v3/pkg/common/util/udp" - "github.com/go-gost/gost/v3/pkg/connector" - "github.com/go-gost/gost/v3/pkg/logger" -) - -var ( - ErrEmptyRoute = errors.New("empty route") -) - -type Route struct { - nodes []*Node - ifceName string - logger logger.Logger -} - -func (r *Route) addNode(node *Node) { - r.nodes = append(r.nodes, node) -} - -func (r *Route) Dial(ctx context.Context, network, address string) (net.Conn, error) { - if r.Len() == 0 { - 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) - if err != nil { - return nil, err - } - - cc, err := r.GetNode(r.Len()-1).Transport.Connect(ctx, conn, network, address) - if err != nil { - conn.Close() - return nil, err - } - return cc, nil -} - -func (r *Route) Bind(ctx context.Context, network, address string, opts ...connector.BindOption) (net.Listener, error) { - if r.Len() == 0 { - return r.bindLocal(ctx, network, address, opts...) - } - - conn, err := r.connect(ctx) - if err != nil { - return nil, err - } - - ln, err := r.GetNode(r.Len()-1).Transport.Bind(ctx, conn, network, address, opts...) - if err != nil { - conn.Close() - return nil, err - } - - return ln, nil -} - -func (r *Route) connect(ctx context.Context) (conn net.Conn, err error) { - if r.Len() == 0 { - return nil, ErrEmptyRoute - } - - network := "ip" - node := r.nodes[0] - - addr, err := resolve(ctx, network, node.Addr, node.Resolver, node.Hosts, r.logger) - if err != nil { - node.Marker.Mark() - return - } - cc, err := node.Transport.Dial(ctx, addr) - if err != nil { - node.Marker.Mark() - return - } - - cn, err := node.Transport.Handshake(ctx, cc) - if err != nil { - cc.Close() - node.Marker.Mark() - return - } - node.Marker.Reset() - - preNode := node - for _, node := range r.nodes[1:] { - addr, err = resolve(ctx, network, node.Addr, node.Resolver, node.Hosts, r.logger) - if err != nil { - cn.Close() - node.Marker.Mark() - return - } - cc, err = preNode.Transport.Connect(ctx, cn, "tcp", addr) - if err != nil { - cn.Close() - node.Marker.Mark() - return - } - cc, err = node.Transport.Handshake(ctx, cc) - if err != nil { - cn.Close() - node.Marker.Mark() - return - } - node.Marker.Reset() - - cn = cc - preNode = node - } - - conn = cn - return -} - -func (r *Route) Len() int { - if r == nil { - return 0 - } - return len(r.nodes) -} - -func (r *Route) GetNode(index int) *Node { - if r.Len() == 0 || index < 0 || index >= len(r.nodes) { - return nil - } - return r.nodes[index] -} - -func (r *Route) Path() (path []*Node) { - if r == nil || len(r.nodes) == 0 { - return nil - } - - for _, node := range r.nodes { - if node.Transport != nil && node.Transport.route != nil { - path = append(path, node.Transport.route.Path()...) - } - path = append(path, node) - } - return -} - -func (r *Route) bindLocal(ctx context.Context, network, address string, opts ...connector.BindOption) (net.Listener, error) { - options := connector.BindOptions{} - for _, opt := range opts { - opt(&options) - } - - switch network { - case "tcp", "tcp4", "tcp6": - addr, err := net.ResolveTCPAddr(network, address) - if err != nil { - return nil, err - } - return net.ListenTCP(network, addr) - case "udp", "udp4", "udp6": - addr, err := net.ResolveUDPAddr(network, address) - if err != nil { - return nil, err - } - conn, err := net.ListenUDP(network, addr) - if err != nil { - return nil, err - } - logger := logger.Default().WithFields(map[string]any{ - "network": network, - "address": address, - }) - ln := udp.NewListener(conn, addr, - options.Backlog, options.UDPDataQueueSize, options.UDPDataBufferSize, - options.UDPConnTTL, logger) - return ln, err - default: - err := fmt.Errorf("network %s unsupported", network) - return nil, err - } -} diff --git a/pkg/chain/router.go b/pkg/chain/router.go deleted file mode 100644 index 86a4364..0000000 --- a/pkg/chain/router.go +++ /dev/null @@ -1,169 +0,0 @@ -package chain - -import ( - "bytes" - "context" - "fmt" - "net" - "time" - - "github.com/go-gost/gost/v3/pkg/connector" - "github.com/go-gost/gost/v3/pkg/hosts" - "github.com/go-gost/gost/v3/pkg/logger" - "github.com/go-gost/gost/v3/pkg/resolver" -) - -type Router struct { - timeout time.Duration - retries int - ifceName string - chain Chainer - 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) { - conn, err = r.dial(ctx, network, address) - if err != nil { - return - } - if network == "udp" || network == "udp4" || network == "udp6" { - if _, ok := conn.(net.PacketConn); !ok { - return &packetConn{conn}, nil - } - } - return -} - -func (r *Router) dial(ctx context.Context, network, address string) (conn net.Conn, err error) { - count := r.retries + 1 - if count <= 0 { - count = 1 - } - r.logger.Debugf("dial %s/%s", address, network) - - for i := 0; i < count; i++ { - var route *Route - if r.chain != nil { - route = r.chain.Route(network, address) - } - - if r.logger.IsLevelEnabled(logger.DebugLevel) { - buf := bytes.Buffer{} - for _, node := range route.Path() { - fmt.Fprintf(&buf, "%s@%s > ", node.Name, node.Addr) - } - fmt.Fprintf(&buf, "%s", address) - r.logger.Debugf("route(retry=%d) %s", i, buf.String()) - } - - address, err = resolve(ctx, "ip", address, r.resolver, r.hosts, r.logger) - if err != nil { - r.logger.Error(err) - break - } - - if route == nil { - route = &Route{} - } - route.ifceName = r.ifceName - route.logger = r.logger - - conn, err = route.Dial(ctx, network, address) - if err == nil { - break - } - r.logger.Errorf("route(retry=%d) %s", i, err) - } - - return -} - -func (r *Router) Bind(ctx context.Context, network, address string, opts ...connector.BindOption) (ln net.Listener, err error) { - count := r.retries + 1 - if count <= 0 { - count = 1 - } - r.logger.Debugf("bind on %s/%s", address, network) - - for i := 0; i < count; i++ { - var route *Route - if r.chain != nil { - route = r.chain.Route(network, address) - } - - if r.logger.IsLevelEnabled(logger.DebugLevel) { - buf := bytes.Buffer{} - for _, node := range route.Path() { - fmt.Fprintf(&buf, "%s@%s > ", node.Name, node.Addr) - } - fmt.Fprintf(&buf, "%s", address) - r.logger.Debugf("route(retry=%d) %s", i, buf.String()) - } - - ln, err = route.Bind(ctx, network, address, opts...) - if err == nil { - break - } - r.logger.Errorf("route(retry=%d) %s", i, err) - } - - return -} - -type packetConn struct { - net.Conn -} - -func (c *packetConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { - n, err = c.Read(b) - addr = c.Conn.RemoteAddr() - return -} - -func (c *packetConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { - return c.Write(b) -} diff --git a/pkg/chain/selector.go b/pkg/chain/selector.go deleted file mode 100644 index 2ad0a03..0000000 --- a/pkg/chain/selector.go +++ /dev/null @@ -1,170 +0,0 @@ -package chain - -import ( - "math/rand" - "net" - "strconv" - "sync" - "sync/atomic" - "time" -) - -// default options for FailFilter -const ( - DefaultFailTimeout = 30 * time.Second -) - -var ( - DefaultSelector = NewSelector(RoundRobinStrategy()) -) - -type Selector interface { - Select(nodes ...*Node) *Node -} - -type selector struct { - strategy Strategy - filters []Filter -} - -func NewSelector(strategy Strategy, filters ...Filter) Selector { - return &selector{ - filters: filters, - strategy: strategy, - } -} - -func (s *selector) Select(nodes ...*Node) *Node { - for _, filter := range s.filters { - nodes = filter.Filter(nodes...) - } - if len(nodes) == 0 { - return nil - } - return s.strategy.Apply(nodes...) -} - -type Strategy interface { - Apply(nodes ...*Node) *Node -} - -type roundRobinStrategy struct { - counter uint64 -} - -// RoundRobinStrategy is a strategy for node selector. -// The node will be selected by round-robin algorithm. -func RoundRobinStrategy() Strategy { - return &roundRobinStrategy{} -} - -func (s *roundRobinStrategy) Apply(nodes ...*Node) *Node { - if len(nodes) == 0 { - return nil - } - - n := atomic.AddUint64(&s.counter, 1) - 1 - return nodes[int(n%uint64(len(nodes)))] -} - -type randomStrategy struct { - rand *rand.Rand - mux sync.Mutex -} - -// RandomStrategy is a strategy for node selector. -// The node will be selected randomly. -func RandomStrategy() Strategy { - return &randomStrategy{ - rand: rand.New(rand.NewSource(time.Now().UnixNano())), - } -} - -func (s *randomStrategy) Apply(nodes ...*Node) *Node { - if len(nodes) == 0 { - return nil - } - - s.mux.Lock() - defer s.mux.Unlock() - - r := s.rand.Int() - - return nodes[r%len(nodes)] -} - -type fifoStrategy struct{} - -// FIFOStrategy is a strategy for node selector. -// The node will be selected from first to last, -// and will stick to the selected node until it is failed. -func FIFOStrategy() Strategy { - return &fifoStrategy{} -} - -// Apply applies the fifo strategy for the nodes. -func (s *fifoStrategy) Apply(nodes ...*Node) *Node { - if len(nodes) == 0 { - return nil - } - return nodes[0] -} - -type Filter interface { - Filter(nodes ...*Node) []*Node -} - -type failFilter struct { - maxFails int - failTimeout time.Duration -} - -// FailFilter filters the dead node. -// A node is marked as dead if its failed count is greater than MaxFails. -func FailFilter(maxFails int, timeout time.Duration) Filter { - return &failFilter{ - maxFails: maxFails, - failTimeout: timeout, - } -} - -// Filter filters dead nodes. -func (f *failFilter) Filter(nodes ...*Node) []*Node { - maxFails := f.maxFails - failTimeout := f.failTimeout - if failTimeout == 0 { - failTimeout = DefaultFailTimeout - } - - if len(nodes) <= 1 || maxFails <= 0 { - return nodes - } - var nl []*Node - for _, node := range nodes { - if node.Marker.FailCount() < int64(maxFails) || - time.Since(time.Unix(node.Marker.FailTime(), 0)) >= failTimeout { - nl = append(nl, node) - } - } - return nl -} - -type invalidFilter struct{} - -// InvalidFilter filters the invalid node. -// A node is invalid if its port is invalid (negative or zero value). -func InvalidFilter() Filter { - return &invalidFilter{} -} - -// Filter filters invalid nodes. -func (f *invalidFilter) Filter(nodes ...*Node) []*Node { - var nl []*Node - for _, node := range nodes { - _, sport, _ := net.SplitHostPort(node.Addr) - if port, _ := strconv.Atoi(sport); port > 0 { - nl = append(nl, node) - } - } - return nl -} diff --git a/pkg/chain/transport.go b/pkg/chain/transport.go deleted file mode 100644 index 989ed1a..0000000 --- a/pkg/chain/transport.go +++ /dev/null @@ -1,100 +0,0 @@ -package chain - -import ( - "context" - "net" - "time" - - net_dialer "github.com/go-gost/gost/v3/pkg/common/net/dialer" - "github.com/go-gost/gost/v3/pkg/connector" - "github.com/go-gost/gost/v3/pkg/dialer" -) - -type Transport struct { - addr string - ifceName string - route *Route - dialer dialer.Dialer - connector connector.Connector -} - -func (tr *Transport) Copy() *Transport { - tr2 := &Transport{} - *tr2 = *tr - return tr -} - -func (tr *Transport) WithInterface(ifceName string) *Transport { - tr.ifceName = ifceName - return tr -} - -func (tr *Transport) WithDialer(dialer dialer.Dialer) *Transport { - tr.dialer = dialer - return tr -} - -func (tr *Transport) WithConnector(connector connector.Connector) *Transport { - tr.connector = connector - return tr -} - -func (tr *Transport) Dial(ctx context.Context, addr string) (net.Conn, error) { - netd := &net_dialer.NetDialer{ - Interface: tr.ifceName, - Timeout: 30 * time.Second, - } - 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{ - dialer.HostDialOption(tr.addr), - dialer.NetDialerDialOption(netd), - } - return tr.dialer.Dial(ctx, addr, opts...) -} - -func (tr *Transport) Handshake(ctx context.Context, conn net.Conn) (net.Conn, error) { - var err error - if hs, ok := tr.dialer.(dialer.Handshaker); ok { - conn, err = hs.Handshake(ctx, conn, - dialer.AddrHandshakeOption(tr.addr)) - if err != nil { - return nil, err - } - } - if hs, ok := tr.connector.(connector.Handshaker); ok { - return hs.Handshake(ctx, conn) - } - return conn, nil -} - -func (tr *Transport) Connect(ctx context.Context, conn net.Conn, network, address string) (net.Conn, error) { - return tr.connector.Connect(ctx, conn, network, address) -} - -func (tr *Transport) Bind(ctx context.Context, conn net.Conn, network, address string, opts ...connector.BindOption) (net.Listener, error) { - if binder, ok := tr.connector.(connector.Binder); ok { - return binder.Bind(ctx, conn, network, address, opts...) - } - return nil, connector.ErrBindUnsupported -} - -func (tr *Transport) Multiplex() bool { - if mux, ok := tr.dialer.(dialer.Multiplexer); ok { - return mux.Multiplex() - } - return false -} - -func (tr *Transport) WithRoute(r *Route) *Transport { - tr.route = r - return tr -} - -func (tr *Transport) WithAddr(addr string) *Transport { - tr.addr = addr - return tr -} diff --git a/pkg/common/bufpool/pool.go b/pkg/common/bufpool/pool.go deleted file mode 100644 index 5af2c87..0000000 --- a/pkg/common/bufpool/pool.go +++ /dev/null @@ -1,113 +0,0 @@ -package bufpool - -import "sync" - -var ( - pools = []struct { - size int - pool sync.Pool - }{ - { - size: 128, - pool: sync.Pool{ - New: func() any { - b := make([]byte, 128) - return &b - }, - }, - }, - { - size: 512, - pool: sync.Pool{ - New: func() any { - b := make([]byte, 512) - return &b - }, - }, - }, - { - size: 1024, - pool: sync.Pool{ - New: func() any { - b := make([]byte, 1024) - return &b - }, - }, - }, - { - size: 4096, - pool: sync.Pool{ - New: func() any { - b := make([]byte, 4096) - return &b - }, - }, - }, - { - size: 8192, - pool: sync.Pool{ - New: func() any { - b := make([]byte, 8192) - return &b - }, - }, - }, - { - size: 16 * 1024, - pool: sync.Pool{ - New: func() any { - b := make([]byte, 16*1024) - return &b - }, - }, - }, - { - size: 32 * 1024, - pool: sync.Pool{ - New: func() any { - b := make([]byte, 32*1024) - return &b - }, - }, - }, - { - size: 64 * 1024, - pool: sync.Pool{ - New: func() any { - b := make([]byte, 64*1024) - return &b - }, - }, - }, - { - size: 65 * 1024, - pool: sync.Pool{ - New: func() any { - b := make([]byte, 65*1024) - return &b - }, - }, - }, - } -) - -// Get returns a buffer of specified size. -func Get(size int) *[]byte { - for i := range pools { - if size <= pools[i].size { - b := pools[i].pool.Get().(*[]byte) - *b = (*b)[:size] - return b - } - } - b := make([]byte, size) - return &b -} - -func Put(b *[]byte) { - for i := range pools { - if cap(*b) == pools[i].size { - pools[i].pool.Put(b) - } - } -} diff --git a/pkg/common/matcher/matcher.go b/pkg/common/matcher/matcher.go deleted file mode 100644 index 81442d3..0000000 --- a/pkg/common/matcher/matcher.go +++ /dev/null @@ -1,99 +0,0 @@ -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) -} diff --git a/pkg/common/net/dialer/dialer.go b/pkg/common/net/dialer/dialer.go deleted file mode 100644 index 9bc0ade..0000000 --- a/pkg/common/net/dialer/dialer.go +++ /dev/null @@ -1,144 +0,0 @@ -package dialer - -import ( - "context" - "fmt" - "net" - "syscall" - "time" - - "github.com/go-gost/gost/v3/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 -} diff --git a/pkg/common/net/dialer/dialer_linux.go b/pkg/common/net/dialer/dialer_linux.go deleted file mode 100644 index cf7f0aa..0000000 --- a/pkg/common/net/dialer/dialer_linux.go +++ /dev/null @@ -1,14 +0,0 @@ -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) -} diff --git a/pkg/common/net/dialer/dialer_other.go b/pkg/common/net/dialer/dialer_other.go deleted file mode 100644 index 6ad6b21..0000000 --- a/pkg/common/net/dialer/dialer_other.go +++ /dev/null @@ -1,7 +0,0 @@ -//go:build !linux - -package dialer - -func bindDevice(fd uintptr, ifceName string) error { - return nil -} diff --git a/pkg/common/net/relay/relay.go b/pkg/common/net/relay/relay.go deleted file mode 100644 index aaed02b..0000000 --- a/pkg/common/net/relay/relay.go +++ /dev/null @@ -1,126 +0,0 @@ -package relay - -import ( - "net" - - "github.com/go-gost/gost/v3/pkg/bypass" - "github.com/go-gost/gost/v3/pkg/common/bufpool" - "github.com/go-gost/gost/v3/pkg/logger" -) - -type UDPRelay struct { - pc1 net.PacketConn - pc2 net.PacketConn - - bypass bypass.Bypass - bufferSize int - logger logger.Logger -} - -func NewUDPRelay(pc1, pc2 net.PacketConn) *UDPRelay { - return &UDPRelay{ - pc1: pc1, - pc2: pc2, - } -} - -func (r *UDPRelay) WithBypass(bp bypass.Bypass) *UDPRelay { - r.bypass = bp - return r -} - -func (r *UDPRelay) WithLogger(logger logger.Logger) *UDPRelay { - r.logger = logger - return r -} - -func (r *UDPRelay) SetBufferSize(n int) { - r.bufferSize = n -} - -func (r *UDPRelay) Run() (err error) { - bufSize := r.bufferSize - if bufSize <= 0 { - bufSize = 1024 - } - - errc := make(chan error, 2) - - go func() { - for { - err := func() error { - b := bufpool.Get(bufSize) - defer bufpool.Put(b) - - n, raddr, err := r.pc1.ReadFrom(*b) - if err != nil { - return err - } - - if r.bypass != nil && r.bypass.Contains(raddr.String()) { - if r.logger != nil { - r.logger.Warn("bypass: ", raddr) - } - return nil - } - - if _, err := r.pc2.WriteTo((*b)[:n], raddr); err != nil { - return err - } - - if r.logger != nil { - r.logger.Debugf("%s >>> %s data: %d", - r.pc2.LocalAddr(), raddr, n) - - } - - return nil - }() - - if err != nil { - errc <- err - return - } - } - }() - - go func() { - for { - err := func() error { - b := bufpool.Get(bufSize) - defer bufpool.Put(b) - - n, raddr, err := r.pc2.ReadFrom(*b) - if err != nil { - return err - } - - if r.bypass != nil && r.bypass.Contains(raddr.String()) { - if r.logger != nil { - r.logger.Warn("bypass: ", raddr) - } - return nil - } - - if _, err := r.pc1.WriteTo((*b)[:n], raddr); err != nil { - return err - } - - if r.logger != nil { - r.logger.Debugf("%s <<< %s data: %d", - r.pc2.LocalAddr(), raddr, n) - - } - - return nil - }() - - if err != nil { - errc <- err - return - } - } - }() - - return <-errc -} diff --git a/pkg/common/net/transport.go b/pkg/common/net/transport.go deleted file mode 100644 index 1879f2f..0000000 --- a/pkg/common/net/transport.go +++ /dev/null @@ -1,50 +0,0 @@ -package net - -import ( - "bufio" - "io" - "net" - - "github.com/go-gost/gost/v3/pkg/common/bufpool" -) - -func Transport(rw1, rw2 io.ReadWriter) error { - errc := make(chan error, 1) - go func() { - errc <- copyBuffer(rw1, rw2) - }() - - go func() { - errc <- copyBuffer(rw2, rw1) - }() - - err := <-errc - if err != nil && err == io.EOF { - err = nil - } - return err -} - -func copyBuffer(dst io.Writer, src io.Reader) error { - buf := bufpool.Get(16 * 1024) - defer bufpool.Put(buf) - - _, err := io.CopyBuffer(dst, src, *buf) - return err -} - -type bufferReaderConn struct { - net.Conn - br *bufio.Reader -} - -func NewBufferReaderConn(conn net.Conn, br *bufio.Reader) net.Conn { - return &bufferReaderConn{ - Conn: conn, - br: br, - } -} - -func (c *bufferReaderConn) Read(b []byte) (int, error) { - return c.br.Read(b) -} diff --git a/pkg/common/net/udp.go b/pkg/common/net/udp.go deleted file mode 100644 index 515060f..0000000 --- a/pkg/common/net/udp.go +++ /dev/null @@ -1,41 +0,0 @@ -package net - -import ( - "io" - "net" - "syscall" -) - -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 -} diff --git a/pkg/common/util/resolver/cache.go b/pkg/common/util/resolver/cache.go deleted file mode 100644 index fe7d50c..0000000 --- a/pkg/common/util/resolver/cache.go +++ /dev/null @@ -1,88 +0,0 @@ -package resolver - -import ( - "fmt" - "sync" - "time" - - "github.com/go-gost/gost/v3/pkg/logger" - "github.com/miekg/dns" -) - -type CacheKey string - -// NewCacheKey generates resolver cache key from question of dns query. -func NewCacheKey(q *dns.Question) CacheKey { - if q == nil { - return "" - } - key := fmt.Sprintf("%s%s.%s", q.Name, dns.Class(q.Qclass).String(), dns.Type(q.Qtype).String()) - return CacheKey(key) -} - -type cacheItem struct { - msg *dns.Msg - ts time.Time - ttl time.Duration -} - -type Cache struct { - m sync.Map - logger logger.Logger -} - -func NewCache() *Cache { - return &Cache{} -} - -func (c *Cache) WithLogger(logger logger.Logger) *Cache { - c.logger = logger - return c -} - -func (c *Cache) Load(key CacheKey) *dns.Msg { - v, ok := c.m.Load(key) - if !ok { - return nil - } - - item, ok := v.(*cacheItem) - if !ok { - return nil - } - - if time.Since(item.ts) > item.ttl { - c.m.Delete(key) - return nil - } - - c.logger.Debugf("hit resolver cache: %s", key) - - return item.msg.Copy() -} - -func (c *Cache) Store(key CacheKey, mr *dns.Msg, ttl time.Duration) { - if key == "" || mr == nil || ttl < 0 { - return - } - - if ttl == 0 { - for _, answer := range mr.Answer { - v := time.Duration(answer.Header().Ttl) * time.Second - if ttl == 0 || ttl > v { - ttl = v - } - } - } - if ttl == 0 { - ttl = 30 * time.Second - } - - c.m.Store(key, &cacheItem{ - msg: mr.Copy(), - ts: time.Now(), - ttl: ttl, - }) - - c.logger.Debugf("resolver cache store: %s, ttl: %v", key, ttl) -} diff --git a/pkg/common/util/resolver/resolver.go b/pkg/common/util/resolver/resolver.go deleted file mode 100644 index 74ec536..0000000 --- a/pkg/common/util/resolver/resolver.go +++ /dev/null @@ -1,30 +0,0 @@ -package resolver - -import ( - "net" - - "github.com/miekg/dns" -) - -func AddSubnetOpt(m *dns.Msg, ip net.IP) { - if m == nil || ip == nil { - return - } - - opt := new(dns.OPT) - opt.Hdr.Name = "." - opt.Hdr.Rrtype = dns.TypeOPT - e := new(dns.EDNS0_SUBNET) - e.Code = dns.EDNS0SUBNET - if ip := ip.To4(); ip != nil { - e.Family = 1 - e.SourceNetmask = 24 - e.Address = ip - } else { - e.Family = 2 - e.SourceNetmask = 128 - e.Address = ip.To16() - } - opt.Option = append(opt.Option, e) - m.Extra = append(m.Extra, opt) -} diff --git a/pkg/common/util/tls/tls.go b/pkg/common/util/tls/tls.go deleted file mode 100644 index 8fa5e3e..0000000 --- a/pkg/common/util/tls/tls.go +++ /dev/null @@ -1,178 +0,0 @@ -package tls - -import ( - "crypto/tls" - "crypto/x509" - "errors" - "io/ioutil" - "net" - "time" -) - -var ( - // DefaultConfig is a default TLS config for global use. - DefaultConfig *tls.Config -) - -// LoadServerConfig loads the certificate from cert & key files and optional client CA file. -func LoadServerConfig(certFile, keyFile, caFile string) (*tls.Config, error) { - if certFile == "" && keyFile == "" { - return DefaultConfig.Clone(), nil - } - - cert, err := tls.LoadX509KeyPair(certFile, keyFile) - if err != nil { - return nil, err - } - - cfg := &tls.Config{Certificates: []tls.Certificate{cert}} - - pool, err := loadCA(caFile) - if err != nil { - return nil, err - } - if pool != nil { - cfg.ClientCAs = pool - cfg.ClientAuth = tls.RequireAndVerifyClientCert - } - - return cfg, nil -} - -// LoadClientConfig loads the certificate from cert & key files and optional CA file. -func LoadClientConfig(certFile, keyFile, caFile string, verify bool, serverName string) (*tls.Config, error) { - var cfg *tls.Config - - if certFile == "" && keyFile == "" { - cfg = &tls.Config{} - } else { - cert, err := tls.LoadX509KeyPair(certFile, keyFile) - if err != nil { - return nil, err - } - - cfg = &tls.Config{ - Certificates: []tls.Certificate{cert}, - } - } - - rootCAs, err := loadCA(caFile) - if err != nil { - return nil, err - } - - cfg.RootCAs = rootCAs - cfg.ServerName = serverName - cfg.InsecureSkipVerify = !verify - - // If the root ca is given, but skip verify, we verify the certificate manually. - if cfg.RootCAs != nil && !verify { - cfg.VerifyConnection = func(state tls.ConnectionState) error { - opts := x509.VerifyOptions{ - Roots: cfg.RootCAs, - CurrentTime: time.Now(), - DNSName: "", - Intermediates: x509.NewCertPool(), - } - - certs := state.PeerCertificates - for i, cert := range certs { - if i == 0 { - continue - } - opts.Intermediates.AddCert(cert) - } - - _, err := certs[0].Verify(opts) - return err - } - } - - return cfg, nil -} - -func loadCA(caFile string) (cp *x509.CertPool, err error) { - if caFile == "" { - return - } - cp = x509.NewCertPool() - data, err := ioutil.ReadFile(caFile) - if err != nil { - return nil, err - } - if !cp.AppendCertsFromPEM(data) { - return nil, errors.New("AppendCertsFromPEM failed") - } - return -} - -// Wrap a net.Conn into a client tls connection, performing any -// additional verification as needed. -// -// As of go 1.3, crypto/tls only supports either doing no certificate -// verification, or doing full verification including of the peer's -// DNS name. For consul, we want to validate that the certificate is -// signed by a known CA, but because consul doesn't use DNS names for -// node names, we don't verify the certificate DNS names. Since go 1.3 -// no longer supports this mode of operation, we have to do it -// manually. -// -// This code is taken from consul: -// https://github.com/hashicorp/consul/blob/master/tlsutil/config.go -func WrapTLSClient(conn net.Conn, tlsConfig *tls.Config, timeout time.Duration) (net.Conn, error) { - var err error - var tlsConn *tls.Conn - - if timeout > 0 { - conn.SetDeadline(time.Now().Add(timeout)) - defer conn.SetDeadline(time.Time{}) - } - - tlsConn = tls.Client(conn, tlsConfig) - - // Otherwise perform handshake, but don't verify the domain - // - // The following is lightly-modified from the doFullHandshake - // method in https://golang.org/src/crypto/tls/handshake_client.go - if err = tlsConn.Handshake(); err != nil { - tlsConn.Close() - return nil, err - } - - // We can do this in `tls.Config.VerifyConnection`, which effective for - // other TLS protocols such as WebSocket. See `route.go:parseChainNode` - /* - // If crypto/tls is doing verification, there's no need to do our own. - if tlsConfig.InsecureSkipVerify == false { - return tlsConn, nil - } - - // Similarly if we use host's CA, we can do full handshake - if tlsConfig.RootCAs == nil { - return tlsConn, nil - } - - opts := x509.VerifyOptions{ - Roots: tlsConfig.RootCAs, - CurrentTime: time.Now(), - DNSName: "", - Intermediates: x509.NewCertPool(), - } - - certs := tlsConn.ConnectionState().PeerCertificates - for i, cert := range certs { - if i == 0 { - continue - } - opts.Intermediates.AddCert(cert) - } - - _, err = certs[0].Verify(opts) - if err != nil { - tlsConn.Close() - return nil, err - } - */ - - return tlsConn, err -} diff --git a/pkg/common/util/udp/conn.go b/pkg/common/util/udp/conn.go deleted file mode 100644 index 893b02b..0000000 --- a/pkg/common/util/udp/conn.go +++ /dev/null @@ -1,102 +0,0 @@ -package udp - -import ( - "errors" - "net" - "sync" - "sync/atomic" - - "github.com/go-gost/gost/v3/pkg/common/bufpool" -) - -// Conn is a server side connection for UDP client peer, it implements net.Conn and net.PacketConn. -type Conn struct { - net.PacketConn - localAddr net.Addr - remoteAddr net.Addr - rc chan []byte // data receive queue - idle int32 // indicate the connection is idle - closed chan struct{} - closeMutex sync.Mutex -} - -func NewConn(c net.PacketConn, localAddr, remoteAddr net.Addr, queueSize int) *Conn { - return &Conn{ - PacketConn: c, - localAddr: localAddr, - remoteAddr: remoteAddr, - rc: make(chan []byte, queueSize), - closed: make(chan struct{}), - } -} - -func (c *Conn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { - select { - case bb := <-c.rc: - n = copy(b, bb) - c.SetIdle(false) - bufpool.Put(&bb) - - case <-c.closed: - err = net.ErrClosed - return - } - - addr = c.remoteAddr - - return -} - -func (c *Conn) Read(b []byte) (n int, err error) { - n, _, err = c.ReadFrom(b) - return -} - -func (c *Conn) Write(b []byte) (n int, err error) { - return c.WriteTo(b, c.remoteAddr) -} - -func (c *Conn) Close() error { - c.closeMutex.Lock() - defer c.closeMutex.Unlock() - - select { - case <-c.closed: - default: - close(c.closed) - } - return nil -} - -func (c *Conn) LocalAddr() net.Addr { - return c.localAddr -} - -func (c *Conn) RemoteAddr() net.Addr { - return c.remoteAddr -} - -func (c *Conn) IsIdle() bool { - return atomic.LoadInt32(&c.idle) > 0 -} - -func (c *Conn) SetIdle(idle bool) { - v := int32(0) - if idle { - v = 1 - } - atomic.StoreInt32(&c.idle, v) -} - -func (c *Conn) WriteQueue(b []byte) error { - select { - case c.rc <- b: - return nil - - case <-c.closed: - return net.ErrClosed - - default: - return errors.New("recv queue is full") - } -} diff --git a/pkg/common/util/udp/listener.go b/pkg/common/util/udp/listener.go deleted file mode 100644 index 9a7632d..0000000 --- a/pkg/common/util/udp/listener.go +++ /dev/null @@ -1,120 +0,0 @@ -package udp - -import ( - "net" - "sync" - "time" - - "github.com/go-gost/gost/v3/pkg/common/bufpool" - "github.com/go-gost/gost/v3/pkg/logger" -) - -type listener struct { - addr net.Addr - conn net.PacketConn - cqueue chan net.Conn - readQueueSize int - readBufferSize int - connPool *ConnPool - mux sync.Mutex - closed chan struct{} - errChan chan error - logger logger.Logger -} - -func NewListener(conn net.PacketConn, addr net.Addr, backlog, dataQueueSize, dataBufferSize int, ttl time.Duration, logger logger.Logger) net.Listener { - ln := &listener{ - conn: conn, - addr: addr, - cqueue: make(chan net.Conn, backlog), - connPool: NewConnPool(ttl).WithLogger(logger), - readQueueSize: dataQueueSize, - readBufferSize: dataBufferSize, - closed: make(chan struct{}), - errChan: make(chan error, 1), - logger: logger, - } - go ln.listenLoop() - - return ln -} - -func (ln *listener) Accept() (conn net.Conn, err error) { - select { - case conn = <-ln.cqueue: - return - case <-ln.closed: - return nil, net.ErrClosed - case err = <-ln.errChan: - if err == nil { - err = net.ErrClosed - } - return - } -} - -func (ln *listener) listenLoop() { - for { - select { - case <-ln.closed: - return - default: - } - - b := bufpool.Get(ln.readBufferSize) - - n, raddr, err := ln.conn.ReadFrom(*b) - if err != nil { - ln.errChan <- err - close(ln.errChan) - return - } - - c := ln.getConn(raddr) - if c == nil { - bufpool.Put(b) - continue - } - - if err := c.WriteQueue((*b)[:n]); err != nil { - ln.logger.Warn("data discarded: ", err) - } - } -} - -func (ln *listener) Addr() net.Addr { - return ln.addr -} - -func (ln *listener) Close() error { - select { - case <-ln.closed: - default: - close(ln.closed) - ln.conn.Close() - ln.connPool.Close() - } - - return nil -} - -func (ln *listener) getConn(raddr net.Addr) *Conn { - ln.mux.Lock() - defer ln.mux.Unlock() - - c, ok := ln.connPool.Get(raddr.String()) - if ok { - return c - } - - c = NewConn(ln.conn, ln.addr, raddr, ln.readQueueSize) - select { - case ln.cqueue <- c: - ln.connPool.Set(raddr.String(), c) - return c - default: - c.Close() - ln.logger.Warnf("connection queue is full, client %s discarded", raddr) - return nil - } -} diff --git a/pkg/common/util/udp/pool.go b/pkg/common/util/udp/pool.go deleted file mode 100644 index 796b47d..0000000 --- a/pkg/common/util/udp/pool.go +++ /dev/null @@ -1,100 +0,0 @@ -package udp - -import ( - "sync" - "time" - - "github.com/go-gost/gost/v3/pkg/logger" -) - -type ConnPool struct { - m sync.Map - ttl time.Duration - closed chan struct{} - logger logger.Logger -} - -func NewConnPool(ttl time.Duration) *ConnPool { - p := &ConnPool{ - ttl: ttl, - closed: make(chan struct{}), - } - go p.idleCheck() - return p -} - -func (p *ConnPool) WithLogger(logger logger.Logger) *ConnPool { - p.logger = logger - return p -} - -func (p *ConnPool) Get(key any) (c *Conn, ok bool) { - v, ok := p.m.Load(key) - if ok { - c, ok = v.(*Conn) - } - return -} - -func (p *ConnPool) Set(key any, c *Conn) { - p.m.Store(key, c) -} - -func (p *ConnPool) Delete(key any) { - p.m.Delete(key) -} - -func (p *ConnPool) Close() { - select { - case <-p.closed: - return - default: - } - - close(p.closed) - - p.m.Range(func(k, v any) bool { - if c, ok := v.(*Conn); ok && c != nil { - c.Close() - } - return true - }) -} - -func (p *ConnPool) idleCheck() { - ticker := time.NewTicker(p.ttl) - defer ticker.Stop() - - for { - select { - case <-ticker.C: - size := 0 - idles := 0 - p.m.Range(func(key, value any) bool { - c, ok := value.(*Conn) - if !ok || c == nil { - p.Delete(key) - return true - } - size++ - - if c.IsIdle() { - idles++ - p.Delete(key) - c.Close() - return true - } - - c.SetIdle(true) - - return true - }) - - if idles > 0 { - p.logger.Debugf("connection pool: size=%d, idle=%d", size, idles) - } - case <-p.closed: - return - } - } -} diff --git a/pkg/connector/binder.go b/pkg/connector/binder.go deleted file mode 100644 index 8af8939..0000000 --- a/pkg/connector/binder.go +++ /dev/null @@ -1,15 +0,0 @@ -package connector - -import ( - "context" - "errors" - "net" -) - -var ( - ErrBindUnsupported = errors.New("bind unsupported") -) - -type Binder interface { - Bind(ctx context.Context, conn net.Conn, network, address string, opts ...BindOption) (net.Listener, error) -} diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go deleted file mode 100644 index afe83e7..0000000 --- a/pkg/connector/connector.go +++ /dev/null @@ -1,18 +0,0 @@ -package connector - -import ( - "context" - "net" - - "github.com/go-gost/gost/v3/pkg/metadata" -) - -// Connector is responsible for connecting to the destination address. -type Connector interface { - Init(metadata.Metadata) error - Connect(ctx context.Context, conn net.Conn, network, address string, opts ...ConnectOption) (net.Conn, error) -} - -type Handshaker interface { - Handshake(ctx context.Context, conn net.Conn) (net.Conn, error) -} diff --git a/pkg/connector/forward/connector.go b/pkg/connector/forward/connector.go deleted file mode 100644 index 1528f5f..0000000 --- a/pkg/connector/forward/connector.go +++ /dev/null @@ -1,45 +0,0 @@ -package forward - -import ( - "context" - "net" - - "github.com/go-gost/gost/v3/pkg/connector" - md "github.com/go-gost/gost/v3/pkg/metadata" - "github.com/go-gost/gost/v3/pkg/registry" -) - -func init() { - registry.ConnectorRegistry().Register("forward", NewConnector) -} - -type forwardConnector struct { - options connector.Options -} - -func NewConnector(opts ...connector.Option) connector.Connector { - options := connector.Options{} - for _, opt := range opts { - opt(&options) - } - - return &forwardConnector{ - options: options, - } -} - -func (c *forwardConnector) Init(md md.Metadata) (err error) { - return nil -} - -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]any{ - "remote": conn.RemoteAddr().String(), - "local": conn.LocalAddr().String(), - "network": network, - "address": address, - }) - log.Infof("connect %s/%s", address, network) - - return conn, nil -} diff --git a/pkg/connector/http/connector.go b/pkg/connector/http/connector.go deleted file mode 100644 index 43dc5e5..0000000 --- a/pkg/connector/http/connector.go +++ /dev/null @@ -1,129 +0,0 @@ -package http - -import ( - "bufio" - "context" - "encoding/base64" - "fmt" - "net" - "net/http" - "net/http/httputil" - "net/url" - "time" - - "github.com/go-gost/gost/v3/pkg/connector" - "github.com/go-gost/gost/v3/pkg/internal/util/socks" - "github.com/go-gost/gost/v3/pkg/logger" - md "github.com/go-gost/gost/v3/pkg/metadata" - "github.com/go-gost/gost/v3/pkg/registry" -) - -func init() { - registry.ConnectorRegistry().Register("http", NewConnector) -} - -type httpConnector struct { - md metadata - options connector.Options -} - -func NewConnector(opts ...connector.Option) connector.Connector { - options := connector.Options{} - for _, opt := range opts { - opt(&options) - } - - return &httpConnector{ - options: options, - } -} - -func (c *httpConnector) Init(md md.Metadata) (err error) { - return c.parseMetadata(md) -} - -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]any{ - "local": conn.LocalAddr().String(), - "remote": conn.RemoteAddr().String(), - "network": network, - "address": address, - }) - log.Infof("connect %s/%s", address, network) - - req := &http.Request{ - Method: http.MethodConnect, - URL: &url.URL{Host: address}, - Host: address, - ProtoMajor: 1, - ProtoMinor: 1, - Header: c.md.header, - } - - if req.Header == nil { - req.Header = http.Header{} - } - req.Header.Set("Proxy-Connection", "keep-alive") - - if user := c.options.Auth; user != nil { - u := user.Username() - p, _ := user.Password() - req.Header.Set("Proxy-Authorization", - "Basic "+base64.StdEncoding.EncodeToString([]byte(u+":"+p))) - } - - switch network { - case "tcp", "tcp4", "tcp6": - if _, ok := conn.(net.PacketConn); ok { - err := fmt.Errorf("tcp over udp is unsupported") - log.Error(err) - return nil, err - } - case "udp", "udp4", "udp6": - req.Header.Set("X-Gost-Protocol", "udp") - default: - err := fmt.Errorf("network %s is unsupported", network) - log.Error(err) - return nil, err - } - - if log.IsLevelEnabled(logger.DebugLevel) { - dump, _ := httputil.DumpRequest(req, false) - log.Debug(string(dump)) - } - - if c.md.connectTimeout > 0 { - conn.SetDeadline(time.Now().Add(c.md.connectTimeout)) - defer conn.SetDeadline(time.Time{}) - } - - req = req.WithContext(ctx) - if err := req.Write(conn); err != nil { - return nil, err - } - - resp, err := http.ReadResponse(bufio.NewReader(conn), req) - if err != nil { - return nil, err - } - // NOTE: the server may return `Transfer-Encoding: chunked` header, - // then the Content-Length of response will be unknown (-1), - // in this case, close body will be blocked, so we leave it untouched. - // defer resp.Body.Close() - - if log.IsLevelEnabled(logger.DebugLevel) { - dump, _ := httputil.DumpResponse(resp, false) - log.Debug(string(dump)) - } - - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("%s", resp.Status) - } - - if network == "udp" { - addr, _ := net.ResolveUDPAddr(network, address) - return socks.UDPTunClientConn(conn, addr), nil - } - - return conn, nil -} diff --git a/pkg/connector/http/metadata.go b/pkg/connector/http/metadata.go deleted file mode 100644 index 39040b8..0000000 --- a/pkg/connector/http/metadata.go +++ /dev/null @@ -1,32 +0,0 @@ -package http - -import ( - "net/http" - "time" - - mdata "github.com/go-gost/gost/v3/pkg/metadata" -) - -type metadata struct { - connectTimeout time.Duration - header http.Header -} - -func (c *httpConnector) parseMetadata(md mdata.Metadata) (err error) { - const ( - connectTimeout = "timeout" - header = "header" - ) - - c.md.connectTimeout = mdata.GetDuration(md, connectTimeout) - - if mm := mdata.GetStringMapString(md, header); len(mm) > 0 { - hd := http.Header{} - for k, v := range mm { - hd.Add(k, v) - } - c.md.header = hd - } - - return -} diff --git a/pkg/connector/option.go b/pkg/connector/option.go deleted file mode 100644 index 5d9e573..0000000 --- a/pkg/connector/option.go +++ /dev/null @@ -1,80 +0,0 @@ -package connector - -import ( - "crypto/tls" - "net/url" - "time" - - "github.com/go-gost/gost/v3/pkg/logger" -) - -type Options struct { - Auth *url.Userinfo - TLSConfig *tls.Config - Logger logger.Logger -} - -type Option func(opts *Options) - -func AuthOption(auth *url.Userinfo) Option { - return func(opts *Options) { - opts.Auth = auth - } -} - -func TLSConfigOption(tlsConfig *tls.Config) Option { - return func(opts *Options) { - opts.TLSConfig = tlsConfig - } -} - -func LoggerOption(logger logger.Logger) Option { - return func(opts *Options) { - opts.Logger = logger - } -} - -type ConnectOptions struct { -} - -type ConnectOption func(opts *ConnectOptions) - -type BindOptions struct { - Mux bool - Backlog int - UDPDataQueueSize int - UDPDataBufferSize int - UDPConnTTL time.Duration -} - -type BindOption func(opts *BindOptions) - -func MuxBindOption(mux bool) BindOption { - return func(opts *BindOptions) { - opts.Mux = mux - } -} - -func BacklogBindOption(backlog int) BindOption { - return func(opts *BindOptions) { - opts.Backlog = backlog - } -} - -func UDPDataQueueSizeBindOption(size int) BindOption { - return func(opts *BindOptions) { - opts.UDPDataQueueSize = size - } -} - -func UDPDataBufferSizeBindOption(size int) BindOption { - return func(opts *BindOptions) { - opts.UDPDataBufferSize = size - } -} - -func UDPConnTTLBindOption(ttl time.Duration) BindOption { - return func(opts *BindOptions) { - opts.UDPConnTTL = ttl - } -} diff --git a/pkg/connector/socks/v4/connector.go b/pkg/connector/socks/v4/connector.go deleted file mode 100644 index 2c7439c..0000000 --- a/pkg/connector/socks/v4/connector.go +++ /dev/null @@ -1,123 +0,0 @@ -package v4 - -import ( - "context" - "errors" - "fmt" - "net" - "strconv" - "time" - - "github.com/go-gost/gosocks4" - "github.com/go-gost/gost/v3/pkg/connector" - md "github.com/go-gost/gost/v3/pkg/metadata" - "github.com/go-gost/gost/v3/pkg/registry" -) - -func init() { - registry.ConnectorRegistry().Register("socks4", NewConnector) - registry.ConnectorRegistry().Register("socks4a", NewConnector) -} - -type socks4Connector struct { - md metadata - options connector.Options -} - -func NewConnector(opts ...connector.Option) connector.Connector { - options := connector.Options{} - for _, opt := range opts { - opt(&options) - } - - return &socks4Connector{ - options: options, - } -} - -func (c *socks4Connector) Init(md md.Metadata) (err error) { - return c.parseMetadata(md) -} - -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]any{ - "remote": conn.RemoteAddr().String(), - "local": conn.LocalAddr().String(), - "network": network, - "address": address, - }) - log.Infof("connect %s/%s", address, network) - - switch network { - case "tcp", "tcp4", "tcp6": - if _, ok := conn.(net.PacketConn); ok { - err := fmt.Errorf("tcp over udp is unsupported") - log.Error(err) - return nil, err - } - default: - err := fmt.Errorf("network %s is unsupported", network) - log.Error(err) - return nil, err - } - - var addr *gosocks4.Addr - - if c.md.disable4a { - taddr, err := net.ResolveTCPAddr("tcp4", address) - if err != nil { - log.Error("resolve: ", err) - return nil, err - } - if len(taddr.IP) == 0 { - taddr.IP = net.IPv4zero - } - addr = &gosocks4.Addr{ - Type: gosocks4.AddrIPv4, - Host: taddr.IP.String(), - Port: uint16(taddr.Port), - } - } else { - host, port, err := net.SplitHostPort(address) - if err != nil { - return nil, err - } - p, _ := strconv.Atoi(port) - addr = &gosocks4.Addr{ - Type: gosocks4.AddrDomain, - Host: host, - Port: uint16(p), - } - } - - if c.md.connectTimeout > 0 { - conn.SetDeadline(time.Now().Add(c.md.connectTimeout)) - defer conn.SetDeadline(time.Time{}) - } - - var userid []byte - if c.options.Auth != nil { - userid = []byte(c.options.Auth.Username()) - } - req := gosocks4.NewRequest(gosocks4.CmdConnect, addr, userid) - if err := req.Write(conn); err != nil { - log.Error(err) - return nil, err - } - log.Debug(req) - - reply, err := gosocks4.ReadReply(conn) - if err != nil { - log.Error(err) - return nil, err - } - log.Debug(reply) - - if reply.Code != gosocks4.Granted { - err = errors.New("host unreachable") - log.Error(err) - return nil, err - } - - return conn, nil -} diff --git a/pkg/connector/socks/v4/metadata.go b/pkg/connector/socks/v4/metadata.go deleted file mode 100644 index 0be7f33..0000000 --- a/pkg/connector/socks/v4/metadata.go +++ /dev/null @@ -1,24 +0,0 @@ -package v4 - -import ( - "time" - - mdata "github.com/go-gost/gost/v3/pkg/metadata" -) - -type metadata struct { - connectTimeout time.Duration - disable4a bool -} - -func (c *socks4Connector) parseMetadata(md mdata.Metadata) (err error) { - const ( - connectTimeout = "timeout" - disable4a = "disable4a" - ) - - c.md.connectTimeout = mdata.GetDuration(md, connectTimeout) - c.md.disable4a = mdata.GetBool(md, disable4a) - - return -} diff --git a/pkg/connector/socks/v5/bind.go b/pkg/connector/socks/v5/bind.go deleted file mode 100644 index 89714d3..0000000 --- a/pkg/connector/socks/v5/bind.go +++ /dev/null @@ -1,130 +0,0 @@ -package v5 - -import ( - "context" - "fmt" - "net" - - "github.com/go-gost/gosocks5" - "github.com/go-gost/gost/v3/pkg/common/util/udp" - "github.com/go-gost/gost/v3/pkg/connector" - "github.com/go-gost/gost/v3/pkg/internal/util/mux" - "github.com/go-gost/gost/v3/pkg/internal/util/socks" - "github.com/go-gost/gost/v3/pkg/logger" -) - -// Bind implements connector.Binder. -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]any{ - "remote": conn.RemoteAddr().String(), - "local": conn.LocalAddr().String(), - "network": network, - "address": address, - }) - log.Infof("bind on %s/%s", address, network) - - options := connector.BindOptions{} - for _, opt := range opts { - opt(&options) - } - - switch network { - case "tcp", "tcp4", "tcp6": - if options.Mux { - return c.muxBindTCP(ctx, conn, network, address, log) - } - return c.bindTCP(ctx, conn, network, address, log) - case "udp", "udp4", "udp6": - return c.bindUDP(ctx, conn, network, address, &options, log) - default: - err := fmt.Errorf("network %s is unsupported", network) - log.Error(err) - return nil, err - } -} - -func (c *socks5Connector) bindTCP(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) (net.Listener, error) { - laddr, err := c.bind(conn, gosocks5.CmdBind, network, address, log) - if err != nil { - return nil, err - } - - return &tcpListener{ - addr: laddr, - conn: conn, - logger: log, - }, nil -} - -func (c *socks5Connector) muxBindTCP(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) (net.Listener, error) { - laddr, err := c.bind(conn, socks.CmdMuxBind, network, address, log) - if err != nil { - return nil, err - } - - session, err := mux.ServerSession(conn) - if err != nil { - return nil, err - } - - return &tcpMuxListener{ - addr: laddr, - session: session, - logger: log, - }, nil -} - -func (c *socks5Connector) bindUDP(ctx context.Context, conn net.Conn, network, address string, opts *connector.BindOptions, log logger.Logger) (net.Listener, error) { - laddr, err := c.bind(conn, socks.CmdUDPTun, network, address, log) - if err != nil { - return nil, err - } - - ln := udp.NewListener( - socks.UDPTunClientPacketConn(conn), - laddr, - opts.Backlog, - opts.UDPDataQueueSize, opts.UDPDataBufferSize, - opts.UDPConnTTL, - log) - - return ln, nil -} - -func (l *socks5Connector) bind(conn net.Conn, cmd uint8, network, address string, log logger.Logger) (net.Addr, error) { - addr := gosocks5.Addr{} - addr.ParseFrom(address) - req := gosocks5.NewRequest(cmd, &addr) - if err := req.Write(conn); err != nil { - return nil, err - } - log.Debug(req) - - // first reply, bind status - reply, err := gosocks5.ReadReply(conn) - if err != nil { - return nil, err - } - - log.Debug(reply) - - if reply.Rep != gosocks5.Succeeded { - return nil, fmt.Errorf("bind on %s/%s failed", address, network) - } - - var baddr net.Addr - switch network { - case "tcp", "tcp4", "tcp6": - baddr, err = net.ResolveTCPAddr(network, reply.Addr.String()) - case "udp", "udp4", "udp6": - baddr, err = net.ResolveUDPAddr(network, reply.Addr.String()) - default: - err = fmt.Errorf("unknown network %s", network) - } - if err != nil { - return nil, err - } - log.Debugf("bind on %s/%s OK", baddr, baddr.Network()) - - return baddr, nil -} diff --git a/pkg/connector/socks/v5/conn.go b/pkg/connector/socks/v5/conn.go deleted file mode 100644 index d11f3b5..0000000 --- a/pkg/connector/socks/v5/conn.go +++ /dev/null @@ -1,17 +0,0 @@ -package v5 - -import "net" - -type bindConn struct { - net.Conn - localAddr net.Addr - remoteAddr net.Addr -} - -func (c *bindConn) LocalAddr() net.Addr { - return c.localAddr -} - -func (c *bindConn) RemoteAddr() net.Addr { - return c.remoteAddr -} diff --git a/pkg/connector/socks/v5/connector.go b/pkg/connector/socks/v5/connector.go deleted file mode 100644 index 62b409b..0000000 --- a/pkg/connector/socks/v5/connector.go +++ /dev/null @@ -1,173 +0,0 @@ -package v5 - -import ( - "context" - "crypto/tls" - "errors" - "fmt" - "net" - "time" - - "github.com/go-gost/gosocks5" - "github.com/go-gost/gost/v3/pkg/connector" - "github.com/go-gost/gost/v3/pkg/internal/util/socks" - "github.com/go-gost/gost/v3/pkg/logger" - md "github.com/go-gost/gost/v3/pkg/metadata" - "github.com/go-gost/gost/v3/pkg/registry" -) - -func init() { - registry.ConnectorRegistry().Register("socks5", NewConnector) - registry.ConnectorRegistry().Register("socks", NewConnector) -} - -type socks5Connector struct { - selector gosocks5.Selector - md metadata - options connector.Options -} - -func NewConnector(opts ...connector.Option) connector.Connector { - options := connector.Options{} - for _, opt := range opts { - opt(&options) - } - - return &socks5Connector{ - options: options, - } -} - -func (c *socks5Connector) Init(md md.Metadata) (err error) { - if err = c.parseMetadata(md); err != nil { - return - } - - selector := &clientSelector{ - methods: []uint8{ - gosocks5.MethodNoAuth, - gosocks5.MethodUserPass, - }, - User: c.options.Auth, - TLSConfig: c.options.TLSConfig, - logger: c.options.Logger, - } - if !c.md.noTLS { - selector.methods = append(selector.methods, socks.MethodTLS) - if selector.TLSConfig == nil { - selector.TLSConfig = &tls.Config{ - InsecureSkipVerify: true, - } - } - } - c.selector = selector - - return -} - -// Handshake implements connector.Handshaker. -func (c *socks5Connector) Handshake(ctx context.Context, conn net.Conn) (net.Conn, error) { - log := c.options.Logger.WithFields(map[string]any{ - "remote": conn.RemoteAddr().String(), - "local": conn.LocalAddr().String(), - }) - - if c.md.connectTimeout > 0 { - conn.SetDeadline(time.Now().Add(c.md.connectTimeout)) - defer conn.SetDeadline(time.Time{}) - } - - cc := gosocks5.ClientConn(conn, c.selector) - if err := cc.Handleshake(); err != nil { - log.Error(err) - return nil, err - } - - return cc, nil -} - -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]any{ - "remote": conn.RemoteAddr().String(), - "local": conn.LocalAddr().String(), - "network": network, - "address": address, - }) - log.Infof("connect %s/%s", address, network) - - if c.md.connectTimeout > 0 { - conn.SetDeadline(time.Now().Add(c.md.connectTimeout)) - defer conn.SetDeadline(time.Time{}) - } - - switch network { - case "udp", "udp4", "udp6": - return c.connectUDP(ctx, conn, network, address, log) - case "tcp", "tcp4", "tcp6": - if _, ok := conn.(net.PacketConn); ok { - err := fmt.Errorf("tcp over udp is unsupported") - log.Error(err) - return nil, err - } - default: - err := fmt.Errorf("network %s is unsupported", network) - log.Error(err) - return nil, err - } - - addr := gosocks5.Addr{} - if err := addr.ParseFrom(address); err != nil { - log.Error(err) - return nil, err - } - - req := gosocks5.NewRequest(gosocks5.CmdConnect, &addr) - if err := req.Write(conn); err != nil { - log.Error(err) - return nil, err - } - log.Debug(req) - - reply, err := gosocks5.ReadReply(conn) - if err != nil { - log.Error(err) - return nil, err - } - log.Debug(reply) - - if reply.Rep != gosocks5.Succeeded { - err = errors.New("host unreachable") - log.Error(err) - return nil, err - } - - return conn, nil -} - -func (c *socks5Connector) connectUDP(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) (net.Conn, error) { - addr, err := net.ResolveUDPAddr(network, address) - if err != nil { - log.Error(err) - return nil, err - } - - req := gosocks5.NewRequest(socks.CmdUDPTun, nil) - if err := req.Write(conn); err != nil { - log.Error(err) - return nil, err - } - log.Debug(req) - - reply, err := gosocks5.ReadReply(conn) - if err != nil { - log.Error(err) - return nil, err - } - log.Debug(reply) - - if reply.Rep != gosocks5.Succeeded { - return nil, errors.New("get socks5 UDP tunnel failure") - } - - return socks.UDPTunClientConn(conn, addr), nil -} diff --git a/pkg/connector/socks/v5/listener.go b/pkg/connector/socks/v5/listener.go deleted file mode 100644 index 6409a40..0000000 --- a/pkg/connector/socks/v5/listener.go +++ /dev/null @@ -1,102 +0,0 @@ -package v5 - -import ( - "fmt" - "net" - - "github.com/go-gost/gosocks5" - "github.com/go-gost/gost/v3/pkg/internal/util/mux" - "github.com/go-gost/gost/v3/pkg/logger" -) - -type tcpListener struct { - addr net.Addr - conn net.Conn - logger logger.Logger -} - -func (p *tcpListener) Accept() (net.Conn, error) { - // second reply, peer connected - rep, err := gosocks5.ReadReply(p.conn) - if err != nil { - return nil, err - } - p.logger.Debug(rep) - - if rep.Rep != gosocks5.Succeeded { - return nil, fmt.Errorf("peer connect failed") - } - - raddr, err := net.ResolveTCPAddr("tcp", rep.Addr.String()) - if err != nil { - return nil, err - } - - return &bindConn{ - Conn: p.conn, - localAddr: p.addr, - remoteAddr: raddr, - }, nil -} - -func (p *tcpListener) Addr() net.Addr { - return p.addr -} - -func (p *tcpListener) Close() error { - return p.conn.Close() -} - -type tcpMuxListener struct { - addr net.Addr - session *mux.Session - logger logger.Logger -} - -func (p *tcpMuxListener) Accept() (net.Conn, error) { - cc, err := p.session.Accept() - if err != nil { - return nil, err - } - - conn, err := p.getPeerConn(cc) - if err != nil { - cc.Close() - return nil, err - } - - return conn, nil -} - -func (p *tcpMuxListener) getPeerConn(conn net.Conn) (net.Conn, error) { - // second reply, peer connected - rep, err := gosocks5.ReadReply(conn) - if err != nil { - return nil, err - } - p.logger.Debug(rep) - - if rep.Rep != gosocks5.Succeeded { - err = fmt.Errorf("peer connect failed") - return nil, err - } - - raddr, err := net.ResolveTCPAddr("tcp", rep.Addr.String()) - if err != nil { - return nil, err - } - - return &bindConn{ - Conn: conn, - localAddr: p.addr, - remoteAddr: raddr, - }, nil -} - -func (p *tcpMuxListener) Addr() net.Addr { - return p.addr -} - -func (p *tcpMuxListener) Close() error { - return p.session.Close() -} diff --git a/pkg/connector/socks/v5/metadata.go b/pkg/connector/socks/v5/metadata.go deleted file mode 100644 index b42af27..0000000 --- a/pkg/connector/socks/v5/metadata.go +++ /dev/null @@ -1,24 +0,0 @@ -package v5 - -import ( - "time" - - mdata "github.com/go-gost/gost/v3/pkg/metadata" -) - -type metadata struct { - connectTimeout time.Duration - noTLS bool -} - -func (c *socks5Connector) parseMetadata(md mdata.Metadata) (err error) { - const ( - connectTimeout = "timeout" - noTLS = "notls" - ) - - c.md.connectTimeout = mdata.GetDuration(md, connectTimeout) - c.md.noTLS = mdata.GetBool(md, noTLS) - - return -} diff --git a/pkg/connector/socks/v5/selector.go b/pkg/connector/socks/v5/selector.go deleted file mode 100644 index f531301..0000000 --- a/pkg/connector/socks/v5/selector.go +++ /dev/null @@ -1,73 +0,0 @@ -package v5 - -import ( - "crypto/tls" - "net" - "net/url" - - "github.com/go-gost/gosocks5" - "github.com/go-gost/gost/v3/pkg/internal/util/socks" - "github.com/go-gost/gost/v3/pkg/logger" -) - -type clientSelector struct { - methods []uint8 - User *url.Userinfo - TLSConfig *tls.Config - logger logger.Logger -} - -func (s *clientSelector) Methods() []uint8 { - s.logger.Debug("methods: ", s.methods) - return s.methods -} - -func (s *clientSelector) AddMethod(methods ...uint8) { - s.methods = append(s.methods, methods...) -} - -func (s *clientSelector) Select(methods ...uint8) (method uint8) { - return -} - -func (s *clientSelector) OnSelected(method uint8, conn net.Conn) (net.Conn, error) { - s.logger.Debug("method selected: ", method) - - switch method { - case socks.MethodTLS: - conn = tls.Client(conn, s.TLSConfig) - - case gosocks5.MethodUserPass, socks.MethodTLSAuth: - if method == socks.MethodTLSAuth { - conn = tls.Client(conn, s.TLSConfig) - } - - var username, password string - if s.User != nil { - username = s.User.Username() - password, _ = s.User.Password() - } - - req := gosocks5.NewUserPassRequest(gosocks5.UserPassVer, username, password) - if err := req.Write(conn); err != nil { - s.logger.Error(err) - return nil, err - } - s.logger.Debug(req) - - resp, err := gosocks5.ReadUserPassResponse(conn) - if err != nil { - s.logger.Error(err) - return nil, err - } - s.logger.Debug(resp) - - if resp.Status != gosocks5.Succeeded { - return nil, gosocks5.ErrAuthFailure - } - case gosocks5.MethodNoAcceptable: - return nil, gosocks5.ErrBadMethod - } - - return conn, nil -} diff --git a/pkg/dialer/dialer.go b/pkg/dialer/dialer.go deleted file mode 100644 index 1d96439..0000000 --- a/pkg/dialer/dialer.go +++ /dev/null @@ -1,22 +0,0 @@ -package dialer - -import ( - "context" - "net" - - "github.com/go-gost/gost/v3/pkg/metadata" -) - -// Transporter is responsible for dialing to the proxy server. -type Dialer interface { - Init(metadata.Metadata) error - Dial(ctx context.Context, addr string, opts ...DialOption) (net.Conn, error) -} - -type Handshaker interface { - Handshake(ctx context.Context, conn net.Conn, opts ...HandshakeOption) (net.Conn, error) -} - -type Multiplexer interface { - Multiplex() bool -} diff --git a/pkg/dialer/option.go b/pkg/dialer/option.go deleted file mode 100644 index d22657a..0000000 --- a/pkg/dialer/option.go +++ /dev/null @@ -1,66 +0,0 @@ -package dialer - -import ( - "crypto/tls" - "net/url" - - "github.com/go-gost/gost/v3/pkg/common/net/dialer" - "github.com/go-gost/gost/v3/pkg/logger" -) - -type Options struct { - Auth *url.Userinfo - TLSConfig *tls.Config - Logger logger.Logger -} - -type Option func(opts *Options) - -func AuthOption(auth *url.Userinfo) Option { - return func(opts *Options) { - opts.Auth = auth - } -} - -func TLSConfigOption(tlsConfig *tls.Config) Option { - return func(opts *Options) { - opts.TLSConfig = tlsConfig - } -} - -func LoggerOption(logger logger.Logger) Option { - return func(opts *Options) { - opts.Logger = logger - } -} - -type DialOptions struct { - Host string - NetDialer *dialer.NetDialer -} - -type DialOption func(opts *DialOptions) - -func HostDialOption(host string) DialOption { - return func(opts *DialOptions) { - opts.Host = host - } -} - -func NetDialerDialOption(netd *dialer.NetDialer) DialOption { - return func(opts *DialOptions) { - opts.NetDialer = netd - } -} - -type HandshakeOptions struct { - Addr string -} - -type HandshakeOption func(opts *HandshakeOptions) - -func AddrHandshakeOption(addr string) HandshakeOption { - return func(opts *HandshakeOptions) { - opts.Addr = addr - } -} diff --git a/pkg/dialer/tcp/dialer.go b/pkg/dialer/tcp/dialer.go deleted file mode 100644 index 7c26c6b..0000000 --- a/pkg/dialer/tcp/dialer.go +++ /dev/null @@ -1,48 +0,0 @@ -package tcp - -import ( - "context" - "net" - - "github.com/go-gost/gost/v3/pkg/dialer" - "github.com/go-gost/gost/v3/pkg/logger" - md "github.com/go-gost/gost/v3/pkg/metadata" - "github.com/go-gost/gost/v3/pkg/registry" -) - -func init() { - registry.DialerRegistry().Register("tcp", NewDialer) -} - -type tcpDialer struct { - md metadata - logger logger.Logger -} - -func NewDialer(opts ...dialer.Option) dialer.Dialer { - options := &dialer.Options{} - for _, opt := range opts { - opt(options) - } - - return &tcpDialer{ - logger: options.Logger, - } -} - -func (d *tcpDialer) Init(md md.Metadata) (err error) { - return d.parseMetadata(md) -} - -func (d *tcpDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (net.Conn, error) { - var options dialer.DialOptions - for _, opt := range opts { - opt(&options) - } - - conn, err := options.NetDialer.Dial(ctx, "tcp", addr) - if err != nil { - d.logger.Error(err) - } - return conn, err -} diff --git a/pkg/dialer/tcp/metadata.go b/pkg/dialer/tcp/metadata.go deleted file mode 100644 index b87739a..0000000 --- a/pkg/dialer/tcp/metadata.go +++ /dev/null @@ -1,23 +0,0 @@ -package tcp - -import ( - "time" - - md "github.com/go-gost/gost/v3/pkg/metadata" -) - -const ( - dialTimeout = "dialTimeout" -) - -const ( - defaultDialTimeout = 5 * time.Second -) - -type metadata struct { - dialTimeout time.Duration -} - -func (d *tcpDialer) parseMetadata(md md.Metadata) (err error) { - return -} diff --git a/pkg/dialer/tls/dialer.go b/pkg/dialer/tls/dialer.go deleted file mode 100644 index 28b43cc..0000000 --- a/pkg/dialer/tls/dialer.go +++ /dev/null @@ -1,68 +0,0 @@ -package tls - -import ( - "context" - "crypto/tls" - "net" - "time" - - "github.com/go-gost/gost/v3/pkg/dialer" - "github.com/go-gost/gost/v3/pkg/logger" - md "github.com/go-gost/gost/v3/pkg/metadata" - "github.com/go-gost/gost/v3/pkg/registry" -) - -func init() { - registry.DialerRegistry().Register("tls", NewDialer) -} - -type tlsDialer struct { - md metadata - logger logger.Logger - options dialer.Options -} - -func NewDialer(opts ...dialer.Option) dialer.Dialer { - options := dialer.Options{} - for _, opt := range opts { - opt(&options) - } - - return &tlsDialer{ - logger: options.Logger, - options: options, - } -} - -func (d *tlsDialer) Init(md md.Metadata) (err error) { - return d.parseMetadata(md) -} - -func (d *tlsDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (net.Conn, error) { - var options dialer.DialOptions - for _, opt := range opts { - opt(&options) - } - - conn, err := options.NetDialer.Dial(ctx, "tcp", addr) - if err != nil { - d.logger.Error(err) - } - return conn, err -} - -// Handshake implements dialer.Handshaker -func (d *tlsDialer) Handshake(ctx context.Context, conn net.Conn, options ...dialer.HandshakeOption) (net.Conn, error) { - if d.md.handshakeTimeout > 0 { - conn.SetDeadline(time.Now().Add(d.md.handshakeTimeout)) - defer conn.SetDeadline(time.Time{}) - } - - tlsConn := tls.Client(conn, d.options.TLSConfig) - if err := tlsConn.HandshakeContext(ctx); err != nil { - conn.Close() - return nil, err - } - - return tlsConn, nil -} diff --git a/pkg/dialer/tls/metadata.go b/pkg/dialer/tls/metadata.go deleted file mode 100644 index 9ddc1f6..0000000 --- a/pkg/dialer/tls/metadata.go +++ /dev/null @@ -1,21 +0,0 @@ -package tls - -import ( - "time" - - mdata "github.com/go-gost/gost/v3/pkg/metadata" -) - -type metadata struct { - handshakeTimeout time.Duration -} - -func (d *tlsDialer) parseMetadata(md mdata.Metadata) (err error) { - const ( - handshakeTimeout = "handshakeTimeout" - ) - - d.md.handshakeTimeout = mdata.GetDuration(md, handshakeTimeout) - - return -} diff --git a/pkg/dialer/udp/conn.go b/pkg/dialer/udp/conn.go deleted file mode 100644 index 33e962d..0000000 --- a/pkg/dialer/udp/conn.go +++ /dev/null @@ -1,17 +0,0 @@ -package udp - -import "net" - -type conn struct { - *net.UDPConn -} - -func (c *conn) WriteTo(b []byte, addr net.Addr) (int, error) { - return c.UDPConn.Write(b) -} - -func (c *conn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { - n, err = c.UDPConn.Read(b) - addr = c.RemoteAddr() - return -} diff --git a/pkg/dialer/udp/dialer.go b/pkg/dialer/udp/dialer.go deleted file mode 100644 index 98869e7..0000000 --- a/pkg/dialer/udp/dialer.go +++ /dev/null @@ -1,50 +0,0 @@ -package udp - -import ( - "context" - "net" - - "github.com/go-gost/gost/v3/pkg/dialer" - "github.com/go-gost/gost/v3/pkg/logger" - md "github.com/go-gost/gost/v3/pkg/metadata" - "github.com/go-gost/gost/v3/pkg/registry" -) - -func init() { - registry.DialerRegistry().Register("udp", NewDialer) -} - -type udpDialer struct { - md metadata - logger logger.Logger -} - -func NewDialer(opts ...dialer.Option) dialer.Dialer { - options := &dialer.Options{} - for _, opt := range opts { - opt(options) - } - - return &udpDialer{ - logger: options.Logger, - } -} - -func (d *udpDialer) Init(md md.Metadata) (err error) { - return d.parseMetadata(md) -} - -func (d *udpDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (net.Conn, error) { - var options dialer.DialOptions - for _, opt := range opts { - opt(&options) - } - - c, err := options.NetDialer.Dial(ctx, "udp", addr) - if err != nil { - return nil, err - } - return &conn{ - UDPConn: c.(*net.UDPConn), - }, nil -} diff --git a/pkg/dialer/udp/metadata.go b/pkg/dialer/udp/metadata.go deleted file mode 100644 index 4e96c3c..0000000 --- a/pkg/dialer/udp/metadata.go +++ /dev/null @@ -1,23 +0,0 @@ -package udp - -import ( - "time" - - md "github.com/go-gost/gost/v3/pkg/metadata" -) - -const ( - dialTimeout = "dialTimeout" -) - -const ( - defaultDialTimeout = 5 * time.Second -) - -type metadata struct { - dialTimeout time.Duration -} - -func (d *udpDialer) parseMetadata(md md.Metadata) (err error) { - return -} diff --git a/pkg/handler/auto/handler.go b/pkg/handler/auto/handler.go deleted file mode 100644 index e13a487..0000000 --- a/pkg/handler/auto/handler.go +++ /dev/null @@ -1,115 +0,0 @@ -package auto - -import ( - "bufio" - "context" - "net" - "time" - - "github.com/go-gost/gosocks4" - "github.com/go-gost/gosocks5" - netpkg "github.com/go-gost/gost/v3/pkg/common/net" - "github.com/go-gost/gost/v3/pkg/handler" - md "github.com/go-gost/gost/v3/pkg/metadata" - "github.com/go-gost/gost/v3/pkg/registry" -) - -func init() { - registry.HandlerRegistry().Register("auto", NewHandler) -} - -type autoHandler struct { - httpHandler handler.Handler - socks4Handler handler.Handler - socks5Handler handler.Handler - options handler.Options -} - -func NewHandler(opts ...handler.Option) handler.Handler { - options := handler.Options{} - for _, opt := range opts { - opt(&options) - } - - h := &autoHandler{ - options: options, - } - - if f := registry.HandlerRegistry().Get("http"); f != nil { - v := append(opts, - handler.LoggerOption(options.Logger.WithFields(map[string]any{"type": "http"}))) - h.httpHandler = f(v...) - } - if f := registry.HandlerRegistry().Get("socks4"); f != nil { - v := append(opts, - handler.LoggerOption(options.Logger.WithFields(map[string]any{"type": "socks4"}))) - h.socks4Handler = f(v...) - } - if f := registry.HandlerRegistry().Get("socks5"); f != nil { - v := append(opts, - handler.LoggerOption(options.Logger.WithFields(map[string]any{"type": "socks5"}))) - h.socks5Handler = f(v...) - } - - return h -} - -func (h *autoHandler) Init(md md.Metadata) error { - if h.httpHandler != nil { - if err := h.httpHandler.Init(md); err != nil { - return err - } - } - if h.socks4Handler != nil { - if err := h.socks4Handler.Init(md); err != nil { - return err - } - } - if h.socks5Handler != nil { - if err := h.socks5Handler.Init(md); err != nil { - return err - } - } - - return nil -} - -func (h *autoHandler) Handle(ctx context.Context, conn net.Conn, opts ...handler.HandleOption) error { - log := h.options.Logger.WithFields(map[string]any{ - "remote": conn.RemoteAddr().String(), - "local": conn.LocalAddr().String(), - }) - - start := time.Now() - log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr()) - defer func() { - log.WithFields(map[string]any{ - "duration": time.Since(start), - }).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr()) - }() - - br := bufio.NewReader(conn) - b, err := br.Peek(1) - if err != nil { - log.Error(err) - conn.Close() - return err - } - - conn = netpkg.NewBufferReaderConn(conn, br) - switch b[0] { - case gosocks4.Ver4: // socks4 - if h.socks4Handler != nil { - return h.socks4Handler.Handle(ctx, conn) - } - case gosocks5.Ver5: // socks5 - if h.socks5Handler != nil { - return h.socks5Handler.Handle(ctx, conn) - } - default: // http - if h.httpHandler != nil { - return h.httpHandler.Handle(ctx, conn) - } - } - return nil -} diff --git a/pkg/handler/forward/local/handler.go b/pkg/handler/forward/local/handler.go deleted file mode 100644 index a6bc3b1..0000000 --- a/pkg/handler/forward/local/handler.go +++ /dev/null @@ -1,117 +0,0 @@ -package local - -import ( - "context" - "errors" - "fmt" - "net" - "time" - - "github.com/go-gost/gost/v3/pkg/chain" - netpkg "github.com/go-gost/gost/v3/pkg/common/net" - "github.com/go-gost/gost/v3/pkg/handler" - md "github.com/go-gost/gost/v3/pkg/metadata" - "github.com/go-gost/gost/v3/pkg/registry" -) - -func init() { - registry.HandlerRegistry().Register("tcp", NewHandler) - registry.HandlerRegistry().Register("udp", NewHandler) - registry.HandlerRegistry().Register("forward", NewHandler) -} - -type forwardHandler struct { - group *chain.NodeGroup - router *chain.Router - md metadata - options handler.Options -} - -func NewHandler(opts ...handler.Option) handler.Handler { - options := handler.Options{} - for _, opt := range opts { - opt(&options) - } - - return &forwardHandler{ - options: options, - } -} - -func (h *forwardHandler) Init(md md.Metadata) (err error) { - if err = h.parseMetadata(md); err != nil { - return - } - - if h.group == nil { - // dummy node used by relay connector. - h.group = chain.NewNodeGroup(&chain.Node{Name: "dummy", Addr: ":0"}) - } - - h.router = h.options.Router - if h.router == nil { - h.router = (&chain.Router{}).WithLogger(h.options.Logger) - } - - return -} - -// Forward implements handler.Forwarder. -func (h *forwardHandler) Forward(group *chain.NodeGroup) { - h.group = group -} - -func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn, opts ...handler.HandleOption) error { - defer conn.Close() - - start := time.Now() - log := h.options.Logger.WithFields(map[string]any{ - "remote": conn.RemoteAddr().String(), - "local": conn.LocalAddr().String(), - }) - - log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr()) - defer func() { - log.WithFields(map[string]any{ - "duration": time.Since(start), - }).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr()) - }() - - target := h.group.Next() - if target == nil { - err := errors.New("target not available") - log.Error(err) - return err - } - - network := "tcp" - if _, ok := conn.(net.PacketConn); ok { - network = "udp" - } - - log = log.WithFields(map[string]any{ - "dst": fmt.Sprintf("%s/%s", target.Addr, network), - }) - - log.Infof("%s >> %s", conn.RemoteAddr(), target.Addr) - - cc, err := h.router.Dial(ctx, network, target.Addr) - if err != nil { - log.Error(err) - // TODO: the router itself may be failed due to the failed node in the router, - // the dead marker may be a wrong operation. - target.Marker.Mark() - return err - } - defer cc.Close() - target.Marker.Reset() - - t := time.Now() - log.Infof("%s <-> %s", conn.RemoteAddr(), target.Addr) - netpkg.Transport(conn, cc) - log.WithFields(map[string]any{ - "duration": time.Since(t), - }).Infof("%s >-< %s", conn.RemoteAddr(), target.Addr) - - return nil -} diff --git a/pkg/handler/forward/local/metadata.go b/pkg/handler/forward/local/metadata.go deleted file mode 100644 index 6be9bc0..0000000 --- a/pkg/handler/forward/local/metadata.go +++ /dev/null @@ -1,20 +0,0 @@ -package local - -import ( - "time" - - mdata "github.com/go-gost/gost/v3/pkg/metadata" -) - -type metadata struct { - readTimeout time.Duration -} - -func (h *forwardHandler) parseMetadata(md mdata.Metadata) (err error) { - const ( - readTimeout = "readTimeout" - ) - - h.md.readTimeout = mdata.GetDuration(md, readTimeout) - return -} diff --git a/pkg/handler/forward/remote/handler.go b/pkg/handler/forward/remote/handler.go deleted file mode 100644 index 676e25f..0000000 --- a/pkg/handler/forward/remote/handler.go +++ /dev/null @@ -1,111 +0,0 @@ -package remote - -import ( - "context" - "errors" - "fmt" - "net" - "time" - - "github.com/go-gost/gost/v3/pkg/chain" - netpkg "github.com/go-gost/gost/v3/pkg/common/net" - "github.com/go-gost/gost/v3/pkg/handler" - md "github.com/go-gost/gost/v3/pkg/metadata" - "github.com/go-gost/gost/v3/pkg/registry" -) - -func init() { - registry.HandlerRegistry().Register("rtcp", NewHandler) - registry.HandlerRegistry().Register("rudp", NewHandler) -} - -type forwardHandler struct { - group *chain.NodeGroup - router *chain.Router - md metadata - options handler.Options -} - -func NewHandler(opts ...handler.Option) handler.Handler { - options := handler.Options{} - for _, opt := range opts { - opt(&options) - } - - return &forwardHandler{ - options: options, - } -} - -func (h *forwardHandler) Init(md md.Metadata) (err error) { - if err = h.parseMetadata(md); err != nil { - return - } - - h.router = h.options.Router - if h.router == nil { - h.router = (&chain.Router{}).WithLogger(h.options.Logger) - } - - return -} - -// Forward implements handler.Forwarder. -func (h *forwardHandler) Forward(group *chain.NodeGroup) { - h.group = group -} - -func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn, opts ...handler.HandleOption) error { - defer conn.Close() - - start := time.Now() - log := h.options.Logger.WithFields(map[string]any{ - "remote": conn.RemoteAddr().String(), - "local": conn.LocalAddr().String(), - }) - - log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr()) - defer func() { - log.WithFields(map[string]any{ - "duration": time.Since(start), - }).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr()) - }() - - target := h.group.Next() - if target == nil { - err := errors.New("target not available") - log.Error(err) - return err - } - - network := "tcp" - if _, ok := conn.(net.PacketConn); ok { - network = "udp" - } - - log = log.WithFields(map[string]any{ - "dst": fmt.Sprintf("%s/%s", target.Addr, network), - }) - - log.Infof("%s >> %s", conn.RemoteAddr(), target.Addr) - - cc, err := h.router.Dial(ctx, network, target.Addr) - if err != nil { - log.Error(err) - // TODO: the router itself may be failed due to the failed node in the router, - // the dead marker may be a wrong operation. - target.Marker.Mark() - return err - } - defer cc.Close() - target.Marker.Reset() - - t := time.Now() - log.Infof("%s <-> %s", conn.RemoteAddr(), target.Addr) - netpkg.Transport(conn, cc) - log.WithFields(map[string]any{ - "duration": time.Since(t), - }).Infof("%s >-< %s", conn.RemoteAddr(), target.Addr) - - return nil -} diff --git a/pkg/handler/forward/remote/metadata.go b/pkg/handler/forward/remote/metadata.go deleted file mode 100644 index b2d00e7..0000000 --- a/pkg/handler/forward/remote/metadata.go +++ /dev/null @@ -1,20 +0,0 @@ -package remote - -import ( - "time" - - mdata "github.com/go-gost/gost/v3/pkg/metadata" -) - -type metadata struct { - readTimeout time.Duration -} - -func (h *forwardHandler) parseMetadata(md mdata.Metadata) (err error) { - const ( - readTimeout = "readTimeout" - ) - - h.md.readTimeout = mdata.GetDuration(md, readTimeout) - return -} diff --git a/pkg/handler/handler.go b/pkg/handler/handler.go deleted file mode 100644 index 4a34985..0000000 --- a/pkg/handler/handler.go +++ /dev/null @@ -1,18 +0,0 @@ -package handler - -import ( - "context" - "net" - - "github.com/go-gost/gost/v3/pkg/chain" - "github.com/go-gost/gost/v3/pkg/metadata" -) - -type Handler interface { - Init(metadata.Metadata) error - Handle(context.Context, net.Conn, ...HandleOption) error -} - -type Forwarder interface { - Forward(*chain.NodeGroup) -} diff --git a/pkg/handler/http/handler.go b/pkg/handler/http/handler.go deleted file mode 100644 index dd829bb..0000000 --- a/pkg/handler/http/handler.go +++ /dev/null @@ -1,337 +0,0 @@ -package http - -import ( - "bufio" - "context" - "encoding/base64" - "encoding/binary" - "errors" - "hash/crc32" - "net" - "net/http" - "net/http/httputil" - "os" - "strconv" - "strings" - "time" - - "github.com/asaskevich/govalidator" - "github.com/go-gost/gost/v3/pkg/chain" - netpkg "github.com/go-gost/gost/v3/pkg/common/net" - "github.com/go-gost/gost/v3/pkg/handler" - "github.com/go-gost/gost/v3/pkg/logger" - md "github.com/go-gost/gost/v3/pkg/metadata" - "github.com/go-gost/gost/v3/pkg/registry" -) - -func init() { - registry.HandlerRegistry().Register("http", NewHandler) -} - -type httpHandler struct { - router *chain.Router - md metadata - options handler.Options -} - -func NewHandler(opts ...handler.Option) handler.Handler { - options := handler.Options{} - for _, opt := range opts { - opt(&options) - } - - return &httpHandler{ - options: options, - } -} - -func (h *httpHandler) Init(md md.Metadata) error { - if err := h.parseMetadata(md); err != nil { - return err - } - - h.router = h.options.Router - if h.router == nil { - h.router = (&chain.Router{}).WithLogger(h.options.Logger) - } - - return nil -} - -func (h *httpHandler) Handle(ctx context.Context, conn net.Conn, opts ...handler.HandleOption) error { - defer conn.Close() - - start := time.Now() - log := h.options.Logger.WithFields(map[string]any{ - "remote": conn.RemoteAddr().String(), - "local": conn.LocalAddr().String(), - }) - log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr()) - defer func() { - log.WithFields(map[string]any{ - "duration": time.Since(start), - }).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr()) - }() - - req, err := http.ReadRequest(bufio.NewReader(conn)) - if err != nil { - log.Error(err) - return err - } - defer req.Body.Close() - - return h.handleRequest(ctx, conn, req, log) -} - -func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *http.Request, log logger.Logger) error { - if h.md.sni && !req.URL.IsAbs() && govalidator.IsDNSName(req.Host) { - req.URL.Scheme = "http" - } - - network := req.Header.Get("X-Gost-Protocol") - if network != "udp" { - network = "tcp" - } - - // Try to get the actual host. - // Compatible with GOST 2.x. - if v := req.Header.Get("Gost-Target"); v != "" { - if h, err := h.decodeServerName(v); err == nil { - req.Host = h - } - } - req.Header.Del("Gost-Target") - - if v := req.Header.Get("X-Gost-Target"); v != "" { - if h, err := h.decodeServerName(v); err == nil { - req.Host = h - } - } - req.Header.Del("X-Gost-Target") - - addr := req.Host - if _, port, _ := net.SplitHostPort(addr); port == "" { - addr = net.JoinHostPort(addr, "80") - } - - fields := map[string]any{ - "dst": addr, - } - if u, _, _ := h.basicProxyAuth(req.Header.Get("Proxy-Authorization"), log); u != "" { - fields["user"] = u - } - log = log.WithFields(fields) - - if log.IsLevelEnabled(logger.DebugLevel) { - dump, _ := httputil.DumpRequest(req, false) - log.Debug(string(dump)) - } - log.Infof("%s >> %s", conn.RemoteAddr(), addr) - - resp := &http.Response{ - ProtoMajor: 1, - ProtoMinor: 1, - Header: h.md.header, - } - if resp.Header == nil { - resp.Header = http.Header{} - } - - if h.options.Bypass != nil && h.options.Bypass.Contains(addr) { - resp.StatusCode = http.StatusForbidden - - if log.IsLevelEnabled(logger.DebugLevel) { - dump, _ := httputil.DumpResponse(resp, false) - log.Debug(string(dump)) - } - log.Info("bypass: ", addr) - - return resp.Write(conn) - } - - if !h.authenticate(conn, req, resp, log) { - return nil - } - - if network == "udp" { - return h.handleUDP(ctx, conn, network, req.Host, log) - } - - if req.Method == "PRI" || - (req.Method != http.MethodConnect && req.URL.Scheme != "http") { - resp.StatusCode = http.StatusBadRequest - - if log.IsLevelEnabled(logger.DebugLevel) { - dump, _ := httputil.DumpResponse(resp, false) - log.Debug(string(dump)) - } - - return resp.Write(conn) - } - - req.Header.Del("Proxy-Authorization") - - cc, err := h.router.Dial(ctx, network, addr) - if err != nil { - resp.StatusCode = http.StatusServiceUnavailable - - if log.IsLevelEnabled(logger.DebugLevel) { - dump, _ := httputil.DumpResponse(resp, false) - log.Debug(string(dump)) - } - resp.Write(conn) - return err - } - defer cc.Close() - - if req.Method == http.MethodConnect { - resp.StatusCode = http.StatusOK - resp.Status = "200 Connection established" - - if log.IsLevelEnabled(logger.DebugLevel) { - dump, _ := httputil.DumpResponse(resp, false) - log.Debug(string(dump)) - } - if err = resp.Write(conn); err != nil { - log.Error(err) - return err - } - } else { - req.Header.Del("Proxy-Connection") - if err = req.Write(cc); err != nil { - log.Error(err) - return err - } - } - - start := time.Now() - log.Infof("%s <-> %s", conn.RemoteAddr(), addr) - netpkg.Transport(conn, cc) - log.WithFields(map[string]any{ - "duration": time.Since(start), - }).Infof("%s >-< %s", conn.RemoteAddr(), addr) - - return nil -} - -func (h *httpHandler) decodeServerName(s string) (string, error) { - b, err := base64.RawURLEncoding.DecodeString(s) - if err != nil { - return "", err - } - if len(b) < 4 { - return "", errors.New("invalid name") - } - v, err := base64.RawURLEncoding.DecodeString(string(b[4:])) - if err != nil { - return "", err - } - if crc32.ChecksumIEEE(v) != binary.BigEndian.Uint32(b[:4]) { - return "", errors.New("invalid name") - } - return string(v), nil -} - -func (h *httpHandler) basicProxyAuth(proxyAuth string, log logger.Logger) (username, password string, ok bool) { - if proxyAuth == "" { - return - } - - if !strings.HasPrefix(proxyAuth, "Basic ") { - return - } - c, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(proxyAuth, "Basic ")) - if err != nil { - return - } - cs := string(c) - s := strings.IndexByte(cs, ':') - if s < 0 { - return - } - - return cs[:s], cs[s+1:], true -} - -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) - if h.options.Auther == nil || h.options.Auther.Authenticate(u, p) { - return true - } - - pr := h.md.probeResistance - // probing resistance is enabled, and knocking host is mismatch. - if pr != nil && (pr.Knock == "" || !strings.EqualFold(req.URL.Hostname(), pr.Knock)) { - resp.StatusCode = http.StatusServiceUnavailable // default status code - - switch pr.Type { - case "code": - resp.StatusCode, _ = strconv.Atoi(pr.Value) - case "web": - url := pr.Value - if !strings.HasPrefix(url, "http") { - url = "http://" + url - } - r, err := http.Get(url) - if err != nil { - log.Error(err) - break - } - resp = r - defer resp.Body.Close() - case "host": - cc, err := net.Dial("tcp", pr.Value) - if err != nil { - log.Error(err) - break - } - defer cc.Close() - - req.Write(cc) - netpkg.Transport(conn, cc) - return - case "file": - f, _ := os.Open(pr.Value) - if f != nil { - defer f.Close() - - resp.StatusCode = http.StatusOK - if finfo, _ := f.Stat(); finfo != nil { - resp.ContentLength = finfo.Size() - } - resp.Header.Set("Content-Type", "text/html") - resp.Body = f - } - } - } - - if resp.Header == nil { - resp.Header = http.Header{} - } - if resp.StatusCode == 0 { - resp.StatusCode = http.StatusProxyAuthRequired - resp.Header.Add("Proxy-Authenticate", "Basic realm=\"gost\"") - if strings.ToLower(req.Header.Get("Proxy-Connection")) == "keep-alive" { - // XXX libcurl will keep sending auth request in same conn - // which we don't supported yet. - resp.Header.Add("Connection", "close") - resp.Header.Add("Proxy-Connection", "close") - } - - log.Info("proxy authentication required") - } else { - resp.Header.Set("Server", "nginx/1.20.1") - resp.Header.Set("Date", time.Now().Format(http.TimeFormat)) - if resp.StatusCode == http.StatusOK { - resp.Header.Set("Connection", "keep-alive") - } - } - - if log.IsLevelEnabled(logger.DebugLevel) { - dump, _ := httputil.DumpResponse(resp, false) - log.Debug(string(dump)) - } - - resp.Write(conn) - return -} diff --git a/pkg/handler/http/metadata.go b/pkg/handler/http/metadata.go deleted file mode 100644 index 585fc48..0000000 --- a/pkg/handler/http/metadata.go +++ /dev/null @@ -1,53 +0,0 @@ -package http - -import ( - "net/http" - "strings" - - mdata "github.com/go-gost/gost/v3/pkg/metadata" -) - -type metadata struct { - probeResistance *probeResistance - sni bool - enableUDP bool - header http.Header -} - -func (h *httpHandler) parseMetadata(md mdata.Metadata) error { - const ( - header = "header" - probeResistKey = "probeResistance" - knock = "knock" - sni = "sni" - enableUDP = "udp" - ) - - if m := mdata.GetStringMapString(md, header); len(m) > 0 { - hd := http.Header{} - for k, v := range m { - hd.Add(k, v) - } - h.md.header = hd - } - - if v := mdata.GetString(md, probeResistKey); v != "" { - if ss := strings.SplitN(v, ":", 2); len(ss) == 2 { - h.md.probeResistance = &probeResistance{ - Type: ss[0], - Value: ss[1], - Knock: mdata.GetString(md, knock), - } - } - } - h.md.sni = mdata.GetBool(md, sni) - h.md.enableUDP = mdata.GetBool(md, enableUDP) - - return nil -} - -type probeResistance struct { - Type string - Value string - Knock string -} diff --git a/pkg/handler/http/udp.go b/pkg/handler/http/udp.go deleted file mode 100644 index a6986c0..0000000 --- a/pkg/handler/http/udp.go +++ /dev/null @@ -1,80 +0,0 @@ -package http - -import ( - "context" - "errors" - "net" - "net/http" - "net/http/httputil" - "time" - - "github.com/go-gost/gost/v3/pkg/common/net/relay" - "github.com/go-gost/gost/v3/pkg/internal/util/socks" - "github.com/go-gost/gost/v3/pkg/logger" -) - -func (h *httpHandler) handleUDP(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) error { - log = log.WithFields(map[string]any{ - "cmd": "udp", - }) - - resp := &http.Response{ - ProtoMajor: 1, - ProtoMinor: 1, - Header: h.md.header, - } - if resp.Header == nil { - resp.Header = http.Header{} - } - - if !h.md.enableUDP { - resp.StatusCode = http.StatusForbidden - - if log.IsLevelEnabled(logger.DebugLevel) { - dump, _ := httputil.DumpResponse(resp, false) - log.Debug(string(dump)) - } - - log.Error("http: UDP relay is disabled") - - return resp.Write(conn) - } - - resp.StatusCode = http.StatusOK - if log.IsLevelEnabled(logger.DebugLevel) { - dump, _ := httputil.DumpResponse(resp, false) - log.Debug(string(dump)) - } - if err := resp.Write(conn); err != nil { - log.Error(err) - return err - } - - // obtain a udp connection - c, err := h.router.Dial(ctx, "udp", "") // UDP association - if err != nil { - log.Error(err) - return err - } - defer c.Close() - - pc, ok := c.(net.PacketConn) - if !ok { - err = errors.New("wrong connection type") - log.Error(err) - return err - } - - relay := relay.NewUDPRelay(socks.UDPTunServerConn(conn), pc). - WithBypass(h.options.Bypass). - WithLogger(log) - - t := time.Now() - log.Infof("%s <-> %s", conn.RemoteAddr(), pc.LocalAddr()) - relay.Run() - log.WithFields(map[string]any{ - "duration": time.Since(t), - }).Infof("%s >-< %s", conn.RemoteAddr(), pc.LocalAddr()) - - return nil -} diff --git a/pkg/handler/option.go b/pkg/handler/option.go deleted file mode 100644 index 35f3a3a..0000000 --- a/pkg/handler/option.go +++ /dev/null @@ -1,71 +0,0 @@ -package handler - -import ( - "crypto/tls" - "net/url" - - "github.com/go-gost/gost/v3/pkg/auth" - "github.com/go-gost/gost/v3/pkg/bypass" - "github.com/go-gost/gost/v3/pkg/chain" - "github.com/go-gost/gost/v3/pkg/logger" - "github.com/go-gost/gost/v3/pkg/metadata" -) - -type Options struct { - Bypass bypass.Bypass - Router *chain.Router - Auth *url.Userinfo - Auther auth.Authenticator - TLSConfig *tls.Config - Logger logger.Logger -} - -type Option func(opts *Options) - -func BypassOption(bypass bypass.Bypass) Option { - return func(opts *Options) { - opts.Bypass = bypass - } -} - -func RouterOption(router *chain.Router) Option { - return func(opts *Options) { - opts.Router = router - } -} - -func AuthOption(auth *url.Userinfo) Option { - return func(opts *Options) { - opts.Auth = auth - } -} - -func AutherOption(auther auth.Authenticator) Option { - return func(opts *Options) { - opts.Auther = auther - } -} - -func TLSConfigOption(tlsConfig *tls.Config) Option { - return func(opts *Options) { - opts.TLSConfig = tlsConfig - } -} - -func LoggerOption(logger logger.Logger) Option { - return func(opts *Options) { - opts.Logger = logger - } -} - -type HandleOptions struct { - Metadata metadata.Metadata -} - -type HandleOption func(opts *HandleOptions) - -func MetadataHandleOption(md metadata.Metadata) HandleOption { - return func(opts *HandleOptions) { - opts.Metadata = md - } -} diff --git a/pkg/handler/socks/v4/handler.go b/pkg/handler/socks/v4/handler.go deleted file mode 100644 index 5ba54c4..0000000 --- a/pkg/handler/socks/v4/handler.go +++ /dev/null @@ -1,152 +0,0 @@ -package v4 - -import ( - "context" - "errors" - "net" - "time" - - "github.com/go-gost/gosocks4" - "github.com/go-gost/gost/v3/pkg/chain" - netpkg "github.com/go-gost/gost/v3/pkg/common/net" - "github.com/go-gost/gost/v3/pkg/handler" - "github.com/go-gost/gost/v3/pkg/logger" - md "github.com/go-gost/gost/v3/pkg/metadata" - "github.com/go-gost/gost/v3/pkg/registry" -) - -var ( - ErrUnknownCmd = errors.New("socks4: unknown command") - ErrUnimplemented = errors.New("socks4: unimplemented") -) - -func init() { - registry.HandlerRegistry().Register("socks4", NewHandler) - registry.HandlerRegistry().Register("socks4a", NewHandler) -} - -type socks4Handler struct { - router *chain.Router - md metadata - options handler.Options -} - -func NewHandler(opts ...handler.Option) handler.Handler { - options := handler.Options{} - for _, opt := range opts { - opt(&options) - } - - return &socks4Handler{ - options: options, - } -} - -func (h *socks4Handler) Init(md md.Metadata) (err error) { - if err := h.parseMetadata(md); err != nil { - return err - } - - h.router = h.options.Router - if h.router == nil { - h.router = (&chain.Router{}).WithLogger(h.options.Logger) - } - - return nil -} - -func (h *socks4Handler) Handle(ctx context.Context, conn net.Conn, opts ...handler.HandleOption) error { - defer conn.Close() - - start := time.Now() - - log := h.options.Logger.WithFields(map[string]any{ - "remote": conn.RemoteAddr().String(), - "local": conn.LocalAddr().String(), - }) - - log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr()) - defer func() { - log.WithFields(map[string]any{ - "duration": time.Since(start), - }).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr()) - }() - - if h.md.readTimeout > 0 { - conn.SetReadDeadline(time.Now().Add(h.md.readTimeout)) - } - - req, err := gosocks4.ReadRequest(conn) - if err != nil { - log.Error(err) - return err - } - log.Debug(req) - - conn.SetReadDeadline(time.Time{}) - - if h.options.Auther != nil && - !h.options.Auther.Authenticate(string(req.Userid), "") { - resp := gosocks4.NewReply(gosocks4.RejectedUserid, nil) - log.Debug(resp) - return resp.Write(conn) - } - - switch req.Cmd { - case gosocks4.CmdConnect: - return h.handleConnect(ctx, conn, req, log) - case gosocks4.CmdBind: - return h.handleBind(ctx, conn, req) - default: - err = ErrUnknownCmd - log.Error(err) - return err - } -} - -func (h *socks4Handler) handleConnect(ctx context.Context, conn net.Conn, req *gosocks4.Request, log logger.Logger) error { - addr := req.Addr.String() - - log = log.WithFields(map[string]any{ - "dst": addr, - }) - log.Infof("%s >> %s", conn.RemoteAddr(), addr) - - if h.options.Bypass != nil && h.options.Bypass.Contains(addr) { - resp := gosocks4.NewReply(gosocks4.Rejected, nil) - log.Debug(resp) - log.Info("bypass: ", addr) - return resp.Write(conn) - } - - cc, err := h.router.Dial(ctx, "tcp", addr) - if err != nil { - resp := gosocks4.NewReply(gosocks4.Failed, nil) - resp.Write(conn) - log.Debug(resp) - return err - } - - defer cc.Close() - - resp := gosocks4.NewReply(gosocks4.Granted, nil) - if err := resp.Write(conn); err != nil { - log.Error(err) - return err - } - log.Debug(resp) - - t := time.Now() - log.Infof("%s <-> %s", conn.RemoteAddr(), addr) - netpkg.Transport(conn, cc) - log.WithFields(map[string]any{ - "duration": time.Since(t), - }).Infof("%s >-< %s", conn.RemoteAddr(), addr) - - return nil -} - -func (h *socks4Handler) handleBind(ctx context.Context, conn net.Conn, req *gosocks4.Request) error { - // TODO: bind - return ErrUnimplemented -} diff --git a/pkg/handler/socks/v4/metadata.go b/pkg/handler/socks/v4/metadata.go deleted file mode 100644 index 48f523b..0000000 --- a/pkg/handler/socks/v4/metadata.go +++ /dev/null @@ -1,20 +0,0 @@ -package v4 - -import ( - "time" - - mdata "github.com/go-gost/gost/v3/pkg/metadata" -) - -type metadata struct { - readTimeout time.Duration -} - -func (h *socks4Handler) parseMetadata(md mdata.Metadata) (err error) { - const ( - readTimeout = "readTimeout" - ) - - h.md.readTimeout = mdata.GetDuration(md, readTimeout) - return -} diff --git a/pkg/handler/socks/v5/bind.go b/pkg/handler/socks/v5/bind.go deleted file mode 100644 index 1c5abf3..0000000 --- a/pkg/handler/socks/v5/bind.go +++ /dev/null @@ -1,149 +0,0 @@ -package v5 - -import ( - "context" - "fmt" - "net" - "time" - - "github.com/go-gost/gosocks5" - netpkg "github.com/go-gost/gost/v3/pkg/common/net" - "github.com/go-gost/gost/v3/pkg/logger" -) - -func (h *socks5Handler) handleBind(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) error { - log = log.WithFields(map[string]any{ - "dst": fmt.Sprintf("%s/%s", address, network), - "cmd": "bind", - }) - - log.Infof("%s >> %s", conn.RemoteAddr(), address) - - if !h.md.enableBind { - reply := gosocks5.NewReply(gosocks5.NotAllowed, nil) - log.Debug(reply) - log.Error("socks5: BIND is disabled") - return reply.Write(conn) - } - - // BIND does not support chain. - return h.bindLocal(ctx, conn, network, address, log) -} - -func (h *socks5Handler) bindLocal(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) error { - ln, err := net.Listen(network, address) // strict mode: if the port already in use, it will return error - if err != nil { - log.Error(err) - reply := gosocks5.NewReply(gosocks5.Failure, nil) - if err := reply.Write(conn); err != nil { - log.Error(err) - } - log.Debug(reply) - return err - } - - socksAddr := gosocks5.Addr{} - if err := socksAddr.ParseFrom(ln.Addr().String()); err != nil { - log.Warn(err) - } - - // Issue: may not reachable when host has multi-interface - socksAddr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) - socksAddr.Type = 0 - reply := gosocks5.NewReply(gosocks5.Succeeded, &socksAddr) - if err := reply.Write(conn); err != nil { - log.Error(err) - ln.Close() - return err - } - log.Debug(reply) - - log = log.WithFields(map[string]any{ - "bind": fmt.Sprintf("%s/%s", ln.Addr(), ln.Addr().Network()), - }) - - log.Debugf("bind on %s OK", ln.Addr()) - - h.serveBind(ctx, conn, ln, log) - return nil -} - -func (h *socks5Handler) serveBind(ctx context.Context, conn net.Conn, ln net.Listener, log logger.Logger) { - var rc net.Conn - accept := func() <-chan error { - errc := make(chan error, 1) - - go func() { - defer close(errc) - defer ln.Close() - - c, err := ln.Accept() - if err != nil { - errc <- err - } - rc = c - }() - - return errc - } - - pc1, pc2 := net.Pipe() - pipe := func() <-chan error { - errc := make(chan error, 1) - - go func() { - defer close(errc) - defer pc1.Close() - - errc <- netpkg.Transport(conn, pc1) - }() - - return errc - } - - defer pc2.Close() - - select { - case err := <-accept(): - if err != nil { - log.Error(err) - - reply := gosocks5.NewReply(gosocks5.Failure, nil) - if err := reply.Write(pc2); err != nil { - log.Error(err) - } - log.Debug(reply) - - return - } - defer rc.Close() - - log.Debugf("peer %s accepted", rc.RemoteAddr()) - - log = log.WithFields(map[string]any{ - "local": rc.LocalAddr().String(), - "remote": rc.RemoteAddr().String(), - }) - - raddr := gosocks5.Addr{} - raddr.ParseFrom(rc.RemoteAddr().String()) - reply := gosocks5.NewReply(gosocks5.Succeeded, &raddr) - if err := reply.Write(pc2); err != nil { - log.Error(err) - } - log.Debug(reply) - - start := time.Now() - log.Infof("%s <-> %s", rc.LocalAddr(), rc.RemoteAddr()) - netpkg.Transport(pc2, rc) - log.WithFields(map[string]any{"duration": time.Since(start)}). - Infof("%s >-< %s", rc.LocalAddr(), rc.RemoteAddr()) - - case err := <-pipe(): - if err != nil { - log.Error(err) - } - ln.Close() - return - } -} diff --git a/pkg/handler/socks/v5/connect.go b/pkg/handler/socks/v5/connect.go deleted file mode 100644 index 9ba41dc..0000000 --- a/pkg/handler/socks/v5/connect.go +++ /dev/null @@ -1,53 +0,0 @@ -package v5 - -import ( - "context" - "fmt" - "net" - "time" - - "github.com/go-gost/gosocks5" - netpkg "github.com/go-gost/gost/v3/pkg/common/net" - "github.com/go-gost/gost/v3/pkg/logger" -) - -func (h *socks5Handler) handleConnect(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) error { - log = log.WithFields(map[string]any{ - "dst": fmt.Sprintf("%s/%s", address, network), - "cmd": "connect", - }) - log.Infof("%s >> %s", conn.RemoteAddr(), address) - - if h.options.Bypass != nil && h.options.Bypass.Contains(address) { - resp := gosocks5.NewReply(gosocks5.NotAllowed, nil) - log.Debug(resp) - log.Info("bypass: ", address) - return resp.Write(conn) - } - - cc, err := h.router.Dial(ctx, network, address) - if err != nil { - resp := gosocks5.NewReply(gosocks5.NetUnreachable, nil) - log.Debug(resp) - resp.Write(conn) - return err - } - - defer cc.Close() - - resp := gosocks5.NewReply(gosocks5.Succeeded, nil) - if err := resp.Write(conn); err != nil { - log.Error(err) - return err - } - log.Debug(resp) - - t := time.Now() - log.Infof("%s <-> %s", conn.RemoteAddr(), address) - netpkg.Transport(conn, cc) - log.WithFields(map[string]any{ - "duration": time.Since(t), - }).Infof("%s >-< %s", conn.RemoteAddr(), address) - - return nil -} diff --git a/pkg/handler/socks/v5/handler.go b/pkg/handler/socks/v5/handler.go deleted file mode 100644 index bf2cebc..0000000 --- a/pkg/handler/socks/v5/handler.go +++ /dev/null @@ -1,115 +0,0 @@ -package v5 - -import ( - "context" - "errors" - "net" - "time" - - "github.com/go-gost/gosocks5" - "github.com/go-gost/gost/v3/pkg/chain" - "github.com/go-gost/gost/v3/pkg/handler" - "github.com/go-gost/gost/v3/pkg/internal/util/socks" - md "github.com/go-gost/gost/v3/pkg/metadata" - "github.com/go-gost/gost/v3/pkg/registry" -) - -var ( - ErrUnknownCmd = errors.New("socks5: unknown command") -) - -func init() { - registry.HandlerRegistry().Register("socks5", NewHandler) - registry.HandlerRegistry().Register("socks", NewHandler) -} - -type socks5Handler struct { - selector gosocks5.Selector - router *chain.Router - md metadata - options handler.Options -} - -func NewHandler(opts ...handler.Option) handler.Handler { - options := handler.Options{} - for _, opt := range opts { - opt(&options) - } - - return &socks5Handler{ - options: options, - } -} - -func (h *socks5Handler) Init(md md.Metadata) (err error) { - if err = h.parseMetadata(md); err != nil { - return - } - - h.router = h.options.Router - if h.router == nil { - h.router = (&chain.Router{}).WithLogger(h.options.Logger) - } - - h.selector = &serverSelector{ - Authenticator: h.options.Auther, - TLSConfig: h.options.TLSConfig, - logger: h.options.Logger, - noTLS: h.md.noTLS, - } - - return -} - -func (h *socks5Handler) Handle(ctx context.Context, conn net.Conn, opts ...handler.HandleOption) error { - defer conn.Close() - - start := time.Now() - - log := h.options.Logger.WithFields(map[string]any{ - "remote": conn.RemoteAddr().String(), - "local": conn.LocalAddr().String(), - }) - - log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr()) - defer func() { - log.WithFields(map[string]any{ - "duration": time.Since(start), - }).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr()) - }() - - if h.md.readTimeout > 0 { - conn.SetReadDeadline(time.Now().Add(h.md.readTimeout)) - } - - conn = gosocks5.ServerConn(conn, h.selector) - req, err := gosocks5.ReadRequest(conn) - if err != nil { - log.Error(err) - return err - } - log.Debug(req) - conn.SetReadDeadline(time.Time{}) - - address := req.Addr.String() - - switch req.Cmd { - case gosocks5.CmdConnect: - return h.handleConnect(ctx, conn, "tcp", address, log) - case gosocks5.CmdBind: - return h.handleBind(ctx, conn, "tcp", address, log) - case socks.CmdMuxBind: - return h.handleMuxBind(ctx, conn, "tcp", address, log) - case gosocks5.CmdUdp: - return h.handleUDP(ctx, conn, log) - case socks.CmdUDPTun: - return h.handleUDPTun(ctx, conn, "udp", address, log) - default: - err = ErrUnknownCmd - log.Error(err) - resp := gosocks5.NewReply(gosocks5.CmdUnsupported, nil) - resp.Write(conn) - log.Debug(resp) - return err - } -} diff --git a/pkg/handler/socks/v5/mbind.go b/pkg/handler/socks/v5/mbind.go deleted file mode 100644 index c2e0eb9..0000000 --- a/pkg/handler/socks/v5/mbind.go +++ /dev/null @@ -1,133 +0,0 @@ -package v5 - -import ( - "context" - "fmt" - "net" - "time" - - "github.com/go-gost/gosocks5" - netpkg "github.com/go-gost/gost/v3/pkg/common/net" - "github.com/go-gost/gost/v3/pkg/internal/util/mux" - "github.com/go-gost/gost/v3/pkg/logger" -) - -func (h *socks5Handler) handleMuxBind(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) error { - log = log.WithFields(map[string]any{ - "dst": fmt.Sprintf("%s/%s", address, network), - "cmd": "mbind", - }) - - log.Infof("%s >> %s", conn.RemoteAddr(), address) - - if !h.md.enableBind { - reply := gosocks5.NewReply(gosocks5.NotAllowed, nil) - log.Debug(reply) - log.Error("socks5: BIND is disabled") - return reply.Write(conn) - } - - return h.muxBindLocal(ctx, conn, network, address, log) -} - -func (h *socks5Handler) muxBindLocal(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) error { - ln, err := net.Listen(network, address) // strict mode: if the port already in use, it will return error - if err != nil { - log.Error(err) - reply := gosocks5.NewReply(gosocks5.Failure, nil) - if err := reply.Write(conn); err != nil { - log.Error(err) - } - log.Debug(reply) - return err - } - - socksAddr := gosocks5.Addr{} - err = socksAddr.ParseFrom(ln.Addr().String()) - if err != nil { - log.Warn(err) - } - - // Issue: may not reachable when host has multi-interface - socksAddr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) - socksAddr.Type = 0 - reply := gosocks5.NewReply(gosocks5.Succeeded, &socksAddr) - if err := reply.Write(conn); err != nil { - log.Error(err) - ln.Close() - return err - } - log.Debug(reply) - - log = log.WithFields(map[string]any{ - "bind": fmt.Sprintf("%s/%s", ln.Addr(), ln.Addr().Network()), - }) - - log.Debugf("bind on %s OK", ln.Addr()) - - return h.serveMuxBind(ctx, conn, ln, log) -} - -func (h *socks5Handler) serveMuxBind(ctx context.Context, conn net.Conn, ln net.Listener, log logger.Logger) error { - // Upgrade connection to multiplex stream. - session, err := mux.ClientSession(conn) - if err != nil { - log.Error(err) - return err - } - defer session.Close() - - go func() { - defer ln.Close() - for { - conn, err := session.Accept() - if err != nil { - log.Error(err) - return - } - conn.Close() // we do not handle incoming connections. - } - }() - - for { - rc, err := ln.Accept() - if err != nil { - log.Error(err) - return err - } - log.Debugf("peer %s accepted", rc.RemoteAddr()) - - go func(c net.Conn) { - defer c.Close() - - log = log.WithFields(map[string]any{ - "local": rc.LocalAddr().String(), - "remote": rc.RemoteAddr().String(), - }) - sc, err := session.GetConn() - if err != nil { - log.Error(err) - return - } - defer sc.Close() - - // incompatible with GOST v2.x - if !h.md.compatibilityMode { - addr := gosocks5.Addr{} - addr.ParseFrom(c.RemoteAddr().String()) - reply := gosocks5.NewReply(gosocks5.Succeeded, &addr) - if err := reply.Write(sc); err != nil { - log.Error(err) - return - } - log.Debug(reply) - } - - t := time.Now() - log.Infof("%s <-> %s", c.LocalAddr(), c.RemoteAddr()) - netpkg.Transport(sc, c) - log.WithFields(map[string]any{"duration": time.Since(t)}). - Infof("%s >-< %s", c.LocalAddr(), c.RemoteAddr()) - }(rc) - } -} diff --git a/pkg/handler/socks/v5/metadata.go b/pkg/handler/socks/v5/metadata.go deleted file mode 100644 index 93d9ed3..0000000 --- a/pkg/handler/socks/v5/metadata.go +++ /dev/null @@ -1,43 +0,0 @@ -package v5 - -import ( - "math" - "time" - - mdata "github.com/go-gost/gost/v3/pkg/metadata" -) - -type metadata struct { - readTimeout time.Duration - noTLS bool - enableBind bool - enableUDP bool - udpBufferSize int - compatibilityMode bool -} - -func (h *socks5Handler) parseMetadata(md mdata.Metadata) (err error) { - const ( - readTimeout = "readTimeout" - noTLS = "notls" - enableBind = "bind" - enableUDP = "udp" - udpBufferSize = "udpBufferSize" - compatibilityMode = "comp" - ) - - h.md.readTimeout = mdata.GetDuration(md, readTimeout) - h.md.noTLS = mdata.GetBool(md, noTLS) - h.md.enableBind = mdata.GetBool(md, enableBind) - h.md.enableUDP = mdata.GetBool(md, enableUDP) - - if bs := mdata.GetInt(md, udpBufferSize); bs > 0 { - h.md.udpBufferSize = int(math.Min(math.Max(float64(bs), 512), 64*1024)) - } else { - h.md.udpBufferSize = 1024 - } - - h.md.compatibilityMode = mdata.GetBool(md, compatibilityMode) - - return nil -} diff --git a/pkg/handler/socks/v5/selector.go b/pkg/handler/socks/v5/selector.go deleted file mode 100644 index 7802c47..0000000 --- a/pkg/handler/socks/v5/selector.go +++ /dev/null @@ -1,90 +0,0 @@ -package v5 - -import ( - "crypto/tls" - "net" - - "github.com/go-gost/gosocks5" - "github.com/go-gost/gost/v3/pkg/auth" - "github.com/go-gost/gost/v3/pkg/internal/util/socks" - "github.com/go-gost/gost/v3/pkg/logger" -) - -type serverSelector struct { - methods []uint8 - Authenticator auth.Authenticator - TLSConfig *tls.Config - logger logger.Logger - noTLS bool -} - -func (selector *serverSelector) Methods() []uint8 { - return selector.methods -} - -func (s *serverSelector) Select(methods ...uint8) (method uint8) { - s.logger.Debugf("%d %d %v", gosocks5.Ver5, len(methods), methods) - method = gosocks5.MethodNoAuth - for _, m := range methods { - if m == socks.MethodTLS && !s.noTLS { - method = m - break - } - } - - // when Authenticator is set, auth is mandatory - if s.Authenticator != nil { - if method == gosocks5.MethodNoAuth { - method = gosocks5.MethodUserPass - } - if method == socks.MethodTLS && !s.noTLS { - method = socks.MethodTLSAuth - } - } - - return -} - -func (s *serverSelector) OnSelected(method uint8, conn net.Conn) (net.Conn, error) { - s.logger.Debugf("%d %d", gosocks5.Ver5, method) - switch method { - case socks.MethodTLS: - conn = tls.Server(conn, s.TLSConfig) - - case gosocks5.MethodUserPass, socks.MethodTLSAuth: - if method == socks.MethodTLSAuth { - conn = tls.Server(conn, s.TLSConfig) - } - - req, err := gosocks5.ReadUserPassRequest(conn) - if err != nil { - s.logger.Error(err) - return nil, err - } - s.logger.Debug(req) - - if s.Authenticator != nil && - !s.Authenticator.Authenticate(req.Username, req.Password) { - resp := gosocks5.NewUserPassResponse(gosocks5.UserPassVer, gosocks5.Failure) - if err := resp.Write(conn); err != nil { - s.logger.Error(err) - return nil, err - } - s.logger.Info(resp) - - return nil, gosocks5.ErrAuthFailure - } - - resp := gosocks5.NewUserPassResponse(gosocks5.UserPassVer, gosocks5.Succeeded) - if err := resp.Write(conn); err != nil { - s.logger.Error(err) - return nil, err - } - s.logger.Debug(resp) - - case gosocks5.MethodNoAcceptable: - return nil, gosocks5.ErrBadMethod - } - - return conn, nil -} diff --git a/pkg/handler/socks/v5/udp.go b/pkg/handler/socks/v5/udp.go deleted file mode 100644 index edbc3a0..0000000 --- a/pkg/handler/socks/v5/udp.go +++ /dev/null @@ -1,85 +0,0 @@ -package v5 - -import ( - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "net" - "time" - - "github.com/go-gost/gosocks5" - "github.com/go-gost/gost/v3/pkg/common/net/relay" - "github.com/go-gost/gost/v3/pkg/internal/util/socks" - "github.com/go-gost/gost/v3/pkg/logger" -) - -func (h *socks5Handler) handleUDP(ctx context.Context, conn net.Conn, log logger.Logger) error { - log = log.WithFields(map[string]any{ - "cmd": "udp", - }) - - if !h.md.enableUDP { - reply := gosocks5.NewReply(gosocks5.NotAllowed, nil) - log.Debug(reply) - log.Error("socks5: UDP relay is disabled") - return reply.Write(conn) - } - - cc, err := net.ListenUDP("udp", nil) - if err != nil { - log.Error(err) - reply := gosocks5.NewReply(gosocks5.Failure, nil) - reply.Write(conn) - log.Debug(reply) - return err - } - defer cc.Close() - - saddr := gosocks5.Addr{} - saddr.ParseFrom(cc.LocalAddr().String()) - saddr.Type = 0 - saddr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) // replace the IP to the out-going interface's - reply := gosocks5.NewReply(gosocks5.Succeeded, &saddr) - if err := reply.Write(conn); err != nil { - log.Error(err) - return err - } - log.Debug(reply) - - log = log.WithFields(map[string]any{ - "bind": fmt.Sprintf("%s/%s", cc.LocalAddr(), cc.LocalAddr().Network()), - }) - log.Debugf("bind on %s OK", cc.LocalAddr()) - - // obtain a udp connection - c, err := h.router.Dial(ctx, "udp", "") // UDP association - if err != nil { - log.Error(err) - return err - } - defer c.Close() - - pc, ok := c.(net.PacketConn) - if !ok { - err := errors.New("socks5: wrong connection type") - log.Error(err) - return err - } - - r := relay.NewUDPRelay(socks.UDPConn(cc, h.md.udpBufferSize), pc). - WithBypass(h.options.Bypass). - WithLogger(log) - r.SetBufferSize(h.md.udpBufferSize) - - go r.Run() - - t := time.Now() - log.Infof("%s <-> %s", conn.RemoteAddr(), cc.LocalAddr()) - io.Copy(ioutil.Discard, conn) - log.WithFields(map[string]any{"duration": time.Since(t)}). - Infof("%s >-< %s", conn.RemoteAddr(), cc.LocalAddr()) - - return nil -} diff --git a/pkg/handler/socks/v5/udp_tun.go b/pkg/handler/socks/v5/udp_tun.go deleted file mode 100644 index 1f0fa6e..0000000 --- a/pkg/handler/socks/v5/udp_tun.go +++ /dev/null @@ -1,72 +0,0 @@ -package v5 - -import ( - "context" - "net" - "time" - - "github.com/go-gost/gosocks5" - "github.com/go-gost/gost/v3/pkg/common/net/relay" - "github.com/go-gost/gost/v3/pkg/internal/util/socks" - "github.com/go-gost/gost/v3/pkg/logger" -) - -func (h *socks5Handler) handleUDPTun(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) error { - log = log.WithFields(map[string]any{ - "cmd": "udp-tun", - }) - - bindAddr, _ := net.ResolveUDPAddr(network, address) - if bindAddr == nil { - bindAddr = &net.UDPAddr{} - } - - if bindAddr.Port == 0 { - // relay mode - if !h.md.enableUDP { - reply := gosocks5.NewReply(gosocks5.NotAllowed, nil) - log.Debug(reply) - log.Error("socks5: UDP relay is disabled") - return reply.Write(conn) - } - } else { - // BIND mode - if !h.md.enableBind { - reply := gosocks5.NewReply(gosocks5.NotAllowed, nil) - log.Debug(reply) - log.Error("socks5: BIND is disabled") - return reply.Write(conn) - } - } - - pc, err := net.ListenUDP(network, bindAddr) - if err != nil { - log.Error(err) - return err - } - defer pc.Close() - - saddr := gosocks5.Addr{} - saddr.ParseFrom(pc.LocalAddr().String()) - reply := gosocks5.NewReply(gosocks5.Succeeded, &saddr) - if err := reply.Write(conn); err != nil { - log.Error(err) - return err - } - log.Debug(reply) - log.Debugf("bind on %s OK", pc.LocalAddr()) - - r := relay.NewUDPRelay(socks.UDPTunServerConn(conn), pc). - WithBypass(h.options.Bypass). - WithLogger(log) - r.SetBufferSize(h.md.udpBufferSize) - - t := time.Now() - log.Infof("%s <-> %s", conn.RemoteAddr(), pc.LocalAddr()) - r.Run() - log.WithFields(map[string]any{ - "duration": time.Since(t), - }).Infof("%s >-< %s", conn.RemoteAddr(), pc.LocalAddr()) - - return nil -} diff --git a/pkg/hosts/hosts.go b/pkg/hosts/hosts.go deleted file mode 100644 index 05fe476..0000000 --- a/pkg/hosts/hosts.go +++ /dev/null @@ -1,132 +0,0 @@ -package hosts - -import ( - "net" - "strings" - "sync" - - "github.com/go-gost/gost/v3/pkg/logger" -) - -// HostMapper is a mapping from hostname to IP. -type HostMapper interface { - Lookup(network, host string) ([]net.IP, bool) -} - -type hostMapping struct { - IPs []net.IP - Hostname string -} - -// Hosts is a static table lookup for hostnames. -// For each host a single line should be present with the following information: -// IP_address canonical_hostname [aliases...] -// Fields of the entry are separated by any number of blanks and/or tab characters. -// Text from a "#" character until the end of the line is a comment, and is ignored. -type Hosts struct { - mappings sync.Map - Logger logger.Logger -} - -func NewHosts() *Hosts { - return &Hosts{} -} - -// Map maps ip to hostname or aliases. -func (h *Hosts) Map(ip net.IP, hostname string, aliases ...string) { - if hostname == "" { - return - } - - v, _ := h.mappings.Load(hostname) - m, _ := v.(*hostMapping) - if m == nil { - m = &hostMapping{ - IPs: []net.IP{ip}, - Hostname: hostname, - } - } else { - m.IPs = append(m.IPs, ip) - } - h.mappings.Store(hostname, m) - - for _, alias := range aliases { - // indirect mapping from alias to hostname - if alias != "" { - h.mappings.Store(alias, &hostMapping{ - Hostname: hostname, - }) - } - } -} - -// Lookup searches the IP address corresponds to the given network and host from the host table. -// The network should be 'ip', 'ip4' or 'ip6', default network is 'ip'. -// the host should be a hostname (example.org) or a hostname with dot prefix (.example.org). -func (h *Hosts) Lookup(network, host string) (ips []net.IP, ok bool) { - m := h.lookup(host) - if m == nil { - m = h.lookup("." + host) - } - if m == nil { - s := host - for { - if index := strings.IndexByte(s, '.'); index > 0 { - m = h.lookup(s[index:]) - s = s[index+1:] - if m == nil { - continue - } - } - break - } - } - - if m == nil { - return - } - - // hostname alias - if !strings.HasPrefix(m.Hostname, ".") && host != m.Hostname { - m = h.lookup(m.Hostname) - if m == nil { - return - } - } - - switch network { - case "ip4": - for _, ip := range m.IPs { - if ip = ip.To4(); ip != nil { - ips = append(ips, ip) - } - } - case "ip6": - for _, ip := range m.IPs { - if ip.To4() == nil { - ips = append(ips, ip) - } - } - default: - ips = m.IPs - } - - if len(ips) > 0 { - h.Logger.Debugf("host mapper: %s -> %s", host, ips) - } - - return -} - -func (h *Hosts) lookup(host string) *hostMapping { - if h == nil || host == "" { - return nil - } - - v, ok := h.mappings.Load(host) - if !ok { - return nil - } - m, _ := v.(*hostMapping) - return m -} diff --git a/pkg/internal/util/mux/mux.go b/pkg/internal/util/mux/mux.go deleted file mode 100644 index 4fae020..0000000 --- a/pkg/internal/util/mux/mux.go +++ /dev/null @@ -1,85 +0,0 @@ -package mux - -import ( - "net" - - smux "github.com/xtaci/smux" -) - -type Session struct { - conn net.Conn - session *smux.Session -} - -func ClientSession(conn net.Conn) (*Session, error) { - s, err := smux.Client(conn, smux.DefaultConfig()) - if err != nil { - return nil, err - } - return &Session{ - conn: conn, - session: s, - }, nil -} - -func ServerSession(conn net.Conn) (*Session, error) { - s, err := smux.Server(conn, smux.DefaultConfig()) - if err != nil { - return nil, err - } - return &Session{ - conn: conn, - session: s, - }, nil -} - -func (session *Session) GetConn() (net.Conn, error) { - stream, err := session.session.OpenStream() - if err != nil { - return nil, err - } - return &streamConn{Conn: session.conn, stream: stream}, nil -} - -func (session *Session) Accept() (net.Conn, error) { - stream, err := session.session.AcceptStream() - if err != nil { - return nil, err - } - return &streamConn{Conn: session.conn, stream: stream}, nil -} - -func (session *Session) Close() error { - if session.session == nil { - return nil - } - return session.session.Close() -} - -func (session *Session) IsClosed() bool { - if session.session == nil { - return true - } - return session.session.IsClosed() -} - -func (session *Session) NumStreams() int { - return session.session.NumStreams() -} - -type streamConn struct { - net.Conn - stream *smux.Stream -} - -func (c *streamConn) Read(b []byte) (n int, err error) { - return c.stream.Read(b) -} - -func (c *streamConn) Write(b []byte) (n int, err error) { - return c.stream.Write(b) -} - -func (c *streamConn) Close() error { - return c.stream.Close() -} diff --git a/pkg/internal/util/socks/conn.go b/pkg/internal/util/socks/conn.go deleted file mode 100644 index 0c14ee0..0000000 --- a/pkg/internal/util/socks/conn.go +++ /dev/null @@ -1,172 +0,0 @@ -package socks - -import ( - "bytes" - "net" - - "github.com/go-gost/gosocks5" - "github.com/go-gost/gost/v3/pkg/common/bufpool" -) - -type udpTunConn struct { - net.Conn - taddr net.Addr -} - -func UDPTunClientConn(c net.Conn, targetAddr net.Addr) net.Conn { - return &udpTunConn{ - Conn: c, - taddr: targetAddr, - } -} - -func UDPTunClientPacketConn(c net.Conn) net.PacketConn { - return &udpTunConn{ - Conn: c, - } -} - -func UDPTunServerConn(c net.Conn) net.PacketConn { - return &udpTunConn{ - Conn: c, - } -} - -func (c *udpTunConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { - socksAddr := gosocks5.Addr{} - header := gosocks5.UDPHeader{ - Addr: &socksAddr, - } - dgram := gosocks5.UDPDatagram{ - Header: &header, - Data: b, - } - _, err = dgram.ReadFrom(c.Conn) - if err != nil { - return - } - - n = len(dgram.Data) - if n > len(b) { - n = copy(b, dgram.Data) - } - addr, err = net.ResolveUDPAddr("udp", socksAddr.String()) - - return -} - -func (c *udpTunConn) Read(b []byte) (n int, err error) { - n, _, err = c.ReadFrom(b) - return -} - -func (c *udpTunConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { - socksAddr := gosocks5.Addr{} - if err = socksAddr.ParseFrom(addr.String()); err != nil { - return - } - - header := gosocks5.UDPHeader{ - Addr: &socksAddr, - } - dgram := gosocks5.UDPDatagram{ - Header: &header, - Data: b, - } - dgram.Header.Rsv = uint16(len(dgram.Data)) - dgram.Header.Frag = 0xff // UDP tun relay flag, used by shadowsocks - _, err = dgram.WriteTo(c.Conn) - n = len(b) - - return -} - -func (c *udpTunConn) Write(b []byte) (n int, err error) { - return c.WriteTo(b, c.taddr) -} - -var ( - DefaultBufferSize = 4096 -) - -type udpConn struct { - net.PacketConn - raddr net.Addr - taddr net.Addr - bufferSize int -} - -func UDPConn(c net.PacketConn, bufferSize int) net.PacketConn { - return &udpConn{ - PacketConn: c, - bufferSize: bufferSize, - } -} - -// ReadFrom reads an UDP datagram. -// NOTE: for server side, -// the returned addr is the target address the client want to relay to. -func (c *udpConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { - rbuf := bufpool.Get(c.bufferSize) - defer bufpool.Put(rbuf) - - n, c.raddr, err = c.PacketConn.ReadFrom(*rbuf) - if err != nil { - return - } - - socksAddr := gosocks5.Addr{} - header := gosocks5.UDPHeader{ - Addr: &socksAddr, - } - hlen, err := header.ReadFrom(bytes.NewReader((*rbuf)[:n])) - if err != nil { - return - } - n = copy(b, (*rbuf)[hlen:n]) - - addr, err = net.ResolveUDPAddr("udp", socksAddr.String()) - return -} - -func (c *udpConn) Read(b []byte) (n int, err error) { - n, _, err = c.ReadFrom(b) - return -} - -func (c *udpConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { - wbuf := bufpool.Get(c.bufferSize) - defer bufpool.Put(wbuf) - - socksAddr := gosocks5.Addr{} - if err = socksAddr.ParseFrom(addr.String()); err != nil { - return - } - - header := gosocks5.UDPHeader{ - Addr: &socksAddr, - } - dgram := gosocks5.UDPDatagram{ - Header: &header, - Data: b, - } - - buf := bytes.NewBuffer((*wbuf)[:0]) - _, err = dgram.WriteTo(buf) - if err != nil { - return - } - - _, err = c.PacketConn.WriteTo(buf.Bytes(), c.raddr) - n = len(b) - - return -} - -func (c *udpConn) Write(b []byte) (n int, err error) { - return c.WriteTo(b, c.taddr) -} - -func (c *udpConn) RemoteAddr() net.Addr { - return c.raddr -} diff --git a/pkg/internal/util/socks/socks.go b/pkg/internal/util/socks/socks.go deleted file mode 100644 index 91d241d..0000000 --- a/pkg/internal/util/socks/socks.go +++ /dev/null @@ -1,18 +0,0 @@ -package socks - -const ( - // MethodTLS is an extended SOCKS5 method with tls encryption support. - MethodTLS uint8 = 0x80 - // MethodTLSAuth is an extended SOCKS5 method with tls encryption and authentication support. - MethodTLSAuth uint8 = 0x82 - // MethodMux is an extended SOCKS5 method for stream multiplexing. - MethodMux = 0x88 -) - -const ( - // CmdMuxBind is an extended SOCKS5 request CMD for - // multiplexing transport with the binding server. - CmdMuxBind uint8 = 0xF2 - // CmdUDPTun is an extended SOCKS5 request CMD for UDP over TCP. - CmdUDPTun uint8 = 0xF3 -) diff --git a/pkg/internal/util/tcp.go b/pkg/internal/util/tcp.go deleted file mode 100644 index b2298fb..0000000 --- a/pkg/internal/util/tcp.go +++ /dev/null @@ -1,32 +0,0 @@ -package util - -import ( - "net" - "time" -) - -const ( - defaultKeepAlivePeriod = 180 * time.Second -) - -// TCPKeepAliveListener is a TCP listener with keep alive enabled. -type TCPKeepAliveListener struct { - KeepAlivePeriod time.Duration - *net.TCPListener -} - -func (l *TCPKeepAliveListener) Accept() (c net.Conn, err error) { - tc, err := l.AcceptTCP() - if err != nil { - return - } - - tc.SetKeepAlive(true) - period := l.KeepAlivePeriod - if period <= 0 { - period = defaultKeepAlivePeriod - } - tc.SetKeepAlivePeriod(period) - - return tc, nil -} diff --git a/pkg/listener/listener.go b/pkg/listener/listener.go deleted file mode 100644 index b06b05e..0000000 --- a/pkg/listener/listener.go +++ /dev/null @@ -1,44 +0,0 @@ -package listener - -import ( - "errors" - "net" - - "github.com/go-gost/gost/v3/pkg/metadata" -) - -var ( - ErrClosed = errors.New("accpet on closed listener") -) - -// Listener is a server listener, just like a net.Listener. -type Listener interface { - Init(metadata.Metadata) error - Accept() (net.Conn, error) - Addr() net.Addr - Close() error -} - -type AcceptError struct { - err error -} - -func NewAcceptError(err error) error { - return &AcceptError{err: err} -} - -func (e *AcceptError) Error() string { - return e.err.Error() -} - -func (e *AcceptError) Timeout() bool { - return false -} - -func (e *AcceptError) Temporary() bool { - return true -} - -func (e *AcceptError) Unwrap() error { - return e.err -} diff --git a/pkg/listener/option.go b/pkg/listener/option.go deleted file mode 100644 index 5435ba0..0000000 --- a/pkg/listener/option.go +++ /dev/null @@ -1,72 +0,0 @@ -package listener - -import ( - "crypto/tls" - "net/url" - - "github.com/go-gost/gost/v3/pkg/admission" - "github.com/go-gost/gost/v3/pkg/auth" - "github.com/go-gost/gost/v3/pkg/chain" - "github.com/go-gost/gost/v3/pkg/logger" -) - -type Options struct { - Addr string - Auther auth.Authenticator - Auth *url.Userinfo - TLSConfig *tls.Config - Admission admission.Admission - Chain chain.Chainer - Logger logger.Logger - Service string -} - -type Option func(opts *Options) - -func AddrOption(addr string) Option { - return func(opts *Options) { - opts.Addr = addr - } -} - -func AutherOption(auther auth.Authenticator) Option { - return func(opts *Options) { - opts.Auther = auther - } -} - -func AuthOption(auth *url.Userinfo) Option { - return func(opts *Options) { - opts.Auth = auth - } -} - -func TLSConfigOption(tlsConfig *tls.Config) Option { - return func(opts *Options) { - opts.TLSConfig = tlsConfig - } -} - -func AdmissionOption(admission admission.Admission) Option { - return func(opts *Options) { - opts.Admission = admission - } -} - -func ChainOption(chain chain.Chainer) Option { - return func(opts *Options) { - opts.Chain = chain - } -} - -func LoggerOption(logger logger.Logger) Option { - return func(opts *Options) { - opts.Logger = logger - } -} - -func ServiceOption(service string) Option { - return func(opts *Options) { - opts.Service = service - } -} diff --git a/pkg/listener/rtcp/listener.go b/pkg/listener/rtcp/listener.go deleted file mode 100644 index b0e7cef..0000000 --- a/pkg/listener/rtcp/listener.go +++ /dev/null @@ -1,102 +0,0 @@ -package rtcp - -import ( - "context" - "net" - - "github.com/go-gost/gost/v3/pkg/chain" - "github.com/go-gost/gost/v3/pkg/connector" - "github.com/go-gost/gost/v3/pkg/listener" - "github.com/go-gost/gost/v3/pkg/logger" - md "github.com/go-gost/gost/v3/pkg/metadata" - "github.com/go-gost/gost/v3/pkg/registry" - metrics "github.com/go-gost/metrics/wrapper" -) - -func init() { - registry.ListenerRegistry().Register("rtcp", NewListener) -} - -type rtcpListener struct { - laddr net.Addr - ln net.Listener - md metadata - router *chain.Router - logger logger.Logger - closed chan struct{} - options listener.Options -} - -func NewListener(opts ...listener.Option) listener.Listener { - options := listener.Options{} - for _, opt := range opts { - opt(&options) - } - return &rtcpListener{ - closed: make(chan struct{}), - logger: options.Logger, - options: options, - } -} - -func (l *rtcpListener) Init(md md.Metadata) (err error) { - if err = l.parseMetadata(md); err != nil { - return - } - - laddr, err := net.ResolveTCPAddr("tcp", l.options.Addr) - if err != nil { - return - } - - l.laddr = laddr - l.router = (&chain.Router{}). - WithChain(l.options.Chain). - WithLogger(l.logger) - - return -} - -func (l *rtcpListener) Accept() (conn net.Conn, err error) { - select { - case <-l.closed: - return nil, net.ErrClosed - default: - } - - if l.ln == nil { - l.ln, err = l.router.Bind( - context.Background(), "tcp", l.laddr.String(), - connector.MuxBindOption(true), - ) - if err != nil { - return nil, listener.NewAcceptError(err) - } - l.ln = metrics.WrapListener(l.options.Service, l.ln) - } - conn, err = l.ln.Accept() - if err != nil { - l.ln.Close() - l.ln = nil - return nil, listener.NewAcceptError(err) - } - return -} - -func (l *rtcpListener) Addr() net.Addr { - return l.laddr -} - -func (l *rtcpListener) Close() error { - select { - case <-l.closed: - default: - close(l.closed) - if l.ln != nil { - l.ln.Close() - l.ln = nil - } - } - - return nil -} diff --git a/pkg/listener/rtcp/metadata.go b/pkg/listener/rtcp/metadata.go deleted file mode 100644 index d378e81..0000000 --- a/pkg/listener/rtcp/metadata.go +++ /dev/null @@ -1,19 +0,0 @@ -package rtcp - -import ( - "time" - - mdata "github.com/go-gost/gost/v3/pkg/metadata" -) - -const ( - defaultKeepAlivePeriod = 180 * time.Second - defaultBacklog = 128 -) - -type metadata struct { -} - -func (l *rtcpListener) parseMetadata(md mdata.Metadata) (err error) { - return -} diff --git a/pkg/listener/rudp/listener.go b/pkg/listener/rudp/listener.go deleted file mode 100644 index 16da00e..0000000 --- a/pkg/listener/rudp/listener.go +++ /dev/null @@ -1,109 +0,0 @@ -package rudp - -import ( - "context" - "net" - - "github.com/go-gost/gost/v3/pkg/chain" - "github.com/go-gost/gost/v3/pkg/connector" - "github.com/go-gost/gost/v3/pkg/listener" - "github.com/go-gost/gost/v3/pkg/logger" - md "github.com/go-gost/gost/v3/pkg/metadata" - "github.com/go-gost/gost/v3/pkg/registry" - metrics "github.com/go-gost/metrics/wrapper" -) - -func init() { - registry.ListenerRegistry().Register("rudp", NewListener) -} - -type rudpListener struct { - laddr net.Addr - ln net.Listener - router *chain.Router - closed chan struct{} - logger logger.Logger - md metadata - options listener.Options -} - -func NewListener(opts ...listener.Option) listener.Listener { - options := listener.Options{} - for _, opt := range opts { - opt(&options) - } - return &rudpListener{ - closed: make(chan struct{}), - logger: options.Logger, - options: options, - } -} - -func (l *rudpListener) Init(md md.Metadata) (err error) { - if err = l.parseMetadata(md); err != nil { - return - } - - laddr, err := net.ResolveUDPAddr("udp", l.options.Addr) - if err != nil { - return - } - - l.laddr = laddr - l.router = (&chain.Router{}). - WithChain(l.options.Chain). - WithLogger(l.logger) - - return -} - -func (l *rudpListener) Accept() (conn net.Conn, err error) { - select { - case <-l.closed: - return nil, net.ErrClosed - default: - } - - if l.ln == nil { - l.ln, err = l.router.Bind( - context.Background(), "udp", l.laddr.String(), - connector.BacklogBindOption(l.md.backlog), - connector.UDPConnTTLBindOption(l.md.ttl), - connector.UDPDataBufferSizeBindOption(l.md.readBufferSize), - connector.UDPDataQueueSizeBindOption(l.md.readQueueSize), - ) - if err != nil { - return nil, listener.NewAcceptError(err) - } - } - conn, err = l.ln.Accept() - if err != nil { - l.ln.Close() - l.ln = nil - return nil, listener.NewAcceptError(err) - } - - if pc, ok := conn.(net.PacketConn); ok { - conn = metrics.WrapUDPConn(l.options.Service, pc) - } - - return -} - -func (l *rudpListener) Addr() net.Addr { - return l.laddr -} - -func (l *rudpListener) Close() error { - select { - case <-l.closed: - default: - close(l.closed) - if l.ln != nil { - l.ln.Close() - l.ln = nil - } - } - - return nil -} diff --git a/pkg/listener/rudp/metadata.go b/pkg/listener/rudp/metadata.go deleted file mode 100644 index ebf5879..0000000 --- a/pkg/listener/rudp/metadata.go +++ /dev/null @@ -1,54 +0,0 @@ -package rudp - -import ( - "time" - - mdata "github.com/go-gost/gost/v3/pkg/metadata" -) - -const ( - defaultTTL = 5 * time.Second - defaultReadBufferSize = 1024 - defaultReadQueueSize = 128 - defaultBacklog = 128 -) - -type metadata struct { - ttl time.Duration - readBufferSize int - readQueueSize int - backlog int - retryCount int -} - -func (l *rudpListener) parseMetadata(md mdata.Metadata) (err error) { - const ( - ttl = "ttl" - readBufferSize = "readBufferSize" - readQueueSize = "readQueueSize" - backlog = "backlog" - retryCount = "retry" - ) - - l.md.ttl = mdata.GetDuration(md, ttl) - if l.md.ttl <= 0 { - l.md.ttl = defaultTTL - } - l.md.readBufferSize = mdata.GetInt(md, readBufferSize) - if l.md.readBufferSize <= 0 { - l.md.readBufferSize = defaultReadBufferSize - } - - l.md.readQueueSize = mdata.GetInt(md, readQueueSize) - if l.md.readQueueSize <= 0 { - l.md.readQueueSize = defaultReadQueueSize - } - - l.md.backlog = mdata.GetInt(md, backlog) - if l.md.backlog <= 0 { - l.md.backlog = defaultBacklog - } - - l.md.retryCount = mdata.GetInt(md, retryCount) - return -} diff --git a/pkg/listener/tcp/listener.go b/pkg/listener/tcp/listener.go deleted file mode 100644 index f12af0a..0000000 --- a/pkg/listener/tcp/listener.go +++ /dev/null @@ -1,60 +0,0 @@ -package tcp - -import ( - "net" - - "github.com/go-gost/gost/v3/pkg/listener" - "github.com/go-gost/gost/v3/pkg/logger" - md "github.com/go-gost/gost/v3/pkg/metadata" - "github.com/go-gost/gost/v3/pkg/registry" - metrics "github.com/go-gost/metrics/wrapper" -) - -func init() { - registry.ListenerRegistry().Register("tcp", NewListener) -} - -type tcpListener struct { - ln net.Listener - logger logger.Logger - md metadata - options listener.Options -} - -func NewListener(opts ...listener.Option) listener.Listener { - options := listener.Options{} - for _, opt := range opts { - opt(&options) - } - return &tcpListener{ - logger: options.Logger, - options: options, - } -} - -func (l *tcpListener) Init(md md.Metadata) (err error) { - if err = l.parseMetadata(md); err != nil { - return - } - - ln, err := net.Listen("tcp", l.options.Addr) - if err != nil { - return - } - - l.ln = metrics.WrapListener(l.options.Service, ln) - - return -} - -func (l *tcpListener) Accept() (conn net.Conn, err error) { - return l.ln.Accept() -} - -func (l *tcpListener) Addr() net.Addr { - return l.ln.Addr() -} - -func (l *tcpListener) Close() error { - return l.ln.Close() -} diff --git a/pkg/listener/tcp/metadata.go b/pkg/listener/tcp/metadata.go deleted file mode 100644 index fcda92f..0000000 --- a/pkg/listener/tcp/metadata.go +++ /dev/null @@ -1,12 +0,0 @@ -package tcp - -import ( - md "github.com/go-gost/gost/v3/pkg/metadata" -) - -type metadata struct { -} - -func (l *tcpListener) parseMetadata(md md.Metadata) (err error) { - return -} diff --git a/pkg/listener/tls/listener.go b/pkg/listener/tls/listener.go deleted file mode 100644 index 3552411..0000000 --- a/pkg/listener/tls/listener.go +++ /dev/null @@ -1,64 +0,0 @@ -package tls - -import ( - "crypto/tls" - "net" - - admission "github.com/go-gost/gost/v3/pkg/admission/wrapper" - "github.com/go-gost/gost/v3/pkg/listener" - "github.com/go-gost/gost/v3/pkg/logger" - md "github.com/go-gost/gost/v3/pkg/metadata" - "github.com/go-gost/gost/v3/pkg/registry" - metrics "github.com/go-gost/metrics/wrapper" -) - -func init() { - registry.ListenerRegistry().Register("tls", NewListener) -} - -type tlsListener struct { - ln net.Listener - logger logger.Logger - md metadata - options listener.Options -} - -func NewListener(opts ...listener.Option) listener.Listener { - options := listener.Options{} - for _, opt := range opts { - opt(&options) - } - return &tlsListener{ - logger: options.Logger, - options: options, - } -} - -func (l *tlsListener) Init(md md.Metadata) (err error) { - if err = l.parseMetadata(md); err != nil { - return - } - - ln, err := net.Listen("tcp", l.options.Addr) - if err != nil { - return - } - ln = metrics.WrapListener(l.options.Service, ln) - ln = admission.WrapListener(l.options.Admission, ln) - - l.ln = tls.NewListener(ln, l.options.TLSConfig) - - return -} - -func (l *tlsListener) Accept() (conn net.Conn, err error) { - return l.ln.Accept() -} - -func (l *tlsListener) Addr() net.Addr { - return l.ln.Addr() -} - -func (l *tlsListener) Close() error { - return l.ln.Close() -} diff --git a/pkg/listener/tls/metadata.go b/pkg/listener/tls/metadata.go deleted file mode 100644 index 07dcc50..0000000 --- a/pkg/listener/tls/metadata.go +++ /dev/null @@ -1,12 +0,0 @@ -package tls - -import ( - mdata "github.com/go-gost/gost/v3/pkg/metadata" -) - -type metadata struct { -} - -func (l *tlsListener) parseMetadata(md mdata.Metadata) (err error) { - return -} diff --git a/pkg/listener/udp/listener.go b/pkg/listener/udp/listener.go deleted file mode 100644 index 195a6ce..0000000 --- a/pkg/listener/udp/listener.go +++ /dev/null @@ -1,73 +0,0 @@ -package udp - -import ( - "net" - - "github.com/go-gost/gost/v3/pkg/common/util/udp" - "github.com/go-gost/gost/v3/pkg/listener" - "github.com/go-gost/gost/v3/pkg/logger" - md "github.com/go-gost/gost/v3/pkg/metadata" - "github.com/go-gost/gost/v3/pkg/registry" - metrics "github.com/go-gost/metrics/wrapper" -) - -func init() { - registry.ListenerRegistry().Register("udp", NewListener) -} - -type udpListener struct { - ln net.Listener - logger logger.Logger - md metadata - options listener.Options -} - -func NewListener(opts ...listener.Option) listener.Listener { - options := listener.Options{} - for _, opt := range opts { - opt(&options) - } - return &udpListener{ - logger: options.Logger, - options: options, - } -} - -func (l *udpListener) Init(md md.Metadata) (err error) { - if err = l.parseMetadata(md); err != nil { - return - } - - laddr, err := net.ResolveUDPAddr("udp", l.options.Addr) - if err != nil { - return - } - - var conn net.PacketConn - conn, err = net.ListenUDP("udp", laddr) - if err != nil { - return - } - conn = metrics.WrapPacketConn(l.options.Service, conn) - - l.ln = udp.NewListener( - conn, - laddr, - l.md.backlog, - l.md.readQueueSize, l.md.readBufferSize, - l.md.ttl, - l.logger) - return -} - -func (l *udpListener) Accept() (conn net.Conn, err error) { - return l.ln.Accept() -} - -func (l *udpListener) Addr() net.Addr { - return l.ln.Addr() -} - -func (l *udpListener) Close() error { - return l.ln.Close() -} diff --git a/pkg/listener/udp/metadata.go b/pkg/listener/udp/metadata.go deleted file mode 100644 index e31ee47..0000000 --- a/pkg/listener/udp/metadata.go +++ /dev/null @@ -1,52 +0,0 @@ -package udp - -import ( - "time" - - mdata "github.com/go-gost/gost/v3/pkg/metadata" -) - -const ( - defaultTTL = 5 * time.Second - defaultReadBufferSize = 1024 - defaultReadQueueSize = 128 - defaultBacklog = 128 -) - -type metadata struct { - ttl time.Duration - - readBufferSize int - readQueueSize int - backlog int -} - -func (l *udpListener) parseMetadata(md mdata.Metadata) (err error) { - const ( - ttl = "ttl" - readBufferSize = "readBufferSize" - readQueueSize = "readQueueSize" - backlog = "backlog" - ) - - l.md.ttl = mdata.GetDuration(md, ttl) - if l.md.ttl <= 0 { - l.md.ttl = defaultTTL - } - l.md.readBufferSize = mdata.GetInt(md, readBufferSize) - if l.md.readBufferSize <= 0 { - l.md.readBufferSize = defaultReadBufferSize - } - - l.md.readQueueSize = mdata.GetInt(md, readQueueSize) - if l.md.readQueueSize <= 0 { - l.md.readQueueSize = defaultReadQueueSize - } - - l.md.backlog = mdata.GetInt(md, backlog) - if l.md.backlog <= 0 { - l.md.backlog = defaultBacklog - } - - return -} diff --git a/pkg/logger/gost_logger.go b/pkg/logger/gost_logger.go deleted file mode 100644 index 7395fb8..0000000 --- a/pkg/logger/gost_logger.go +++ /dev/null @@ -1,155 +0,0 @@ -package logger - -import ( - "fmt" - "path/filepath" - "runtime" - - "github.com/sirupsen/logrus" -) - -var ( - defaultLogger = NewLogger() -) - -func Default() Logger { - return defaultLogger -} - -func SetDefault(logger Logger) { - defaultLogger = logger -} - -type logger struct { - logger *logrus.Entry -} - -func NewLogger(opts ...LoggerOption) Logger { - var options LoggerOptions - for _, opt := range opts { - opt(&options) - } - - log := logrus.New() - if options.Output != nil { - log.SetOutput(options.Output) - } - - switch options.Format { - case TextFormat: - log.SetFormatter(&logrus.TextFormatter{ - FullTimestamp: true, - }) - default: - log.SetFormatter(&logrus.JSONFormatter{ - DisableHTMLEscape: true, - // PrettyPrint: true, - }) - } - - switch options.Level { - case DebugLevel, InfoLevel, WarnLevel, ErrorLevel, FatalLevel: - lvl, _ := logrus.ParseLevel(string(options.Level)) - log.SetLevel(lvl) - default: - log.SetLevel(logrus.InfoLevel) - } - - return &logger{ - logger: logrus.NewEntry(log), - } -} - -// WithFields adds new fields to log. -func (l *logger) WithFields(fields map[string]any) Logger { - return &logger{ - logger: l.logger.WithFields(logrus.Fields(fields)), - } -} - -// Debug logs a message at level Debug. -func (l *logger) Debug(args ...any) { - l.log(logrus.DebugLevel, args...) -} - -// Debugf logs a message at level Debug. -func (l *logger) Debugf(format string, args ...any) { - l.logf(logrus.DebugLevel, format, args...) -} - -// Info logs a message at level Info. -func (l *logger) Info(args ...any) { - l.log(logrus.InfoLevel, args...) -} - -// Infof logs a message at level Info. -func (l *logger) Infof(format string, args ...any) { - l.logf(logrus.InfoLevel, format, args...) -} - -// Warn logs a message at level Warn. -func (l *logger) Warn(args ...any) { - l.log(logrus.WarnLevel, args...) -} - -// Warnf logs a message at level Warn. -func (l *logger) Warnf(format string, args ...any) { - l.logf(logrus.WarnLevel, format, args...) -} - -// Error logs a message at level Error. -func (l *logger) Error(args ...any) { - l.log(logrus.ErrorLevel, args...) -} - -// Errorf logs a message at level Error. -func (l *logger) Errorf(format string, args ...any) { - l.logf(logrus.ErrorLevel, format, args...) -} - -// Fatal logs a message at level Fatal then the process will exit with status set to 1. -func (l *logger) Fatal(args ...any) { - l.log(logrus.FatalLevel, args...) - l.logger.Logger.Exit(1) -} - -// Fatalf logs a message at level Fatal then the process will exit with status set to 1. -func (l *logger) Fatalf(format string, args ...any) { - l.logf(logrus.FatalLevel, format, args...) - l.logger.Logger.Exit(1) -} - -func (l *logger) GetLevel() LogLevel { - return LogLevel(l.logger.Logger.GetLevel().String()) -} - -func (l *logger) IsLevelEnabled(level LogLevel) bool { - lvl, _ := logrus.ParseLevel(string(level)) - return l.logger.Logger.IsLevelEnabled(lvl) -} - -func (l *logger) log(level logrus.Level, args ...any) { - lg := l.logger - if l.logger.Logger.IsLevelEnabled(logrus.DebugLevel) { - lg = lg.WithField("caller", l.caller(3)) - } - lg.Log(level, args...) -} - -func (l *logger) logf(level logrus.Level, format string, args ...any) { - lg := l.logger - if l.logger.Logger.IsLevelEnabled(logrus.DebugLevel) { - lg = lg.WithField("caller", l.caller(3)) - } - lg.Logf(level, format, args...) -} - -func (l *logger) caller(skip int) string { - _, file, line, ok := runtime.Caller(skip) - if !ok { - file = "" - } else { - file = filepath.Join(filepath.Base(filepath.Dir(file)), filepath.Base(file)) - } - return fmt.Sprintf("%s:%d", file, line) -} diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go deleted file mode 100644 index 6aa1e99..0000000 --- a/pkg/logger/logger.go +++ /dev/null @@ -1,71 +0,0 @@ -package logger - -import ( - "io" -) - -// LogFormat is format type -type LogFormat string - -const ( - TextFormat LogFormat = "text" - JSONFormat LogFormat = "json" -) - -// LogLevel is Logger Level type -type LogLevel string - -const ( - // DebugLevel has verbose message - DebugLevel LogLevel = "debug" - // InfoLevel is default log level - InfoLevel LogLevel = "info" - // WarnLevel is for logging messages about possible issues - WarnLevel LogLevel = "warn" - // ErrorLevel is for logging errors - ErrorLevel LogLevel = "error" - // FatalLevel is for logging fatal messages. The system shuts down after logging the message. - FatalLevel LogLevel = "fatal" -) - -type Logger interface { - WithFields(map[string]any) Logger - Debug(args ...any) - Debugf(format string, args ...any) - Info(args ...any) - Infof(format string, args ...any) - Warn(args ...any) - Warnf(format string, args ...any) - Error(args ...any) - Errorf(format string, args ...any) - Fatal(args ...any) - Fatalf(format string, args ...any) - GetLevel() LogLevel - IsLevelEnabled(level LogLevel) bool -} - -type LoggerOptions struct { - Output io.Writer - Format LogFormat - Level LogLevel -} - -type LoggerOption func(opts *LoggerOptions) - -func OutputLoggerOption(out io.Writer) LoggerOption { - return func(opts *LoggerOptions) { - opts.Output = out - } -} - -func FormatLoggerOption(format LogFormat) LoggerOption { - return func(opts *LoggerOptions) { - opts.Format = format - } -} - -func LevelLoggerOption(level LogLevel) LoggerOption { - return func(opts *LoggerOptions) { - opts.Level = level - } -} diff --git a/pkg/logger/nop_logger.go b/pkg/logger/nop_logger.go deleted file mode 100644 index 5a131fe..0000000 --- a/pkg/logger/nop_logger.go +++ /dev/null @@ -1,53 +0,0 @@ -package logger - -var ( - nop = &nopLogger{} -) - -func Nop() Logger { - return nop -} - -type nopLogger struct{} - -func (l *nopLogger) WithFields(fields map[string]any) Logger { - return l -} - -func (l *nopLogger) Debug(args ...any) { -} - -func (l *nopLogger) Debugf(format string, args ...any) { -} - -func (l *nopLogger) Info(args ...any) { -} - -func (l *nopLogger) Infof(format string, args ...any) { -} - -func (l *nopLogger) Warn(args ...any) { -} - -func (l *nopLogger) Warnf(format string, args ...any) { -} - -func (l *nopLogger) Error(args ...any) { -} - -func (l *nopLogger) Errorf(format string, args ...any) { -} - -func (l *nopLogger) Fatal(args ...any) { -} - -func (l *nopLogger) Fatalf(format string, args ...any) { -} - -func (l *nopLogger) GetLevel() LogLevel { - return "" -} - -func (l *nopLogger) IsLevelEnabled(level LogLevel) bool { - return false -} diff --git a/pkg/metadata/metadata.go b/pkg/metadata/metadata.go deleted file mode 100644 index 19aadb9..0000000 --- a/pkg/metadata/metadata.go +++ /dev/null @@ -1,156 +0,0 @@ -package metadata - -import ( - "fmt" - "strconv" - "time" -) - -type Metadatable interface { - GetMetadata() Metadata -} - -type Metadata interface { - IsExists(key string) bool - Set(key string, value any) - Get(key string) any -} - -type MapMetadata map[string]any - -func (m MapMetadata) IsExists(key string) bool { - _, ok := m[key] - return ok -} - -func (m MapMetadata) Set(key string, value any) { - m[key] = value -} - -func (m MapMetadata) Get(key string) any { - if m != nil { - return m[key] - } - return nil -} - -func (m MapMetadata) Del(key string) { - delete(m, key) -} - -func GetBool(md Metadata, key string) (v bool) { - if md == nil || !md.IsExists(key) { - return - } - switch vv := md.Get(key).(type) { - case bool: - return vv - case int: - return vv != 0 - case string: - v, _ = strconv.ParseBool(vv) - return - } - return -} - -func GetInt(md Metadata, key string) (v int) { - if md == nil { - return - } - - switch vv := md.Get(key).(type) { - case bool: - if vv { - v = 1 - } - case int: - return vv - case string: - v, _ = strconv.Atoi(vv) - return - } - return -} - -func GetFloat(md Metadata, key string) (v float64) { - if md == nil { - return - } - - switch vv := md.Get(key).(type) { - case int: - return float64(vv) - case string: - v, _ = strconv.ParseFloat(vv, 64) - return - } - return -} - -func GetDuration(md Metadata, key string) (v time.Duration) { - if md == nil { - return - } - switch vv := md.Get(key).(type) { - case int: - return time.Duration(vv) * time.Second - case string: - v, _ = time.ParseDuration(vv) - if v == 0 { - n, _ := strconv.Atoi(vv) - v = time.Duration(n) * time.Second - } - } - return -} - -func GetString(md Metadata, key string) (v string) { - if md != nil { - v, _ = md.Get(key).(string) - } - return -} - -func GetStrings(md Metadata, key string) (ss []string) { - switch v := md.Get(key).(type) { - case []string: - ss = v - case []any: - for _, vv := range v { - if s, ok := vv.(string); ok { - ss = append(ss, s) - } - } - } - return -} - -func GetStringMap(md Metadata, key string) (m map[string]any) { - switch vv := md.Get(key).(type) { - case map[string]any: - return vv - case map[any]any: - m = make(map[string]any) - for k, v := range vv { - m[fmt.Sprintf("%v", k)] = v - } - } - return -} - -func GetStringMapString(md Metadata, key string) (m map[string]string) { - switch vv := md.Get(key).(type) { - case map[string]any: - m = make(map[string]string) - for k, v := range vv { - m[k] = fmt.Sprintf("%v", v) - } - case map[any]any: - m = make(map[string]string) - for k, v := range vv { - m[fmt.Sprintf("%v", k)] = fmt.Sprintf("%v", v) - } - } - return -} diff --git a/pkg/registry/admission.go b/pkg/registry/admission.go deleted file mode 100644 index c6a624c..0000000 --- a/pkg/registry/admission.go +++ /dev/null @@ -1,40 +0,0 @@ -package registry - -import ( - "github.com/go-gost/gost/v3/pkg/admission" -) - -type admissionRegistry struct { - registry -} - -func (r *admissionRegistry) Register(name string, v admission.Admission) error { - return r.registry.Register(name, v) -} - -func (r *admissionRegistry) Get(name string) admission.Admission { - if name != "" { - return &admissionWrapper{name: name, r: r} - } - return nil -} - -func (r *admissionRegistry) get(name string) admission.Admission { - if v := r.registry.Get(name); v != nil { - return v.(admission.Admission) - } - return nil -} - -type admissionWrapper struct { - name string - r *admissionRegistry -} - -func (w *admissionWrapper) Admit(addr string) bool { - p := w.r.get(w.name) - if p == nil { - return false - } - return p.Admit(addr) -} diff --git a/pkg/registry/auther.go b/pkg/registry/auther.go deleted file mode 100644 index e411074..0000000 --- a/pkg/registry/auther.go +++ /dev/null @@ -1,40 +0,0 @@ -package registry - -import ( - "github.com/go-gost/gost/v3/pkg/auth" -) - -type autherRegistry struct { - registry -} - -func (r *autherRegistry) Register(name string, v auth.Authenticator) error { - return r.registry.Register(name, v) -} - -func (r *autherRegistry) Get(name string) auth.Authenticator { - if name != "" { - return &autherWrapper{name: name, r: r} - } - return nil -} - -func (r *autherRegistry) get(name string) auth.Authenticator { - if v := r.registry.Get(name); v != nil { - return v.(auth.Authenticator) - } - return nil -} - -type autherWrapper struct { - name string - r *autherRegistry -} - -func (w *autherWrapper) Authenticate(user, password string) bool { - v := w.r.get(w.name) - if v == nil { - return true - } - return v.Authenticate(user, password) -} diff --git a/pkg/registry/bypass.go b/pkg/registry/bypass.go deleted file mode 100644 index c06cf62..0000000 --- a/pkg/registry/bypass.go +++ /dev/null @@ -1,40 +0,0 @@ -package registry - -import ( - "github.com/go-gost/gost/v3/pkg/bypass" -) - -type bypassRegistry struct { - registry -} - -func (r *bypassRegistry) Register(name string, v bypass.Bypass) error { - return r.registry.Register(name, v) -} - -func (r *bypassRegistry) Get(name string) bypass.Bypass { - if name != "" { - return &bypassWrapper{name: name, r: r} - } - return nil -} - -func (r *bypassRegistry) get(name string) bypass.Bypass { - if v := r.registry.Get(name); v != nil { - return v.(bypass.Bypass) - } - return nil -} - -type bypassWrapper struct { - name string - r *bypassRegistry -} - -func (w *bypassWrapper) Contains(addr string) bool { - bp := w.r.get(w.name) - if bp == nil { - return false - } - return bp.Contains(addr) -} diff --git a/pkg/registry/chain.go b/pkg/registry/chain.go deleted file mode 100644 index 150489d..0000000 --- a/pkg/registry/chain.go +++ /dev/null @@ -1,40 +0,0 @@ -package registry - -import ( - "github.com/go-gost/gost/v3/pkg/chain" -) - -type chainRegistry struct { - registry -} - -func (r *chainRegistry) Register(name string, v chain.Chainer) error { - return r.registry.Register(name, v) -} - -func (r *chainRegistry) Get(name string) chain.Chainer { - if name != "" { - return &chainWrapper{name: name, r: r} - } - return nil -} - -func (r *chainRegistry) get(name string) chain.Chainer { - if v := r.registry.Get(name); v != nil { - return v.(chain.Chainer) - } - return nil -} - -type chainWrapper struct { - name string - r *chainRegistry -} - -func (w *chainWrapper) Route(network, address string) *chain.Route { - v := w.r.get(w.name) - if v == nil { - return nil - } - return v.Route(network, address) -} diff --git a/pkg/registry/connector.go b/pkg/registry/connector.go deleted file mode 100644 index ea06eaa..0000000 --- a/pkg/registry/connector.go +++ /dev/null @@ -1,26 +0,0 @@ -package registry - -import ( - "github.com/go-gost/gost/v3/pkg/connector" - "github.com/go-gost/gost/v3/pkg/logger" -) - -type NewConnector func(opts ...connector.Option) connector.Connector - -type connectorRegistry struct { - registry -} - -func (r *connectorRegistry) Register(name string, v NewConnector) error { - if err := r.registry.Register(name, v); err != nil { - logger.Default().Fatal(err) - } - return nil -} - -func (r *connectorRegistry) Get(name string) NewConnector { - if v := r.registry.Get(name); v != nil { - return v.(NewConnector) - } - return nil -} diff --git a/pkg/registry/dialer.go b/pkg/registry/dialer.go deleted file mode 100644 index d72ec53..0000000 --- a/pkg/registry/dialer.go +++ /dev/null @@ -1,26 +0,0 @@ -package registry - -import ( - "github.com/go-gost/gost/v3/pkg/dialer" - "github.com/go-gost/gost/v3/pkg/logger" -) - -type NewDialer func(opts ...dialer.Option) dialer.Dialer - -type dialerRegistry struct { - registry -} - -func (r *dialerRegistry) Register(name string, v NewDialer) error { - if err := r.registry.Register(name, v); err != nil { - logger.Default().Fatal(err) - } - return nil -} - -func (r *dialerRegistry) Get(name string) NewDialer { - if v := r.registry.Get(name); v != nil { - return v.(NewDialer) - } - return nil -} diff --git a/pkg/registry/handler.go b/pkg/registry/handler.go deleted file mode 100644 index cec9a7e..0000000 --- a/pkg/registry/handler.go +++ /dev/null @@ -1,26 +0,0 @@ -package registry - -import ( - "github.com/go-gost/gost/v3/pkg/handler" - "github.com/go-gost/gost/v3/pkg/logger" -) - -type NewHandler func(opts ...handler.Option) handler.Handler - -type handlerRegistry struct { - registry -} - -func (r *handlerRegistry) Register(name string, v NewHandler) error { - if err := r.registry.Register(name, v); err != nil { - logger.Default().Fatal(err) - } - return nil -} - -func (r *handlerRegistry) Get(name string) NewHandler { - if v := r.registry.Get(name); v != nil { - return v.(NewHandler) - } - return nil -} diff --git a/pkg/registry/hosts.go b/pkg/registry/hosts.go deleted file mode 100644 index 64442cd..0000000 --- a/pkg/registry/hosts.go +++ /dev/null @@ -1,42 +0,0 @@ -package registry - -import ( - "net" - - "github.com/go-gost/gost/v3/pkg/hosts" -) - -type hostsRegistry struct { - registry -} - -func (r *hostsRegistry) Register(name string, v hosts.HostMapper) error { - return r.registry.Register(name, v) -} - -func (r *hostsRegistry) Get(name string) hosts.HostMapper { - if name != "" { - return &hostsWrapper{name: name, r: r} - } - return nil -} - -func (r *hostsRegistry) get(name string) hosts.HostMapper { - if v := r.registry.Get(name); v != nil { - return v.(hosts.HostMapper) - } - return nil -} - -type hostsWrapper struct { - name string - r *hostsRegistry -} - -func (w *hostsWrapper) Lookup(network, host string) ([]net.IP, bool) { - v := w.r.get(w.name) - if v == nil { - return nil, false - } - return v.Lookup(network, host) -} diff --git a/pkg/registry/listener.go b/pkg/registry/listener.go deleted file mode 100644 index c35918e..0000000 --- a/pkg/registry/listener.go +++ /dev/null @@ -1,26 +0,0 @@ -package registry - -import ( - "github.com/go-gost/gost/v3/pkg/listener" - "github.com/go-gost/gost/v3/pkg/logger" -) - -type NewListener func(opts ...listener.Option) listener.Listener - -type listenerRegistry struct { - registry -} - -func (r *listenerRegistry) Register(name string, v NewListener) error { - if err := r.registry.Register(name, v); err != nil { - logger.Default().Fatal(err) - } - return nil -} - -func (r *listenerRegistry) Get(name string) NewListener { - if v := r.registry.Get(name); v != nil { - return v.(NewListener) - } - return nil -} diff --git a/pkg/registry/registry.go b/pkg/registry/registry.go deleted file mode 100644 index ccdd3a2..0000000 --- a/pkg/registry/registry.go +++ /dev/null @@ -1,116 +0,0 @@ -package registry - -import ( - "errors" - "sync" - - "github.com/go-gost/gost/v3/pkg/admission" - "github.com/go-gost/gost/v3/pkg/auth" - "github.com/go-gost/gost/v3/pkg/bypass" - "github.com/go-gost/gost/v3/pkg/chain" - "github.com/go-gost/gost/v3/pkg/hosts" - "github.com/go-gost/gost/v3/pkg/resolver" - "github.com/go-gost/gost/v3/pkg/service" -) - -var ( - ErrDup = errors.New("registry: duplicate object") -) - -var ( - listenerReg Registry[NewListener] = &listenerRegistry{} - handlerReg Registry[NewHandler] = &handlerRegistry{} - dialerReg Registry[NewDialer] = &dialerRegistry{} - connectorReg Registry[NewConnector] = &connectorRegistry{} - - serviceReg Registry[service.Service] = &serviceRegistry{} - chainReg Registry[chain.Chainer] = &chainRegistry{} - autherReg Registry[auth.Authenticator] = &autherRegistry{} - admissionReg Registry[admission.Admission] = &admissionRegistry{} - bypassReg Registry[bypass.Bypass] = &bypassRegistry{} - resolverReg Registry[resolver.Resolver] = &resolverRegistry{} - hostsReg Registry[hosts.HostMapper] = &hostsRegistry{} -) - -type Registry[T any] interface { - Register(name string, v T) error - Unregister(name string) - IsRegistered(name string) bool - Get(name string) T -} - -type registry struct { - m sync.Map -} - -func (r *registry) Register(name string, v any) error { - if name == "" || v == nil { - return nil - } - if _, loaded := r.m.LoadOrStore(name, v); loaded { - return ErrDup - } - - return nil -} - -func (r *registry) Unregister(name string) { - r.m.Delete(name) -} - -func (r *registry) IsRegistered(name string) bool { - _, ok := r.m.Load(name) - return ok -} - -func (r *registry) Get(name string) any { - if name == "" { - return nil - } - v, _ := r.m.Load(name) - return v -} - -func ListenerRegistry() Registry[NewListener] { - return listenerReg -} - -func HandlerRegistry() Registry[NewHandler] { - return handlerReg -} - -func DialerRegistry() Registry[NewDialer] { - return dialerReg -} - -func ConnectorRegistry() Registry[NewConnector] { - return connectorReg -} - -func ServiceRegistry() Registry[service.Service] { - return serviceReg -} - -func ChainRegistry() Registry[chain.Chainer] { - return chainReg -} - -func AutherRegistry() Registry[auth.Authenticator] { - return autherReg -} - -func AdmissionRegistry() Registry[admission.Admission] { - return admissionReg -} - -func BypassRegistry() Registry[bypass.Bypass] { - return bypassReg -} - -func ResolverRegistry() Registry[resolver.Resolver] { - return resolverReg -} - -func HostsRegistry() Registry[hosts.HostMapper] { - return hostsReg -} diff --git a/pkg/registry/resolver.go b/pkg/registry/resolver.go deleted file mode 100644 index ee13d9b..0000000 --- a/pkg/registry/resolver.go +++ /dev/null @@ -1,43 +0,0 @@ -package registry - -import ( - "context" - "net" - - "github.com/go-gost/gost/v3/pkg/resolver" -) - -type resolverRegistry struct { - registry -} - -func (r *resolverRegistry) Register(name string, v resolver.Resolver) error { - return r.registry.Register(name, v) -} - -func (r *resolverRegistry) Get(name string) resolver.Resolver { - if name != "" { - return &resolverWrapper{name: name, r: r} - } - return nil -} - -func (r *resolverRegistry) get(name string) resolver.Resolver { - if v := r.registry.Get(name); v != nil { - return v.(resolver.Resolver) - } - return nil -} - -type resolverWrapper struct { - name string - r *resolverRegistry -} - -func (w *resolverWrapper) Resolve(ctx context.Context, network, host string) ([]net.IP, error) { - r := w.r.get(w.name) - if r == nil { - return nil, resolver.ErrInvalid - } - return r.Resolve(ctx, network, host) -} diff --git a/pkg/registry/service.go b/pkg/registry/service.go deleted file mode 100644 index 5d73738..0000000 --- a/pkg/registry/service.go +++ /dev/null @@ -1,20 +0,0 @@ -package registry - -import ( - "github.com/go-gost/gost/v3/pkg/service" -) - -type serviceRegistry struct { - registry -} - -func (r *serviceRegistry) Register(name string, v service.Service) error { - return r.registry.Register(name, v) -} - -func (r *serviceRegistry) Get(name string) service.Service { - if v := r.registry.Get(name); v != nil { - return v.(service.Service) - } - return nil -} diff --git a/pkg/resolver/exchanger/exchanger.go b/pkg/resolver/exchanger/exchanger.go deleted file mode 100644 index d7889c5..0000000 --- a/pkg/resolver/exchanger/exchanger.go +++ /dev/null @@ -1,220 +0,0 @@ -package exchanger - -import ( - "bytes" - "context" - "crypto/tls" - "fmt" - "io/ioutil" - "net" - "net/http" - "net/url" - "strings" - "time" - - "github.com/go-gost/gost/v3/pkg/chain" - "github.com/go-gost/gost/v3/pkg/logger" - "github.com/miekg/dns" -) - -type Options struct { - router *chain.Router - tlsConfig *tls.Config - timeout time.Duration - logger logger.Logger -} - -// Option allows a common way to set Exchanger options. -type Option func(opts *Options) - -// RouterOption sets the router for Exchanger. -func RouterOption(router *chain.Router) Option { - return func(opts *Options) { - opts.router = router - } -} - -// TLSConfigOption sets the TLS config for Exchanger. -func TLSConfigOption(cfg *tls.Config) Option { - return func(opts *Options) { - opts.tlsConfig = cfg - } -} - -// LoggerOption sets the logger for Exchanger. -func LoggerOption(logger logger.Logger) Option { - return func(opts *Options) { - opts.logger = logger - } -} - -// TimeoutOption sets the timeout for Exchanger. -func TimeoutOption(timeout time.Duration) Option { - return func(opts *Options) { - opts.timeout = timeout - } -} - -// Exchanger is an interface for DNS synchronous query. -type Exchanger interface { - Exchange(ctx context.Context, msg []byte) ([]byte, error) - String() string -} - -type exchanger struct { - network string - addr string - rawAddr string - router *chain.Router - client *http.Client - options Options -} - -// NewExchanger create an Exchanger. -// The addr should be URL-like format, -// e.g. udp://1.1.1.1:53, tls://1.1.1.1:853, https://1.0.0.1/dns-query -func NewExchanger(addr string, opts ...Option) (Exchanger, error) { - var options Options - for _, opt := range opts { - opt(&options) - } - - if !strings.Contains(addr, "://") { - addr = "udp://" + addr - } - u, err := url.Parse(addr) - if err != nil { - return nil, err - } - - if options.timeout <= 0 { - options.timeout = 5 * time.Second - } - - ex := &exchanger{ - network: u.Scheme, - addr: u.Host, - rawAddr: addr, - router: options.router, - options: options, - } - if _, port, _ := net.SplitHostPort(ex.addr); port == "" { - ex.addr = net.JoinHostPort(ex.addr, "53") - } - if ex.router == nil { - ex.router = (&chain.Router{}).WithLogger(options.logger) - } - - switch ex.network { - case "tcp": - case "dot", "tls": - if ex.options.tlsConfig == nil { - ex.options.tlsConfig = &tls.Config{ - InsecureSkipVerify: true, - } - } - ex.network = "tcp" - case "https": - ex.addr = addr - if ex.options.tlsConfig == nil { - ex.options.tlsConfig = &tls.Config{ - InsecureSkipVerify: true, - } - } - ex.client = &http.Client{ - Timeout: options.timeout, - Transport: &http.Transport{ - TLSClientConfig: options.tlsConfig, - ForceAttemptHTTP2: true, - MaxIdleConns: 100, - IdleConnTimeout: 90 * time.Second, - TLSHandshakeTimeout: options.timeout, - ExpectContinueTimeout: 1 * time.Second, - DialContext: ex.dial, - }, - } - default: - ex.network = "udp" - } - - return ex, nil -} - -func (ex *exchanger) Exchange(ctx context.Context, msg []byte) ([]byte, error) { - if ex.network == "https" { - return ex.dohExchange(ctx, msg) - } - return ex.exchange(ctx, msg) -} - -func (ex *exchanger) dohExchange(ctx context.Context, msg []byte) ([]byte, error) { - req, err := http.NewRequestWithContext(ctx, "POST", ex.addr, bytes.NewBuffer(msg)) - if err != nil { - return nil, fmt.Errorf("failed to create an HTTPS request: %w", err) - } - - // req.Header.Add("Content-Type", "application/dns-udpwireformat") - req.Header.Add("Content-Type", "application/dns-message") - - client := ex.client - if client == nil { - client = http.DefaultClient - } - resp, err := client.Do(req) - if err != nil { - return nil, fmt.Errorf("failed to perform an HTTPS request: %w", err) - } - - // Check response status code - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("returned status code %d", resp.StatusCode) - } - - // Read wireformat response from the body - buf, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("failed to read the response body: %w", err) - } - - return buf, nil -} - -func (ex *exchanger) exchange(ctx context.Context, msg []byte) ([]byte, error) { - if ex.options.timeout > 0 { - var cancel context.CancelFunc - ctx, cancel = context.WithTimeout(ctx, ex.options.timeout) - defer cancel() - } - - c, err := ex.dial(ctx, ex.network, ex.addr) - if err != nil { - return nil, err - } - defer c.Close() - - if ex.options.tlsConfig != nil { - c = tls.Client(c, ex.options.tlsConfig) - } - - conn := &dns.Conn{Conn: c} - - if _, err = conn.Write(msg); err != nil { - return nil, err - } - - mr, err := conn.ReadMsg() - if err != nil { - return nil, err - } - - return mr.Pack() -} - -func (ex *exchanger) dial(ctx context.Context, network, address string) (net.Conn, error) { - return ex.router.Dial(ctx, network, address) -} - -func (ex *exchanger) String() string { - return ex.rawAddr -} diff --git a/pkg/resolver/impl/resolver.go b/pkg/resolver/impl/resolver.go deleted file mode 100644 index bc3708a..0000000 --- a/pkg/resolver/impl/resolver.go +++ /dev/null @@ -1,178 +0,0 @@ -package impl - -import ( - "context" - "net" - "strings" - "time" - - "github.com/go-gost/gost/v3/pkg/chain" - resolver_util "github.com/go-gost/gost/v3/pkg/common/util/resolver" - "github.com/go-gost/gost/v3/pkg/logger" - resolverpkg "github.com/go-gost/gost/v3/pkg/resolver" - "github.com/go-gost/gost/v3/pkg/resolver/exchanger" - "github.com/miekg/dns" -) - -type NameServer struct { - Addr string - Chain chain.Chainer - TTL time.Duration - Timeout time.Duration - ClientIP net.IP - Prefer string - Hostname string // for TLS handshake verification - exchanger exchanger.Exchanger -} - -type resolverOptions struct { - domain string - logger logger.Logger -} - -type ResolverOption func(opts *resolverOptions) - -func DomainResolverOption(domain string) ResolverOption { - return func(opts *resolverOptions) { - opts.domain = domain - } -} - -func LoggerResolverOption(logger logger.Logger) ResolverOption { - return func(opts *resolverOptions) { - opts.logger = logger - } -} - -type resolver struct { - servers []NameServer - cache *resolver_util.Cache - options resolverOptions -} - -func NewResolver(nameservers []NameServer, opts ...ResolverOption) (resolverpkg.Resolver, error) { - options := resolverOptions{} - for _, opt := range opts { - opt(&options) - } - - var servers []NameServer - for _, server := range nameservers { - addr := strings.TrimSpace(server.Addr) - if addr == "" { - continue - } - ex, err := exchanger.NewExchanger( - addr, - exchanger.RouterOption( - (&chain.Router{}). - WithChain(server.Chain). - WithLogger(options.logger), - ), - exchanger.TimeoutOption(server.Timeout), - exchanger.LoggerOption(options.logger), - ) - if err != nil { - options.logger.Warnf("parse %s: %v", server, err) - continue - } - - server.exchanger = ex - servers = append(servers, server) - } - cache := resolver_util.NewCache(). - WithLogger(options.logger) - - return &resolver{ - servers: servers, - cache: cache, - options: options, - }, nil -} - -func (r *resolver) Resolve(ctx context.Context, network, host string) (ips []net.IP, err error) { - if ip := net.ParseIP(host); ip != nil { - return []net.IP{ip}, nil - } - - if r.options.domain != "" && - !strings.Contains(host, ".") { - host = host + "." + r.options.domain - } - - for _, server := range r.servers { - ips, err = r.resolve(ctx, &server, host) - if err != nil { - r.options.logger.Error(err) - continue - } - - r.options.logger.Debugf("resolve %s via %s: %v", host, server.exchanger.String(), ips) - - if len(ips) > 0 { - break - } - } - - return -} - -func (r *resolver) resolve(ctx context.Context, server *NameServer, host string) (ips []net.IP, err error) { - if server == nil { - return - } - - if server.Prefer == "ipv6" { // prefer ipv6 - mq := dns.Msg{} - mq.SetQuestion(dns.Fqdn(host), dns.TypeAAAA) - ips, err = r.resolveIPs(ctx, server, &mq) - if err != nil || len(ips) > 0 { - return - } - } - - // fallback to ipv4 - mq := dns.Msg{} - mq.SetQuestion(dns.Fqdn(host), dns.TypeA) - return r.resolveIPs(ctx, server, &mq) -} - -func (r *resolver) resolveIPs(ctx context.Context, server *NameServer, mq *dns.Msg) (ips []net.IP, err error) { - key := resolver_util.NewCacheKey(&mq.Question[0]) - mr := r.cache.Load(key) - if mr == nil { - resolver_util.AddSubnetOpt(mq, server.ClientIP) - mr, err = r.exchange(ctx, server.exchanger, mq) - if err != nil { - return - } - r.cache.Store(key, mr, server.TTL) - } - - for _, ans := range mr.Answer { - if ar, _ := ans.(*dns.AAAA); ar != nil { - ips = append(ips, ar.AAAA) - } - if ar, _ := ans.(*dns.A); ar != nil { - ips = append(ips, ar.A) - } - } - - return -} - -func (r *resolver) exchange(ctx context.Context, ex exchanger.Exchanger, mq *dns.Msg) (mr *dns.Msg, err error) { - query, err := mq.Pack() - if err != nil { - return - } - reply, err := ex.Exchange(ctx, query) - if err != nil { - return - } - - mr = &dns.Msg{} - err = mr.Unpack(reply) - - return -} diff --git a/pkg/resolver/resolver.go b/pkg/resolver/resolver.go deleted file mode 100644 index ad0435c..0000000 --- a/pkg/resolver/resolver.go +++ /dev/null @@ -1,17 +0,0 @@ -package resolver - -import ( - "context" - "errors" - "net" -) - -var ( - ErrInvalid = errors.New("resolver is invalid") -) - -type Resolver interface { - // Resolve returns a slice of the host's IPv4 and IPv6 addresses. - // The network should be 'ip', 'ip4' or 'ip6', default network is 'ip'. - Resolve(ctx context.Context, network, host string) ([]net.IP, error) -} diff --git a/pkg/service/service.go b/pkg/service/service.go deleted file mode 100644 index 5f17257..0000000 --- a/pkg/service/service.go +++ /dev/null @@ -1,120 +0,0 @@ -package service - -import ( - "context" - "net" - "time" - - "github.com/go-gost/gost/v3/pkg/admission" - "github.com/go-gost/gost/v3/pkg/handler" - "github.com/go-gost/gost/v3/pkg/listener" - "github.com/go-gost/gost/v3/pkg/logger" - "github.com/go-gost/metrics" -) - -type options struct { - admission admission.Admission - logger logger.Logger -} - -type Option func(opts *options) - -func AdmissionOption(admission admission.Admission) Option { - return func(opts *options) { - opts.admission = admission - } -} - -func LoggerOption(logger logger.Logger) Option { - return func(opts *options) { - opts.logger = logger - } -} - -type Service interface { - Serve() error - Addr() net.Addr - Close() error -} - -type service struct { - name string - listener listener.Listener - handler handler.Handler - options options -} - -func NewService(name string, ln listener.Listener, h handler.Handler, opts ...Option) Service { - var options options - for _, opt := range opts { - opt(&options) - } - return &service{ - name: name, - listener: ln, - handler: h, - options: options, - } -} - -func (s *service) Addr() net.Addr { - return s.listener.Addr() -} - -func (s *service) Close() error { - return s.listener.Close() -} - -func (s *service) Serve() error { - metrics.Services().Inc() - defer metrics.Services().Dec() - - var tempDelay time.Duration - for { - conn, e := s.listener.Accept() - if e != nil { - if ne, ok := e.(net.Error); ok && ne.Temporary() { - if tempDelay == 0 { - tempDelay = 1 * time.Second - } else { - tempDelay *= 2 - } - if max := 5 * time.Second; tempDelay > max { - tempDelay = max - } - s.options.logger.Warnf("accept: %v, retrying in %v", e, tempDelay) - time.Sleep(tempDelay) - continue - } - s.options.logger.Errorf("accept: %v", e) - return e - } - tempDelay = 0 - - if s.options.admission != nil && - !s.options.admission.Admit(conn.RemoteAddr().String()) { - conn.Close() - continue - } - - go func() { - metrics.Requests(s.name).Inc() - - metrics.RequestsInFlight(s.name).Inc() - defer metrics.RequestsInFlight(s.name).Dec() - - start := time.Now() - defer func() { - metrics.RequestSeconds(s.name).Observe(time.Since(start).Seconds()) - }() - - if err := s.handler.Handle( - context.Background(), - conn, - ); err != nil { - s.options.logger.Error(err) - metrics.HandlerErrors(s.name).Inc() - } - }() - } -}