Compare commits

..

51 Commits

Author SHA1 Message Date
世界
75f526cb29
documentation: Bump version 2025-03-11 20:21:53 +08:00
Restia-Ashbell
ca37772b9e
documentation: Fix typo 2025-03-11 20:21:53 +08:00
anytls
8bd0d978d2
Update sing-anytls
Co-authored-by: anytls <anytls>
2025-03-11 20:21:53 +08:00
k9982874
6358fd6a08
Fix hosts DNS server 2025-03-11 20:21:47 +08:00
世界
1a8994b44c
Fix UDP DNS server crash 2025-03-11 20:21:47 +08:00
世界
5c628f3ada
documentation: Fix missing ip_accept_any DNS rule option 2025-03-11 20:21:47 +08:00
世界
4c7fc4765b
Fix anytls dialer usage 2025-03-11 20:21:46 +08:00
世界
86a68e8588
Move predefined DNS server to rule action 2025-03-11 20:21:46 +08:00
世界
400dbb4214
Fix domain resolver on direct outbound 2025-03-11 20:21:46 +08:00
Zephyruso
9a521c76a7
Fix missing AnyTLS display name 2025-03-11 20:21:46 +08:00
anytls
02d3e7e44a
Update sing-anytls
Co-authored-by: anytls <anytls>
2025-03-11 20:21:46 +08:00
Estel
94cb87e920
documentation: Fix typo
Signed-off-by: Estel <callmebedrockdigger@gmail.com>
2025-03-11 20:21:27 +08:00
TargetLocked
d1c4fa4e45
Fix parsing legacy DNS options 2025-03-11 20:21:27 +08:00
世界
4bec17c391
Fix DNS fallback 2025-03-11 20:21:27 +08:00
世界
609918dd93
documentation: Fix missing hosts DNS server 2025-03-11 20:21:27 +08:00
anytls
21feafab1a
Add MinIdleSession option to AnyTLS outbound
Co-authored-by: anytls <anytls>
2025-03-11 20:21:18 +08:00
ReleTor
84f13073cd
documentation: Minor fixes 2025-03-11 20:21:18 +08:00
libtry486
a120f8a7ea
documentation: Fix typo
fix typo

