Compare commits

...

10 Commits

Author SHA1 Message Date
世界
97f0dc8a60 Bump version 2025-08-20 09:20:41 +08:00
dyhkwong
ee02532ab5 Fix tlsfragment fallback writeAndWaitAck 2025-08-20 09:20:41 +08:00
世界
f1dd0dba78 Make ReadWaitConn reader replaceable 2025-08-20 09:18:03 +08:00
wwqgtxx
f4ed684146 Update cast using in sing-vmess 2025-08-20 08:45:09 +08:00
wwqgtxx
83f02d0bfb Make utlsConnWrapper replaceable 2025-08-20 08:45:09 +08:00
wwqgtxx
52fa5f20a3 Make realityConnWrapper replaceable 2025-08-20 08:45:09 +08:00
世界
f462ce5615 Update tfo-go 2025-08-19 21:56:05 +08:00
世界
cef3e538ba Fix failed DNS responses being incorrectly rejected 2025-08-19 11:14:46 +08:00
世界
acda4ce985 Fix bind_interface not working with auto_redirect 2025-08-17 14:48:01 +08:00
世界
354ece2bdf Fix resolved service 2025-08-16 00:09:29 +08:00
19 changed files with 121 additions and 63 deletions

View File

@@ -20,6 +20,7 @@ type NetworkManager interface {
DefaultOptions() NetworkOptions
RegisterAutoRedirectOutputMark(mark uint32) error
AutoRedirectOutputMark() uint32
AutoRedirectOutputMarkFunc() control.Func
NetworkMonitor() tun.NetworkUpdateMonitor
InterfaceMonitor() tun.DefaultInterfaceMonitor
PackageManager() tun.PackageManager

View File

@@ -30,7 +30,7 @@ type Manager struct {
outboundByTag map[string]adapter.Outbound
dependByTag map[string][]string
defaultOutbound adapter.Outbound
defaultOutboundFallback adapter.Outbound
defaultOutboundFallback func() (adapter.Outbound, error)
}
func NewManager(logger logger.ContextLogger, registry adapter.OutboundRegistry, endpoint adapter.EndpointManager, defaultTag string) *Manager {
@@ -44,7 +44,7 @@ func NewManager(logger logger.ContextLogger, registry adapter.OutboundRegistry,
}
}
func (m *Manager) Initialize(defaultOutboundFallback adapter.Outbound) {
func (m *Manager) Initialize(defaultOutboundFallback func() (adapter.Outbound, error)) {
m.defaultOutboundFallback = defaultOutboundFallback
}
@@ -55,18 +55,31 @@ func (m *Manager) Start(stage adapter.StartStage) error {
}
m.started = true
m.stage = stage
outbounds := m.outbounds
m.access.Unlock()
if stage == adapter.StartStateStart {
if m.defaultOutbound == nil {
directOutbound, err := m.defaultOutboundFallback()
if err != nil {
m.access.Unlock()
return E.Cause(err, "create direct outbound for fallback")
}
m.outbounds = append(m.outbounds, directOutbound)
m.outboundByTag[directOutbound.Tag()] = directOutbound
m.defaultOutbound = directOutbound
}
if m.defaultTag != "" && m.defaultOutbound == nil {
defaultEndpoint, loaded := m.endpoint.Get(m.defaultTag)
if !loaded {
m.access.Unlock()
return E.New("default outbound not found: ", m.defaultTag)
}
m.defaultOutbound = defaultEndpoint
}
outbounds := m.outbounds
m.access.Unlock()
return m.startOutbounds(append(outbounds, common.Map(m.endpoint.Endpoints(), func(it adapter.Endpoint) adapter.Outbound { return it })...))
} else {
outbounds := m.outbounds
m.access.Unlock()
for _, outbound := range outbounds {
err := adapter.LegacyStart(outbound, stage)
if err != nil {
@@ -187,11 +200,7 @@ func (m *Manager) Outbound(tag string) (adapter.Outbound, bool) {
func (m *Manager) Default() adapter.Outbound {
m.access.RLock()
defer m.access.RUnlock()
if m.defaultOutbound != nil {
return m.defaultOutbound
} else {
return m.defaultOutboundFallback
}
return m.defaultOutbound
}
func (m *Manager) Remove(tag string) error {

8
box.go
View File

@@ -314,15 +314,15 @@ func New(options Options) (*Box, error) {
return nil, E.Cause(err, "initialize service[", i, "]")
}
}
outboundManager.Initialize(common.Must1(
direct.NewOutbound(
outboundManager.Initialize(func() (adapter.Outbound, error) {
return direct.NewOutbound(
ctx,
router,
logFactory.NewLogger("outbound/direct"),
"direct",
option.DirectOutboundOptions{},
),
))
)
})
dnsTransportManager.Initialize(common.Must1(
local.NewTransport(
ctx,

View File

@@ -128,6 +128,10 @@ func (c *ReadWaitConn) Upstream() any {
return c.Conn
}
func (c *ReadWaitConn) ReaderReplaceable() bool {
return true
}
var tlsRegistry []func(conn net.Conn) (loaded bool, tlsReadRecord func() error, tlsHandlePostHandshakeMessage func() error)
func init() {

View File

@@ -6,22 +6,26 @@ import (
"net"
_ "unsafe"
"github.com/sagernet/sing/common"
"github.com/metacubex/utls"
)
func init() {
tlsRegistry = append(tlsRegistry, func(conn net.Conn) (loaded bool, tlsReadRecord func() error, tlsHandlePostHandshakeMessage func() error) {
tlsConn, loaded := common.Cast[*tls.UConn](conn)
if !loaded {
return
switch tlsConn := conn.(type) {
case *tls.UConn:
return true, func() error {
return utlsReadRecord(tlsConn.Conn)
}, func() error {
return utlsHandlePostHandshakeMessage(tlsConn.Conn)
}
case *tls.Conn:
return true, func() error {
return utlsReadRecord(tlsConn)
}, func() error {
return utlsHandlePostHandshakeMessage(tlsConn)
}
}
return true, func() error {
return utlsReadRecord(tlsConn.Conn)
}, func() error {
return utlsHandlePostHandshakeMessage(tlsConn.Conn)
}
return
})
}

View File

@@ -121,11 +121,16 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial
listener.Control = control.Append(listener.Control, bindFunc)
}
}
if options.RoutingMark == 0 && defaultOptions.RoutingMark != 0 {
dialer.Control = control.Append(dialer.Control, setMarkWrapper(networkManager, defaultOptions.RoutingMark, true))
listener.Control = control.Append(listener.Control, setMarkWrapper(networkManager, defaultOptions.RoutingMark, true))
}
}
if options.RoutingMark == 0 && defaultOptions.RoutingMark != 0 {
dialer.Control = control.Append(dialer.Control, setMarkWrapper(networkManager, defaultOptions.RoutingMark, true))
listener.Control = control.Append(listener.Control, setMarkWrapper(networkManager, defaultOptions.RoutingMark, true))
}
}
if networkManager != nil {
markFunc := networkManager.AutoRedirectOutputMarkFunc()
dialer.Control = control.Append(dialer.Control, markFunc)
listener.Control = control.Append(listener.Control, markFunc)
}
if options.ReuseAddr {
listener.Control = control.Append(listener.Control, control.ReuseAddr())

View File

@@ -206,3 +206,11 @@ func (c *realityConnWrapper) Upstream() any {
func (c *realityConnWrapper) CloseWrite() error {
return c.Close()
}
func (c *realityConnWrapper) ReaderReplaceable() bool {
return true
}
func (c *realityConnWrapper) WriterReplaceable() bool {
return true
}

View File

@@ -106,6 +106,14 @@ func (c *utlsConnWrapper) Upstream() any {
return c.UConn
}
func (c *utlsConnWrapper) ReaderReplaceable() bool {
return true
}
func (c *utlsConnWrapper) WriterReplaceable() bool {
return true
}
type utlsALPNWrapper struct {
utlsConnWrapper
nextProtocols []string

View File

@@ -109,6 +109,9 @@ func (c *Conn) Write(b []byte) (n int, err error) {
if err != nil {
return
}
if i != len(splitIndexes) {
time.Sleep(c.fallbackDelay)
}
}
}
}

View File

@@ -9,6 +9,10 @@ import (
)
func writeAndWaitAck(ctx context.Context, conn *net.TCPConn, payload []byte, fallbackDelay time.Duration) error {
_, err := conn.Write(payload)
if err != nil {
return err
}
time.Sleep(fallbackDelay)
return nil
}

View File

@@ -16,6 +16,9 @@ func writeAndWaitAck(ctx context.Context, conn *net.TCPConn, payload []byte, fal
err := winiphlpapi.WriteAndWaitAck(ctx, conn, payload)
if err != nil {
if errors.Is(err, windows.ERROR_ACCESS_DENIED) {
if _, err := conn.Write(payload); err != nil {
return err
}
time.Sleep(fallbackDelay)
return nil
}

View File

@@ -293,12 +293,7 @@ func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg, options adapte
} else if errors.Is(err, ErrResponseRejected) {
rejected = true
r.logger.DebugContext(ctx, E.Cause(err, "response rejected for ", FormatQuestion(message.Question[0].String())))
/*} else if responseCheck!= nil && errors.Is(err, RcodeError(mDNS.RcodeNameError)) {
rejected = true
r.logger.DebugContext(ctx, E.Cause(err, "response rejected for ", FormatQuestion(message.Question[0].String())))
*/
} else if len(message.Question) > 0 {
rejected = true
r.logger.ErrorContext(ctx, E.Cause(err, "exchange failed for ", FormatQuestion(message.Question[0].String())))
} else {
r.logger.ErrorContext(ctx, E.Cause(err, "exchange failed for <empty query>"))

View File

@@ -2,6 +2,10 @@
icon: material/alert-decagram
---
#### 1.12.2
* Fixes and improvements
#### 1.12.1
* Fixes and improvements

4
go.mod
View File

@@ -15,7 +15,7 @@ require (
github.com/libdns/alidns v1.0.5-libdns.v1.beta1
github.com/libdns/cloudflare v0.2.2-0.20250708034226-c574dccb31a6
github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4
github.com/metacubex/utls v1.8.0
github.com/mholt/acmez/v3 v3.1.2
github.com/miekg/dns v1.1.67
@@ -34,7 +34,7 @@ require (
github.com/sagernet/sing-shadowsocks2 v0.2.1
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11
github.com/sagernet/sing-tun v0.7.0-beta.1
github.com/sagernet/sing-vmess v0.2.6
github.com/sagernet/sing-vmess v0.2.7
github.com/sagernet/smux v1.5.34-mod.2
github.com/sagernet/tailscale v1.80.3-mod.5
github.com/sagernet/wireguard-go v0.0.1-beta.7

8
go.sum
View File

@@ -122,8 +122,8 @@ github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ
github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE=
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 h1:zGeQt3UyNydIVrMRB97AA5WsYEau/TyCnRtTf1yUmJY=
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 h1:j1VRTiC9JLR4nUbSikx9OGdu/3AgFDqgcLj4GoqyQkc=
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/utls v1.8.0 h1:mSYi6FMnmc5riARl5UZDmWVy710z+P5b7xuGW0lV9ac=
github.com/metacubex/utls v1.8.0/go.mod h1:FdjYzVfCtgtna19hX0ER1Xsa5uJInwdQ4IcaaI98lEQ=
github.com/mholt/acmez/v3 v3.1.2 h1:auob8J/0FhmdClQicvJvuDavgd5ezwLBfKuYmynhYzc=
@@ -181,8 +181,8 @@ github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
github.com/sagernet/sing-tun v0.7.0-beta.1 h1:mBIFXYAnGO5ey/HcCYanqnBx61E7yF8zTFGRZonGYmY=
github.com/sagernet/sing-tun v0.7.0-beta.1/go.mod h1:AHJuRrLbNRJuivuFZ2VhXwDj4ViYp14szG5EkkKAqRQ=
github.com/sagernet/sing-vmess v0.2.6 h1:1c4dGzeGy0kpBXXrT1sgiMZtHhdJylIT8eWrGhJYZec=
github.com/sagernet/sing-vmess v0.2.6/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs=
github.com/sagernet/sing-vmess v0.2.7 h1:2ee+9kO0xW5P4mfe6TYVWf9VtY8k1JhNysBqsiYj0sk=
github.com/sagernet/sing-vmess v0.2.7/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs=
github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4=
github.com/sagernet/smux v1.5.34-mod.2/go.mod h1:0KW0+R+ycvA2INW4gbsd7BNyg+HEfLIAxa5N02/28Zc=
github.com/sagernet/tailscale v1.80.3-mod.5 h1:7V7z+p2C//TGtff20pPnDCt3qP6uFyY62peJoKF9z/A=

View File

@@ -312,7 +312,7 @@ func (r *NetworkManager) AutoDetectInterfaceFunc() control.Func {
if r.interfaceMonitor == nil {
return nil
}
bindFunc := control.BindToInterfaceFunc(r.interfaceFinder, func(network string, address string) (interfaceName string, interfaceIndex int, err error) {
return control.BindToInterfaceFunc(r.interfaceFinder, func(network string, address string) (interfaceName string, interfaceIndex int, err error) {
remoteAddr := M.ParseSocksaddr(address).Addr
if remoteAddr.IsValid() {
iif, err := r.interfaceFinder.ByAddr(remoteAddr)
@@ -326,16 +326,6 @@ func (r *NetworkManager) AutoDetectInterfaceFunc() control.Func {
}
return defaultInterface.Name, defaultInterface.Index, nil
})
return func(network, address string, conn syscall.RawConn) error {
err := bindFunc(network, address, conn)
if err != nil {
return err
}
if r.autoRedirectOutputMark > 0 {
return control.RoutingMark(r.autoRedirectOutputMark)(network, address, conn)
}
return nil
}
}
}
@@ -366,6 +356,15 @@ func (r *NetworkManager) AutoRedirectOutputMark() uint32 {
return r.autoRedirectOutputMark
}
func (r *NetworkManager) AutoRedirectOutputMarkFunc() control.Func {
return func(network, address string, conn syscall.RawConn) error {
if r.autoRedirectOutputMark == 0 {
return nil
}
return control.RoutingMark(r.autoRedirectOutputMark)(network, address, conn)
}
}
func (r *NetworkManager) NetworkMonitor() tun.NetworkUpdateMonitor {
return r.networkMonitor
}

View File

@@ -182,9 +182,9 @@ func (t *resolve1Manager) logRequest(sender dbus.Sender, message ...any) context
} else if metadata.ProcessInfo.UserId != 0 {
prefix = F.ToString("uid:", metadata.ProcessInfo.UserId)
}
t.logger.InfoContext(ctx, "(", prefix, ") ", F.ToString(message...))
t.logger.InfoContext(ctx, "(", prefix, ") ", strings.Join(F.MapToString(message), " "))
} else {
t.logger.InfoContext(ctx, F.ToString(message...))
t.logger.InfoContext(ctx, strings.Join(F.MapToString(message), " "))
}
return adapter.WithContext(ctx, &metadata)
}
@@ -280,7 +280,10 @@ func (t *resolve1Manager) ResolveAddress(sender dbus.Sender, ifIndex int32, fami
},
}
ctx := t.logRequest(sender, "ResolveAddress ", link.iif.Name, familyToString(family), addr, flags)
response, lookupErr := t.dnsRouter.Exchange(ctx, request, adapter.DNSQueryOptions{})
var metadata adapter.InboundContext
metadata.InboundType = t.Type()
metadata.Inbound = t.Tag()
response, lookupErr := t.dnsRouter.Exchange(adapter.WithContext(ctx, &metadata), request, adapter.DNSQueryOptions{})
if lookupErr != nil {
err = wrapError(err)
return
@@ -301,7 +304,7 @@ func (t *resolve1Manager) ResolveAddress(sender dbus.Sender, ifIndex int32, fami
return
}
func (t *resolve1Manager) ResolveRecord(sender dbus.Sender, ifIndex int32, family int32, hostname string, qClass uint16, qType uint16, flags uint64) (records []ResourceRecord, outflags uint64, err *dbus.Error) {
func (t *resolve1Manager) ResolveRecord(sender dbus.Sender, ifIndex int32, hostname string, qClass uint16, qType uint16, flags uint64) (records []ResourceRecord, outflags uint64, err *dbus.Error) {
t.linkAccess.Lock()
link, err := t.getLink(ifIndex)
if err != nil {
@@ -320,8 +323,11 @@ func (t *resolve1Manager) ResolveRecord(sender dbus.Sender, ifIndex int32, famil
},
},
}
ctx := t.logRequest(sender, "ResolveRecord ", link.iif.Name, familyToString(family), hostname, mDNS.Class(qClass), mDNS.Type(qType), flags)
response, exchangeErr := t.dnsRouter.Exchange(ctx, request, adapter.DNSQueryOptions{})
ctx := t.logRequest(sender, "ResolveRecord", link.iif.Name, hostname, mDNS.Class(qClass), mDNS.Type(qType), flags)
var metadata adapter.InboundContext
metadata.InboundType = t.Type()
metadata.Inbound = t.Tag()
response, exchangeErr := t.dnsRouter.Exchange(adapter.WithContext(ctx, &metadata), request, adapter.DNSQueryOptions{})
if exchangeErr != nil {
err = wrapError(exchangeErr)
return
@@ -341,6 +347,7 @@ func (t *resolve1Manager) ResolveRecord(sender dbus.Sender, ifIndex int32, famil
err = wrapError(unpackErr)
}
record.Data = data
records = append(records, record)
}
return
}
@@ -380,8 +387,10 @@ func (t *resolve1Manager) ResolveService(sender dbus.Sender, ifIndex int32, host
},
},
}
srvResponse, exchangeErr := t.dnsRouter.Exchange(ctx, srvRequest, adapter.DNSQueryOptions{})
var metadata adapter.InboundContext
metadata.InboundType = t.Type()
metadata.Inbound = t.Tag()
srvResponse, exchangeErr := t.dnsRouter.Exchange(adapter.WithContext(ctx, &metadata), srvRequest, adapter.DNSQueryOptions{})
if exchangeErr != nil {
err = wrapError(exchangeErr)
return

View File

@@ -91,11 +91,6 @@ func (i *Service) Start(stage adapter.StartStage) error {
return E.New("multiple resolved service are not supported")
}
}
case adapter.StartStateStart:
err := i.listener.Start()
if err != nil {
return err
}
systemBus, err := dbus.SystemBus()
if err != nil {
return err
@@ -117,6 +112,11 @@ func (i *Service) Start(stage adapter.StartStage) error {
return E.New("unknown request name reply: ", reply)
}
i.networkUpdateCallback = i.network.NetworkMonitor().RegisterCallback(i.onNetworkUpdate)
case adapter.StartStateStart:
err := i.listener.Start()
if err != nil {
return err
}
}
return nil
}
@@ -167,6 +167,8 @@ func (i *Service) exchangePacket0(ctx context.Context, buffer *buf.Buffer, oob [
}
var metadata adapter.InboundContext
metadata.Source = source
metadata.InboundType = i.Type()
metadata.Inbound = i.Tag()
response, err := i.dnsRouter.Exchange(adapter.WithContext(ctx, &metadata), &message, adapter.DNSQueryOptions{})
if err != nil {
return err