mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-08-22 10:07:36 +08:00
Fix resolve using resolved
This commit is contained in:
parent
c54eb3381f
commit
1d72a6b30e
@ -2,15 +2,19 @@ package local
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/service/resolved"
|
"github.com/sagernet/sing-box/service/resolved"
|
||||||
"github.com/sagernet/sing-tun"
|
"github.com/sagernet/sing-tun"
|
||||||
"github.com/sagernet/sing/common/atomic"
|
"github.com/sagernet/sing/common/atomic"
|
||||||
|
"github.com/sagernet/sing/common/control"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/logger"
|
"github.com/sagernet/sing/common/logger"
|
||||||
|
"github.com/sagernet/sing/common/x/list"
|
||||||
"github.com/sagernet/sing/service"
|
"github.com/sagernet/sing/service"
|
||||||
|
|
||||||
"github.com/godbus/dbus/v5"
|
"github.com/godbus/dbus/v5"
|
||||||
@ -18,11 +22,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type DBusResolvedResolver struct {
|
type DBusResolvedResolver struct {
|
||||||
logger logger.ContextLogger
|
ctx context.Context
|
||||||
interfaceMonitor tun.DefaultInterfaceMonitor
|
logger logger.ContextLogger
|
||||||
systemBus *dbus.Conn
|
interfaceMonitor tun.DefaultInterfaceMonitor
|
||||||
resoledObject atomic.TypedValue[dbus.BusObject]
|
interfaceCallback *list.Element[tun.DefaultInterfaceUpdateCallback]
|
||||||
closeOnce sync.Once
|
systemBus *dbus.Conn
|
||||||
|
resoledObject atomic.Pointer[ResolvedObject]
|
||||||
|
closeOnce sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResolvedObject struct {
|
||||||
|
dbus.BusObject
|
||||||
|
InterfaceIndex int32
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewResolvedResolver(ctx context.Context, logger logger.ContextLogger) (ResolvedResolver, error) {
|
func NewResolvedResolver(ctx context.Context, logger logger.ContextLogger) (ResolvedResolver, error) {
|
||||||
@ -35,6 +46,7 @@ func NewResolvedResolver(ctx context.Context, logger logger.ContextLogger) (Reso
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &DBusResolvedResolver{
|
return &DBusResolvedResolver{
|
||||||
|
ctx: ctx,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
interfaceMonitor: interfaceMonitor,
|
interfaceMonitor: interfaceMonitor,
|
||||||
systemBus: systemBus,
|
systemBus: systemBus,
|
||||||
@ -43,6 +55,7 @@ func NewResolvedResolver(ctx context.Context, logger logger.ContextLogger) (Reso
|
|||||||
|
|
||||||
func (t *DBusResolvedResolver) Start() error {
|
func (t *DBusResolvedResolver) Start() error {
|
||||||
t.updateStatus()
|
t.updateStatus()
|
||||||
|
t.interfaceCallback = t.interfaceMonitor.RegisterCallback(t.updateDefaultInterface)
|
||||||
err := t.systemBus.BusObject().AddMatchSignal(
|
err := t.systemBus.BusObject().AddMatchSignal(
|
||||||
"org.freedesktop.DBus",
|
"org.freedesktop.DBus",
|
||||||
"NameOwnerChanged",
|
"NameOwnerChanged",
|
||||||
@ -58,6 +71,9 @@ func (t *DBusResolvedResolver) Start() error {
|
|||||||
|
|
||||||
func (t *DBusResolvedResolver) Close() error {
|
func (t *DBusResolvedResolver) Close() error {
|
||||||
t.closeOnce.Do(func() {
|
t.closeOnce.Do(func() {
|
||||||
|
if t.interfaceCallback != nil {
|
||||||
|
t.interfaceMonitor.UnregisterCallback(t.interfaceCallback)
|
||||||
|
}
|
||||||
if t.systemBus != nil {
|
if t.systemBus != nil {
|
||||||
_ = t.systemBus.Close()
|
_ = t.systemBus.Close()
|
||||||
}
|
}
|
||||||
@ -70,22 +86,23 @@ func (t *DBusResolvedResolver) Object() any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *DBusResolvedResolver) Exchange(object any, ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
func (t *DBusResolvedResolver) Exchange(object any, ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||||
defaultInterface := t.interfaceMonitor.DefaultInterface()
|
|
||||||
if defaultInterface == nil {
|
|
||||||
return nil, E.New("missing default interface")
|
|
||||||
}
|
|
||||||
question := message.Question[0]
|
question := message.Question[0]
|
||||||
call := object.(*dbus.Object).CallWithContext(
|
resolvedObject := object.(*ResolvedObject)
|
||||||
|
call := resolvedObject.CallWithContext(
|
||||||
ctx,
|
ctx,
|
||||||
"org.freedesktop.resolve1.Manager.ResolveRecord",
|
"org.freedesktop.resolve1.Manager.ResolveRecord",
|
||||||
0,
|
0,
|
||||||
int32(defaultInterface.Index),
|
resolvedObject.InterfaceIndex,
|
||||||
question.Name,
|
question.Name,
|
||||||
question.Qclass,
|
question.Qclass,
|
||||||
question.Qtype,
|
question.Qtype,
|
||||||
uint64(0),
|
uint64(0),
|
||||||
)
|
)
|
||||||
if call.Err != nil {
|
if call.Err != nil {
|
||||||
|
var dbusError dbus.Error
|
||||||
|
if errors.As(call.Err, &dbusError) && dbusError.Name == "org.freedesktop.resolve1.NoNameServers" {
|
||||||
|
t.updateStatus()
|
||||||
|
}
|
||||||
return nil, E.Cause(call.Err, " resolve record via resolved")
|
return nil, E.Cause(call.Err, " resolve record via resolved")
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
@ -137,14 +154,76 @@ func (t *DBusResolvedResolver) loopUpdateStatus() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *DBusResolvedResolver) updateStatus() {
|
func (t *DBusResolvedResolver) updateStatus() {
|
||||||
dbusObject := t.systemBus.Object("org.freedesktop.resolve1", "/org/freedesktop/resolve1")
|
dbusObject, err := t.checkResolved(context.Background())
|
||||||
err := dbusObject.Call("org.freedesktop.DBus.Peer.Ping", 0).Err
|
oldValue := t.resoledObject.Swap(dbusObject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if t.resoledObject.Swap(nil) != nil {
|
var dbusErr dbus.Error
|
||||||
|
if !errors.As(err, &dbusErr) || dbusErr.Name != "org.freedesktop.DBus.Error.NameHasNoOwnerCould" {
|
||||||
|
t.logger.Debug(E.Cause(err, "systemd-resolved service unavailable"))
|
||||||
|
}
|
||||||
|
if oldValue != nil {
|
||||||
t.logger.Debug("systemd-resolved service is gone")
|
t.logger.Debug("systemd-resolved service is gone")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
} else if oldValue == nil {
|
||||||
|
t.logger.Debug("using systemd-resolved service as resolver")
|
||||||
}
|
}
|
||||||
t.resoledObject.Store(dbusObject)
|
}
|
||||||
t.logger.Debug("using systemd-resolved service as resolver")
|
|
||||||
|
func (t *DBusResolvedResolver) checkResolved(ctx context.Context) (*ResolvedObject, error) {
|
||||||
|
dbusObject := t.systemBus.Object("org.freedesktop.resolve1", "/org/freedesktop/resolve1")
|
||||||
|
err := dbusObject.Call("org.freedesktop.DBus.Peer.Ping", 0).Err
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defaultInterface := t.interfaceMonitor.DefaultInterface()
|
||||||
|
if defaultInterface == nil {
|
||||||
|
return nil, E.New("missing default interface")
|
||||||
|
}
|
||||||
|
call := dbusObject.(*dbus.Object).CallWithContext(
|
||||||
|
ctx,
|
||||||
|
"org.freedesktop.resolve1.Manager.GetLink",
|
||||||
|
0,
|
||||||
|
int32(defaultInterface.Index),
|
||||||
|
)
|
||||||
|
if call.Err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var linkPath dbus.ObjectPath
|
||||||
|
err = call.Store(&linkPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
linkObject := t.systemBus.Object("org.freedesktop.resolve1", linkPath)
|
||||||
|
if linkObject == nil {
|
||||||
|
return nil, E.New("missing link object for default interface")
|
||||||
|
}
|
||||||
|
dnsProp, err := linkObject.GetProperty("org.freedesktop.resolve1.Link.DNS")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var linkDNS []resolved.LinkDNS
|
||||||
|
err = dnsProp.Store(&linkDNS)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(linkDNS) == 0 {
|
||||||
|
for _, inbound := range service.FromContext[adapter.InboundManager](t.ctx).Inbounds() {
|
||||||
|
if inbound.Type() == C.TypeTun {
|
||||||
|
return nil, E.New("No appropriate name servers or networks for name found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &ResolvedObject{
|
||||||
|
BusObject: dbusObject,
|
||||||
|
}, nil
|
||||||
|
} else {
|
||||||
|
return &ResolvedObject{
|
||||||
|
BusObject: dbusObject,
|
||||||
|
InterfaceIndex: int32(defaultInterface.Index),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *DBusResolvedResolver) updateDefaultInterface(defaultInterface *control.Interface, flags int) {
|
||||||
|
t.updateStatus()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user