Add bittorrent protocol sniffer support

This commit is contained in:
PuerNya 2023-08-31 12:08:43 +08:00
parent fcb5a0157b
commit 683bda9838
5 changed files with 113 additions and 24 deletions

View File

@ -0,0 +1,86 @@
package sniff
import (
"bytes"
"context"
"encoding/binary"
"io"
"io/ioutil"
"math"
"os"
"time"
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
)
func BittorrentTCPMessage(ctx context.Context, reader io.Reader) (*adapter.InboundContext, error) {
packet, err := ioutil.ReadAll(reader)
if err != nil {
return nil, os.ErrInvalid
}
if len(packet) < 20 {
return nil, os.ErrInvalid
}
if packet[0] != 19 || string(packet[1:20]) != "BitTorrent protocol" {
return nil, os.ErrInvalid
}
return &adapter.InboundContext{Protocol: C.ProtocolBittorrent}, nil
}
func BittorrentUDPMessage(ctx context.Context, packet []byte) (*adapter.InboundContext, error) {
pLen := len(packet)
if pLen < 20 {
return nil, os.ErrInvalid
}
buffer := bytes.NewReader(packet)
var typeAndVersion uint8
if binary.Read(buffer, binary.BigEndian, &typeAndVersion) != nil {
return nil, os.ErrInvalid
} else if packet[0]>>4&0xF > 4 || packet[0]&0xF != 1 {
return nil, os.ErrInvalid
}
var extension uint8
if binary.Read(buffer, binary.BigEndian, &extension) != nil {
return nil, os.ErrInvalid
} else if extension != 0 && extension != 1 {
return nil, os.ErrInvalid
}
for extension != 0 {
if extension != 1 {
return nil, os.ErrInvalid
}
if binary.Read(buffer, binary.BigEndian, &extension) != nil {
return nil, os.ErrInvalid
}
var length uint8
if err := binary.Read(buffer, binary.BigEndian, &length); err != nil {
return nil, os.ErrInvalid
}
if int32(pLen) >= int32(length) {
return nil, os.ErrInvalid
}
}
if int32(pLen) >= int32(2) {
return nil, os.ErrInvalid
}
var timestamp uint32
if err := binary.Read(buffer, binary.BigEndian, &timestamp); err != nil {
return nil, os.ErrInvalid
}
if math.Abs(float64(time.Now().UnixMicro()-int64(timestamp))) > float64(24*time.Hour) {
return nil, os.ErrInvalid
}
return &adapter.InboundContext{Protocol: C.ProtocolBittorrent}, nil
}

View File

@ -1,9 +1,10 @@
package constant package constant
const ( const (
ProtocolTLS = "tls" ProtocolTLS = "tls"
ProtocolHTTP = "http" ProtocolHTTP = "http"
ProtocolQUIC = "quic" ProtocolQUIC = "quic"
ProtocolDNS = "dns" ProtocolDNS = "dns"
ProtocolSTUN = "stun" ProtocolSTUN = "stun"
ProtocolBittorrent = "bittorrent"
) )

View File

@ -2,10 +2,11 @@ If enabled in the inbound, the protocol and domain name (if present) of by the c
#### Supported Protocols #### Supported Protocols
| Network | Protocol | Domain Name | | Network | Protocol | Domain Name |
|:-------:|:--------:|:-----------:| |:-------:|:----------:|:-----------:|
| TCP | HTTP | Host | | TCP | HTTP | Host |
| TCP | TLS | Server Name | | TCP | TLS | Server Name |
| UDP | QUIC | Server Name | | UDP | QUIC | Server Name |
| UDP | STUN | / | | UDP | STUN | / |
| TCP/UDP | DNS | / | | TCP/UDP | DNS | / |
| TCP/UDP | Bittorrent | / |

View File

@ -2,10 +2,11 @@
#### 支持的协议 #### 支持的协议
| 网络 | 协议 | 域名 | | 网络 | 协议 | 域名 |
|:-------:|:----:|:-----------:| |:-------:|:----------:|:-----------:|
| TCP | HTTP | Host | | TCP | HTTP | Host |
| TCP | TLS | Server Name | | TCP | TLS | Server Name |
| UDP | QUIC | Server Name | | UDP | QUIC | Server Name |
| UDP | STUN | / | | UDP | STUN | / |
| TCP/UDP | DNS | / | | TCP/UDP | DNS | / |
| TCP/UDP | Bittorrent | / |

View File

@ -26,9 +26,9 @@ import (
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/outbound" "github.com/sagernet/sing-box/outbound"
"github.com/sagernet/sing-box/transport/fakeip" "github.com/sagernet/sing-box/transport/fakeip"
"github.com/sagernet/sing-dns" dns "github.com/sagernet/sing-dns"
"github.com/sagernet/sing-tun" tun "github.com/sagernet/sing-tun"
"github.com/sagernet/sing-vmess" vmess "github.com/sagernet/sing-vmess"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio" "github.com/sagernet/sing/common/bufio"
@ -652,7 +652,7 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
if metadata.InboundOptions.SniffEnabled { if metadata.InboundOptions.SniffEnabled {
buffer := buf.NewPacket() buffer := buf.NewPacket()
buffer.FullReset() buffer.FullReset()
sniffMetadata, err := sniff.PeekStream(ctx, conn, buffer, time.Duration(metadata.InboundOptions.SniffTimeout), sniff.StreamDomainNameQuery, sniff.TLSClientHello, sniff.HTTPHost) sniffMetadata, err := sniff.PeekStream(ctx, conn, buffer, time.Duration(metadata.InboundOptions.SniffTimeout), sniff.StreamDomainNameQuery, sniff.TLSClientHello, sniff.HTTPHost, sniff.BittorrentTCPMessage)
if sniffMetadata != nil { if sniffMetadata != nil {
metadata.Protocol = sniffMetadata.Protocol metadata.Protocol = sniffMetadata.Protocol
metadata.Domain = sniffMetadata.Domain metadata.Domain = sniffMetadata.Domain
@ -771,7 +771,7 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
metadata.Destination = destination metadata.Destination = destination
} }
if metadata.InboundOptions.SniffEnabled { if metadata.InboundOptions.SniffEnabled {
sniffMetadata, _ := sniff.PeekPacket(ctx, buffer.Bytes(), sniff.DomainNameQuery, sniff.QUICClientHello, sniff.STUNMessage) sniffMetadata, _ := sniff.PeekPacket(ctx, buffer.Bytes(), sniff.DomainNameQuery, sniff.QUICClientHello, sniff.STUNMessage, sniff.BittorrentUDPMessage)
if sniffMetadata != nil { if sniffMetadata != nil {
metadata.Protocol = sniffMetadata.Protocol metadata.Protocol = sniffMetadata.Protocol
metadata.Domain = sniffMetadata.Domain metadata.Domain = sniffMetadata.Domain