Przeglądaj źródła

Add SSH sniffer

世界 1 rok temu
rodzic
commit
04613c27e2

+ 26 - 0
common/sniff/ssh.go

@@ -0,0 +1,26 @@
+package sniff
+
+import (
+	"bufio"
+	"context"
+	"io"
+	"os"
+	"strings"
+
+	"github.com/sagernet/sing-box/adapter"
+	C "github.com/sagernet/sing-box/constant"
+)
+
+func SSH(_ context.Context, metadata *adapter.InboundContext, reader io.Reader) error {
+	scanner := bufio.NewScanner(reader)
+	if !scanner.Scan() {
+		return os.ErrInvalid
+	}
+	fistLine := scanner.Text()
+	if !strings.HasPrefix(fistLine, "SSH-2.0-") {
+		return os.ErrInvalid
+	}
+	metadata.Protocol = C.ProtocolSSH
+	metadata.Client = fistLine[8:]
+	return nil
+}

+ 26 - 0
common/sniff/ssh_test.go

@@ -0,0 +1,26 @@
+package sniff_test
+
+import (
+	"bytes"
+	"context"
+	"encoding/hex"
+	"testing"
+
+	"github.com/sagernet/sing-box/adapter"
+	"github.com/sagernet/sing-box/common/sniff"
+	C "github.com/sagernet/sing-box/constant"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestSniffSSH(t *testing.T) {
+	t.Parallel()
+
+	pkt, err := hex.DecodeString("5353482d322e302d64726f70626561720d0a000001a40a1492892570d1223aef61b0d647972c8bd30000009f637572766532353531392d7368613235362c637572766532353531392d736861323536406c69627373682e6f72672c6469666669652d68656c6c6d616e2d67726f757031342d7368613235362c6469666669652d68656c6c6d616e2d67726f757031342d736861312c6b6578677565737332406d6174742e7563632e61736e2e61752c6b65782d7374726963742d732d763030406f70656e7373682e636f6d000000207373682d656432353531392c7273612d736861322d3235362c7373682d7273610000003363686163686132302d706f6c7931333035406f70656e7373682e636f6d2c6165733132382d6374722c6165733235362d6374720000003363686163686132302d706f6c7931333035406f70656e7373682e636f6d2c6165733132382d6374722c6165733235362d63747200000017686d61632d736861312c686d61632d736861322d32353600000017686d61632d736861312c686d61632d736861322d323536000000046e6f6e65000000046e6f6e65000000000000000000000000002aa6ed090585b7d635b6")
+	require.NoError(t, err)
+	var metadata adapter.InboundContext
+	err = sniff.SSH(context.TODO(), &metadata, bytes.NewReader(pkt))
+	require.NoError(t, err)
+	require.Equal(t, C.ProtocolSSH, metadata.Protocol)
+	require.Equal(t, "dropbear", metadata.Client)
+}

+ 1 - 0
constant/protocol.go

@@ -8,6 +8,7 @@ const (
 	ProtocolSTUN       = "stun"
 	ProtocolBitTorrent = "bittorrent"
 	ProtocolDTLS       = "dtls"
+	ProtocolSSH        = "ssh"
 )
 
 const (

+ 5 - 3
docs/configuration/route/sniff.md

@@ -7,14 +7,15 @@ icon: material/new-box
     :material-plus: QUIC client type detect support for QUIC  
     :material-plus: Chromium support for QUIC  
     :material-plus: BitTorrent support  
-    :material-plus: DTLS support
+    :material-plus: DTLS support  
+    :material-plus: SSH support
 
 If enabled in the inbound, the protocol and domain name (if present) of by the connection can be sniffed.
 
 #### Supported Protocols
 
 | Network |   Protocol   | Domain Name |      Client      |
-|:-------:|:------------:|:-----------:|:----------------:|
+| :-----: | :----------: | :---------: | :--------------: |
 |   TCP   |    `http`    |    Host     |        /         |
 |   TCP   |    `tls`     | Server Name |        /         |
 |   UDP   |    `quic`    | Server Name | QUIC Client Type |
@@ -22,9 +23,10 @@ If enabled in the inbound, the protocol and domain name (if present) of by the c
 | TCP/UDP |    `dns`     |      /      |        /         |
 | TCP/UDP | `bittorrent` |      /      |        /         |
 |   UDP   |    `dtls`    |      /      |        /         |
+|   TCP   |    `ssh`     |      /      | SSH Client Name  |
 
 |       QUIC Client        |    Type    |
-|:------------------------:|:----------:|
+| :----------------------: | :--------: |
 |     Chromium/Cronet      | `chrimium` |
 | Safari/Apple Network API |  `safari`  |
 | Firefox / uquic firefox  | `firefox`  |

+ 13 - 11
docs/configuration/route/sniff.zh.md

@@ -7,24 +7,26 @@ icon: material/new-box
     :material-plus: QUIC 的 客户端类型探测支持  
     :material-plus: QUIC 的 Chromium 支持  
     :material-plus: BitTorrent 支持  
-    :material-plus: DTLS 支持
+    :material-plus: DTLS 支持  
+    :material-plus: SSH 支持
 
 如果在入站中启用,则可以嗅探连接的协议和域名(如果存在)。
 
 #### 支持的协议
 
-|   网络    |      协议      |     域名      |    客户端     |
-|:-------:|:------------:|:-----------:|:----------:|
-|   TCP   |    `http`    |    Host     |     /      |
-|   TCP   |    `tls`     | Server Name |     /      |
+|  网络   |     协议     |    域名     |     客户端      |
+| :-----: | :----------: | :---------: | :-------------: |
+|   TCP   |    `http`    |    Host     |        /        |
+|   TCP   |    `tls`     | Server Name |        /        |
 |   UDP   |    `quic`    | Server Name | QUIC 客户端类型 |
-|   UDP   |    `stun`    |      /      |     /      |
-| TCP/UDP |    `dns`     |      /      |     /      |
-| TCP/UDP | `bittorrent` |      /      |     /      |
-|   UDP   |    `dtls`    |      /      |     /      |
+|   UDP   |    `stun`    |      /      |        /        |
+| TCP/UDP |    `dns`     |      /      |        /        |
+| TCP/UDP | `bittorrent` |      /      |        /        |
+|   UDP   |    `dtls`    |      /      |        /        |
+|   TCP   |    `SSH`     |      /      | SSH 客户端名称  |
 
-|         QUIC 客户端         |     类型     |
-|:------------------------:|:----------:|
+|       QUIC 客户端        |    类型    |
+| :----------------------: | :--------: |
 |     Chromium/Cronet      | `chrimium` |
 | Safari/Apple Network API |  `safari`  |
 | Firefox / uquic firefox  | `firefox`  |

+ 2 - 1
route/router.go

@@ -860,9 +860,10 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
 			conn,
 			buffer,
 			time.Duration(metadata.InboundOptions.SniffTimeout),
-			sniff.StreamDomainNameQuery,
 			sniff.TLSClientHello,
 			sniff.HTTPHost,
+			sniff.StreamDomainNameQuery,
+			sniff.SSH,
 			sniff.BitTorrent,
 		)
 		if err == nil {