mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-22 00:21:30 +00:00
Add SSH sniffer
This commit is contained in:
parent
b2c708a3e6
commit
e39a28ed5a
26
common/sniff/ssh.go
Normal file
26
common/sniff/ssh.go
Normal file
|
@ -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
common/sniff/ssh_test.go
Normal file
26
common/sniff/ssh_test.go
Normal file
|
@ -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)
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ const (
|
||||||
ProtocolSTUN = "stun"
|
ProtocolSTUN = "stun"
|
||||||
ProtocolBitTorrent = "bittorrent"
|
ProtocolBitTorrent = "bittorrent"
|
||||||
ProtocolDTLS = "dtls"
|
ProtocolDTLS = "dtls"
|
||||||
|
ProtocolSSH = "ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -7,14 +7,15 @@ icon: material/new-box
|
||||||
:material-plus: QUIC client type detect support for QUIC
|
:material-plus: QUIC client type detect support for QUIC
|
||||||
:material-plus: Chromium support for QUIC
|
:material-plus: Chromium support for QUIC
|
||||||
:material-plus: BitTorrent support
|
: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.
|
If enabled in the inbound, the protocol and domain name (if present) of by the connection can be sniffed.
|
||||||
|
|
||||||
#### Supported Protocols
|
#### Supported Protocols
|
||||||
|
|
||||||
| Network | Protocol | Domain Name | Client |
|
| Network | Protocol | Domain Name | Client |
|
||||||
|:-------:|:------------:|:-----------:|:----------------:|
|
| :-----: | :----------: | :---------: | :--------------: |
|
||||||
| TCP | `http` | Host | / |
|
| TCP | `http` | Host | / |
|
||||||
| TCP | `tls` | Server Name | / |
|
| TCP | `tls` | Server Name | / |
|
||||||
| UDP | `quic` | Server Name | QUIC Client Type |
|
| 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 | `dns` | / | / |
|
||||||
| TCP/UDP | `bittorrent` | / | / |
|
| TCP/UDP | `bittorrent` | / | / |
|
||||||
| UDP | `dtls` | / | / |
|
| UDP | `dtls` | / | / |
|
||||||
|
| TCP | `ssh` | / | SSH Client Name |
|
||||||
|
|
||||||
| QUIC Client | Type |
|
| QUIC Client | Type |
|
||||||
|:------------------------:|:----------:|
|
| :----------------------: | :--------: |
|
||||||
| Chromium/Cronet | `chrimium` |
|
| Chromium/Cronet | `chrimium` |
|
||||||
| Safari/Apple Network API | `safari` |
|
| Safari/Apple Network API | `safari` |
|
||||||
| Firefox / uquic firefox | `firefox` |
|
| Firefox / uquic firefox | `firefox` |
|
||||||
|
|
|
@ -7,24 +7,26 @@ icon: material/new-box
|
||||||
:material-plus: QUIC 的 客户端类型探测支持
|
:material-plus: QUIC 的 客户端类型探测支持
|
||||||
:material-plus: QUIC 的 Chromium 支持
|
:material-plus: QUIC 的 Chromium 支持
|
||||||
:material-plus: BitTorrent 支持
|
:material-plus: BitTorrent 支持
|
||||||
:material-plus: DTLS 支持
|
:material-plus: DTLS 支持
|
||||||
|
:material-plus: SSH 支持
|
||||||
|
|
||||||
如果在入站中启用,则可以嗅探连接的协议和域名(如果存在)。
|
如果在入站中启用,则可以嗅探连接的协议和域名(如果存在)。
|
||||||
|
|
||||||
#### 支持的协议
|
#### 支持的协议
|
||||||
|
|
||||||
| 网络 | 协议 | 域名 | 客户端 |
|
| 网络 | 协议 | 域名 | 客户端 |
|
||||||
|:-------:|:------------:|:-----------:|:----------:|
|
| :-----: | :----------: | :---------: | :-------------: |
|
||||||
| TCP | `http` | Host | / |
|
| TCP | `http` | Host | / |
|
||||||
| TCP | `tls` | Server Name | / |
|
| TCP | `tls` | Server Name | / |
|
||||||
| UDP | `quic` | Server Name | QUIC 客户端类型 |
|
| UDP | `quic` | Server Name | QUIC 客户端类型 |
|
||||||
| UDP | `stun` | / | / |
|
| UDP | `stun` | / | / |
|
||||||
| TCP/UDP | `dns` | / | / |
|
| TCP/UDP | `dns` | / | / |
|
||||||
| TCP/UDP | `bittorrent` | / | / |
|
| TCP/UDP | `bittorrent` | / | / |
|
||||||
| UDP | `dtls` | / | / |
|
| UDP | `dtls` | / | / |
|
||||||
|
| TCP | `SSH` | / | SSH 客户端名称 |
|
||||||
|
|
||||||
| QUIC 客户端 | 类型 |
|
| QUIC 客户端 | 类型 |
|
||||||
|:------------------------:|:----------:|
|
| :----------------------: | :--------: |
|
||||||
| Chromium/Cronet | `chrimium` |
|
| Chromium/Cronet | `chrimium` |
|
||||||
| Safari/Apple Network API | `safari` |
|
| Safari/Apple Network API | `safari` |
|
||||||
| Firefox / uquic firefox | `firefox` |
|
| Firefox / uquic firefox | `firefox` |
|
||||||
|
|
|
@ -860,9 +860,10 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
|
||||||
conn,
|
conn,
|
||||||
buffer,
|
buffer,
|
||||||
time.Duration(metadata.InboundOptions.SniffTimeout),
|
time.Duration(metadata.InboundOptions.SniffTimeout),
|
||||||
sniff.StreamDomainNameQuery,
|
|
||||||
sniff.TLSClientHello,
|
sniff.TLSClientHello,
|
||||||
sniff.HTTPHost,
|
sniff.HTTPHost,
|
||||||
|
sniff.StreamDomainNameQuery,
|
||||||
|
sniff.SSH,
|
||||||
sniff.BitTorrent,
|
sniff.BitTorrent,
|
||||||
)
|
)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
Loading…
Reference in a new issue