Signed-off-by: libtry486 <89328481+libtry486@users.noreply.github.com>
2025-03-11 20:21:18 +08:00
Alireza Ahmadi
ca09454708
Fix Outbound deadlock 2025-03-11 20:21:18 +08:00
世界
c3da006859
documentation: Fix AnyTLS doc 2025-03-11 20:21:18 +08:00
anytls
bc72bcc053
Add AnyTLS protocol 2025-03-11 20:21:17 +08:00
世界
bb7989e81f
Migrate to stdlib ECH support 2025-03-11 20:21:17 +08:00
世界
fd16af06ab
Add fallback local DNS server for iOS 2025-03-11 20:21:17 +08:00
世界
b7311fd2cc
Get darwin local DNS server from libresolv 2025-03-11 20:21:17 +08:00
世界
53344f789f
Improve resolve action 2025-03-11 20:21:17 +08:00
世界
b43c4e0c87
Fix toolchain version 2025-03-11 20:21:16 +08:00
世界
8b1fcf7903
Add back port hopping to hysteria 1 2025-03-11 20:21:16 +08:00
世界
764d4b1950
Update dependencies 2025-03-11 20:21:16 +08:00
xchacha20-poly1305
1645cd30d9
Remove single quotes of raw Moziila certs 2025-03-11 20:21:16 +08:00
世界
32ac8fe7ec
Add Tailscale endpoint 2025-03-11 20:21:11 +08:00
世界
23778984ab
Build legacy binaries with latest Go 2025-03-11 20:21:09 +08:00
世界
10faff797a
documentation: Remove outdated icons 2025-03-11 20:21:05 +08:00
世界
7a7cf6216b
documentation: Certificate store 2025-03-11 20:21:03 +08:00
世界
ef82c51077
documentation: TLS fragment 2025-03-11 20:21:01 +08:00
世界
23a0d12834
documentation: Outbound domain resolver 2025-03-11 20:20:59 +08:00
世界
5ac18ce8ad
documentation: Refactor DNS 2025-03-11 20:20:56 +08:00
世界
6c38fec376
Add certificate store 2025-03-11 20:20:51 +08:00
世界
6c598746d5
Add TLS fragment support 2025-03-11 20:20:50 +08:00
世界
fe0ce58864
refactor: Outbound domain resolver 2025-03-11 20:20:48 +08:00
世界
7372d239a4
refactor: DNS 2025-03-11 20:20:46 +08:00
世界
8e2baf40f1
Bump version 2025-03-11 20:18:34 +08:00
世界
c24c40dfee
platform: Fix android start 2025-03-11 20:18:34 +08:00
世界
32e52ce1ed
Fix udp nat for fakeip 2025-03-11 19:09:27 +08:00
世界
ed46438359
release: Use nightly goreleaser to fix rpm bug 2025-03-11 13:29:08 +08:00
世界
0b5490d5a3
Fix resolve domain for WireGuard 2025-03-11 12:02:25 +08:00
Tal Rasha
2d73ef511d
Fix grpclite memory leak
Co-authored-by: talrasha007 <talrasha007@gmail.om>
2025-03-10 14:48:02 +08:00
Mahdi
63e6c85f6f
Fix shadowsocks UoT 2025-03-10 14:47:59 +08:00
世界
8946a6d2d0
release: Use latest goreleaser 2025-03-09 15:27:04 +08:00
世界
d3132645fb
documentation: Fix description of the UoT protocol 2025-03-09 15:26:42 +08:00
世界
373f158fe0
Fix download external ui with query params 2025-03-09 15:26:36 +08:00
世界
ce36835fab
Fix override destination 2025-03-09 15:25:06 +08:00
27 changed files with 170 additions and 95 deletions

View File

@ -155,7 +155,7 @@ jobs:
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser-pro
version: '~> v2'
version: nightly
install-only: true
- name: Extract signing key
run: |-

9
box.go
View File

