Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
e26e0d7
Add MAC and hostname rule items
nekohasekai Mar 3, 2026
7f34daa
Add Android support for MAC and hostname rule items
nekohasekai Mar 4, 2026
503e4d8
Add macOS support for MAC and hostname rule items
nekohasekai Mar 6, 2026
8280a9b
documentation: Update descriptions for neighbor rules
nekohasekai Mar 6, 2026
1b82808
cronet-go: Update chromium to 145.0.7632.159
nekohasekai Mar 7, 2026
7f2316a
Bump version
nekohasekai Mar 7, 2026
00b0bdb
Apply legacy transport strategy for default DNS transport in matchDNS
reF1nd Mar 3, 2026
90bf604
Revert "Disable TCP slow open for anytls"
reF1nd Oct 11, 2025
f21e6a2
Restore proxy protocol
reF1nd Mar 19, 2025
c7b3092
Add configurable `gso` option for WireGuard and Tailscale endpoint
reF1nd Feb 6, 2026
d943e67
Add `direct_domain_strategy` option to direct outbound
reF1nd Sep 7, 2025
9f88d95
Improve sniffer
reF1nd Mar 17, 2025
372715f
Add `domain_match_strategy` and `default_domain_match_strategy`
reF1nd May 6, 2025
62930f8
Add `rcode` option for DNS reject action
reF1nd May 20, 2025
2e19898
Add `sniff-override-destination` to rule action
reF1nd Mar 17, 2025
b0da8a7
Add `match_only` option for resolve action
reF1nd Mar 19, 2025
12aaa96
Add `auto_redirect_disable_mark_mode` option for tun inbound
reF1nd Apr 8, 2025
e02c4ef
Add fallback support for AnyTLS inbound
reF1nd Jun 11, 2025
8ff1ab9
clash-api: Add support for upgrading external UI automatically
reF1nd Apr 10, 2025
a7c1c04
clash-api: Add DNS rules support
reF1nd Mar 4, 2026
47feb27
DNS: Add group transport for concurrent multi-server querying
reF1nd Mar 2, 2026
0ae79a2
feature: TLS certificate pinning
dyhkwong Sep 17, 2023
8e222c7
clash-api: Add restart support
yelnoo Apr 13, 2025
80631cb
add outbound provider
yelnoo Mar 11, 2025
a932f8c
Start DNS transports before providers
reF1nd Jan 29, 2026
3f21733
Add kTLS support for outbound provider
reF1nd Sep 11, 2025
412e1a9
Add AnyTLS link parser for outbound provider
reF1nd Aug 14, 2025
b6d64ca
Add tls-pin-sha256 support to outbound provider
reF1nd Jun 17, 2025
281cc22
Add `override_dialer` option for outbound provider
reF1nd May 23, 2025
1409579
Add `path` option for remote provider
reF1nd Apr 18, 2025
fb78a14
provider: Fix clash `tls` parser
reF1nd Nov 2, 2025
fd9a24b
provider: Fix slow startup
reF1nd Dec 4, 2025
5a2a66c
provider: Rewrite detour tags to use provider-prefixed names
reF1nd Mar 3, 2026
7337caa
Add reload support
0xffffharry Oct 10, 2023
6bb68a9
Add URLTest Fallback Support
0xffffharry Apr 13, 2023
31af41b
use static file instead of cache file
PuerNya Aug 12, 2024
de7db05
makes remote rule-set `path` correct
reF1nd Apr 18, 2025
d90b9c9
add rule-provider clash-api
PuerNya Aug 12, 2024
405551a
support multi `clash_mode` item in rule item
PuerNya Jul 4, 2024
33cfd48
set correct inbound type when using `auto_redirect`
PuerNya Aug 14, 2024
111f3cf
Support `GET` method for doh
PuerNya May 5, 2025
c7b38d9
tls: Reject unknown SNI
xchacha20-poly1305 Jul 11, 2024
b7eb8f0
DNS: Add `reuse` option for TCP
xchacha20-poly1305 Jul 6, 2025
8882d8e
feat: add `tcp_keep_alive_count` option for listen fields and dial fi…
lurixo Dec 6, 2025
4824d2c
Add TCP keep alive options to outbound provider's `override_dialer`
reF1nd May 23, 2025
8a2eb75
tls: Add `server_names` and enhance `reject_unknown_sni`
reF1nd Nov 24, 2025
0ef2b6d
DNS: Add pipeline support for TCP and TLS
reF1nd Nov 26, 2025
a705e74
add outbound type loadbalance
lux5am Jun 8, 2025
8f39d17
add outbound type pass
lux5am Dec 18, 2024
ee4c25b
add `urltest_unified_delay` in experimental config
lux5am Jan 21, 2025
7a37274
add `min_cache_ttl` and `max_cache_ttl` in dns config
lux5am Feb 3, 2025
88a9e58
add `round_robin_cache` in dns config
lux5am Feb 3, 2025
d1a65c7
add `lazy_cache_ttl` in dns config
reF1nd Dec 24, 2025
c012564
DNS: support `lazy_cache_ttl` in DNS rules
reF1nd Dec 2, 2025
6ebb8a7
Support temporary disable rule
xireiki Oct 8, 2025
4ed2356
Support override TLS option
xireiki Oct 21, 2025
77bc1f0
文档新增 reF1nd 分支特性
DustinWin Mar 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/CRONET_GO_VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
cba7b9ac0399055aa49fbdc57c03c374f58e1597
d181863d6a4aa2e7bb7eaf67c1d512c5e4827fde
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/.idea/
/.vscode/
/vendor/
/*.json
/*.srs
Expand Down
135 changes: 135 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,141 @@ The universal proxy platform.

https://sing-box.sagernet.org

## Inbound TLS

```json
{
"inbounds": [
{
"type": "trojan",
"tag": "trojan-in",
"tls": {
"enabled": true,
"server_name": "sekai.love",
"certificate_path": "cert.pem",
"key_path": "key.key",
"reject_unknown_sni": true
}
},
{
"type": "anytls",
"tag": "anytls-in",
"tls": {
"enabled": true,
"server_names": [
"sagernet.sekai.love",
"sekai.love"
],
"certificate_path": "cert.pem",
"key_path": "key.key",
"reject_unknown_sni": true
}
}
]
}
```

Reject unknown SNI: If the server name of connection does not match `server_name` or any domain in `server_names`,
and is not included in the certificate, it will be rejected.

拒绝未知 SNI:如果连接的 server name 与 `server_name` 或者 `server_names` 中包含的域名 不符 且 证书中不包含它,则拒绝连接。

## Dialer

```json
{
"outbounds": [
{
"type": "direct",
"tag": "direct",
"tcp_keep_alive": "5m",
"tcp_keep_alive_interval": "75s",
"tcp_keep_alive_count": 0,
"disable_tcp_keep_alive": false
}
]
}
```

TCP Keep alive options.

## DNS

### TCP

```json
{
"dns": {
"servers": [
{
"type": "tcp",
"tag": "cloudlfare-tcp",
"server": "1.1.1.1",
"server_port": 53,
"reuse": true,
"pipeline": true
}
]
}
}
```

- `reuse`: Reuse TCP connection. Always enabled when `pipeline` is true.
- `pipeline`: Enable DNS pipelining (RFC 9210). Multiple queries can be sent without waiting for responses, improving performance.

### DoT

```json
{
"dns": {
"servers": [
{
"type": "tls",
"tag": "cloudflare-dot",
"server": "1.1.1.1",
"server_port": 853,
"pipeline": true
}
]
}
}
```

- `pipeline`: Enable DNS pipelining (RFC 9210). Multiple queries can be sent over the same TLS connection without waiting for responses,
significantly improving performance in high-concurrency scenarios.

## URLTest Fallback 支持

按照**可用性**和**顺序**选择出站

可用:指 URL 测试存在有效结果

配置示例:
```
{
"tag": "fallback",
"type": "urltest",
"outbounds": [
"A",
"B",
"C"
],
"fallback": {
"enabled": true, // 开启 fallback
"max_delay": "200ms" // 可选配置
// 若某节点可用,但是延迟超过 max_delay,则认为该节点不可用,淘汰忽略该节点,继续匹配选择下一个节点
// 但若所有节点均不可用,但是存在被 max_delay 规则淘汰的节点,则选择延迟最低的被淘汰节点
}
}
```
以上配置为例子:
1. 当 A, B, C 都可用时,优选选择 A。当 A 不可用时,优选选择 B。当 A, B 都不可用时,选择 C,若 C 也不可用,则返回第一个出站:A
2. (配置了 max_delay) 当 A, C 都不可用,B 延迟超过 200ms 时(在第一轮选择时淘汰,被认为是不可用节点),则选择 B

For extended features

- Providers: [中文](./docs/configuration/provider/index.zh.md), [English](./docs/configuration/provider/index.md)

## License

```
Expand Down
9 changes: 7 additions & 2 deletions adapter/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@ type DNSRouter interface {
Lookup(ctx context.Context, domain string, options DNSQueryOptions) ([]netip.Addr, error)
ClearCache()
LookupReverseMapping(ip netip.Addr) (string, bool)
Rules() []DNSRule
Rule(uuid string) (DNSRule, bool)
ResetNetwork()
}

type DNSClient interface {
Start()
Exchange(ctx context.Context, transport DNSTransport, message *dns.Msg, options DNSQueryOptions, responseChecker func(responseAddrs []netip.Addr) bool) (*dns.Msg, error)
Lookup(ctx context.Context, transport DNSTransport, domain string, options DNSQueryOptions, responseChecker func(responseAddrs []netip.Addr) bool) ([]netip.Addr, error)
Exchange(ctx context.Context, transport DNSTransport, message *dns.Msg, options DNSQueryOptions, responseChecker func(responseAddrs []netip.Addr) bool) (*dns.Msg, error, bool)
Lookup(ctx context.Context, transport DNSTransport, domain string, options DNSQueryOptions, responseChecker func(responseAddrs []netip.Addr) bool) ([]netip.Addr, error, bool)
ClearCache()
UpdateDnsCacheFromContext(ctx context.Context) bool
UpdateDnsCacheToContext(ctx context.Context) context.Context
}

type DNSQueryOptions struct {
Expand All @@ -37,6 +41,7 @@ type DNSQueryOptions struct {
DisableCache bool
RewriteTTL *uint32
ClientSubnet netip.Prefix
LazyCacheTTL *uint32
}

func DNSQueryOptionsFrom(ctx context.Context, options *option.DomainResolveOptions) (*DNSQueryOptions, error) {
Expand Down
44 changes: 43 additions & 1 deletion adapter/experimental.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io"
"time"

"github.com/sagernet/sing-box/common/hash"
"github.com/sagernet/sing/common/observable"
"github.com/sagernet/sing/common/varbin"
)
Expand Down Expand Up @@ -55,9 +56,14 @@ type CacheFile interface {
StoreGroupExpand(group string, expand bool) error
LoadRuleSet(tag string) *SavedBinary
SaveRuleSet(tag string, set *SavedBinary) error
LoadExternalUI(tag string) *SavedBinary
SaveExternalUI(tag string, info *SavedBinary) error
LoadSubscription(tag string) *SavedBinary
SaveSubscription(tag string, sub *SavedBinary) error
}

type SavedBinary struct {
Hash hash.HashType
Content []byte
LastUpdated time.Time
LastEtag string
Expand All @@ -69,6 +75,18 @@ func (s *SavedBinary) MarshalBinary() ([]byte, error) {
if err != nil {
return nil, err
}
hash, err := s.Hash.MarshalBinary()
if err != nil {
return nil, err
}
_, err = varbin.WriteUvarint(&buffer, uint64(len(hash)))
if err != nil {
return nil, err
}
_, err = buffer.Write(hash)
if err != nil {
return nil, err
}
_, err = varbin.WriteUvarint(&buffer, uint64(len(s.Content)))
if err != nil {
return nil, err
Expand Down Expand Up @@ -99,6 +117,19 @@ func (s *SavedBinary) UnmarshalBinary(data []byte) error {
if err != nil {
return err
}
hashLength, err := binary.ReadUvarint(reader)
if err != nil {
return err
}
hash := make([]byte, hashLength)
_, err = io.ReadFull(reader, hash)
if err != nil {
return err
}
err = s.Hash.UnmarshalBinary(hash)
if err != nil {
return err
}
contentLength, err := binary.ReadUvarint(reader)
if err != nil {
return err
Expand Down Expand Up @@ -138,9 +169,20 @@ type URLTestGroup interface {
URLTest(ctx context.Context) (map[string]uint16, error)
}

type LoadBalanceGroup interface {
OutboundGroup
URLTest(ctx context.Context) (map[string]uint16, error)
}

type SelectorGroup interface {
Selected() Outbound
}

func OutboundTag(detour Outbound) string {
if group, isGroup := detour.(OutboundGroup); isGroup {
return group.Now()
if now := group.Now(); now != "" {
return now
}
}
return detour.Tag()
}
36 changes: 35 additions & 1 deletion adapter/inbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package adapter

import (
"context"
"net"
"net/netip"
"time"

Expand Down Expand Up @@ -53,14 +54,17 @@ type InboundContext struct {
// sniffer

Protocol string
Domain string
SniffHost string
Client string
SniffContext any
SnifferNames []string
SniffError error

// cache

CacheIPs []netip.Addr
Domain string

// Deprecated: implement in rule action
InboundDetour string
LastInbound string
Expand All @@ -82,8 +86,11 @@ type InboundContext struct {
SourceGeoIPCode string
GeoIPCode string
ProcessInfo *ConnectionOwner
SourceMACAddress net.HardwareAddr
SourceHostname string
QueryType uint16
FakeIP bool
DestOverride bool

// rule cache

Expand All @@ -96,6 +103,32 @@ type InboundContext struct {
DestinationPortMatch bool
DidMatch bool
IgnoreDestinationIPCIDRMatch bool

// extended metadata
Extended *InboundContextExtended
}

type InboundContextExtended struct {
RealOutboundChain []string
}

func (c *InboundContext) InitExtended() {
if c.Extended == nil {
c.Extended = new(InboundContextExtended)
}
}

func (c *InboundContext) AppendRealOutbound(tag string) {
if c.Extended != nil {
c.Extended.RealOutboundChain = append(c.Extended.RealOutboundChain, tag)
}
}

func (c *InboundContext) GetRealOutboundChain() []string {
if c.Extended != nil {
return c.Extended.RealOutboundChain
}
return nil
}

func (c *InboundContext) ResetRuleCache() {
Expand All @@ -111,6 +144,7 @@ func (c *InboundContext) ResetRuleCache() {
type inboundContextKey struct{}

func WithContext(ctx context.Context, inboundContext *InboundContext) context.Context {
inboundContext.InitExtended()
return context.WithValue(ctx, (*inboundContextKey)(nil), inboundContext)
}

Expand Down
23 changes: 23 additions & 0 deletions adapter/neighbor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package adapter

import (
"net"
"net/netip"
)

type NeighborEntry struct {
Address netip.Addr
MACAddress net.HardwareAddr
Hostname string
}

type NeighborResolver interface {
LookupMAC(address netip.Addr) (net.HardwareAddr, bool)
LookupHostname(address netip.Addr) (string, bool)
Start() error
Close() error
}

type NeighborUpdateListener interface {
UpdateNeighborTable(entries []NeighborEntry)
}
4 changes: 4 additions & 0 deletions adapter/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ type PlatformInterface interface {

UsePlatformNotification() bool
SendNotification(notification *Notification) error

UsePlatformNeighborResolver() bool
StartNeighborMonitor(listener NeighborUpdateListener) error
CloseNeighborMonitor(listener NeighborUpdateListener) error
}

type FindConnectionOwnerRequest struct {
Expand Down
Loading