Skip to content

Commit 6d48666

Browse files
committed
Fix resolve using resolved
1 parent c54eb33 commit 6d48666

File tree

1 file changed

+92
-16
lines changed

1 file changed

+92
-16
lines changed

dns/transport/local/local_resolved_linux.go

Lines changed: 92 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,38 @@ package local
22

33
import (
44
"context"
5+
"errors"
56
"os"
67
"sync"
78

89
"github.com/sagernet/sing-box/adapter"
10+
C "github.com/sagernet/sing-box/constant"
911
"github.com/sagernet/sing-box/service/resolved"
1012
"github.com/sagernet/sing-tun"
1113
"github.com/sagernet/sing/common/atomic"
14+
"github.com/sagernet/sing/common/control"
1215
E "github.com/sagernet/sing/common/exceptions"
1316
"github.com/sagernet/sing/common/logger"
17+
"github.com/sagernet/sing/common/x/list"
1418
"github.com/sagernet/sing/service"
1519

1620
"github.com/godbus/dbus/v5"
1721
mDNS "github.com/miekg/dns"
1822
)
1923

2024
type DBusResolvedResolver struct {
21-
logger logger.ContextLogger
22-
interfaceMonitor tun.DefaultInterfaceMonitor
23-
systemBus *dbus.Conn
24-
resoledObject atomic.TypedValue[dbus.BusObject]
25-
closeOnce sync.Once
25+
ctx context.Context
26+
logger logger.ContextLogger
27+
interfaceMonitor tun.DefaultInterfaceMonitor
28+
interfaceCallback *list.Element[tun.DefaultInterfaceUpdateCallback]
29+
systemBus *dbus.Conn
30+
resoledObject atomic.Pointer[ResolvedObject]
31+
closeOnce sync.Once
32+
}
33+
34+
type ResolvedObject struct {
35+
dbus.BusObject
36+
InterfaceIndex int32
2637
}
2738