@ -216,8 +216,15 @@ func New(options Options) (*Box, error) {
} else {
tag = F.ToString(i)
}
endpointCtx := ctx
if tag != "" {
// TODO: remove this
endpointCtx = adapter.WithContext(endpointCtx, &adapter.InboundContext{
Outbound: tag,
})
}
err = endpointManager.Create(
ctx,
endpointCtx,
router,
logFactory.NewLogger(F.ToString("endpoint/", endpointOptions.Type, "[", tag, "]")),
tag,

@ -1 +1 @@
Subproject commit 0576fd75a67e56048c29d00ef539b4f8f05aec2a
Subproject commit aefe3c029096ddac5189a20a8203a68858152f0a

@ -1 +1 @@
Subproject commit a828bb3a93b57d0c1b13d74246f0675c5244466d
Subproject commit ae5818ee5a24af965dc91f80bffa16e1e6c109c1

View File

@ -537,7 +537,7 @@ func FixedResponse(id uint16, question dns.Question, addresses []netip.Addr, tim
Question: []dns.Question{question},
}
for _, address := range addresses {
if address.Is4() {
if address.Is4() && question.Qtype == dns.TypeA {
response.Answer = append(response.Answer, &dns.A{
Hdr: dns.RR_Header{
Name: question.Name,
@ -547,7 +547,7 @@ func FixedResponse(id uint16, question dns.Question, addresses []netip.Addr, tim
},
A: address.AsSlice(),
})
} else {
} else if address.Is6() && question.Qtype == dns.TypeAAAA {
response.Answer = append(response.Answer, &dns.AAAA{
Hdr: dns.RR_Header{
Name: question.Name,

View File

@ -2,6 +2,7 @@ package hosts
import (
"context"
"net/netip"
"os"
"github.com/sagernet/sing-box/adapter"
@ -22,11 +23,15 @@ var _ adapter.DNSTransport = (*Transport)(nil)
type Transport struct {
dns.TransportAdapter
files []*File
files []*File
predefined map[string][]netip.Addr
}
func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.HostsDNSServerOptions) (adapter.DNSTransport, error) {
var files []*File
var (
files []*File
predefined = make(map[string][]netip.Addr)
)
if len(options.Path) == 0 {
files = append(files, NewFile(DefaultPath))
} else {
@ -34,9 +39,15 @@ func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, opt
files = append(files, NewFile(filemanager.BasePath(ctx, os.ExpandEnv(path))))
}
}
if options.Predefined != nil {
for _, entry := range options.Predefined.Entries() {
predefined[mDNS.CanonicalName(entry.Key)] = entry.Value
}
}
return &Transport{
TransportAdapter: dns.NewTransportAdapter(C.DNSTypeHosts, tag, nil),
files: files,
predefined: predefined,
}, nil
}
@ -45,8 +56,11 @@ func (t *Transport) Reset() {
func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
question := message.Question[0]
domain := dns.FqdnToDomain(question.Name)
domain := mDNS.CanonicalName(question.Name)
if question.Qtype == mDNS.TypeA || question.Qtype == mDNS.TypeAAAA {
if addresses, ok := t.predefined[domain]; ok {
return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil
}
for _, file := range t.files {
addresses := file.Lookup(domain)
if len(addresses) > 0 {

View File

@ -34,7 +34,7 @@ func (f *File) Lookup(name string) []netip.Addr {
f.access.Lock()
defer f.access.Unlock()
f.update()
return f.byName[name]
return f.byName[dns.CanonicalName(name)]
}
func (f *File) update() {

View File

@ -11,6 +11,6 @@ import (
func TestHosts(t *testing.T) {
t.Parallel()
require.Equal(t, []netip.Addr{netip.AddrFrom4([4]byte{127, 0, 0, 1}), netip.IPv6Loopback()}, hosts.NewFile("testdata/hosts").Lookup("localhost."))
require.NotEmpty(t, hosts.NewFile(hosts.DefaultPath).Lookup("localhost."))
require.Equal(t, []netip.Addr{netip.AddrFrom4([4]byte{127, 0, 0, 1}), netip.IPv6Loopback()}, hosts.NewFile("testdata/hosts").Lookup("localhost"))
require.NotEmpty(t, hosts.NewFile(hosts.DefaultPath).Lookup("localhost"))
}

View File

@ -110,13 +110,6 @@ func (t *UDPTransport) exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.M
conn.access.Lock()
delete(conn.callbacks, messageId)
conn.access.Unlock()
callback.access.Lock()
select {
case <-callback.done:
default:
close(callback.done)
}
callback.access.Unlock()
}()
rawMessage, err := exMessage.PackBuffer(buffer.FreeBytes())
if err != nil {

View File

@ -2,6 +2,16 @@
icon: material/alert-decagram
---
#### 1.12.0-alpha.14
* Fixes and improvements
### 1.11.5
* Fixes and improvements
_We are temporarily unable to update sing-box apps on the App Store because the reviewer mistakenly found that we violated the rules (TestFlight users are not affected)._
#### 1.12.0-alpha.13
* Move `predefined` DNS server to DNS rule action **1**

View File

@ -7,6 +7,10 @@ icon: material/apple
SFI/SFM/SFT allows users to manage and run local or remote sing-box configuration files, and provides
platform-specific function implementation, such as TUN transparent proxy implementation.
!!! failure ""
We are temporarily unable to update sing-box apps on the App Store because the reviewer mistakenly found that we violated the rules (TestFlight users are not affected).
## :material-graph: Requirements
* iOS 15.0+ / macOS 13.0+ / Apple tvOS 17.0+

View File

@ -4,6 +4,7 @@ icon: material/alert-decagram
!!! quote "Changes in sing-box 1.12.0"
:material-plus: [ip_accept_any](#ip_accept_any)
:material-delete-clock: [outbound](#outbound)
!!! quote "Changes in sing-box 1.11.0"
@ -77,15 +78,6 @@ icon: material/alert-decagram
"domain_regex": [
"^stun\\..+"
],
"geosite": [
"cn"
],
"source_geoip": [
"private"
],
"geoip": [
"cn"
],
"source_ip_cidr": [
"10.0.0.0/24",
"192.168.0.1"
@ -96,6 +88,7 @@ icon: material/alert-decagram
"192.168.0.1"
],
"ip_is_private": false,
"ip_accept_any": false,
"source_port": [
12345
],
@ -147,8 +140,6 @@ icon: material/alert-decagram
"geoip-cn",
"geosite-cn"
],
// deprecated
"rule_set_ipcidr_match_source": false,
"rule_set_ip_cidr_match_source": false,
"rule_set_ip_cidr_accept_empty": false,
"invert": false,
@ -156,7 +147,20 @@ icon: material/alert-decagram
"direct"
],
"action": "route",
"server": "local"
"server": "local",
// Deprecated
"rule_set_ipcidr_match_source": false,
"geosite": [
"cn"
],
"source_geoip": [
"private"
],
"geoip": [
"cn"
]
},
{
"type": "logical",
@ -451,7 +455,9 @@ Only takes effect for address requests (A/AAAA/HTTPS). When the query results do
#### geoip
!!! question "Since sing-box 1.9.0"
!!! failure "Removed in sing-box 1.12.0"
GeoIP is deprecated in sing-box 1.8.0 and removed in sing-box 1.12.0, check [Migration](/migration/#migrate-geoip-to-rule-sets).
Match GeoIP with query response.
@ -473,6 +479,12 @@ Match private IP with query response.
Make `ip_cidr` rules in rule-sets accept empty query response.
#### ip_accept_any
!!! question "Since sing-box 1.12.0"
Match any IP with query response.
### Logical Fields
#### type

View File

@ -4,6 +4,7 @@ icon: material/alert-decagram
!!! quote "sing-box 1.12.0 中的更改"
:material-plus: [ip_accept_any](#ip_accept_any)
:material-delete-clock: [outbound](#outbound)
!!! quote "sing-box 1.11.0 中的更改"
@ -77,15 +78,6 @@ icon: material/alert-decagram
"domain_regex": [
"^stun\\..+"
],
"geosite": [
"cn"
],
"source_geoip": [
"private"
],
"geoip": [
"cn"
],
"source_ip_cidr": [
"10.0.0.0/24",
"192.168.0.1"
@ -96,6 +88,7 @@ icon: material/alert-decagram
"192.168.0.1"
],
"ip_is_private": false,
"ip_accept_any": false,
"source_port": [
12345
],
@ -147,8 +140,6 @@ icon: material/alert-decagram
"geoip-cn",
"geosite-cn"
],
// 已弃用
"rule_set_ipcidr_match_source": false,
"rule_set_ip_cidr_match_source": false,
"rule_set_ip_cidr_accept_empty": false,
"invert": false,
@ -156,7 +147,19 @@ icon: material/alert-decagram
"direct"
],
"action": "route",
"server": "local"
"server": "local",
// 已弃用
"rule_set_ipcidr_match_source": false,
"geosite": [
"cn"
],
"source_geoip": [
"private"
],
"geoip": [
"cn"
]
},
{
"type": "logical",
@ -232,17 +235,17 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
#### geosite
!!! failure "已在 sing-box 1.8.0 废弃"
!!! failure "已在 sing-box 1.12.0 中被移除"
Geosite 已废弃且可能在不久的将来移除,参阅 [迁移指南](/zh/migration/#geosite)。
GeoSite 已在 sing-box 1.8.0 废弃且在 sing-box 1.12.0 中被移除,参阅 [迁移指南](/zh/migration/#geosite)。
匹配 Geosite。
#### source_geoip
!!! failure "已在 sing-box 1.8.0 废弃"
!!! failure "已在 sing-box 1.12.0 中被移除"
GeoIP 已废弃且可能在不久的将来移除,参阅 [迁移指南](/zh/migration/#geoip)。
GeoIP 已在 sing-box 1.8.0 废弃且在 sing-box 1.12.0 中被移除,参阅 [迁移指南](/zh/migration/#geoip)。
匹配源 GeoIP。
@ -451,7 +454,10 @@ Available values: `wifi`, `cellular`, `ethernet` and `other`.
#### geoip
!!! question "自 sing-box 1.9.0 起"
!!! failure "已在 sing-box 1.12.0 中被移除"
GeoIP 已在 sing-box 1.8.0 废弃且在 sing-box 1.12.0 中被移除,参阅 [迁移指南](/zh/migration/#geoip)。
与查询响应匹配 GeoIP。
@ -467,6 +473,12 @@ Available values: `wifi`, `cellular`, `ethernet` and `other`.
与查询响应匹配非公开 IP。
#### ip_accept_any
!!! question "自 sing-box 1.12.0 起"
匹配任意 IP。
#### rule_set_ip_cidr_accept_empty
!!! question "自 sing-box 1.10.0 起"

View File

@ -13,8 +13,7 @@ icon: material/new-box
```json
{
"action": "route",
// 默认
"action": "route", // 默认
"server": "",
"strategy": "",
"disable_cache": false,

View File

@ -31,12 +31,11 @@ The protocol version, `1` or `2`.
### Application support
| Project | UoT v1 | UoT v2 |
|--------------|----------------------|-------------------------------------------------------------------------------------------------------------------|
| sing-box | v0 (2022/08/11) | v1.2-beta9 |
| Xray-core | v1.5.7 (2022/06/05) | [f57ec13](https://github.com/XTLS/Xray-core/commit/f57ec1388084df041a2289bacab14e446bf1b357) (Not released) |
| Clash.Meta | v1.12.0 (2022/07/02) | [8cb67b6](https://github.com/MetaCubeX/Clash.Meta/commit/8cb67b6480649edfa45dcc9ac89ce0789651e8b3) (Not released) |
| Shadowrocket | v2.2.12 (2022/08/13) | / |
| Project | UoT v1 | UoT v2 |
|--------------|----------------------|----------------------|
| sing-box | v0 (2022/08/11) | v1.2-beta9 |
| Clash.Meta | v1.12.0 (2022/07/02) | v1.14.3 (2023/03/31) |
| Shadowrocket | v2.2.12 (2022/08/13) | / |
### Protocol details
@ -50,7 +49,13 @@ The client requests the magic address to the upper layer proxy protocol to indic
|------|----------|-------|--------|----------|
| u8 | variable | u16be | u16be | variable |
**ATYP / address / port**: Uses the SOCKS address format.
**ATYP / address / port**: Uses the SOCKS address format, but with different address types:
| ATYP | Address type |
|--------|--------------|
| `0x00` | IPv4 Address |
| `0x01` | IPv6 Address |
| `0x02` | Domain Name |
#### Protocol version 2

View File

@ -567,7 +567,7 @@ The legacy outbound DNS rules are deprecated and can be replaced by new domain r
"server_port": 2080,
"domain_resolver": {
"server": "local",
"rewrite_tll": 60,
"rewrite_ttl": 60,
"client_subnet": "1.1.1.1"
},
// or "domain_resolver": "local",
@ -579,7 +579,7 @@ The legacy outbound DNS rules are deprecated and can be replaced by new domain r
"route": {
"default_domain_resolver": {
"server": "local",
"rewrite_tll": 60,
"rewrite_ttl": 60,
"client_subnet": "1.1.1.1"
}
}

View File

@ -565,13 +565,21 @@ DNS 服务器已经重构。
"type": "socks",
"server": "example.org",
"server_port": 2080,
"domain_resolver": "local",
"domain_resolver": {
"server": "local",
"rewrite_ttl": 60,
"client_subnet": "1.1.1.1"
},
// 或 "domain_resolver": "local",
}
],
// 或
"route": {
"default_domain_resolver": {
"server": "local",
"rewrite_tll": 60,
"rewrite_ttl": 60,
"client_subnet": "1.1.1.1"
}
}

View File

@ -77,15 +77,15 @@ func (s *Server) downloadExternalUI() error {
if response.StatusCode != http.StatusOK {
return E.New("download external ui failed: ", response.Status)
}
err = s.downloadZIP(filepath.Base(downloadURL), response.Body, s.externalUI)
err = s.downloadZIP(response.Body, s.externalUI)
if err != nil {
removeAllInDirectory(s.externalUI)
}
return err
}
func (s *Server) downloadZIP(name string, body io.Reader, output string) error {
tempFile, err := filemanager.CreateTemp(s.ctx, name)
func (s *Server) downloadZIP(body io.Reader, output string) error {
tempFile, err := filemanager.CreateTemp(s.ctx, "external-ui.zip")
if err != nil {
return err
}

View File

@ -56,7 +56,12 @@ func (m *platformDefaultInterfaceMonitor) UnregisterCallback(element *list.Eleme
func (m *platformDefaultInterfaceMonitor) UpdateDefaultInterface(interfaceName string, interfaceIndex32 int32, isExpensive bool, isConstrained bool) {
if sFixAndroidStack {
go m.updateDefaultInterface(interfaceName, interfaceIndex32, isExpensive, isConstrained)
done := make(chan struct{})
go func() {
m.updateDefaultInterface(interfaceName, interfaceIndex32, isExpensive, isConstrained)
close(done)
}()
<-done
} else {
m.updateDefaultInterface(interfaceName, interfaceIndex32, isExpensive, isConstrained)
}

4
go.mod
View File

@ -3,7 +3,7 @@ module github.com/sagernet/sing-box
go 1.23.1
require (
github.com/anytls/sing-anytls v0.0.5
github.com/anytls/sing-anytls v0.0.6
github.com/caddyserver/certmagic v0.21.7
github.com/cloudflare/circl v1.6.0
github.com/cretz/bine v0.2.0
@ -26,7 +26,7 @@ require (
github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff
github.com/sagernet/quic-go v0.49.0-beta.1
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
github.com/sagernet/sing v0.6.2-0.20250210072154-8dff604468ff
github.com/sagernet/sing v0.6.4-0.20250309232452-1c3b777fe509
github.com/sagernet/sing-mux v0.3.1
github.com/sagernet/sing-quic v0.4.1-beta.1
github.com/sagernet/sing-shadowsocks v0.2.7

8
go.sum
View File

@ -8,8 +8,8 @@ github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7V
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/anytls/sing-anytls v0.0.5 h1:I1NIh3zKTSXThLG5UgjsOOT/x2DZJqjfBzjuP/wZlDk=
github.com/anytls/sing-anytls v0.0.5/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8=
github.com/anytls/sing-anytls v0.0.6 h1:UatIjl/OvzWQGXQ1I2bAIkabL9WtihW0fA7G+DXGBUg=
github.com/anytls/sing-anytls v0.0.6/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8=
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/caddyserver/certmagic v0.21.7 h1:66KJioPFJwttL43KYSWk7ErSmE6LfaJgCQuhm8Sg6fg=
@ -182,8 +182,8 @@ github.com/sagernet/quic-go v0.49.0-beta.1/go.mod h1:uesWD1Ihrldq1M3XtjuEvIUqi8W
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
github.com/sagernet/sing v0.6.2-0.20250210072154-8dff604468ff h1:5UGghwx8cI14qFa0ienrLekAYfhdKAiWvJUkY7rHmsI=
github.com/sagernet/sing v0.6.2-0.20250210072154-8dff604468ff/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing v0.6.4-0.20250309232452-1c3b777fe509 h1:rDWToc7O295Xh/uFSLqg67MVPftzXnICH/EUI4NL/a8=
github.com/sagernet/sing v0.6.4-0.20250309232452-1c3b777fe509/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-mux v0.3.1 h1:kvCc8HyGAskDHDQ0yQvoTi/7J4cZPB/VJMsAM3MmdQI=
github.com/sagernet/sing-mux v0.3.1/go.mod h1:Mkdz8LnDstthz0HWuA/5foncnDIdcNN5KZ6AdJX+x78=
github.com/sagernet/sing-quic v0.4.1-beta.1 h1:V2VfMckT3EQR3ZdfSzJgZZDsvfZZH42QAZpnOnHKa0s=

View File

@ -316,8 +316,8 @@ type LegacyDNSServerOptions struct {
}
type HostsDNSServerOptions struct {
Path badoption.Listable[string] `json:"path,omitempty"`
Predefined badjson.TypedMap[string, badoption.Listable[netip.Addr]] `json:"predefined,omitempty"`
Path badoption.Listable[string] `json:"path,omitempty"`
Predefined *badjson.TypedMap[string, badoption.Listable[netip.Addr]] `json:"predefined,omitempty"`
}
type LocalDNSServerOptions struct {

View File

@ -51,8 +51,9 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
outbound.tlsConfig = tlsConfig
outboundDialer, err := dialer.NewWithOptions(dialer.Options{
Context: ctx,
Options: options.DialerOptions,
Context: ctx,
Options: options.DialerOptions,
RemoteIsDomain: options.ServerIsDomain(),
})
if err != nil {
return nil, err

View File

@ -12,6 +12,7 @@ import (
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/udpnat2"
@ -80,7 +81,7 @@ func (i *Inbound) Close() error {
}
func (i *Inbound) NewPacketEx(buffer *buf.Buffer, source M.Socksaddr) {
i.udpNat.NewPacket([][]byte{buffer.Bytes()}, source, M.Socksaddr{}, nil)
i.udpNat.NewPacket([][]byte{buffer.Bytes()}, source, i.listener.UDPAddr(), nil)
}
func (i *Inbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
@ -104,7 +105,6 @@ func (i *Inbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata a
func (i *Inbound) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) {
i.logger.InfoContext(ctx, "inbound packet connection from ", source)
i.logger.InfoContext(ctx, "inbound packet connection to ", destination)
var metadata adapter.InboundContext
metadata.Inbound = i.Tag()
metadata.InboundType = i.Type()
@ -123,8 +123,11 @@ func (i *Inbound) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn,
destination.Port = i.overrideDestination.Port
default:
}
i.logger.InfoContext(ctx, "inbound packet connection to ", destination)
metadata.Destination = destination
metadata.OriginDestination = i.listener.UDPAddr()
if i.overrideOption != 0 {
conn = bufio.NewDestinationNATPacketConn(bufio.NewNetPacketConn(conn), i.listener.UDPAddr(), destination)
}
i.router.RoutePacketConnectionEx(ctx, conn, metadata, onClose)
}

View File

@ -61,7 +61,7 @@ func newInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
logger: logger,
}
var err error
inbound.router, err = mux.NewRouterWithOptions(router, logger, common.PtrValueOrDefault(options.Multiplex))
inbound.router, err = mux.NewRouterWithOptions(inbound.router, logger, common.PtrValueOrDefault(options.Multiplex))
if err != nil {
return nil, err
}

View File

@ -165,22 +165,17 @@ func (m *ConnectionManager) NewPacketConnection(ctx context.Context, this N.Dial
} else {
originDestination = metadata.Destination
}
if metadata.Destination != M.SocksaddrFrom(destinationAddress, metadata.Destination.Port) {
if natConn, loaded := common.Cast[bufio.NATPacketConn](conn); loaded {
natConn.UpdateDestination(destinationAddress)
} else if metadata.Destination != M.SocksaddrFrom(destinationAddress, metadata.Destination.Port) {
if metadata.UDPDisableDomainUnmapping {
remotePacketConn = bufio.NewUnidirectionalNATPacketConn(bufio.NewPacketConn(remotePacketConn), M.SocksaddrFrom(destinationAddress, metadata.Destination.Port), originDestination)
} else {
remotePacketConn = bufio.NewNATPacketConn(bufio.NewPacketConn(remotePacketConn), M.SocksaddrFrom(destinationAddress, metadata.Destination.Port), originDestination)
}
}
if natConn, loaded := common.Cast[bufio.NATPacketConn](conn); loaded {
natConn.UpdateDestination(destinationAddress)
}
} else if metadata.RouteOriginalDestination.IsValid() && metadata.RouteOriginalDestination != metadata.Destination {
if metadata.UDPDisableDomainUnmapping {
remotePacketConn = bufio.NewUnidirectionalNATPacketConn(bufio.NewPacketConn(remotePacketConn), metadata.Destination, metadata.RouteOriginalDestination)
} else {
remotePacketConn = bufio.NewNATPacketConn(bufio.NewPacketConn(remotePacketConn), metadata.Destination, metadata.RouteOriginalDestination)
}
remotePacketConn = bufio.NewDestinationNATPacketConn(bufio.NewPacketConn(remotePacketConn), metadata.Destination, metadata.RouteOriginalDestination)
}
var udpTimeout time.Duration
if metadata.UDPTimeout > 0 {
@ -295,13 +290,17 @@ func (m *ConnectionManager) connectionCopy(ctx context.Context, source io.Reader
func (m *ConnectionManager) packetConnectionCopy(ctx context.Context, source N.PacketReader, destination N.PacketWriter, direction bool, done *atomic.Bool, onClose N.CloseHandlerFunc) {
_, err := bufio.CopyPacket(destination, source)
if !direction {
if E.IsClosedOrCanceled(err) {
if err == nil {
m.logger.DebugContext(ctx, "packet upload finished")
} else if E.IsClosedOrCanceled(err) {
m.logger.TraceContext(ctx, "packet upload closed")
} else {
m.logger.DebugContext(ctx, "packet upload closed: ", err)
}
} else {
if E.IsClosedOrCanceled(err) {
if err == nil {
m.logger.DebugContext(ctx, "packet download finished")
} else if E.IsClosedOrCanceled(err) {
m.logger.TraceContext(ctx, "packet download closed")
} else {
m.logger.DebugContext(ctx, "packet download closed: ", err)

View File

@ -21,6 +21,7 @@ import (
var _ net.Conn = (*GunConn)(nil)
type GunConn struct {
rawReader io.Reader
reader *std_bufio.Reader
writer io.Writer
flusher http.Flusher
@ -31,9 +32,10 @@ type GunConn struct {
func newGunConn(reader io.Reader, writer io.Writer, flusher http.Flusher) *GunConn {
return &GunConn{
reader: std_bufio.NewReader(reader),
writer: writer,
flusher: flusher,
rawReader: reader,
reader: std_bufio.NewReader(reader),
writer: writer,
flusher: flusher,
}
}
@ -46,6 +48,7 @@ func newLateGunConn(writer io.Writer) *GunConn {
func (c *GunConn) setup(reader io.Reader, err error) {
if reader != nil {
c.rawReader = reader
c.reader = std_bufio.NewReader(reader)
}
c.err = err
@ -138,7 +141,7 @@ func (c *GunConn) FrontHeadroom() int {
}
func (c *GunConn) Close() error {
return common.Close(c.reader, c.writer)
return common.Close(c.rawReader, c.writer)
}
func (c *GunConn) LocalAddr() net.Addr {