From c428b37a36224fa33a041e60051a56a837801def Mon Sep 17 00:00:00 2001 From: ginuerzh Date: Tue, 4 Jan 2022 21:56:58 +0800 Subject: [PATCH] update handler options --- cmd/gost/config.go | 29 ++--- pkg/auth/auth.go | 11 +- pkg/common/util/auth/auth.go | 24 ++++ pkg/config/config.go | 1 + pkg/connector/http/metadata.go | 1 - pkg/connector/socks/v5/connector.go | 14 +-- pkg/connector/ss/connector.go | 23 ++-- pkg/connector/ss/udp/connector.go | 23 ++-- pkg/handler/dns/handler.go | 27 ++-- pkg/handler/forward/local/handler.go | 30 +++-- pkg/handler/forward/remote/handler.go | 33 ++--- pkg/handler/forward/ssh/handler.go | 38 +++--- pkg/handler/http/handler.go | 24 ++-- pkg/handler/http/udp.go | 2 +- pkg/handler/http2/handler.go | 174 +++----------------------- pkg/handler/option.go | 42 +++++-- pkg/handler/redirect/handler.go | 34 +++-- pkg/handler/relay/bind.go | 4 +- pkg/handler/relay/connect.go | 2 +- pkg/handler/relay/handler.go | 21 ++-- pkg/handler/sni/handler.go | 22 ++-- pkg/handler/socks/v4/handler.go | 24 ++-- pkg/handler/socks/v5/connect.go | 2 +- pkg/handler/socks/v5/handler.go | 33 ++--- pkg/handler/socks/v5/udp.go | 2 +- pkg/handler/socks/v5/udp_tun.go | 2 +- pkg/handler/ss/handler.go | 48 ++++--- pkg/handler/ss/metadata.go | 22 +--- pkg/handler/ss/udp/handler.go | 55 +++++--- pkg/handler/ss/udp/metadata.go | 22 +--- pkg/handler/tap/handler.go | 56 ++++++--- pkg/handler/tap/metadata.go | 29 +---- pkg/handler/tun/handler.go | 56 ++++++--- pkg/handler/tun/metadata.go | 28 +---- pkg/listener/option.go | 13 +- pkg/listener/ssh/listener.go | 21 ++-- 36 files changed, 468 insertions(+), 524 deletions(-) create mode 100644 pkg/common/util/auth/auth.go diff --git a/cmd/gost/config.go b/cmd/gost/config.go index 54c305c..0155c55 100644 --- a/cmd/gost/config.go +++ b/cmd/gost/config.go @@ -7,7 +7,6 @@ import ( "os" "strings" - "github.com/go-gost/gost/pkg/auth" "github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/chain" "github.com/go-gost/gost/pkg/config" @@ -71,7 +70,7 @@ func buildService(cfg *config.Config) (services []*service.Service) { }) ln := registry.GetListener(svc.Listener.Type)( listener.AddrOption(svc.Addr), - listener.AuthenticatorOption(authFromConfig(svc.Listener.Auths...)), + listener.AuthsOption(authsFromConfig(svc.Listener.Auths...)...), listener.LoggerOption(listenerLogger), ) @@ -91,15 +90,13 @@ func buildService(cfg *config.Config) (services []*service.Service) { }) h := registry.GetHandler(svc.Handler.Type)( - handler.LoggerOption(handlerLogger), + handler.RetriesOption(svc.Handler.Retries), + handler.ChainOption(chains[svc.Handler.Chain]), + handler.ResolverOption(resolvers[svc.Handler.Resolver]), + handler.HostsOption(hosts[svc.Handler.Hosts]), handler.BypassOption(bypasses[svc.Handler.Bypass]), - handler.AuthenticatorOption(authFromConfig(svc.Handler.Auths...)), - handler.RouterOption(&chain.Router{ - Chain: chains[svc.Handler.Chain], - Resolver: resolvers[svc.Handler.Resolver], - Hosts: hosts[svc.Handler.Hosts], - Logger: handlerLogger, - }), + handler.AuthsOption(authsFromConfig(svc.Handler.Auths...)...), + handler.LoggerOption(handlerLogger), ) if forwarder, ok := h.(handler.Forwarder); ok { @@ -331,17 +328,15 @@ func hostsFromConfig(cfg *config.HostsConfig) hostspkg.HostMapper { return hosts } -func authFromConfig(cfgs ...config.AuthConfig) auth.Authenticator { - auths := make(map[string]string) +func authsFromConfig(cfgs ...config.AuthConfig) []*url.Userinfo { + var auths []*url.Userinfo + for _, cfg := range cfgs { if cfg.Username == "" { continue } - auths[cfg.Username] = cfg.Password - } - if len(auths) > 0 { - return auth.NewMapAuthenticator(auths) + auths = append(auths, url.UserPassword(cfg.Username, cfg.Password)) } - return nil + return auths } diff --git a/pkg/auth/auth.go b/pkg/auth/auth.go index 5c2428c..b175418 100644 --- a/pkg/auth/auth.go +++ b/pkg/auth/auth.go @@ -11,10 +11,7 @@ type MapAuthenticator struct { } // NewMapAuthenticator creates an Authenticator that authenticates client by local infos. -func NewMapAuthenticator(kvs map[string]string) *MapAuthenticator { - if kvs == nil { - kvs = make(map[string]string) - } +func NewMapAuthenticator(kvs map[string]string) Authenticator { return &MapAuthenticator{ kvs: kvs, } @@ -22,11 +19,7 @@ func NewMapAuthenticator(kvs map[string]string) *MapAuthenticator { // Authenticate checks the validity of the provided user-password pair. func (au *MapAuthenticator) Authenticate(user, password string) bool { - if au == nil { - return true - } - - if len(au.kvs) == 0 { + if au == nil || len(au.kvs) == 0 { return true } diff --git a/pkg/common/util/auth/auth.go b/pkg/common/util/auth/auth.go new file mode 100644 index 0000000..09bb4ef --- /dev/null +++ b/pkg/common/util/auth/auth.go @@ -0,0 +1,24 @@ +package auth + +import ( + "net/url" + + "github.com/go-gost/gost/pkg/auth" +) + +func AuthFromUsers(users ...*url.Userinfo) auth.Authenticator { + kvs := make(map[string]string) + for _, v := range users { + if v == nil || v.Username() == "" { + continue + } + kvs[v.Username()], _ = v.Password() + } + + var authenticator auth.Authenticator + if len(kvs) > 0 { + authenticator = auth.NewMapAuthenticator(kvs) + } + + return authenticator +} diff --git a/pkg/config/config.go b/pkg/config/config.go index 6f0484a..4c61dd9 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -88,6 +88,7 @@ type ListenerConfig struct { type HandlerConfig struct { Type string + Retries int `yaml:",omitempty"` Chain string `yaml:",omitempty"` Bypass string `yaml:",omitempty"` Resolver string `yaml:",omitempty"` diff --git a/pkg/connector/http/metadata.go b/pkg/connector/http/metadata.go index 3208989..b2c31c1 100644 --- a/pkg/connector/http/metadata.go +++ b/pkg/connector/http/metadata.go @@ -15,7 +15,6 @@ type metadata struct { func (c *httpConnector) parseMetadata(md mdata.Metadata) (err error) { const ( connectTimeout = "timeout" - user = "user" header = "header" ) diff --git a/pkg/connector/socks/v5/connector.go b/pkg/connector/socks/v5/connector.go index db20e8e..1a4abf9 100644 --- a/pkg/connector/socks/v5/connector.go +++ b/pkg/connector/socks/v5/connector.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "net" - "net/url" "time" "github.com/go-gost/gosocks5" @@ -24,20 +23,19 @@ func init() { type socks5Connector struct { selector gosocks5.Selector - user *url.Userinfo logger logger.Logger md metadata + options connector.Options } func NewConnector(opts ...connector.Option) connector.Connector { - options := &connector.Options{} + options := connector.Options{} for _, opt := range opts { - opt(options) + opt(&options) } return &socks5Connector{ - user: options.User, - logger: options.Logger, + options: options, } } @@ -46,13 +44,15 @@ func (c *socks5Connector) Init(md md.Metadata) (err error) { return } + c.logger = c.options.Logger + selector := &clientSelector{ methods: []uint8{ gosocks5.MethodNoAuth, gosocks5.MethodUserPass, }, logger: c.logger, - User: c.user, + User: c.options.User, TLSConfig: c.md.tlsConfig, } if !c.md.noTLS { diff --git a/pkg/connector/ss/connector.go b/pkg/connector/ss/connector.go index b956861..148f61a 100644 --- a/pkg/connector/ss/connector.go +++ b/pkg/connector/ss/connector.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "net" - "net/url" "time" "github.com/go-gost/gosocks5" @@ -22,21 +21,21 @@ func init() { } type ssConnector struct { - user *url.Userinfo - cipher core.Cipher - md metadata - logger logger.Logger + cipher core.Cipher + md metadata + logger logger.Logger + options connector.Options } func NewConnector(opts ...connector.Option) connector.Connector { - options := &connector.Options{} + options := connector.Options{} for _, opt := range opts { - opt(options) + opt(&options) } return &ssConnector{ - user: options.User, - logger: options.Logger, + options: options, + logger: options.Logger, } } @@ -45,9 +44,9 @@ func (c *ssConnector) Init(md md.Metadata) (err error) { return } - if c.user != nil { - method := c.user.Username() - password, _ := c.user.Password() + if c.options.User != nil { + method := c.options.User.Username() + password, _ := c.options.User.Password() c.cipher, err = ss.ShadowCipher(method, password, c.md.key) } diff --git a/pkg/connector/ss/udp/connector.go b/pkg/connector/ss/udp/connector.go index e45bbe6..ccb62a6 100644 --- a/pkg/connector/ss/udp/connector.go +++ b/pkg/connector/ss/udp/connector.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "net" - "net/url" "time" "github.com/go-gost/gost/pkg/common/util/socks" @@ -21,21 +20,21 @@ func init() { } type ssuConnector struct { - user *url.Userinfo - cipher core.Cipher - md metadata - logger logger.Logger + cipher core.Cipher + md metadata + logger logger.Logger + options connector.Options } func NewConnector(opts ...connector.Option) connector.Connector { - options := &connector.Options{} + options := connector.Options{} for _, opt := range opts { - opt(options) + opt(&options) } return &ssuConnector{ - user: options.User, - logger: options.Logger, + options: options, + logger: options.Logger, } } @@ -44,9 +43,9 @@ func (c *ssuConnector) Init(md md.Metadata) (err error) { return } - if c.user != nil { - method := c.user.Username() - password, _ := c.user.Password() + if c.options.User != nil { + method := c.options.User.Username() + password, _ := c.options.User.Password() c.cipher, err = ss.ShadowCipher(method, password, c.md.key) } diff --git a/pkg/handler/dns/handler.go b/pkg/handler/dns/handler.go index c823373..dc81f8e 100644 --- a/pkg/handler/dns/handler.go +++ b/pkg/handler/dns/handler.go @@ -9,7 +9,6 @@ import ( "strings" "time" - "github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/chain" "github.com/go-gost/gost/pkg/common/bufpool" "github.com/go-gost/gost/pkg/handler" @@ -30,27 +29,22 @@ func init() { } type dnsHandler struct { - bypass bypass.Bypass - router *chain.Router exchangers []exchanger.Exchanger cache *resolver_util.Cache + router *chain.Router logger logger.Logger md metadata + options handler.Options } func NewHandler(opts ...handler.Option) handler.Handler { - options := &handler.Options{} + options := handler.Options{} for _, opt := range opts { - opt(options) + opt(&options) } - cache := resolver_util.NewCache().WithLogger(options.Logger) - return &dnsHandler{ - bypass: options.Bypass, - router: options.Router, - cache: cache, - logger: options.Logger, + options: options, } } @@ -59,6 +53,16 @@ func (h *dnsHandler) Init(md md.Metadata) (err error) { return } + h.cache = resolver_util.NewCache().WithLogger(h.options.Logger) + h.router = &chain.Router{ + Retries: h.options.Retries, + Chain: h.options.Chain, + Resolver: h.options.Resolver, + Hosts: h.options.Hosts, + Logger: h.options.Logger, + } + h.logger = h.options.Logger + for _, server := range h.md.servers { server = strings.TrimSpace(server) if server == "" { @@ -89,6 +93,7 @@ func (h *dnsHandler) Init(md md.Metadata) (err error) { } h.exchangers = append(h.exchangers, ex) } + return } diff --git a/pkg/handler/forward/local/handler.go b/pkg/handler/forward/local/handler.go index df42666..05295e4 100644 --- a/pkg/handler/forward/local/handler.go +++ b/pkg/handler/forward/local/handler.go @@ -6,7 +6,6 @@ import ( "net" "time" - "github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/chain" "github.com/go-gost/gost/pkg/handler" "github.com/go-gost/gost/pkg/logger" @@ -21,23 +20,21 @@ func init() { } type forwardHandler struct { - group *chain.NodeGroup - bypass bypass.Bypass - router *chain.Router - logger logger.Logger - md metadata + group *chain.NodeGroup + router *chain.Router + logger logger.Logger + md metadata + options handler.Options } func NewHandler(opts ...handler.Option) handler.Handler { - options := &handler.Options{} + options := handler.Options{} for _, opt := range opts { - opt(options) + opt(&options) } return &forwardHandler{ - bypass: options.Bypass, - router: options.Router, - logger: options.Logger, + options: options, } } @@ -51,7 +48,16 @@ func (h *forwardHandler) Init(md md.Metadata) (err error) { h.group = chain.NewNodeGroup(chain.NewNode("dummy", ":0")) } - return nil + h.router = &chain.Router{ + Retries: h.options.Retries, + Chain: h.options.Chain, + Resolver: h.options.Resolver, + Hosts: h.options.Hosts, + Logger: h.options.Logger, + } + h.logger = h.options.Logger + + return } // Forward implements handler.Forwarder. diff --git a/pkg/handler/forward/remote/handler.go b/pkg/handler/forward/remote/handler.go index cdb2ced..2fc0699 100644 --- a/pkg/handler/forward/remote/handler.go +++ b/pkg/handler/forward/remote/handler.go @@ -6,7 +6,6 @@ import ( "net" "time" - "github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/chain" "github.com/go-gost/gost/pkg/handler" "github.com/go-gost/gost/pkg/logger" @@ -20,27 +19,21 @@ func init() { } type forwardHandler struct { - group *chain.NodeGroup - bypass bypass.Bypass - router *chain.Router - logger logger.Logger - md metadata + group *chain.NodeGroup + router *chain.Router + logger logger.Logger + md metadata + options handler.Options } func NewHandler(opts ...handler.Option) handler.Handler { - options := &handler.Options{} + options := handler.Options{} for _, opt := range opts { - opt(options) + opt(&options) } return &forwardHandler{ - bypass: options.Bypass, - router: &chain.Router{ - Retries: options.Router.Retries, - Resolver: options.Resolver, - Logger: options.Logger, - }, - logger: options.Logger, + options: options, } } @@ -48,6 +41,16 @@ func (h *forwardHandler) Init(md md.Metadata) (err error) { if err = h.parseMetadata(md); err != nil { return } + + h.router = &chain.Router{ + Retries: h.options.Retries, + Chain: h.options.Chain, + Resolver: h.options.Resolver, + Hosts: h.options.Hosts, + Logger: h.options.Logger, + } + h.logger = h.options.Logger + return } diff --git a/pkg/handler/forward/ssh/handler.go b/pkg/handler/forward/ssh/handler.go index 8846763..0791912 100644 --- a/pkg/handler/forward/ssh/handler.go +++ b/pkg/handler/forward/ssh/handler.go @@ -8,9 +8,8 @@ import ( "strconv" "time" - "github.com/go-gost/gost/pkg/auth" - "github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/chain" + auth_util "github.com/go-gost/gost/pkg/common/util/auth" "github.com/go-gost/gost/pkg/handler" ssh_util "github.com/go-gost/gost/pkg/internal/util/ssh" "github.com/go-gost/gost/pkg/logger" @@ -32,24 +31,21 @@ func init() { } type forwardHandler struct { - bypass bypass.Bypass - config *ssh.ServerConfig - router *chain.Router - authenticator auth.Authenticator - logger logger.Logger - md metadata + config *ssh.ServerConfig + router *chain.Router + logger logger.Logger + md metadata + options handler.Options } func NewHandler(opts ...handler.Option) handler.Handler { - options := &handler.Options{} + options := handler.Options{} for _, opt := range opts { - opt(options) + opt(&options) } return &forwardHandler{ - bypass: options.Bypass, - router: options.Router, - logger: options.Logger, + options: options, } } @@ -58,18 +54,28 @@ func (h *forwardHandler) Init(md md.Metadata) (err error) { return } + authenticator := auth_util.AuthFromUsers(h.options.Auths...) + config := &ssh.ServerConfig{ - PasswordCallback: ssh_util.PasswordCallback(h.authenticator), + PasswordCallback: ssh_util.PasswordCallback(authenticator), PublicKeyCallback: ssh_util.PublicKeyCallback(h.md.authorizedKeys), } config.AddHostKey(h.md.signer) - if h.authenticator == nil && len(h.md.authorizedKeys) == 0 { + if authenticator == nil && len(h.md.authorizedKeys) == 0 { config.NoClientAuth = true } h.config = config + h.router = &chain.Router{ + Retries: h.options.Retries, + Chain: h.options.Chain, + Resolver: h.options.Resolver, + Hosts: h.options.Hosts, + Logger: h.options.Logger, + } + h.logger = h.options.Logger return nil } @@ -161,7 +167,7 @@ func (h *forwardHandler) directPortForwardChannel(ctx context.Context, channel s } */ - if h.bypass != nil && h.bypass.Contains(raddr) { + if h.options.Bypass != nil && h.options.Bypass.Contains(raddr) { h.logger.Infof("bypass %s", raddr) return } diff --git a/pkg/handler/http/handler.go b/pkg/handler/http/handler.go index 1f732a2..55f2179 100644 --- a/pkg/handler/http/handler.go +++ b/pkg/handler/http/handler.go @@ -17,8 +17,8 @@ import ( "github.com/asaskevich/govalidator" "github.com/go-gost/gost/pkg/auth" - "github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/chain" + auth_util "github.com/go-gost/gost/pkg/common/util/auth" "github.com/go-gost/gost/pkg/handler" "github.com/go-gost/gost/pkg/logger" md "github.com/go-gost/gost/pkg/metadata" @@ -30,23 +30,21 @@ func init() { } type httpHandler struct { - bypass bypass.Bypass router *chain.Router authenticator auth.Authenticator logger logger.Logger md metadata + options handler.Options } func NewHandler(opts ...handler.Option) handler.Handler { - options := &handler.Options{} + options := handler.Options{} for _, opt := range opts { - opt(options) + opt(&options) } return &httpHandler{ - bypass: options.Bypass, - router: options.Router, - logger: options.Logger, + options: options, } } @@ -55,6 +53,16 @@ func (h *httpHandler) Init(md md.Metadata) error { return err } + h.authenticator = auth_util.AuthFromUsers(h.options.Auths...) + h.router = &chain.Router{ + Retries: h.options.Retries, + Chain: h.options.Chain, + Resolver: h.options.Resolver, + Hosts: h.options.Hosts, + Logger: h.options.Logger, + } + h.logger = h.options.Logger + return nil } @@ -141,7 +149,7 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt resp.Header = http.Header{} } - if h.bypass != nil && h.bypass.Contains(addr) { + if h.options.Bypass != nil && h.options.Bypass.Contains(addr) { resp.StatusCode = http.StatusForbidden if h.logger.IsLevelEnabled(logger.DebugLevel) { diff --git a/pkg/handler/http/udp.go b/pkg/handler/http/udp.go index 582c750..c35991d 100644 --- a/pkg/handler/http/udp.go +++ b/pkg/handler/http/udp.go @@ -64,7 +64,7 @@ func (h *httpHandler) handleUDP(ctx context.Context, conn net.Conn, network, add } relay := handler.NewUDPRelay(socks.UDPTunServerConn(conn), pc). - WithBypass(h.bypass). + WithBypass(h.options.Bypass). WithLogger(h.logger) t := time.Now() diff --git a/pkg/handler/http2/handler.go b/pkg/handler/http2/handler.go index 1e06e03..d76d97b 100644 --- a/pkg/handler/http2/handler.go +++ b/pkg/handler/http2/handler.go @@ -14,10 +14,9 @@ import ( "strings" "time" - "github.com/asaskevich/govalidator" "github.com/go-gost/gost/pkg/auth" - "github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/chain" + auth_util "github.com/go-gost/gost/pkg/common/util/auth" "github.com/go-gost/gost/pkg/handler" http2_util "github.com/go-gost/gost/pkg/internal/util/http2" "github.com/go-gost/gost/pkg/logger" @@ -30,23 +29,21 @@ func init() { } type http2Handler struct { - bypass bypass.Bypass router *chain.Router authenticator auth.Authenticator logger logger.Logger md metadata + options handler.Options } func NewHandler(opts ...handler.Option) handler.Handler { - options := &handler.Options{} + options := handler.Options{} for _, opt := range opts { - opt(options) + opt(&options) } return &http2Handler{ - bypass: options.Bypass, - router: options.Router, - logger: options.Logger, + options: options, } } @@ -55,6 +52,15 @@ func (h *http2Handler) Init(md md.Metadata) error { return err } + h.authenticator = auth_util.AuthFromUsers(h.options.Auths...) + h.router = &chain.Router{ + Retries: h.options.Retries, + Chain: h.options.Chain, + Resolver: h.options.Resolver, + Hosts: h.options.Hosts, + Logger: h.options.Logger, + } + h.logger = h.options.Logger return nil } @@ -133,7 +139,7 @@ func (h *http2Handler) roundTrip(ctx context.Context, w http.ResponseWriter, req } */ - if h.bypass != nil && h.bypass.Contains(addr) { + if h.options.Bypass != nil && h.options.Bypass.Contains(addr) { w.WriteHeader(http.StatusForbidden) h.logger.Info("bypass: ", addr) return @@ -203,156 +209,6 @@ func (h *http2Handler) roundTrip(ctx context.Context, w http.ResponseWriter, req } } -func (h *http2Handler) handleRequest(ctx context.Context, conn net.Conn, req *http.Request) { - if req == nil { - return - } - - 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]interface{}{ - "dst": addr, - } - if u, _, _ := h.basicProxyAuth(req.Header.Get("Proxy-Authorization")); u != "" { - fields["user"] = u - } - h.logger = h.logger.WithFields(fields) - - if h.logger.IsLevelEnabled(logger.DebugLevel) { - dump, _ := httputil.DumpRequest(req, false) - h.logger.Debug(string(dump)) - } - h.logger.Infof("%s >> %s", conn.RemoteAddr(), addr) - - resp := &http.Response{ - ProtoMajor: 1, - ProtoMinor: 1, - Header: http.Header{}, - } - - if h.md.proxyAgent != "" { - resp.Header.Add("Proxy-Agent", h.md.proxyAgent) - } - - /* - if !Can("tcp", host, h.options.Whitelist, h.options.Blacklist) { - log.Logf("[http] %s - %s : Unauthorized to tcp connect to %s", - conn.RemoteAddr(), conn.LocalAddr(), host) - resp.StatusCode = http.StatusForbidden - - if Debug { - dump, _ := httputil.DumpResponse(resp, false) - log.Logf("[http] %s <- %s\n%s", conn.RemoteAddr(), conn.LocalAddr(), string(dump)) - } - - resp.Write(conn) - return - } - */ - - if h.bypass != nil && h.bypass.Contains(addr) { - resp.StatusCode = http.StatusForbidden - - if h.logger.IsLevelEnabled(logger.DebugLevel) { - dump, _ := httputil.DumpResponse(resp, false) - h.logger.Debug(string(dump)) - } - h.logger.Info("bypass: ", addr) - - resp.Write(conn) - return - } - - if !h.authenticate(conn, req, resp) { - return - } - - if req.Method == "PRI" || - (req.Method != http.MethodConnect && req.URL.Scheme != "http") { - resp.StatusCode = http.StatusBadRequest - resp.Write(conn) - - if h.logger.IsLevelEnabled(logger.DebugLevel) { - dump, _ := httputil.DumpResponse(resp, false) - h.logger.Debug(string(dump)) - } - - return - } - - req.Header.Del("Proxy-Authorization") - - cc, err := h.router.Dial(ctx, network, addr) - if err != nil { - resp.StatusCode = http.StatusServiceUnavailable - resp.Write(conn) - - if h.logger.IsLevelEnabled(logger.DebugLevel) { - dump, _ := httputil.DumpResponse(resp, false) - h.logger.Debug(string(dump)) - } - return - } - defer cc.Close() - - if req.Method == http.MethodConnect { - resp.StatusCode = http.StatusOK - resp.Status = "200 Connection established" - - if h.logger.IsLevelEnabled(logger.DebugLevel) { - dump, _ := httputil.DumpResponse(resp, false) - h.logger.Debug(string(dump)) - } - if err = resp.Write(conn); err != nil { - h.logger.Error(err) - return - } - } else { - req.Header.Del("Proxy-Connection") - if err = req.Write(cc); err != nil { - h.logger.Error(err) - return - } - } - - start := time.Now() - h.logger.Infof("%s <-> %s", conn.RemoteAddr(), addr) - handler.Transport(conn, cc) - h.logger. - WithFields(map[string]interface{}{ - "duration": time.Since(start), - }). - Infof("%s >-< %s", conn.RemoteAddr(), addr) -} - func (h *http2Handler) decodeServerName(s string) (string, error) { b, err := base64.RawURLEncoding.DecodeString(s) if err != nil { diff --git a/pkg/handler/option.go b/pkg/handler/option.go index f3eb8ec..501f6a4 100644 --- a/pkg/handler/option.go +++ b/pkg/handler/option.go @@ -1,26 +1,48 @@ package handler import ( - "github.com/go-gost/gost/pkg/auth" + "net/url" + "github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/chain" + "github.com/go-gost/gost/pkg/hosts" "github.com/go-gost/gost/pkg/logger" "github.com/go-gost/gost/pkg/resolver" ) type Options struct { - Router *chain.Router - Bypass bypass.Bypass - Resolver resolver.Resolver - Authenticator auth.Authenticator - Logger logger.Logger + Retries int + Chain *chain.Chain + Resolver resolver.Resolver + Hosts hosts.HostMapper + Bypass bypass.Bypass + Auths []*url.Userinfo + Logger logger.Logger } type Option func(opts *Options) -func RouterOption(router *chain.Router) Option { +func RetriesOption(retries int) Option { return func(opts *Options) { - opts.Router = router + opts.Retries = retries + } +} + +func ChainOption(chain *chain.Chain) Option { + return func(opts *Options) { + opts.Chain = chain + } +} + +func ResolverOption(resolver resolver.Resolver) Option { + return func(opts *Options) { + opts.Resolver = resolver + } +} + +func HostsOption(hosts hosts.HostMapper) Option { + return func(opts *Options) { + opts.Hosts = hosts } } @@ -30,9 +52,9 @@ func BypassOption(bypass bypass.Bypass) Option { } } -func AuthenticatorOption(auth auth.Authenticator) Option { +func AuthsOption(auths ...*url.Userinfo) Option { return func(opts *Options) { - opts.Authenticator = auth + opts.Auths = auths } } diff --git a/pkg/handler/redirect/handler.go b/pkg/handler/redirect/handler.go index bc9c6bd..73878e4 100644 --- a/pkg/handler/redirect/handler.go +++ b/pkg/handler/redirect/handler.go @@ -6,7 +6,6 @@ import ( "net" "time" - "github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/chain" "github.com/go-gost/gost/pkg/handler" "github.com/go-gost/gost/pkg/logger" @@ -22,27 +21,38 @@ func init() { } type redirectHandler struct { - bypass bypass.Bypass - router *chain.Router - logger logger.Logger - md metadata + router *chain.Router + logger logger.Logger + md metadata + options handler.Options } func NewHandler(opts ...handler.Option) handler.Handler { - options := &handler.Options{} + options := handler.Options{} for _, opt := range opts { - opt(options) + opt(&options) } return &redirectHandler{ - bypass: options.Bypass, - router: options.Router, - logger: options.Logger, + options: options, } } func (h *redirectHandler) Init(md md.Metadata) (err error) { - return h.parseMetadata(md) + if err = h.parseMetadata(md); err != nil { + return + } + + h.router = &chain.Router{ + Retries: h.options.Retries, + Chain: h.options.Chain, + Resolver: h.options.Resolver, + Hosts: h.options.Hosts, + Logger: h.options.Logger, + } + h.logger = h.options.Logger + + return } func (h *redirectHandler) Handle(ctx context.Context, conn net.Conn) { @@ -84,7 +94,7 @@ func (h *redirectHandler) Handle(ctx context.Context, conn net.Conn) { h.logger.Infof("%s >> %s", conn.RemoteAddr(), dstAddr) - if h.bypass != nil && h.bypass.Contains(dstAddr.String()) { + if h.options.Bypass != nil && h.options.Bypass.Contains(dstAddr.String()) { h.logger.Info("bypass: ", dstAddr) return } diff --git a/pkg/handler/relay/bind.go b/pkg/handler/relay/bind.go index 8602f89..f821774 100644 --- a/pkg/handler/relay/bind.go +++ b/pkg/handler/relay/bind.go @@ -201,7 +201,7 @@ func (h *relayHandler) tunnelServerUDP(tunnel, c net.PacketConn) (err error) { return err } - if h.bypass != nil && h.bypass.Contains(raddr.String()) { + if h.options.Bypass != nil && h.options.Bypass.Contains(raddr.String()) { h.logger.Warn("bypass: ", raddr) return nil } @@ -234,7 +234,7 @@ func (h *relayHandler) tunnelServerUDP(tunnel, c net.PacketConn) (err error) { return err } - if h.bypass != nil && h.bypass.Contains(raddr.String()) { + if h.options.Bypass != nil && h.options.Bypass.Contains(raddr.String()) { h.logger.Warn("bypass: ", raddr) return nil } diff --git a/pkg/handler/relay/connect.go b/pkg/handler/relay/connect.go index cf97351..5ce5e71 100644 --- a/pkg/handler/relay/connect.go +++ b/pkg/handler/relay/connect.go @@ -30,7 +30,7 @@ func (h *relayHandler) handleConnect(ctx context.Context, conn net.Conn, network return } - if h.bypass != nil && h.bypass.Contains(address) { + if h.options.Bypass != nil && h.options.Bypass.Contains(address) { h.logger.Info("bypass: ", address) resp.Status = relay.StatusForbidden resp.WriteTo(conn) diff --git a/pkg/handler/relay/handler.go b/pkg/handler/relay/handler.go index f4cad73..9bb943f 100644 --- a/pkg/handler/relay/handler.go +++ b/pkg/handler/relay/handler.go @@ -7,8 +7,8 @@ import ( "time" "github.com/go-gost/gost/pkg/auth" - "github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/chain" + auth_util "github.com/go-gost/gost/pkg/common/util/auth" "github.com/go-gost/gost/pkg/handler" "github.com/go-gost/gost/pkg/logger" md "github.com/go-gost/gost/pkg/metadata" @@ -22,23 +22,21 @@ func init() { type relayHandler struct { group *chain.NodeGroup - bypass bypass.Bypass router *chain.Router authenticator auth.Authenticator logger logger.Logger md metadata + options handler.Options } func NewHandler(opts ...handler.Option) handler.Handler { - options := &handler.Options{} + options := handler.Options{} for _, opt := range opts { - opt(options) + opt(&options) } return &relayHandler{ - bypass: options.Bypass, - router: options.Router, - logger: options.Logger, + options: options, } } @@ -47,6 +45,15 @@ func (h *relayHandler) Init(md md.Metadata) (err error) { return err } + h.authenticator = auth_util.AuthFromUsers(h.options.Auths...) + h.router = &chain.Router{ + Retries: h.options.Retries, + Chain: h.options.Chain, + Resolver: h.options.Resolver, + Hosts: h.options.Hosts, + Logger: h.options.Logger, + } + h.logger = h.options.Logger return nil } diff --git a/pkg/handler/sni/handler.go b/pkg/handler/sni/handler.go index 22c8845..ff396da 100644 --- a/pkg/handler/sni/handler.go +++ b/pkg/handler/sni/handler.go @@ -11,7 +11,6 @@ import ( "net" "time" - "github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/chain" "github.com/go-gost/gost/pkg/common/bufpool" "github.com/go-gost/gost/pkg/handler" @@ -27,16 +26,16 @@ func init() { type sniHandler struct { httpHandler handler.Handler - bypass bypass.Bypass router *chain.Router logger logger.Logger md metadata + options handler.Options } func NewHandler(opts ...handler.Option) handler.Handler { - options := &handler.Options{} + options := handler.Options{} for _, opt := range opts { - opt(options) + opt(&options) } log := options.Logger @@ -45,9 +44,8 @@ func NewHandler(opts ...handler.Option) handler.Handler { } h := &sniHandler{ - bypass: options.Bypass, - router: options.Router, - logger: log, + options: options, + logger: log, } if f := registry.GetHandler("http"); f != nil { @@ -72,6 +70,14 @@ func (h *sniHandler) Init(md md.Metadata) (err error) { } } + h.router = &chain.Router{ + Retries: h.options.Retries, + Chain: h.options.Chain, + Resolver: h.options.Resolver, + Hosts: h.options.Hosts, + Logger: h.options.Logger, + } + return nil } @@ -132,7 +138,7 @@ func (h *sniHandler) Handle(ctx context.Context, conn net.Conn) { }) h.logger.Infof("%s >> %s", conn.RemoteAddr(), target) - if h.bypass != nil && h.bypass.Contains(target) { + if h.options.Bypass != nil && h.options.Bypass.Contains(target) { h.logger.Info("bypass: ", target) return } diff --git a/pkg/handler/socks/v4/handler.go b/pkg/handler/socks/v4/handler.go index 8332835..d6eda4e 100644 --- a/pkg/handler/socks/v4/handler.go +++ b/pkg/handler/socks/v4/handler.go @@ -7,8 +7,8 @@ import ( "github.com/go-gost/gosocks4" "github.com/go-gost/gost/pkg/auth" - "github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/chain" + auth_util "github.com/go-gost/gost/pkg/common/util/auth" "github.com/go-gost/gost/pkg/handler" "github.com/go-gost/gost/pkg/logger" md "github.com/go-gost/gost/pkg/metadata" @@ -21,23 +21,21 @@ func init() { } type socks4Handler struct { - bypass bypass.Bypass router *chain.Router authenticator auth.Authenticator logger logger.Logger md metadata + options handler.Options } func NewHandler(opts ...handler.Option) handler.Handler { - options := &handler.Options{} + options := handler.Options{} for _, opt := range opts { - opt(options) + opt(&options) } return &socks4Handler{ - bypass: options.Bypass, - router: options.Router, - logger: options.Logger, + options: options, } } @@ -46,6 +44,16 @@ func (h *socks4Handler) Init(md md.Metadata) (err error) { return err } + h.authenticator = auth_util.AuthFromUsers(h.options.Auths...) + h.router = &chain.Router{ + Retries: h.options.Retries, + Chain: h.options.Chain, + Resolver: h.options.Resolver, + Hosts: h.options.Hosts, + Logger: h.options.Logger, + } + h.logger = h.options.Logger + return nil } @@ -105,7 +113,7 @@ func (h *socks4Handler) handleConnect(ctx context.Context, conn net.Conn, req *g }) h.logger.Infof("%s >> %s", conn.RemoteAddr(), addr) - if h.bypass != nil && h.bypass.Contains(addr) { + if h.options.Bypass != nil && h.options.Bypass.Contains(addr) { resp := gosocks4.NewReply(gosocks4.Rejected, nil) resp.Write(conn) h.logger.Debug(resp) diff --git a/pkg/handler/socks/v5/connect.go b/pkg/handler/socks/v5/connect.go index 6792358..672abc7 100644 --- a/pkg/handler/socks/v5/connect.go +++ b/pkg/handler/socks/v5/connect.go @@ -17,7 +17,7 @@ func (h *socks5Handler) handleConnect(ctx context.Context, conn net.Conn, networ }) h.logger.Infof("%s >> %s", conn.RemoteAddr(), address) - if h.bypass != nil && h.bypass.Contains(address) { + if h.options.Bypass != nil && h.options.Bypass.Contains(address) { resp := gosocks5.NewReply(gosocks5.NotAllowed, nil) resp.Write(conn) h.logger.Debug(resp) diff --git a/pkg/handler/socks/v5/handler.go b/pkg/handler/socks/v5/handler.go index 6cca33c..71f5a89 100644 --- a/pkg/handler/socks/v5/handler.go +++ b/pkg/handler/socks/v5/handler.go @@ -6,9 +6,8 @@ import ( "time" "github.com/go-gost/gosocks5" - "github.com/go-gost/gost/pkg/auth" - "github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/chain" + auth_util "github.com/go-gost/gost/pkg/common/util/auth" "github.com/go-gost/gost/pkg/common/util/socks" "github.com/go-gost/gost/pkg/handler" "github.com/go-gost/gost/pkg/logger" @@ -22,24 +21,21 @@ func init() { } type socks5Handler struct { - selector gosocks5.Selector - bypass bypass.Bypass - router *chain.Router - authenticator auth.Authenticator - logger logger.Logger - md metadata + selector gosocks5.Selector + router *chain.Router + logger logger.Logger + md metadata + options handler.Options } func NewHandler(opts ...handler.Option) handler.Handler { - options := &handler.Options{} + options := handler.Options{} for _, opt := range opts { - opt(options) + opt(&options) } return &socks5Handler{ - bypass: options.Bypass, - router: options.Router, - logger: options.Logger, + options: options, } } @@ -48,8 +44,17 @@ func (h *socks5Handler) Init(md md.Metadata) (err error) { return } + h.logger = h.options.Logger + h.router = &chain.Router{ + Retries: h.options.Retries, + Chain: h.options.Chain, + Resolver: h.options.Resolver, + Hosts: h.options.Hosts, + Logger: h.options.Logger, + } + h.selector = &serverSelector{ - Authenticator: h.authenticator, + Authenticator: auth_util.AuthFromUsers(h.options.Auths...), TLSConfig: h.md.tlsConfig, logger: h.logger, noTLS: h.md.noTLS, diff --git a/pkg/handler/socks/v5/udp.go b/pkg/handler/socks/v5/udp.go index 59564ae..07a77ff 100644 --- a/pkg/handler/socks/v5/udp.go +++ b/pkg/handler/socks/v5/udp.go @@ -67,7 +67,7 @@ func (h *socks5Handler) handleUDP(ctx context.Context, conn net.Conn) { } relay := handler.NewUDPRelay(socks.UDPConn(cc, h.md.udpBufferSize), pc). - WithBypass(h.bypass). + WithBypass(h.options.Bypass). WithLogger(h.logger) relay.SetBufferSize(h.md.udpBufferSize) diff --git a/pkg/handler/socks/v5/udp_tun.go b/pkg/handler/socks/v5/udp_tun.go index cfaca1f..339f368 100644 --- a/pkg/handler/socks/v5/udp_tun.go +++ b/pkg/handler/socks/v5/udp_tun.go @@ -46,7 +46,7 @@ func (h *socks5Handler) handleUDPTun(ctx context.Context, conn net.Conn, network } relay := handler.NewUDPRelay(socks.UDPTunServerConn(conn), pc). - WithBypass(h.bypass). + WithBypass(h.options.Bypass). WithLogger(h.logger) relay.SetBufferSize(h.md.udpBufferSize) diff --git a/pkg/handler/ss/handler.go b/pkg/handler/ss/handler.go index 0921eec..2b8ad77 100644 --- a/pkg/handler/ss/handler.go +++ b/pkg/handler/ss/handler.go @@ -8,13 +8,13 @@ import ( "time" "github.com/go-gost/gosocks5" - "github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/chain" "github.com/go-gost/gost/pkg/common/util/ss" "github.com/go-gost/gost/pkg/handler" "github.com/go-gost/gost/pkg/logger" md "github.com/go-gost/gost/pkg/metadata" "github.com/go-gost/gost/pkg/registry" + "github.com/shadowsocks/go-shadowsocks2/core" ) func init() { @@ -22,31 +22,47 @@ func init() { } type ssHandler struct { - bypass bypass.Bypass - router *chain.Router - logger logger.Logger - md metadata + cipher core.Cipher + router *chain.Router + logger logger.Logger + md metadata + options handler.Options } func NewHandler(opts ...handler.Option) handler.Handler { - options := &handler.Options{} + options := handler.Options{} for _, opt := range opts { - opt(options) + opt(&options) } return &ssHandler{ - bypass: options.Bypass, - router: options.Router, - logger: options.Logger, + options: options, } } func (h *ssHandler) Init(md md.Metadata) (err error) { - if err := h.parseMetadata(md); err != nil { - return err + if err = h.parseMetadata(md); err != nil { + return + } + if len(h.options.Auths) > 0 { + method := h.options.Auths[0].Username() + password, _ := h.options.Auths[0].Password() + h.cipher, err = ss.ShadowCipher(method, password, h.md.key) + if err != nil { + return + } } - return nil + h.router = &chain.Router{ + Retries: h.options.Retries, + Chain: h.options.Chain, + Resolver: h.options.Resolver, + Hosts: h.options.Hosts, + Logger: h.options.Logger, + } + h.logger = h.options.Logger + + return } func (h *ssHandler) Handle(ctx context.Context, conn net.Conn) { @@ -65,8 +81,8 @@ func (h *ssHandler) Handle(ctx context.Context, conn net.Conn) { }).Infof("%s >< %s", conn.RemoteAddr(), conn.LocalAddr()) }() - if h.md.cipher != nil { - conn = ss.ShadowConn(h.md.cipher.StreamConn(conn), nil) + if h.cipher != nil { + conn = ss.ShadowConn(h.cipher.StreamConn(conn), nil) } if h.md.readTimeout > 0 { @@ -86,7 +102,7 @@ func (h *ssHandler) Handle(ctx context.Context, conn net.Conn) { h.logger.Infof("%s >> %s", conn.RemoteAddr(), addr) - if h.bypass != nil && h.bypass.Contains(addr.String()) { + if h.options.Bypass != nil && h.options.Bypass.Contains(addr.String()) { h.logger.Info("bypass: ", addr.String()) return } diff --git a/pkg/handler/ss/metadata.go b/pkg/handler/ss/metadata.go index 6833bbf..60218da 100644 --- a/pkg/handler/ss/metadata.go +++ b/pkg/handler/ss/metadata.go @@ -1,41 +1,23 @@ package ss import ( - "strings" "time" - "github.com/go-gost/gost/pkg/common/util/ss" mdata "github.com/go-gost/gost/pkg/metadata" - "github.com/shadowsocks/go-shadowsocks2/core" ) type metadata struct { - cipher core.Cipher + key string readTimeout time.Duration } func (h *ssHandler) parseMetadata(md mdata.Metadata) (err error) { const ( - users = "users" key = "key" readTimeout = "readTimeout" ) - var method, password string - if auths := mdata.GetStrings(md, users); len(auths) > 0 { - auth := auths[0] - ss := strings.SplitN(auth, ":", 2) - if len(ss) == 1 { - method = ss[0] - } else { - method, password = ss[0], ss[1] - } - } - h.md.cipher, err = ss.ShadowCipher(method, password, mdata.GetString(md, key)) - if err != nil { - return - } - + h.md.key = mdata.GetString(md, key) h.md.readTimeout = mdata.GetDuration(md, readTimeout) return diff --git a/pkg/handler/ss/udp/handler.go b/pkg/handler/ss/udp/handler.go index b12f50d..d861c2a 100644 --- a/pkg/handler/ss/udp/handler.go +++ b/pkg/handler/ss/udp/handler.go @@ -5,7 +5,6 @@ import ( "net" "time" - "github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/chain" "github.com/go-gost/gost/pkg/common/bufpool" "github.com/go-gost/gost/pkg/common/util/socks" @@ -14,6 +13,7 @@ import ( "github.com/go-gost/gost/pkg/logger" md "github.com/go-gost/gost/pkg/metadata" "github.com/go-gost/gost/pkg/registry" + "github.com/shadowsocks/go-shadowsocks2/core" ) func init() { @@ -21,31 +21,48 @@ func init() { } type ssuHandler struct { - bypass bypass.Bypass - router *chain.Router - logger logger.Logger - md metadata + cipher core.Cipher + router *chain.Router + logger logger.Logger + md metadata + options handler.Options } func NewHandler(opts ...handler.Option) handler.Handler { - options := &handler.Options{} + options := handler.Options{} for _, opt := range opts { - opt(options) + opt(&options) } return &ssuHandler{ - bypass: options.Bypass, - router: options.Router, - logger: options.Logger, + options: options, } } func (h *ssuHandler) Init(md md.Metadata) (err error) { - if err := h.parseMetadata(md); err != nil { - return err + if err = h.parseMetadata(md); err != nil { + return } - return nil + if len(h.options.Auths) > 0 { + method := h.options.Auths[0].Username() + password, _ := h.options.Auths[0].Password() + h.cipher, err = ss.ShadowCipher(method, password, h.md.key) + if err != nil { + return + } + } + + h.router = &chain.Router{ + Retries: h.options.Retries, + Chain: h.options.Chain, + Resolver: h.options.Resolver, + Hosts: h.options.Hosts, + Logger: h.options.Logger, + } + h.logger = h.options.Logger + + return } func (h *ssuHandler) Handle(ctx context.Context, conn net.Conn) { @@ -66,14 +83,14 @@ func (h *ssuHandler) Handle(ctx context.Context, conn net.Conn) { pc, ok := conn.(net.PacketConn) if ok { - if h.md.cipher != nil { - pc = h.md.cipher.PacketConn(pc) + if h.cipher != nil { + pc = h.cipher.PacketConn(pc) } // standard UDP relay. pc = ss.UDPServerConn(pc, conn.RemoteAddr(), h.md.bufferSize) } else { - if h.md.cipher != nil { - conn = ss.ShadowConn(h.md.cipher.StreamConn(conn), nil) + if h.cipher != nil { + conn = ss.ShadowConn(h.cipher.StreamConn(conn), nil) } // UDP over TCP pc = socks.UDPTunServerConn(conn) @@ -116,7 +133,7 @@ func (h *ssuHandler) relayPacket(pc1, pc2 net.PacketConn) (err error) { return err } - if h.bypass != nil && h.bypass.Contains(addr.String()) { + if h.options.Bypass != nil && h.options.Bypass.Contains(addr.String()) { h.logger.Warn("bypass: ", addr) return nil } @@ -148,7 +165,7 @@ func (h *ssuHandler) relayPacket(pc1, pc2 net.PacketConn) (err error) { return err } - if h.bypass != nil && h.bypass.Contains(raddr.String()) { + if h.options.Bypass != nil && h.options.Bypass.Contains(raddr.String()) { h.logger.Warn("bypass: ", raddr) return nil } diff --git a/pkg/handler/ss/udp/metadata.go b/pkg/handler/ss/udp/metadata.go index 42a6ec1..ba30b15 100644 --- a/pkg/handler/ss/udp/metadata.go +++ b/pkg/handler/ss/udp/metadata.go @@ -2,43 +2,25 @@ package ss import ( "math" - "strings" "time" - "github.com/go-gost/gost/pkg/common/util/ss" mdata "github.com/go-gost/gost/pkg/metadata" - "github.com/shadowsocks/go-shadowsocks2/core" ) type metadata struct { - cipher core.Cipher + key string readTimeout time.Duration bufferSize int } func (h *ssuHandler) parseMetadata(md mdata.Metadata) (err error) { const ( - users = "users" key = "key" readTimeout = "readTimeout" bufferSize = "bufferSize" ) - var method, password string - if auths := mdata.GetStrings(md, users); len(auths) > 0 { - auth := auths[0] - ss := strings.SplitN(auth, ":", 2) - if len(ss) == 1 { - method = ss[0] - } else { - method, password = ss[0], ss[1] - } - } - h.md.cipher, err = ss.ShadowCipher(method, password, mdata.GetString(md, key)) - if err != nil { - return - } - + h.md.key = mdata.GetString(md, key) h.md.readTimeout = mdata.GetDuration(md, readTimeout) if bs := mdata.GetInt(md, bufferSize); bs > 0 { diff --git a/pkg/handler/tap/handler.go b/pkg/handler/tap/handler.go index a3b613a..5861543 100644 --- a/pkg/handler/tap/handler.go +++ b/pkg/handler/tap/handler.go @@ -10,14 +10,15 @@ import ( "sync" "time" - "github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/chain" "github.com/go-gost/gost/pkg/common/bufpool" + "github.com/go-gost/gost/pkg/common/util/ss" "github.com/go-gost/gost/pkg/handler" tap_util "github.com/go-gost/gost/pkg/internal/util/tap" "github.com/go-gost/gost/pkg/logger" md "github.com/go-gost/gost/pkg/metadata" "github.com/go-gost/gost/pkg/registry" + "github.com/shadowsocks/go-shadowsocks2/core" "github.com/shadowsocks/go-shadowsocks2/shadowaead" "github.com/songgao/water/waterutil" ) @@ -27,35 +28,52 @@ func init() { } type tapHandler struct { - group *chain.NodeGroup - bypass bypass.Bypass - routes sync.Map - exit chan struct{} - router *chain.Router - logger logger.Logger - md metadata + group *chain.NodeGroup + routes sync.Map + exit chan struct{} + cipher core.Cipher + router *chain.Router + logger logger.Logger + md metadata + options handler.Options } func NewHandler(opts ...handler.Option) handler.Handler { - options := &handler.Options{} + options := handler.Options{} for _, opt := range opts { - opt(options) + opt(&options) } return &tapHandler{ - bypass: options.Bypass, - router: options.Router, - logger: options.Logger, - exit: make(chan struct{}, 1), + exit: make(chan struct{}, 1), + options: options, } } func (h *tapHandler) Init(md md.Metadata) (err error) { - if err := h.parseMetadata(md); err != nil { - return err + if err = h.parseMetadata(md); err != nil { + return } - return nil + if len(h.options.Auths) > 0 { + method := h.options.Auths[0].Username() + password, _ := h.options.Auths[0].Password() + h.cipher, err = ss.ShadowCipher(method, password, h.md.key) + if err != nil { + return + } + } + + h.router = &chain.Router{ + Retries: h.options.Retries, + Chain: h.options.Chain, + Resolver: h.options.Resolver, + Hosts: h.options.Hosts, + Logger: h.options.Logger, + } + h.logger = h.options.Logger + + return } // Forward implements handler.Forwarder. @@ -132,8 +150,8 @@ func (h *tapHandler) handleLoop(ctx context.Context, conn net.Conn, addr net.Add return err } - if h.md.cipher != nil { - pc = h.md.cipher.PacketConn(pc) + if h.cipher != nil { + pc = h.cipher.PacketConn(pc) } return h.transport(conn, pc, addr) diff --git a/pkg/handler/tap/metadata.go b/pkg/handler/tap/metadata.go index f15a0f5..f4053af 100644 --- a/pkg/handler/tap/metadata.go +++ b/pkg/handler/tap/metadata.go @@ -1,42 +1,21 @@ package tap import ( - "strings" - - "github.com/go-gost/gost/pkg/common/util/ss" mdata "github.com/go-gost/gost/pkg/metadata" - "github.com/shadowsocks/go-shadowsocks2/core" ) type metadata struct { - cipher core.Cipher - retryCount int + key string bufferSize int } func (h *tapHandler) parseMetadata(md mdata.Metadata) (err error) { const ( - users = "users" - key = "key" - readTimeout = "readTimeout" - bufferSize = "bufferSize" + key = "key" + bufferSize = "bufferSize" ) - var method, password string - if auths := mdata.GetStrings(md, users); len(auths) > 0 { - auth := auths[0] - ss := strings.SplitN(auth, ":", 2) - if len(ss) == 1 { - method = ss[0] - } else { - method, password = ss[0], ss[1] - } - } - h.md.cipher, err = ss.ShadowCipher(method, password, mdata.GetString(md, key)) - if err != nil { - return - } - + h.md.key = mdata.GetString(md, key) h.md.bufferSize = mdata.GetInt(md, bufferSize) if h.md.bufferSize <= 0 { h.md.bufferSize = 1024 diff --git a/pkg/handler/tun/handler.go b/pkg/handler/tun/handler.go index b732104..0c7cb7e 100644 --- a/pkg/handler/tun/handler.go +++ b/pkg/handler/tun/handler.go @@ -10,14 +10,15 @@ import ( "sync" "time" - "github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/chain" "github.com/go-gost/gost/pkg/common/bufpool" + "github.com/go-gost/gost/pkg/common/util/ss" "github.com/go-gost/gost/pkg/handler" tun_util "github.com/go-gost/gost/pkg/internal/util/tun" "github.com/go-gost/gost/pkg/logger" md "github.com/go-gost/gost/pkg/metadata" "github.com/go-gost/gost/pkg/registry" + "github.com/shadowsocks/go-shadowsocks2/core" "github.com/shadowsocks/go-shadowsocks2/shadowaead" "github.com/songgao/water/waterutil" "golang.org/x/net/ipv4" @@ -29,35 +30,52 @@ func init() { } type tunHandler struct { - group *chain.NodeGroup - bypass bypass.Bypass - routes sync.Map - exit chan struct{} - router *chain.Router - logger logger.Logger - md metadata + group *chain.NodeGroup + routes sync.Map + exit chan struct{} + cipher core.Cipher + router *chain.Router + logger logger.Logger + md metadata + options handler.Options } func NewHandler(opts ...handler.Option) handler.Handler { - options := &handler.Options{} + options := handler.Options{} for _, opt := range opts { - opt(options) + opt(&options) } return &tunHandler{ - bypass: options.Bypass, - router: options.Router, - logger: options.Logger, - exit: make(chan struct{}, 1), + exit: make(chan struct{}, 1), + options: options, } } func (h *tunHandler) Init(md md.Metadata) (err error) { - if err := h.parseMetadata(md); err != nil { - return err + if err = h.parseMetadata(md); err != nil { + return } - return nil + if len(h.options.Auths) > 0 { + method := h.options.Auths[0].Username() + password, _ := h.options.Auths[0].Password() + h.cipher, err = ss.ShadowCipher(method, password, h.md.key) + if err != nil { + return + } + } + + h.router = &chain.Router{ + Retries: h.options.Retries, + Chain: h.options.Chain, + Resolver: h.options.Resolver, + Hosts: h.options.Hosts, + Logger: h.options.Logger, + } + h.logger = h.options.Logger + + return } // Forward implements handler.Forwarder. @@ -133,8 +151,8 @@ func (h *tunHandler) handleLoop(ctx context.Context, conn net.Conn, addr net.Add return err } - if h.md.cipher != nil { - pc = h.md.cipher.PacketConn(pc) + if h.cipher != nil { + pc = h.cipher.PacketConn(pc) } return h.transport(conn, pc, addr) diff --git a/pkg/handler/tun/metadata.go b/pkg/handler/tun/metadata.go index 2aa19d8..52bd853 100644 --- a/pkg/handler/tun/metadata.go +++ b/pkg/handler/tun/metadata.go @@ -1,41 +1,21 @@ package tun import ( - "strings" - - "github.com/go-gost/gost/pkg/common/util/ss" mdata "github.com/go-gost/gost/pkg/metadata" - "github.com/shadowsocks/go-shadowsocks2/core" ) type metadata struct { - cipher core.Cipher + key string bufferSize int } func (h *tunHandler) parseMetadata(md mdata.Metadata) (err error) { const ( - users = "users" - key = "key" - readTimeout = "readTimeout" - bufferSize = "bufferSize" + key = "key" + bufferSize = "bufferSize" ) - var method, password string - if auths := mdata.GetStrings(md, users); len(auths) > 0 { - auth := auths[0] - ss := strings.SplitN(auth, ":", 2) - if len(ss) == 1 { - method = ss[0] - } else { - method, password = ss[0], ss[1] - } - } - h.md.cipher, err = ss.ShadowCipher(method, password, mdata.GetString(md, key)) - if err != nil { - return - } - + h.md.key = mdata.GetString(md, key) h.md.bufferSize = mdata.GetInt(md, bufferSize) if h.md.bufferSize <= 0 { h.md.bufferSize = 1024 diff --git a/pkg/listener/option.go b/pkg/listener/option.go index 1f25865..828aa75 100644 --- a/pkg/listener/option.go +++ b/pkg/listener/option.go @@ -1,14 +1,15 @@ package listener import ( - "github.com/go-gost/gost/pkg/auth" + "net/url" + "github.com/go-gost/gost/pkg/logger" ) type Options struct { - Addr string - Authenticator auth.Authenticator - Logger logger.Logger + Addr string + Auths []*url.Userinfo + Logger logger.Logger } type Option func(opts *Options) @@ -19,9 +20,9 @@ func AddrOption(addr string) Option { } } -func AuthenticatorOption(auth auth.Authenticator) Option { +func AuthsOption(auths ...*url.Userinfo) Option { return func(opts *Options) { - opts.Authenticator = auth + opts.Auths = auths } } diff --git a/pkg/listener/ssh/listener.go b/pkg/listener/ssh/listener.go index 5ba1ff9..88403ab 100644 --- a/pkg/listener/ssh/listener.go +++ b/pkg/listener/ssh/listener.go @@ -4,7 +4,7 @@ import ( "fmt" "net" - "github.com/go-gost/gost/pkg/auth" + auth_util "github.com/go-gost/gost/pkg/common/util/auth" ssh_util "github.com/go-gost/gost/pkg/internal/util/ssh" "github.com/go-gost/gost/pkg/listener" "github.com/go-gost/gost/pkg/logger" @@ -20,12 +20,12 @@ func init() { type sshListener struct { addr string net.Listener - config *ssh.ServerConfig - authenticator auth.Authenticator - cqueue chan net.Conn - errChan chan error - logger logger.Logger - md metadata + config *ssh.ServerConfig + cqueue chan net.Conn + errChan chan error + logger logger.Logger + md metadata + options listener.Options } func NewListener(opts ...listener.Option) listener.Listener { @@ -51,14 +51,13 @@ func (l *sshListener) Init(md md.Metadata) (err error) { l.Listener = ln + authenticator := auth_util.AuthFromUsers(l.options.Auths...) config := &ssh.ServerConfig{ - PasswordCallback: ssh_util.PasswordCallback(l.authenticator), + PasswordCallback: ssh_util.PasswordCallback(authenticator), PublicKeyCallback: ssh_util.PublicKeyCallback(l.md.authorizedKeys), } - config.AddHostKey(l.md.signer) - - if l.authenticator == nil && len(l.md.authorizedKeys) == 0 { + if authenticator == nil && len(l.md.authorizedKeys) == 0 { config.NoClientAuth = true }