2839
func NewResolvedResolver(ctx context.Context, logger logger.ContextLogger) (ResolvedResolver, error) {
@@ -35,6 +46,7 @@ func NewResolvedResolver(ctx context.Context, logger logger.ContextLogger) (Reso
3546
return nil, err
3647
}
3748
return &DBusResolvedResolver{
49+
ctx: ctx,
3850
logger: logger,
3951
interfaceMonitor: interfaceMonitor,
4052
systemBus: systemBus,
@@ -43,6 +55,7 @@ func NewResolvedResolver(ctx context.Context, logger logger.ContextLogger) (Reso
4355

4456
func (t *DBusResolvedResolver) Start() error {
4557
t.updateStatus()
58+
t.interfaceCallback = t.interfaceMonitor.RegisterCallback(t.updateDefaultInterface)
4659
err := t.systemBus.BusObject().AddMatchSignal(
4760
"org.freedesktop.DBus",
4861
"NameOwnerChanged",
@@ -70,22 +83,23 @@ func (t *DBusResolvedResolver) Object() any {
7083
}
7184

7285
func (t *DBusResolvedResolver) Exchange(object any, ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
73-
defaultInterface := t.interfaceMonitor.DefaultInterface()
74-
if defaultInterface == nil {
75-
return nil, E.New("missing default interface")
76-
}
7786
question := message.Question[0]
78-
call := object.(*dbus.Object).CallWithContext(
87+
resolvedObject := object.(*ResolvedObject)
88+
call := resolvedObject.CallWithContext(
7989
ctx,
8090
"org.freedesktop.resolve1.Manager.ResolveRecord",
8191
0,
82-
int32(defaultInterface.Index),
92+
resolvedObject.InterfaceIndex,
8393
question.Name,
8494
question.Qclass,
8595
question.Qtype,
8696
uint64(0),
8797
)
8898
if call.Err != nil {
99+
var dbusError dbus.Error
100+
if errors.As(call.Err, &dbusError) && dbusError.Name == "org.freedesktop.resolve1.NoNameServers" {
101+
t.updateStatus()
102+
}
89103
return nil, E.Cause(call.Err, " resolve record via resolved")
90104
}
91105
var (
@@ -137,14 +151,76 @@ func (t *DBusResolvedResolver) loopUpdateStatus() {
137151
}
138152

139153
func (t *DBusResolvedResolver) updateStatus() {
140-
dbusObject := t.systemBus.Object("org.freedesktop.resolve1", "/org/freedesktop/resolve1")
141-
err := dbusObject.Call("org.freedesktop.DBus.Peer.Ping", 0).Err
154+
dbusObject, err := t.checkResolved(context.Background())
155+
oldValue := t.resoledObject.Swap(dbusObject)
142156
if err != nil {
143-
if t.resoledObject.Swap(nil) != nil {
157+
var dbusErr dbus.Error
158+
if !errors.As(err, &dbusErr) || dbusErr.Name != "org.freedesktop.DBus.Error.NameHasNoOwnerCould" {
159+
t.logger.Debug(E.Cause(err, "systemd-resolved service unavailable"))
160+
}
161+
if oldValue != nil {
144162
t.logger.Debug("systemd-resolved service is gone")
145163
}
146164
return
165+
} else if oldValue == nil {
166+
t.logger.Debug("using systemd-resolved service as resolver")
167+
}
168+
}
169+
170+
func (t *DBusResolvedResolver) checkResolved(ctx context.Context) (*ResolvedObject, error) {
171+
dbusObject := t.systemBus.Object("org.freedesktop.resolve1", "/org/freedesktop/resolve1")
172+
err := dbusObject.Call("org.freedesktop.DBus.Peer.Ping", 0).Err
173+
if err != nil {
174+
return nil, err
175+
}
176+
defaultInterface := t.interfaceMonitor.DefaultInterface()
177+
if defaultInterface == nil {
178+
return nil, E.New("missing default interface")
147179
}
148-
t.resoledObject.Store(dbusObject)
149-
t.logger.Debug("using systemd-resolved service as resolver")
180+
call := dbusObject.(*dbus.Object).CallWithContext(
181+
ctx,
182+
"org.freedesktop.resolve1.Manager.GetLink",
183+
0,
184+
int32(defaultInterface.Index),
185+
)
186+
if call.Err != nil {
187+
return nil, err
188+
}
189+
var linkPath dbus.ObjectPath
190+
err = call.Store(&linkPath)
191+
if err != nil {
192+
return nil, err
193+
}
194+
linkObject := t.systemBus.Object("org.freedesktop.resolve1", linkPath)
195+
if linkObject == nil {
196+
return nil, E.New("missing link object for default interface")
197+
}
198+
dnsProp, err := linkObject.GetProperty("org.freedesktop.resolve1.Link.DNS")
199+
if err != nil {
200+
return nil, err
201+
}
202+
var linkDNS []resolved.LinkDNS
203+
err = dnsProp.Store(&linkDNS)
204+
if err != nil {
205+
return nil, err
206+
}
207+
if len(linkDNS) == 0 {
208+
for _, inbound := range service.FromContext[adapter.InboundManager](t.ctx).Inbounds() {
209+
if inbound.Type() == C.TypeTun {
210+
return nil, E.New("No appropriate name servers or networks for name found")
211+
}
212+
}
213+
return &ResolvedObject{
214+
BusObject: dbusObject,
215+
}, nil
216+
} else {
217+
return &ResolvedObject{
218+
BusObject: dbusObject,
219+
InterfaceIndex: int32(defaultInterface.Index),
220+
}, nil
221+
}
222+
}
223+
224+
func (t *DBusResolvedResolver) updateDefaultInterface(defaultInterface *control.Interface, flags int) {
225+
t.updateStatus()
150226
}

0 commit comments

Comments
 (0)