diff --git a/chain/hop.go b/chain/hop.go index eec212c..1e3ef2b 100644 --- a/chain/hop.go +++ b/chain/hop.go @@ -103,6 +103,16 @@ func (p *chainHop) Select(ctx context.Context, opts ...chain.SelectOption) *chai if len(filters) == 0 { filters = nodes } + } else if protocol := options.Protocol; protocol != "" { + filters = nil + for _, node := range p.nodes { + if node == nil { + continue + } + if node.Options().Protocol == protocol { + filters = append(filters, node) + } + } } var nodes []*chain.Node diff --git a/config/config.go b/config/config.go index c74867f..7c0367c 100644 --- a/config/config.go +++ b/config/config.go @@ -261,6 +261,7 @@ type ForwardNodeConfig struct { Name string `yaml:",omitempty" json:"name,omitempty"` Addr string `yaml:",omitempty" json:"addr,omitempty"` Host string `yaml:",omitempty" json:"host,omitempty"` + Protocol string `yaml:",omitempty" json:"protocol,omitempty"` Bypass string `yaml:",omitempty" json:"bypass,omitempty"` Bypasses []string `yaml:",omitempty" json:"bypasses,omitempty"` } @@ -335,6 +336,7 @@ type NodeConfig struct { Name string `json:"name"` Addr string `yaml:",omitempty" json:"addr,omitempty"` Host string `yaml:",omitempty" json:"host,omitempty"` + Protocol string `yaml:",omitempty" json:"protocol,omitempty"` Interface string `yaml:",omitempty" json:"interface,omitempty"` SockOpts *SockOptsConfig `yaml:"sockopts,omitempty" json:"sockopts,omitempty"` Bypass string `yaml:",omitempty" json:"bypass,omitempty"` diff --git a/config/parsing/chain.go b/config/parsing/chain.go index 98fe7f6..beabd1d 100644 --- a/config/parsing/chain.go +++ b/config/parsing/chain.go @@ -216,6 +216,7 @@ func ParseHop(cfg *config.HopConfig) (chain.Hop, error) { chain.HostMapperNodeOption(registry.HostsRegistry().Get(v.Hosts)), chain.MetadataNodeOption(nm), chain.HostNodeOption(host), + chain.ProtocolNodeOption(v.Protocol), ) nodes = append(nodes, node) } diff --git a/config/parsing/service.go b/config/parsing/service.go index 263b515..6bfb26c 100644 --- a/config/parsing/service.go +++ b/config/parsing/service.go @@ -250,6 +250,7 @@ func parseForwarder(cfg *config.ForwarderConfig) (chain.Hop, error) { Name: node.Name, Addr: node.Addr, Host: node.Host, + Protocol: node.Protocol, Bypass: node.Bypass, Bypasses: node.Bypasses, }, diff --git a/go.mod b/go.mod index 64d8b37..67f96c2 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/gin-contrib/cors v1.3.1 github.com/gin-gonic/gin v1.7.7 - github.com/go-gost/core v0.0.0-20221129013900-0f0679a3ecbc + github.com/go-gost/core v0.0.0-20221130024727-8effb0b8b971 github.com/go-gost/gosocks4 v0.0.1 github.com/go-gost/gosocks5 v0.3.1-0.20211109033403-d894d75b7f09 github.com/go-gost/relay v0.1.1-0.20211123134818-8ef7fd81ffd7 diff --git a/go.sum b/go.sum index e019e65..aeb66b2 100644 --- a/go.sum +++ b/go.sum @@ -96,8 +96,8 @@ github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ 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/core v0.0.0-20221129013900-0f0679a3ecbc h1:LkielnJLsiOAnmgU88bW+73jZ07T4tyNb4jx94upm9g= -github.com/go-gost/core v0.0.0-20221129013900-0f0679a3ecbc/go.mod h1:bHVbCS9da6XtKNYMkMUVcck5UqDDUkyC37erVfs4GXQ= +github.com/go-gost/core v0.0.0-20221130024727-8effb0b8b971 h1:0AauAKN4J0ueS5yAdpQZEfhmUrPg1MZ/FBrGDmXyJi8= +github.com/go-gost/core v0.0.0-20221130024727-8effb0b8b971/go.mod h1:bHVbCS9da6XtKNYMkMUVcck5UqDDUkyC37erVfs4GXQ= 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= diff --git a/handler/forward/internal/forward/forward.go b/handler/forward/internal/forward/forward.go index 9544b32..e08a945 100644 --- a/handler/forward/internal/forward/forward.go +++ b/handler/forward/internal/forward/forward.go @@ -14,7 +14,7 @@ import ( xio "github.com/go-gost/x/internal/io" ) -func SniffHost(ctx context.Context, rdw io.ReadWriter) (rw io.ReadWriter, host string, err error) { +func Sniffing(ctx context.Context, rdw io.ReadWriter) (rw io.ReadWriter, host string, protocol string, err error) { rw = rdw // try to sniff TLS traffic @@ -24,7 +24,8 @@ func SniffHost(ctx context.Context, rdw io.ReadWriter) (rw io.ReadWriter, host s if err == nil && hdr[0] == dissector.Handshake && binary.BigEndian.Uint16(hdr[1:3]) == tls.VersionTLS10 { - return sniffSNI(ctx, rw) + rw, host, err = sniffSNI(ctx, rw) + return } // try to sniff HTTP traffic @@ -39,6 +40,8 @@ func SniffHost(ctx context.Context, rdw io.ReadWriter) (rw io.ReadWriter, host s } } + protocol = sniffProtocol(hdr[:]) + return } @@ -82,3 +85,14 @@ func isHTTP(s string) bool { strings.HasPrefix(http.MethodConnect, s) || strings.HasPrefix(http.MethodTrace, s) } + +const ( + SSHv2 = "SSH-2" +) + +func sniffProtocol(hdr []byte) string { + if string(hdr) == SSHv2 { + return "ssh" + } + return "" +} diff --git a/handler/forward/local/handler.go b/handler/forward/local/handler.go index e8d761c..5f8ec12 100644 --- a/handler/forward/local/handler.go +++ b/handler/forward/local/handler.go @@ -93,15 +93,20 @@ func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn, opts ...hand var rw io.ReadWriter = conn var host string + var protocol string if h.md.sniffing { if network == "tcp" { - rw, host, _ = forward.SniffHost(ctx, conn) + rw, host, protocol, _ = forward.Sniffing(ctx, conn) + h.options.Logger.Debugf("sniffing: host=%s, protocol=%s", host, protocol) } } var target *chain.Node if h.hop != nil { - target = h.hop.Select(ctx, chain.HostSelectOption(host)) + target = h.hop.Select(ctx, + chain.HostSelectOption(host), + chain.ProtocolSelectOption(protocol), + ) } if target == nil { err := errors.New("target not available") diff --git a/handler/forward/remote/handler.go b/handler/forward/remote/handler.go index 071e1e4..d2b7abf 100644 --- a/handler/forward/remote/handler.go +++ b/handler/forward/remote/handler.go @@ -84,14 +84,18 @@ func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn, opts ...hand var rw io.ReadWriter = conn var host string + var protocol string if h.md.sniffing { if network == "tcp" { - rw, host, _ = forward.SniffHost(ctx, conn) + rw, host, protocol, _ = forward.Sniffing(ctx, conn) } } var target *chain.Node if h.hop != nil { - target = h.hop.Select(ctx, chain.HostSelectOption(host)) + target = h.hop.Select(ctx, + chain.HostSelectOption(host), + chain.ProtocolSelectOption(protocol), + ) } if target == nil { err := errors.New("target not available")