local_resolved_linux.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. package local
  2. import (
  3. "context"
  4. "errors"
  5. "os"
  6. "sync"
  7. "sync/atomic"
  8. "github.com/sagernet/sing-box/adapter"
  9. C "github.com/sagernet/sing-box/constant"
  10. "github.com/sagernet/sing-box/service/resolved"
  11. "github.com/sagernet/sing-tun"
  12. "github.com/sagernet/sing/common"
  13. "github.com/sagernet/sing/common/control"
  14. E "github.com/sagernet/sing/common/exceptions"
  15. "github.com/sagernet/sing/common/logger"
  16. "github.com/sagernet/sing/common/x/list"
  17. "github.com/sagernet/sing/service"
  18. "github.com/godbus/dbus/v5"
  19. mDNS "github.com/miekg/dns"
  20. )
  21. type DBusResolvedResolver struct {
  22. ctx context.Context
  23. logger logger.ContextLogger
  24. interfaceMonitor tun.DefaultInterfaceMonitor
  25. interfaceCallback *list.Element[tun.DefaultInterfaceUpdateCallback]
  26. systemBus *dbus.Conn
  27. resoledObject atomic.Pointer[ResolvedObject]
  28. closeOnce sync.Once
  29. }
  30. type ResolvedObject struct {
  31. dbus.BusObject
  32. InterfaceIndex int32
  33. }
  34. func NewResolvedResolver(ctx context.Context, logger logger.ContextLogger) (ResolvedResolver, error) {
  35. interfaceMonitor := service.FromContext[adapter.NetworkManager](ctx).InterfaceMonitor()
  36. if interfaceMonitor == nil {
  37. return nil, os.ErrInvalid
  38. }
  39. systemBus, err := dbus.SystemBus()
  40. if err != nil {
  41. return nil, err
  42. }
  43. return &DBusResolvedResolver{
  44. ctx: ctx,
  45. logger: logger,
  46. interfaceMonitor: interfaceMonitor,
  47. systemBus: systemBus,
  48. }, nil
  49. }
  50. func (t *DBusResolvedResolver) Start() error {
  51. t.updateStatus()
  52. t.interfaceCallback = t.interfaceMonitor.RegisterCallback(t.updateDefaultInterface)
  53. err := t.systemBus.BusObject().AddMatchSignal(
  54. "org.freedesktop.DBus",
  55. "NameOwnerChanged",
  56. dbus.WithMatchSender("org.freedesktop.DBus"),
  57. dbus.WithMatchArg(0, "org.freedesktop.resolve1.Manager"),
  58. ).Err
  59. if err != nil {
  60. return E.Cause(err, "configure resolved restart listener")
  61. }
  62. go t.loopUpdateStatus()
  63. return nil
  64. }
  65. func (t *DBusResolvedResolver) Close() error {
  66. t.closeOnce.Do(func() {
  67. if t.interfaceCallback != nil {
  68. t.interfaceMonitor.UnregisterCallback(t.interfaceCallback)
  69. }
  70. if t.systemBus != nil {
  71. _ = t.systemBus.Close()
  72. }
  73. })
  74. return nil
  75. }
  76. func (t *DBusResolvedResolver) Object() any {
  77. return common.PtrOrNil(t.resoledObject.Load())
  78. }
  79. func (t *DBusResolvedResolver) Exchange(object any, ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
  80. question := message.Question[0]
  81. resolvedObject := object.(*ResolvedObject)
  82. call := resolvedObject.CallWithContext(
  83. ctx,
  84. "org.freedesktop.resolve1.Manager.ResolveRecord",
  85. 0,
  86. resolvedObject.InterfaceIndex,
  87. question.Name,
  88. question.Qclass,
  89. question.Qtype,
  90. uint64(0),
  91. )
  92. if call.Err != nil {
  93. var dbusError dbus.Error
  94. if errors.As(call.Err, &dbusError) && dbusError.Name == "org.freedesktop.resolve1.NoNameServers" {
  95. t.updateStatus()
  96. }
  97. return nil, E.Cause(call.Err, " resolve record via resolved")
  98. }
  99. var (
  100. records []resolved.ResourceRecord
  101. outflags uint64
  102. )
  103. err := call.Store(&records, &outflags)
  104. if err != nil {
  105. return nil, err
  106. }
  107. response := &mDNS.Msg{
  108. MsgHdr: mDNS.MsgHdr{
  109. Id: message.Id,
  110. Response: true,
  111. Authoritative: true,
  112. RecursionDesired: true,
  113. RecursionAvailable: true,
  114. Rcode: mDNS.RcodeSuccess,
  115. },
  116. Question: []mDNS.Question{question},
  117. }
  118. for _, record := range records {
  119. var rr mDNS.RR
  120. rr, _, err = mDNS.UnpackRR(record.Data, 0)
  121. if err != nil {
  122. return nil, E.Cause(err, "unpack resource record")
  123. }
  124. response.Answer = append(response.Answer, rr)
  125. }
  126. return response, nil
  127. }
  128. func (t *DBusResolvedResolver) loopUpdateStatus() {
  129. signalChan := make(chan *dbus.Signal, 1)
  130. t.systemBus.Signal(signalChan)
  131. for signal := range signalChan {
  132. var restarted bool
  133. if signal.Name == "org.freedesktop.DBus.NameOwnerChanged" {
  134. if len(signal.Body) != 3 || signal.Body[2].(string) == "" {
  135. continue
  136. } else {
  137. restarted = true
  138. }
  139. }
  140. if restarted {
  141. t.updateStatus()
  142. }
  143. }
  144. }
  145. func (t *DBusResolvedResolver) updateStatus() {
  146. dbusObject, err := t.checkResolved(context.Background())
  147. oldValue := t.resoledObject.Swap(dbusObject)
  148. if err != nil {
  149. var dbusErr dbus.Error
  150. if !errors.As(err, &dbusErr) || dbusErr.Name != "org.freedesktop.DBus.Error.NameHasNoOwnerCould" {
  151. t.logger.Debug(E.Cause(err, "systemd-resolved service unavailable"))
  152. }
  153. if oldValue != nil {
  154. t.logger.Debug("systemd-resolved service is gone")
  155. }
  156. return
  157. } else if oldValue == nil {
  158. t.logger.Debug("using systemd-resolved service as resolver")
  159. }
  160. }
  161. func (t *DBusResolvedResolver) checkResolved(ctx context.Context) (*ResolvedObject, error) {
  162. dbusObject := t.systemBus.Object("org.freedesktop.resolve1", "/org/freedesktop/resolve1")
  163. err := dbusObject.Call("org.freedesktop.DBus.Peer.Ping", 0).Err
  164. if err != nil {
  165. return nil, err
  166. }
  167. defaultInterface := t.interfaceMonitor.DefaultInterface()
  168. if defaultInterface == nil {
  169. return nil, E.New("missing default interface")
  170. }
  171. call := dbusObject.(*dbus.Object).CallWithContext(
  172. ctx,
  173. "org.freedesktop.resolve1.Manager.GetLink",
  174. 0,
  175. int32(defaultInterface.Index),
  176. )
  177. if call.Err != nil {
  178. return nil, err
  179. }
  180. var linkPath dbus.ObjectPath
  181. err = call.Store(&linkPath)
  182. if err != nil {
  183. return nil, err
  184. }
  185. linkObject := t.systemBus.Object("org.freedesktop.resolve1", linkPath)
  186. if linkObject == nil {
  187. return nil, E.New("missing link object for default interface")
  188. }
  189. dnsProp, err := linkObject.GetProperty("org.freedesktop.resolve1.Link.DNS")
  190. if err != nil {
  191. return nil, err
  192. }
  193. var linkDNS []resolved.LinkDNS
  194. err = dnsProp.Store(&linkDNS)
  195. if err != nil {
  196. return nil, err
  197. }
  198. if len(linkDNS) == 0 {
  199. for _, inbound := range service.FromContext[adapter.InboundManager](t.ctx).Inbounds() {
  200. if inbound.Type() == C.TypeTun {
  201. return nil, E.New("No appropriate name servers or networks for name found")
  202. }
  203. }
  204. return &ResolvedObject{
  205. BusObject: dbusObject,
  206. }, nil
  207. } else {
  208. return &ResolvedObject{
  209. BusObject: dbusObject,
  210. InterfaceIndex: int32(defaultInterface.Index),
  211. }, nil
  212. }
  213. }
  214. func (t *DBusResolvedResolver) updateDefaultInterface(defaultInterface *control.Interface, flags int) {
  215. t.updateStatus()
  216. }