mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-06-13 21:54:13 +08:00
Compare commits
96 Commits
12eee45448
...
c70bf269b6
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c70bf269b6 | ||
![]() |
2af4882275 | ||
![]() |
253f225abd | ||
![]() |
2202bbdb3d | ||
![]() |
20268e4a87 | ||
![]() |
57b1d5ca3a | ||
![]() |
685241dedf | ||
![]() |
9cba09ccc5 | ||
![]() |
2fc3f12edf | ||
![]() |
c688a9b92e | ||
![]() |
4d2ace40c4 | ||
![]() |
8419088475 | ||
![]() |
fed96eb252 | ||
![]() |
fd8c6a9ee4 | ||
![]() |
449b486138 | ||
![]() |
03eab6951f | ||
![]() |
e1d9afc1ed | ||
![]() |
1cb22abc07 | ||
![]() |
22695b7d63 | ||
![]() |
ec0f414668 | ||
![]() |
55ac578082 | ||
![]() |
df751c7973 | ||
![]() |
190a359dea | ||
![]() |
11d9a5e9c2 | ||
![]() |
879303f8e6 | ||
![]() |
7d149a1d3d | ||
![]() |
368f530dbb | ||
![]() |
4eb32b8a36 | ||
![]() |
f936691a1e | ||
![]() |
00d45aaf2a | ||
![]() |
2e58c8bfec | ||
![]() |
1c9e166e75 | ||
![]() |
2eed6d48db | ||
![]() |
6632a09768 | ||
![]() |
5df05814d6 | ||
![]() |
ffed1a4146 | ||
![]() |
e3cb295dc9 | ||
![]() |
2ca21439f2 | ||
![]() |
d8e10c662d | ||
![]() |
33606be587 | ||
![]() |
65518412cc | ||
![]() |
903f80aa0d | ||
![]() |
7a92ededcc | ||
![]() |
97611f62b7 | ||
![]() |
e116651e8c | ||
![]() |
4fac90e801 | ||
![]() |
819636ea01 | ||
![]() |
31a312c421 | ||
![]() |
de7900aea7 | ||
![]() |
0b6737da3d | ||
![]() |
25d9e62b65 | ||
![]() |
25081f6c14 | ||
![]() |
1d8fa0a0d4 | ||
![]() |
81d518f91f | ||
![]() |
be0d544118 | ||
![]() |
83ca910712 | ||
![]() |
57e54958d8 | ||
![]() |
09039f423d | ||
![]() |
cd8e8fcab2 | ||
![]() |
57a8466abd | ||
![]() |
037b953ab9 | ||
![]() |
7cb918961b | ||
![]() |
d25ca4c5e5 | ||
![]() |
355504ada1 | ||
![]() |
f27de457fc | ||
![]() |
d8bed740da | ||
![]() |
4039dd2b5a | ||
![]() |
0d8f2aa698 | ||
![]() |
bd08267e13 | ||
![]() |
4273d86999 | ||
![]() |
380edfde64 | ||
![]() |
cd9ddd681f | ||
![]() |
d6f0f711d4 | ||
![]() |
6beb5904ab | ||
![]() |
e04ca64762 | ||
![]() |
ec852544ed | ||
![]() |
40a5e03450 | ||
![]() |
1be10c37f0 | ||
![]() |
328476c0c9 | ||
![]() |
d3fc706099 | ||
![]() |
aa08f9217f | ||
![]() |
a5d7f9ab8b | ||
![]() |
41ea4f999a | ||
![]() |
06c782d150 | ||
![]() |
4811a2fc11 | ||
![]() |
f491a8aa8a | ||
![]() |
1ef095f617 | ||
![]() |
22fa3e22b9 | ||
![]() |
e3a2435798 | ||
![]() |
78a6b65962 | ||
![]() |
b8a5559af1 | ||
![]() |
e11198ab06 | ||
![]() |
2a3f95fe8e | ||
![]() |
2fdf97cf14 | ||
![]() |
191d30cad5 | ||
![]() |
4efa3e0868 |
@ -1,58 +0,0 @@
|
||||
package sniff
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"os"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
)
|
||||
|
||||
func NTP(ctx context.Context, metadata *adapter.InboundContext, packet []byte) error {
|
||||
// NTP packets must be at least 48 bytes long (standard NTP header size).
|
||||
pLen := len(packet)
|
||||
if pLen < 48 {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
// Check the LI (Leap Indicator) and Version Number (VN) in the first byte.
|
||||
// We'll primarily focus on ensuring the version is valid for NTP.
|
||||
// Many NTP versions are used, but let's check for generally accepted ones (3 & 4 for IPv4, plus potential extensions/customizations)
|
||||
firstByte := packet[0]
|
||||
li := (firstByte >> 6) & 0x03 // Extract LI
|
||||
vn := (firstByte >> 3) & 0x07 // Extract VN
|
||||
mode := firstByte & 0x07 // Extract Mode
|
||||
|
||||
// Leap Indicator should be a valid value (0-3).
|
||||
if li > 3 {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
|
||||
// Version Check (common NTP versions are 3 and 4)
|
||||
if vn != 3 && vn != 4 {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
|
||||
// Check the Mode field for a client request (Mode 3). This validates it *is* a request.
|
||||
if mode != 3 {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
|
||||
// Check Root Delay and Root Dispersion. While not strictly *required* for a request,
|
||||
// we can check if they appear to be reasonable values (not excessively large).
|
||||
rootDelay := binary.BigEndian.Uint32(packet[4:8])
|
||||
rootDispersion := binary.BigEndian.Uint32(packet[8:12])
|
||||
|
||||
// Check for unreasonably large root delay and dispersion. NTP RFC specifies max values of approximately 16 seconds.
|
||||
// Convert to milliseconds for easy comparison. Each unit is 1/2^16 seconds.
|
||||
if float64(rootDelay)/65536.0 > 16.0 {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
if float64(rootDispersion)/65536.0 > 16.0 {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
|
||||
metadata.Protocol = C.ProtocolNTP
|
||||
|
||||
return nil
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
package sniff_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"os"
|
||||
"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 TestSniffNTP(t *testing.T) {
|
||||
t.Parallel()
|
||||
packet, err := hex.DecodeString("1b0006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
||||
require.NoError(t, err)
|
||||
var metadata adapter.InboundContext
|
||||
err = sniff.NTP(context.Background(), &metadata, packet)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, metadata.Protocol, C.ProtocolNTP)
|
||||
}
|
||||
|
||||
func TestSniffNTPFailed(t *testing.T) {
|
||||
t.Parallel()
|
||||
packet, err := hex.DecodeString("400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
||||
require.NoError(t, err)
|
||||
var metadata adapter.InboundContext
|
||||
err = sniff.NTP(context.Background(), &metadata, packet)
|
||||
require.ErrorIs(t, err, os.ErrInvalid)
|
||||
}
|
@ -34,7 +34,6 @@ type Client struct {
|
||||
disableCache bool
|
||||
disableExpire bool
|
||||
independentCache bool
|
||||
clientSubnet netip.Prefix
|
||||
rdrc adapter.RDRCStore
|
||||
initRDRCFunc func() adapter.RDRCStore
|
||||
logger logger.ContextLogger
|
||||
@ -48,7 +47,6 @@ type ClientOptions struct {
|
||||
DisableExpire bool
|
||||
IndependentCache bool
|
||||
CacheCapacity uint32
|
||||
ClientSubnet netip.Prefix
|
||||
RDRC func() adapter.RDRCStore
|
||||
Logger logger.ContextLogger
|
||||
}
|
||||
@ -59,7 +57,6 @@ func NewClient(options ClientOptions) *Client {
|
||||
disableCache: options.DisableCache,
|
||||
disableExpire: options.DisableExpire,
|
||||
independentCache: options.IndependentCache,
|
||||
clientSubnet: options.ClientSubnet,
|
||||
initRDRCFunc: options.RDRC,
|
||||
logger: options.Logger,
|
||||
}
|
||||
@ -107,12 +104,8 @@ func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, m
|
||||
return &responseMessage, nil
|
||||
}
|
||||
question := message.Question[0]
|
||||
clientSubnet := options.ClientSubnet
|
||||
if !clientSubnet.IsValid() {
|
||||
clientSubnet = c.clientSubnet
|
||||
}
|
||||
if clientSubnet.IsValid() {
|
||||
message = SetClientSubnet(message, clientSubnet)
|
||||
if options.ClientSubnet.IsValid() {
|
||||
message = SetClientSubnet(message, options.ClientSubnet)
|
||||
}
|
||||
isSimpleRequest := len(message.Question) == 1 &&
|
||||
len(message.Ns) == 0 &&
|
||||
|
@ -55,7 +55,6 @@ func NewRouter(ctx context.Context, logFactory log.Factory, options option.DNSOp
|
||||
DisableExpire: options.DNSClientOptions.DisableExpire,
|
||||
IndependentCache: options.DNSClientOptions.IndependentCache,
|
||||
CacheCapacity: options.DNSClientOptions.CacheCapacity,
|
||||
ClientSubnet: options.DNSClientOptions.ClientSubnet.Build(netip.Prefix{}),
|
||||
RDRC: func() adapter.RDRCStore {
|
||||
cacheFile := service.FromContext[adapter.CacheFile](ctx)
|
||||
if cacheFile == nil {
|
||||
|
@ -1,11 +1,7 @@
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "Changes in sing-box 1.12.0"
|
||||
|
||||
:material-decagram: [servers](#servers)
|
||||
|
||||
!!! quote "Changes in sing-box 1.11.0"
|
||||
|
||||
:material-plus: [cache_capacity](#cache_capacity)
|
||||
|
@ -1,11 +1,7 @@
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "sing-box 1.12.0 中的更改"
|
||||
|
||||
:material-decagram: [servers](#servers)
|
||||
|
||||
!!! quote "sing-box 1.11.0 中的更改"
|
||||
|
||||
:material-plus: [cache_capacity](#cache_capacity)
|
||||
|
@ -22,7 +22,6 @@ If enabled in the inbound, the protocol and domain name (if present) of by the c
|
||||
| UDP | `dtls` | / | / |
|
||||
| TCP | `ssh` | / | SSH Client Name |
|
||||
| TCP | `rdp` | / | / |
|
||||
| UDP | `ntp` | / | / |
|
||||
|
||||
| QUIC Client | Type |
|
||||
|:------------------------:|:----------:|
|
||||
|
@ -22,7 +22,6 @@
|
||||
| UDP | `dtls` | / | / |
|
||||
| TCP | `ssh` | / | SSH 客户端名称 |
|
||||
| TCP | `rdp` | / | / |
|
||||
| UDP | `ntp` | / | / |
|
||||
|
||||
| QUIC 客户端 | 类型 |
|
||||
|:------------------------:|:----------:|
|
||||
|
@ -564,7 +564,6 @@ func (r *Router) actionSniff(
|
||||
sniff.UTP,
|
||||
sniff.UDPTracker,
|
||||
sniff.DTLSRecord,
|
||||
sniff.NTP,
|
||||
}
|
||||
}
|
||||
for {
|
||||
|
@ -379,8 +379,6 @@ func (r *RuleActionSniff) build() error {
|
||||
r.StreamSniffers = append(r.StreamSniffers, sniff.SSH)
|
||||
case C.ProtocolRDP:
|
||||
r.StreamSniffers = append(r.StreamSniffers, sniff.RDP)
|
||||
case C.ProtocolNTP:
|
||||
r.PacketSniffers = append(r.PacketSniffers, sniff.NTP)
|
||||
default:
|
||||
return E.New("unknown sniffer: ", name)
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package v2raywebsocket
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
@ -62,7 +61,7 @@ func (c *WebsocketConn) Close() error {
|
||||
func (c *WebsocketConn) Read(b []byte) (n int, err error) {
|
||||
var header ws.Header
|
||||
for {
|
||||
n, err = wrapWsError0(c.reader.Read(b))
|
||||
n, err = c.reader.Read(b)
|
||||
if n > 0 {
|
||||
err = nil
|
||||
return
|
||||
@ -96,7 +95,7 @@ func (c *WebsocketConn) Read(b []byte) (n int, err error) {
|
||||
}
|
||||
|
||||
func (c *WebsocketConn) Write(p []byte) (n int, err error) {
|
||||
err = wrapWsError(wsutil.WriteMessage(c.Conn, c.state, ws.OpBinary, p))
|
||||
err = wsutil.WriteMessage(c.Conn, c.state, ws.OpBinary, p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -147,7 +146,7 @@ func (c *EarlyWebsocketConn) Read(b []byte) (n int, err error) {
|
||||
return 0, c.err
|
||||
}
|
||||
}
|
||||
return wrapWsError0(c.conn.Read(b))
|
||||
return c.conn.Read(b)
|
||||
}
|
||||
|
||||
func (c *EarlyWebsocketConn) writeRequest(content []byte) error {
|
||||
@ -178,12 +177,12 @@ func (c *EarlyWebsocketConn) writeRequest(content []byte) error {
|
||||
conn, err = c.dialContext(c.ctx, &c.requestURL, c.headers)
|
||||
}
|
||||
if err != nil {
|
||||
return wrapWsError(err)
|
||||
return err
|
||||
}
|
||||
if len(lateData) > 0 {
|
||||
_, err = conn.Write(lateData)
|
||||
if err != nil {
|
||||
return wrapWsError(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
c.conn = conn
|
||||
@ -192,7 +191,7 @@ func (c *EarlyWebsocketConn) writeRequest(content []byte) error {
|
||||
|
||||
func (c *EarlyWebsocketConn) Write(b []byte) (n int, err error) {
|
||||
if c.conn != nil {
|
||||
return wrapWsError0(c.conn.Write(b))
|
||||
return c.conn.Write(b)
|
||||
}
|
||||
c.access.Lock()
|
||||
defer c.access.Unlock()
|
||||
@ -200,9 +199,9 @@ func (c *EarlyWebsocketConn) Write(b []byte) (n int, err error) {
|
||||
return 0, c.err
|
||||
}
|
||||
if c.conn != nil {
|
||||
return wrapWsError0(c.conn.Write(b))
|
||||
return c.conn.Write(b)
|
||||
}
|
||||
err = wrapWsError(c.writeRequest(b))
|
||||
err = c.writeRequest(b)
|
||||
c.err = err
|
||||
close(c.create)
|
||||
if err != nil {
|
||||
@ -213,17 +212,17 @@ func (c *EarlyWebsocketConn) Write(b []byte) (n int, err error) {
|
||||
|
||||
func (c *EarlyWebsocketConn) WriteBuffer(buffer *buf.Buffer) error {
|
||||
if c.conn != nil {
|
||||
return wrapWsError(c.conn.WriteBuffer(buffer))
|
||||
return c.conn.WriteBuffer(buffer)
|
||||
}
|
||||
c.access.Lock()
|
||||
defer c.access.Unlock()
|
||||
if c.conn != nil {
|
||||
return wrapWsError(c.conn.WriteBuffer(buffer))
|
||||
return c.conn.WriteBuffer(buffer)
|
||||
}
|
||||
if c.err != nil {
|
||||
return c.err
|
||||
}
|
||||
err := wrapWsError(c.writeRequest(buffer.Bytes()))
|
||||
err := c.writeRequest(buffer.Bytes())
|
||||
c.err = err
|
||||
close(c.create)
|
||||
return err
|
||||
@ -273,23 +272,3 @@ func (c *EarlyWebsocketConn) Upstream() any {
|
||||
func (c *EarlyWebsocketConn) LazyHeadroom() bool {
|
||||
return c.conn == nil
|
||||
}
|
||||
|
||||
func wrapWsError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
var closedErr *wsutil.ClosedError
|
||||
if errors.As(err, &closedErr) {
|
||||
if closedErr.Code == ws.StatusNormalClosure {
|
||||
err = io.EOF
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func wrapWsError0[T any](value T, err error) (T, error) {
|
||||
if err == nil {
|
||||
return value, nil
|
||||
}
|
||||
return common.DefaultValue[T](), wrapWsError(err)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user