forwarder.go 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package resolver
  4. import (
  5. "bytes"
  6. "context"
  7. "crypto/sha256"
  8. "crypto/tls"
  9. "encoding/base64"
  10. "encoding/binary"
  11. "errors"
  12. "fmt"
  13. "io"
  14. "net"
  15. "net/http"
  16. "net/netip"
  17. "net/url"
  18. "runtime"
  19. "sort"
  20. "strings"
  21. "sync"
  22. "sync/atomic"
  23. "time"
  24. dns "golang.org/x/net/dns/dnsmessage"
  25. "tailscale.com/control/controlknobs"
  26. "tailscale.com/envknob"
  27. "tailscale.com/feature"
  28. "tailscale.com/feature/buildfeatures"
  29. "tailscale.com/health"
  30. "tailscale.com/net/dns/publicdns"
  31. "tailscale.com/net/dnscache"
  32. "tailscale.com/net/neterror"
  33. "tailscale.com/net/netmon"
  34. "tailscale.com/net/netx"
  35. "tailscale.com/net/sockstats"
  36. "tailscale.com/net/tsdial"
  37. "tailscale.com/syncs"
  38. "tailscale.com/types/dnstype"
  39. "tailscale.com/types/logger"
  40. "tailscale.com/types/nettype"
  41. "tailscale.com/util/cloudenv"
  42. "tailscale.com/util/dnsname"
  43. "tailscale.com/util/race"
  44. "tailscale.com/version"
  45. )
  46. // headerBytes is the number of bytes in a DNS message header.
  47. const headerBytes = 12
  48. // dnsFlagTruncated is set in the flags word when the packet is truncated.
  49. const dnsFlagTruncated = 0x200
  50. // truncatedFlagSet returns true if the DNS packet signals that it has
  51. // been truncated. False is also returned if the packet was too small
  52. // to be valid.
  53. func truncatedFlagSet(pkt []byte) bool {
  54. if len(pkt) < headerBytes {
  55. return false
  56. }
  57. return (binary.BigEndian.Uint16(pkt[2:4]) & dnsFlagTruncated) != 0
  58. }
  59. const (
  60. // dohIdleConnTimeout is how long to keep idle HTTP connections
  61. // open to DNS-over-HTTPS servers. 10 seconds is a sensible
  62. // default, as it's long enough to handle a burst of queries
  63. // coming in a row, but short enough to not keep idle connections
  64. // open for too long. In theory, idle connections could be kept
  65. // open for a long time without any battery impact as no traffic
  66. // is supposed to be flowing on them.
  67. // However, in practice, DoH servers will send TCP keepalives (e.g.
  68. // NextDNS sends them every ~10s). Handling these keepalives
  69. // wakes up the modem, and that uses battery. Therefore, we keep
  70. // the idle timeout low enough to allow idle connections to be
  71. // closed during an extended period with no DNS queries, killing
  72. // keepalive network activity.
  73. dohIdleConnTimeout = 10 * time.Second
  74. // dohTransportTimeout is how much of a head start to give a DoH query
  75. // that was upgraded from a well-known public DNS provider's IP before
  76. // normal UDP mode is attempted as a fallback.
  77. dohHeadStart = 500 * time.Millisecond
  78. // wellKnownHostBackupDelay is how long to artificially delay upstream
  79. // DNS queries to the "fallback" DNS server IP for a known provider
  80. // (e.g. how long to wait to query Google's 8.8.4.4 after 8.8.8.8).
  81. wellKnownHostBackupDelay = 200 * time.Millisecond
  82. // udpRaceTimeout is the timeout after which we will start a DNS query
  83. // over TCP while waiting for the UDP query to complete.
  84. udpRaceTimeout = 2 * time.Second
  85. // tcpQueryTimeout is the timeout for a DNS query performed over TCP.
  86. // It matches the default 5sec timeout of the 'dig' utility.
  87. tcpQueryTimeout = 5 * time.Second
  88. )
  89. // txid identifies a DNS transaction.
  90. //
  91. // As the standard DNS Request ID is only 16 bits, we extend it:
  92. // the lower 32 bits are the zero-extended bits of the DNS Request ID;
  93. // the upper 32 bits are the CRC32 checksum of the first question in the request.
  94. // This makes probability of txid collision negligible.
  95. type txid uint64
  96. // getTxID computes the txid of the given DNS packet.
  97. func getTxID(packet []byte) txid {
  98. if len(packet) < headerBytes {
  99. return 0
  100. }
  101. dnsid := binary.BigEndian.Uint16(packet[0:2])
  102. // Previously, we hashed the question and combined it with the original txid
  103. // which was useful when concurrent queries were multiplexed on a single
  104. // local source port. We encountered some situations where the DNS server
  105. // canonicalizes the question in the response (uppercase converted to
  106. // lowercase in this case), which resulted in responses that we couldn't
  107. // match to the original request due to hash mismatches.
  108. return txid(dnsid)
  109. }
  110. func getRCode(packet []byte) dns.RCode {
  111. if len(packet) < headerBytes {
  112. // treat invalid packets as a refusal
  113. return dns.RCode(5)
  114. }
  115. // get bottom 4 bits of 3rd byte
  116. return dns.RCode(packet[3] & 0x0F)
  117. }
  118. // clampEDNSSize attempts to limit the maximum EDNS response size. This is not
  119. // an exhaustive solution, instead only easy cases are currently handled in the
  120. // interest of speed and reduced complexity. Only OPT records at the very end of
  121. // the message with no option codes are addressed.
  122. // TODO: handle more situations if we discover that they happen often
  123. func clampEDNSSize(packet []byte, maxSize uint16) {
  124. // optFixedBytes is the size of an OPT record with no option codes.
  125. const optFixedBytes = 11
  126. const edns0Version = 0
  127. if len(packet) < headerBytes+optFixedBytes {
  128. return
  129. }
  130. arCount := binary.BigEndian.Uint16(packet[10:12])
  131. if arCount == 0 {
  132. // OPT shows up in an AR, so there must be no OPT
  133. return
  134. }
  135. // https://datatracker.ietf.org/doc/html/rfc6891#section-6.1.2
  136. opt := packet[len(packet)-optFixedBytes:]
  137. if opt[0] != 0 {
  138. // OPT NAME must be 0 (root domain)
  139. return
  140. }
  141. if dns.Type(binary.BigEndian.Uint16(opt[1:3])) != dns.TypeOPT {
  142. // Not an OPT record
  143. return
  144. }
  145. requestedSize := binary.BigEndian.Uint16(opt[3:5])
  146. // Ignore extended RCODE in opt[5]
  147. if opt[6] != edns0Version {
  148. // Be conservative and don't touch unknown versions.
  149. return
  150. }
  151. // Ignore flags in opt[6:9]
  152. if binary.BigEndian.Uint16(opt[9:11]) != 0 {
  153. // RDLEN must be 0 (no variable length data). We're at the end of the
  154. // packet so this should be 0 anyway)..
  155. return
  156. }
  157. if requestedSize <= maxSize {
  158. return
  159. }
  160. // Clamp the maximum size
  161. binary.BigEndian.PutUint16(opt[3:5], maxSize)
  162. }
  163. // dnsForwarderFailing should be raised when the forwarder is unable to reach the
  164. // upstream resolvers. This is a high severity warning as it results in "no internet".
  165. // This warning must be cleared when the forwarder is working again.
  166. //
  167. // We allow for 5 second grace period to ensure this is not raised for spurious errors
  168. // under the assumption that DNS queries are relatively frequent and a subsequent
  169. // successful query will clear any one-off errors.
  170. var dnsForwarderFailing = health.Register(&health.Warnable{
  171. Code: "dns-forward-failing",
  172. Title: "DNS unavailable",
  173. Severity: health.SeverityMedium,
  174. DependsOn: []*health.Warnable{health.NetworkStatusWarnable},
  175. Text: health.StaticMessage("Tailscale can't reach the configured DNS servers. Internet connectivity may be affected."),
  176. ImpactsConnectivity: true,
  177. TimeToVisible: 15 * time.Second,
  178. })
  179. type route struct {
  180. Suffix dnsname.FQDN
  181. Resolvers []resolverAndDelay
  182. }
  183. // resolverAndDelay is an upstream DNS resolver and a delay for how
  184. // long to wait before querying it.
  185. type resolverAndDelay struct {
  186. // name is the upstream resolver.
  187. name *dnstype.Resolver
  188. // startDelay is an amount to delay this resolver at
  189. // start. It's used when, say, there are four Google or
  190. // Cloudflare DNS IPs (two IPv4 + two IPv6) and we don't want
  191. // to race all four at once.
  192. startDelay time.Duration
  193. }
  194. // forwarder forwards DNS packets to a number of upstream nameservers.
  195. type forwarder struct {
  196. logf logger.Logf
  197. netMon *netmon.Monitor // always non-nil
  198. linkSel ForwardLinkSelector // TODO(bradfitz): remove this when tsdial.Dialer absorbs it
  199. dialer *tsdial.Dialer
  200. health *health.Tracker // always non-nil
  201. verboseFwd bool // if true, log all DNS forwarding
  202. controlKnobs *controlknobs.Knobs // or nil
  203. ctx context.Context // good until Close
  204. ctxCancel context.CancelFunc // closes ctx
  205. mu syncs.Mutex // guards following
  206. dohClient map[string]*http.Client // urlBase -> client
  207. // routes are per-suffix resolvers to use, with
  208. // the most specific routes first.
  209. routes []route
  210. // cloudHostFallback are last resort resolvers to use if no per-suffix
  211. // resolver matches. These are only populated on cloud hosts where the
  212. // platform provides a well-known recursive resolver.
  213. //
  214. // That is, if we're running on GCP or AWS where there's always a well-known
  215. // IP of a recursive resolver, return that rather than having callers return
  216. // SERVFAIL. This fixes both normal 100.100.100.100 resolution when
  217. // /etc/resolv.conf is missing/corrupt, and the peerapi ExitDNS stub
  218. // resolver lookup.
  219. cloudHostFallback []resolverAndDelay
  220. }
  221. func newForwarder(logf logger.Logf, netMon *netmon.Monitor, linkSel ForwardLinkSelector, dialer *tsdial.Dialer, health *health.Tracker, knobs *controlknobs.Knobs) *forwarder {
  222. if !buildfeatures.HasDNS {
  223. return nil
  224. }
  225. if netMon == nil {
  226. panic("nil netMon")
  227. }
  228. f := &forwarder{
  229. logf: logger.WithPrefix(logf, "forward: "),
  230. netMon: netMon,
  231. linkSel: linkSel,
  232. dialer: dialer,
  233. health: health,
  234. controlKnobs: knobs,
  235. verboseFwd: verboseDNSForward(),
  236. }
  237. f.ctx, f.ctxCancel = context.WithCancel(context.Background())
  238. return f
  239. }
  240. func (f *forwarder) Close() error {
  241. f.ctxCancel()
  242. return nil
  243. }
  244. // resolversWithDelays maps from a set of DNS server names to a slice of a type
  245. // that included a startDelay, upgrading any well-known DoH (DNS-over-HTTP)
  246. // servers in the process, insert a DoH lookup first before UDP fallbacks.
  247. func resolversWithDelays(resolvers []*dnstype.Resolver) []resolverAndDelay {
  248. rr := make([]resolverAndDelay, 0, len(resolvers)+2)
  249. type dohState uint8
  250. const addedDoH = dohState(1)
  251. const addedDoHAndDontAddUDP = dohState(2)
  252. // Add the known DoH ones first, starting immediately.
  253. didDoH := map[string]dohState{}
  254. for _, r := range resolvers {
  255. ipp, ok := r.IPPort()
  256. if !ok {
  257. continue
  258. }
  259. dohBase, dohOnly, ok := publicdns.DoHEndpointFromIP(ipp.Addr())
  260. if !ok || didDoH[dohBase] != 0 {
  261. continue
  262. }
  263. if dohOnly {
  264. didDoH[dohBase] = addedDoHAndDontAddUDP
  265. } else {
  266. didDoH[dohBase] = addedDoH
  267. }
  268. rr = append(rr, resolverAndDelay{name: &dnstype.Resolver{Addr: dohBase}})
  269. }
  270. type hostAndFam struct {
  271. host string // some arbitrary string representing DNS host (currently the DoH base)
  272. bits uint8 // either 32 or 128 for IPv4 vs IPv6s address family
  273. }
  274. done := map[hostAndFam]int{}
  275. for _, r := range resolvers {
  276. ipp, ok := r.IPPort()
  277. if !ok {
  278. // Pass non-IP ones through unchanged, without delay.
  279. // (e.g. DNS-over-ExitDNS when using an exit node)
  280. rr = append(rr, resolverAndDelay{name: r})
  281. continue
  282. }
  283. ip := ipp.Addr()
  284. var startDelay time.Duration
  285. if host, _, ok := publicdns.DoHEndpointFromIP(ip); ok {
  286. if didDoH[host] == addedDoHAndDontAddUDP {
  287. continue
  288. }
  289. // We already did the DoH query early. These
  290. // are for normal dns53 UDP queries.
  291. startDelay = dohHeadStart
  292. key := hostAndFam{host, uint8(ip.BitLen())}
  293. if done[key] > 0 {
  294. startDelay += wellKnownHostBackupDelay
  295. }
  296. done[key]++
  297. }
  298. rr = append(rr, resolverAndDelay{
  299. name: r,
  300. startDelay: startDelay,
  301. })
  302. }
  303. return rr
  304. }
  305. var (
  306. cloudResolversOnce sync.Once
  307. cloudResolversLazy []resolverAndDelay
  308. )
  309. func cloudResolvers() []resolverAndDelay {
  310. cloudResolversOnce.Do(func() {
  311. if ip := cloudenv.Get().ResolverIP(); ip != "" {
  312. cloudResolver := []*dnstype.Resolver{{Addr: ip}}
  313. cloudResolversLazy = resolversWithDelays(cloudResolver)
  314. }
  315. })
  316. return cloudResolversLazy
  317. }
  318. // setRoutes sets the routes to use for DNS forwarding. It's called by
  319. // Resolver.SetConfig on reconfig.
  320. //
  321. // The memory referenced by routesBySuffix should not be modified.
  322. func (f *forwarder) setRoutes(routesBySuffix map[dnsname.FQDN][]*dnstype.Resolver) {
  323. routes := make([]route, 0, len(routesBySuffix))
  324. cloudHostFallback := cloudResolvers()
  325. for suffix, rs := range routesBySuffix {
  326. if suffix == "." && len(rs) == 0 && len(cloudHostFallback) > 0 {
  327. routes = append(routes, route{
  328. Suffix: suffix,
  329. Resolvers: cloudHostFallback,
  330. })
  331. } else {
  332. routes = append(routes, route{
  333. Suffix: suffix,
  334. Resolvers: resolversWithDelays(rs),
  335. })
  336. }
  337. }
  338. if cloudenv.Get().HasInternalTLD() && len(cloudHostFallback) > 0 {
  339. if _, ok := routesBySuffix["internal."]; !ok {
  340. routes = append(routes, route{
  341. Suffix: "internal.",
  342. Resolvers: cloudHostFallback,
  343. })
  344. }
  345. }
  346. // Sort from longest prefix to shortest.
  347. sort.Slice(routes, func(i, j int) bool {
  348. return routes[i].Suffix.NumLabels() > routes[j].Suffix.NumLabels()
  349. })
  350. f.mu.Lock()
  351. defer f.mu.Unlock()
  352. f.routes = routes
  353. f.cloudHostFallback = cloudHostFallback
  354. }
  355. var stdNetPacketListener nettype.PacketListenerWithNetIP = nettype.MakePacketListenerWithNetIP(new(net.ListenConfig))
  356. func (f *forwarder) packetListener(ip netip.Addr) (nettype.PacketListenerWithNetIP, error) {
  357. if f.linkSel == nil || initListenConfig == nil {
  358. return stdNetPacketListener, nil
  359. }
  360. linkName := f.linkSel.PickLink(ip)
  361. if linkName == "" {
  362. return stdNetPacketListener, nil
  363. }
  364. lc := new(net.ListenConfig)
  365. if err := initListenConfig(lc, f.netMon, linkName); err != nil {
  366. return nil, err
  367. }
  368. return nettype.MakePacketListenerWithNetIP(lc), nil
  369. }
  370. // getKnownDoHClientForProvider returns an HTTP client for a specific DoH
  371. // provider named by its DoH base URL (like "https://dns.google/dns-query").
  372. //
  373. // The returned client race/Happy Eyeballs dials all IPs for urlBase (usually
  374. // 4), as statically known by the publicdns package.
  375. func (f *forwarder) getKnownDoHClientForProvider(urlBase string) (c *http.Client, ok bool) {
  376. f.mu.Lock()
  377. defer f.mu.Unlock()
  378. if c, ok := f.dohClient[urlBase]; ok {
  379. return c, true
  380. }
  381. allIPs := publicdns.DoHIPsOfBase(urlBase)
  382. if len(allIPs) == 0 {
  383. return nil, false
  384. }
  385. dohURL, err := url.Parse(urlBase)
  386. if err != nil {
  387. return nil, false
  388. }
  389. dialer := dnscache.Dialer(f.getDialerType(), &dnscache.Resolver{
  390. SingleHost: dohURL.Hostname(),
  391. SingleHostStaticResult: allIPs,
  392. Logf: f.logf,
  393. })
  394. tlsConfig := &tls.Config{
  395. // Enforce TLS 1.3, as all of our supported DNS-over-HTTPS servers are compatible with it
  396. // (see tailscale.com/net/dns/publicdns/publicdns.go).
  397. MinVersion: tls.VersionTLS13,
  398. }
  399. c = &http.Client{
  400. Transport: &http.Transport{
  401. ForceAttemptHTTP2: true,
  402. IdleConnTimeout: dohIdleConnTimeout,
  403. // On mobile platforms TCP KeepAlive is disabled in the dialer,
  404. // ensure that we timeout if the connection appears to be hung.
  405. ResponseHeaderTimeout: 10 * time.Second,
  406. MaxIdleConnsPerHost: 1,
  407. DialContext: func(ctx context.Context, netw, addr string) (net.Conn, error) {
  408. if !strings.HasPrefix(netw, "tcp") {
  409. return nil, fmt.Errorf("unexpected network %q", netw)
  410. }
  411. return dialer(ctx, netw, addr)
  412. },
  413. TLSClientConfig: tlsConfig,
  414. },
  415. }
  416. if f.dohClient == nil {
  417. f.dohClient = map[string]*http.Client{}
  418. }
  419. f.dohClient[urlBase] = c
  420. return c, true
  421. }
  422. const dohType = "application/dns-message"
  423. func (f *forwarder) sendDoH(ctx context.Context, urlBase string, c *http.Client, packet []byte) ([]byte, error) {
  424. ctx = sockstats.WithSockStats(ctx, sockstats.LabelDNSForwarderDoH, f.logf)
  425. metricDNSFwdDoH.Add(1)
  426. req, err := http.NewRequestWithContext(ctx, "POST", urlBase, bytes.NewReader(packet))
  427. if err != nil {
  428. return nil, err
  429. }
  430. req.Header.Set("Content-Type", dohType)
  431. req.Header.Set("Accept", dohType)
  432. req.Header.Set("User-Agent", "tailscaled/"+version.Long())
  433. hres, err := c.Do(req)
  434. if err != nil {
  435. metricDNSFwdDoHErrorTransport.Add(1)
  436. return nil, err
  437. }
  438. defer hres.Body.Close()
  439. if hres.StatusCode != 200 {
  440. metricDNSFwdDoHErrorStatus.Add(1)
  441. if hres.StatusCode/100 == 5 {
  442. // Translate 5xx HTTP server errors into SERVFAIL DNS responses.
  443. return nil, fmt.Errorf("%w: %s", errServerFailure, hres.Status)
  444. }
  445. return nil, errors.New(hres.Status)
  446. }
  447. if ct := hres.Header.Get("Content-Type"); ct != dohType {
  448. metricDNSFwdDoHErrorCT.Add(1)
  449. return nil, fmt.Errorf("unexpected response Content-Type %q", ct)
  450. }
  451. res, err := io.ReadAll(hres.Body)
  452. if err != nil {
  453. metricDNSFwdDoHErrorBody.Add(1)
  454. }
  455. if truncatedFlagSet(res) {
  456. metricDNSFwdTruncated.Add(1)
  457. }
  458. return res, err
  459. }
  460. var (
  461. verboseDNSForward = envknob.RegisterBool("TS_DEBUG_DNS_FORWARD_SEND")
  462. skipTCPRetry = envknob.RegisterBool("TS_DNS_FORWARD_SKIP_TCP_RETRY")
  463. // For correlating log messages in the send() function; only used when
  464. // verboseDNSForward() is true.
  465. forwarderCount atomic.Uint64
  466. )
  467. // send sends packet to dst. It is best effort.
  468. //
  469. // send expects the reply to have the same txid as txidOut.
  470. func (f *forwarder) send(ctx context.Context, fq *forwardQuery, rr resolverAndDelay) (ret []byte, err error) {
  471. if f.verboseFwd {
  472. id := forwarderCount.Add(1)
  473. domain, typ, _ := nameFromQuery(fq.packet)
  474. f.logf("forwarder.send(%q, %d, %v, %d) from %v [%d] ...", rr.name.Addr, fq.txid, typ, len(domain), fq.src, id)
  475. defer func() {
  476. f.logf("forwarder.send(%q, %d, %v, %d) from %v [%d] = %v, %v", rr.name.Addr, fq.txid, typ, len(domain), fq.src, id, len(ret), err)
  477. }()
  478. }
  479. if strings.HasPrefix(rr.name.Addr, "http://") {
  480. if !buildfeatures.HasPeerAPIClient {
  481. return nil, feature.ErrUnavailable
  482. }
  483. return f.sendDoH(ctx, rr.name.Addr, f.dialer.PeerAPIHTTPClient(), fq.packet)
  484. }
  485. if strings.HasPrefix(rr.name.Addr, "https://") {
  486. // Only known DoH providers are supported currently. Specifically, we
  487. // only support DoH providers where we can TCP connect to them on port
  488. // 443 at the same IP address they serve normal UDP DNS from (1.1.1.1,
  489. // 8.8.8.8, 9.9.9.9, etc.) That's why OpenDNS and custom DoH providers
  490. // aren't currently supported. There's no backup DNS resolution path for
  491. // them.
  492. urlBase := rr.name.Addr
  493. if hc, ok := f.getKnownDoHClientForProvider(urlBase); ok {
  494. return f.sendDoH(ctx, urlBase, hc, fq.packet)
  495. }
  496. metricDNSFwdErrorType.Add(1)
  497. return nil, fmt.Errorf("arbitrary https:// resolvers not supported yet")
  498. }
  499. if strings.HasPrefix(rr.name.Addr, "tls://") {
  500. metricDNSFwdErrorType.Add(1)
  501. return nil, fmt.Errorf("tls:// resolvers not supported yet")
  502. }
  503. ctx, cancel := context.WithCancel(ctx)
  504. defer cancel()
  505. isUDPQuery := fq.family == "udp"
  506. skipTCP := skipTCPRetry() || (f.controlKnobs != nil && f.controlKnobs.DisableDNSForwarderTCPRetries.Load())
  507. // Print logs about retries if this was because of a truncated response.
  508. var explicitRetry atomic.Bool // true if truncated UDP response retried
  509. defer func() {
  510. if !explicitRetry.Load() {
  511. return
  512. }
  513. if err == nil {
  514. f.logf("forwarder.send(%q): successfully retried via TCP", rr.name.Addr)
  515. } else {
  516. f.logf("forwarder.send(%q): could not retry via TCP: %v", rr.name.Addr, err)
  517. }
  518. }()
  519. firstUDP := func(ctx context.Context) ([]byte, error) {
  520. resp, err := f.sendUDP(ctx, fq, rr)
  521. if err != nil {
  522. return nil, err
  523. }
  524. if !truncatedFlagSet(resp) {
  525. // Successful, non-truncated response; no retry.
  526. return resp, nil
  527. }
  528. // If this is a UDP query, return it regardless of whether the
  529. // response is truncated or not; the client can retry
  530. // communicating with tailscaled over TCP. There's no point
  531. // falling back to TCP for a truncated query if we can't return
  532. // the results to the client.
  533. if isUDPQuery {
  534. return resp, nil
  535. }
  536. if skipTCP {
  537. // Envknob or control knob disabled the TCP retry behaviour;
  538. // just return what we have.
  539. return resp, nil
  540. }
  541. // This is a TCP query from the client, and the UDP response
  542. // from the upstream DNS server is truncated; map this to an
  543. // error to cause our retry helper to immediately kick off the
  544. // TCP retry.
  545. explicitRetry.Store(true)
  546. return nil, truncatedResponseError{resp}
  547. }
  548. thenTCP := func(ctx context.Context) ([]byte, error) {
  549. // If we're skipping the TCP fallback, then wait until the
  550. // context is canceled and return that error (i.e. not
  551. // returning anything).
  552. if skipTCP {
  553. <-ctx.Done()
  554. return nil, ctx.Err()
  555. }
  556. return f.sendTCP(ctx, fq, rr)
  557. }
  558. // If the input query is TCP, then don't have a timeout between
  559. // starting UDP and TCP.
  560. timeout := udpRaceTimeout
  561. if !isUDPQuery {
  562. timeout = 0
  563. }
  564. // Kick off the race between the UDP and TCP queries.
  565. rh := race.New(timeout, firstUDP, thenTCP)
  566. resp, err := rh.Start(ctx)
  567. if err == nil {
  568. return resp, nil
  569. }
  570. // If we got a truncated UDP response, return that instead of an error.
  571. var trErr truncatedResponseError
  572. if errors.As(err, &trErr) {
  573. return trErr.res, nil
  574. }
  575. return nil, err
  576. }
  577. type truncatedResponseError struct {
  578. res []byte
  579. }
  580. func (tr truncatedResponseError) Error() string { return "response truncated" }
  581. var errServerFailure = errors.New("response code indicates server issue")
  582. var errTxIDMismatch = errors.New("txid doesn't match")
  583. func (f *forwarder) sendUDP(ctx context.Context, fq *forwardQuery, rr resolverAndDelay) (ret []byte, err error) {
  584. ipp, ok := rr.name.IPPort()
  585. if !ok {
  586. metricDNSFwdErrorType.Add(1)
  587. return nil, fmt.Errorf("unrecognized resolver type %q", rr.name.Addr)
  588. }
  589. metricDNSFwdUDP.Add(1)
  590. ctx = sockstats.WithSockStats(ctx, sockstats.LabelDNSForwarderUDP, f.logf)
  591. ln, err := f.packetListener(ipp.Addr())
  592. if err != nil {
  593. return nil, err
  594. }
  595. // Specify the exact UDP family to work around https://github.com/golang/go/issues/52264
  596. udpFam := "udp4"
  597. if ipp.Addr().Is6() {
  598. udpFam = "udp6"
  599. }
  600. conn, err := ln.ListenPacket(ctx, udpFam, ":0")
  601. if err != nil {
  602. f.logf("ListenPacket failed: %v", err)
  603. return nil, err
  604. }
  605. defer conn.Close()
  606. fq.closeOnCtxDone.Add(conn)
  607. defer fq.closeOnCtxDone.Remove(conn)
  608. if _, err := conn.WriteToUDPAddrPort(fq.packet, ipp); err != nil {
  609. metricDNSFwdUDPErrorWrite.Add(1)
  610. if err := ctx.Err(); err != nil {
  611. return nil, err
  612. }
  613. return nil, err
  614. }
  615. metricDNSFwdUDPWrote.Add(1)
  616. // The 1 extra byte is to detect packet truncation.
  617. out := make([]byte, maxResponseBytes+1)
  618. n, _, err := conn.ReadFromUDPAddrPort(out)
  619. if err != nil {
  620. if err := ctx.Err(); err != nil {
  621. return nil, err
  622. }
  623. if neterror.PacketWasTruncated(err) {
  624. err = nil
  625. } else {
  626. metricDNSFwdUDPErrorRead.Add(1)
  627. return nil, err
  628. }
  629. }
  630. truncated := n > maxResponseBytes
  631. if truncated {
  632. n = maxResponseBytes
  633. }
  634. if n < headerBytes {
  635. f.logf("recv: packet too small (%d bytes)", n)
  636. }
  637. out = out[:n]
  638. txid := getTxID(out)
  639. if txid != fq.txid {
  640. metricDNSFwdUDPErrorTxID.Add(1)
  641. return nil, errTxIDMismatch
  642. }
  643. rcode := getRCode(out)
  644. // don't forward transient errors back to the client when the server fails
  645. if rcode == dns.RCodeServerFailure {
  646. f.logf("recv: response code indicating server failure: %d", rcode)
  647. metricDNSFwdUDPErrorServer.Add(1)
  648. return nil, errServerFailure
  649. }
  650. if truncated {
  651. // Set the truncated bit if it wasn't already.
  652. flags := binary.BigEndian.Uint16(out[2:4])
  653. flags |= dnsFlagTruncated
  654. binary.BigEndian.PutUint16(out[2:4], flags)
  655. // TODO(#2067): Remove any incomplete records? RFC 1035 section 6.2
  656. // states that truncation should head drop so that the authority
  657. // section can be preserved if possible. However, the UDP read with
  658. // a too-small buffer has already dropped the end, so that's the
  659. // best we can do.
  660. }
  661. if truncatedFlagSet(out) {
  662. metricDNSFwdTruncated.Add(1)
  663. }
  664. clampEDNSSize(out, maxResponseBytes)
  665. metricDNSFwdUDPSuccess.Add(1)
  666. return out, nil
  667. }
  668. var optDNSForwardUseRoutes = envknob.RegisterOptBool("TS_DEBUG_DNS_FORWARD_USE_ROUTES")
  669. // ShouldUseRoutes reports whether the DNS resolver should consider routes when dialing
  670. // upstream nameservers via TCP.
  671. //
  672. // If true, routes should be considered ([tsdial.Dialer.UserDial]), otherwise defer
  673. // to the system routes ([tsdial.Dialer.SystemDial]).
  674. //
  675. // TODO(nickkhyl): Update [tsdial.Dialer] to reuse the bart.Table we create in net/tstun.Wrapper
  676. // to avoid having two bart tables in memory, especially on iOS. Once that's done,
  677. // we can get rid of the nodeAttr/control knob and always use UserDial for DNS.
  678. //
  679. // See tailscale/tailscale#12027.
  680. func ShouldUseRoutes(knobs *controlknobs.Knobs) bool {
  681. if !buildfeatures.HasDNS {
  682. return false
  683. }
  684. switch runtime.GOOS {
  685. case "android", "ios":
  686. // On mobile platforms with lower memory limits (e.g., 50MB on iOS),
  687. // this behavior is still gated by the "user-dial-routes" nodeAttr.
  688. return knobs != nil && knobs.UserDialUseRoutes.Load()
  689. default:
  690. // On all other platforms, it is the default behavior,
  691. // but it can be overridden with the "TS_DEBUG_DNS_FORWARD_USE_ROUTES" env var.
  692. doNotUseRoutes := optDNSForwardUseRoutes().EqualBool(false)
  693. return !doNotUseRoutes
  694. }
  695. }
  696. func (f *forwarder) getDialerType() netx.DialFunc {
  697. if ShouldUseRoutes(f.controlKnobs) {
  698. return f.dialer.UserDial
  699. }
  700. return f.dialer.SystemDial
  701. }
  702. func (f *forwarder) sendTCP(ctx context.Context, fq *forwardQuery, rr resolverAndDelay) (ret []byte, err error) {
  703. ipp, ok := rr.name.IPPort()
  704. if !ok {
  705. metricDNSFwdErrorType.Add(1)
  706. return nil, fmt.Errorf("unrecognized resolver type %q", rr.name.Addr)
  707. }
  708. metricDNSFwdTCP.Add(1)
  709. ctx = sockstats.WithSockStats(ctx, sockstats.LabelDNSForwarderTCP, f.logf)
  710. // Specify the exact family to work around https://github.com/golang/go/issues/52264
  711. tcpFam := "tcp4"
  712. if ipp.Addr().Is6() {
  713. tcpFam = "tcp6"
  714. }
  715. ctx, cancel := context.WithTimeout(ctx, tcpQueryTimeout)
  716. defer cancel()
  717. conn, err := f.getDialerType()(ctx, tcpFam, ipp.String())
  718. if err != nil {
  719. return nil, err
  720. }
  721. defer conn.Close()
  722. fq.closeOnCtxDone.Add(conn)
  723. defer fq.closeOnCtxDone.Remove(conn)
  724. ctxOrErr := func(err2 error) ([]byte, error) {
  725. if err := ctx.Err(); err != nil {
  726. return nil, err
  727. }
  728. return nil, err2
  729. }
  730. // Write the query to the server.
  731. query := make([]byte, len(fq.packet)+2)
  732. binary.BigEndian.PutUint16(query, uint16(len(fq.packet)))
  733. copy(query[2:], fq.packet)
  734. if _, err := conn.Write(query); err != nil {
  735. metricDNSFwdTCPErrorWrite.Add(1)
  736. return ctxOrErr(err)
  737. }
  738. metricDNSFwdTCPWrote.Add(1)
  739. // Read the header length back from the server
  740. var length uint16
  741. if err := binary.Read(conn, binary.BigEndian, &length); err != nil {
  742. metricDNSFwdTCPErrorRead.Add(1)
  743. return ctxOrErr(err)
  744. }
  745. // Now read the response
  746. out := make([]byte, length)
  747. n, err := io.ReadFull(conn, out)
  748. if err != nil {
  749. metricDNSFwdTCPErrorRead.Add(1)
  750. return ctxOrErr(err)
  751. }
  752. if n < int(length) {
  753. f.logf("sendTCP: packet too small (%d bytes)", n)
  754. return nil, io.ErrUnexpectedEOF
  755. }
  756. out = out[:n]
  757. txid := getTxID(out)
  758. if txid != fq.txid {
  759. metricDNSFwdTCPErrorTxID.Add(1)
  760. return nil, errTxIDMismatch
  761. }
  762. rcode := getRCode(out)
  763. // don't forward transient errors back to the client when the server fails
  764. if rcode == dns.RCodeServerFailure {
  765. f.logf("sendTCP: response code indicating server failure: %d", rcode)
  766. metricDNSFwdTCPErrorServer.Add(1)
  767. return nil, errServerFailure
  768. }
  769. // TODO(andrew): do we need to do this?
  770. //clampEDNSSize(out, maxResponseBytes)
  771. metricDNSFwdTCPSuccess.Add(1)
  772. return out, nil
  773. }
  774. // resolvers returns the resolvers to use for domain.
  775. func (f *forwarder) resolvers(domain dnsname.FQDN) []resolverAndDelay {
  776. f.mu.Lock()
  777. routes := f.routes
  778. cloudHostFallback := f.cloudHostFallback
  779. f.mu.Unlock()
  780. for _, route := range routes {
  781. if route.Suffix == "." || route.Suffix.Contains(domain) {
  782. return route.Resolvers
  783. }
  784. }
  785. return cloudHostFallback // or nil if no fallback
  786. }
  787. // GetUpstreamResolvers returns the resolvers that would be used to resolve
  788. // the given FQDN.
  789. func (f *forwarder) GetUpstreamResolvers(name dnsname.FQDN) []*dnstype.Resolver {
  790. resolvers := f.resolvers(name)
  791. upstreamResolvers := make([]*dnstype.Resolver, 0, len(resolvers))
  792. for _, r := range resolvers {
  793. upstreamResolvers = append(upstreamResolvers, r.name)
  794. }
  795. return upstreamResolvers
  796. }
  797. // forwardQuery is information and state about a forwarded DNS query that's
  798. // being sent to 1 or more upstreams.
  799. //
  800. // In the case of racing against multiple equivalent upstreams
  801. // (e.g. Google or CloudFlare's 4 DNS IPs: 2 IPv4 + 2 IPv6), this type
  802. // handles racing them more intelligently than just blasting away 4
  803. // queries at once.
  804. type forwardQuery struct {
  805. txid txid
  806. packet []byte
  807. family string // "tcp" or "udp"
  808. src netip.AddrPort
  809. // closeOnCtxDone lets send register values to Close if the
  810. // caller's ctx expires. This avoids send from allocating its
  811. // own waiting goroutine to interrupt the ReadFrom, as memory
  812. // is tight on iOS and we want the number of pending DNS
  813. // lookups to be bursty without too much associated
  814. // goroutine/memory cost.
  815. closeOnCtxDone *closePool
  816. // TODO(bradfitz): add race delay state:
  817. // mu sync.Mutex
  818. // ...
  819. }
  820. // forwardWithDestChan forwards the query to all upstream nameservers
  821. // and waits for the first response.
  822. //
  823. // It either sends to responseChan and returns nil, or returns a
  824. // non-nil error (without sending to the channel).
  825. //
  826. // If resolvers is non-empty, it's used explicitly (notably, for exit
  827. // node DNS proxy queries), otherwise f.resolvers is used.
  828. func (f *forwarder) forwardWithDestChan(ctx context.Context, query packet, responseChan chan<- packet, resolvers ...resolverAndDelay) error {
  829. metricDNSFwd.Add(1)
  830. domain, typ, err := nameFromQuery(query.bs)
  831. if err != nil {
  832. metricDNSFwdErrorName.Add(1)
  833. return err
  834. }
  835. // Guarantee that the ctx we use below is done when this function returns.
  836. ctx, cancel := context.WithCancel(ctx)
  837. defer cancel()
  838. // Drop DNS service discovery spam, primarily for battery life
  839. // on mobile. Things like Spotify on iOS generate this traffic,
  840. // when browsing for LAN devices. But even when filtering this
  841. // out, playing on Sonos still works.
  842. if hasRDNSBonjourPrefix(domain) {
  843. metricDNSFwdDropBonjour.Add(1)
  844. res, err := nxDomainResponse(query)
  845. if err != nil {
  846. return err
  847. }
  848. select {
  849. case <-ctx.Done():
  850. return fmt.Errorf("waiting to send NXDOMAIN: %w", ctx.Err())
  851. case responseChan <- res:
  852. return nil
  853. }
  854. }
  855. if fl := fwdLogAtomic.Load(); fl != nil {
  856. fl.addName(string(domain))
  857. }
  858. clampEDNSSize(query.bs, maxResponseBytes)
  859. if len(resolvers) == 0 {
  860. resolvers = f.resolvers(domain)
  861. if len(resolvers) == 0 {
  862. metricDNSFwdErrorNoUpstream.Add(1)
  863. f.health.SetUnhealthy(dnsForwarderFailing, health.Args{health.ArgDNSServers: ""})
  864. f.logf("no upstream resolvers set, returning SERVFAIL")
  865. res, err := servfailResponse(query)
  866. if err != nil {
  867. return err
  868. }
  869. select {
  870. case <-ctx.Done():
  871. return fmt.Errorf("waiting to send SERVFAIL: %w", ctx.Err())
  872. case responseChan <- res:
  873. return nil
  874. }
  875. } else {
  876. f.health.SetHealthy(dnsForwarderFailing)
  877. }
  878. }
  879. fq := &forwardQuery{
  880. txid: getTxID(query.bs),
  881. packet: query.bs,
  882. family: query.family,
  883. src: query.addr,
  884. closeOnCtxDone: new(closePool),
  885. }
  886. defer fq.closeOnCtxDone.Close()
  887. if f.verboseFwd {
  888. domainSha256 := sha256.Sum256([]byte(domain))
  889. domainSig := base64.RawStdEncoding.EncodeToString(domainSha256[:3])
  890. f.logf("request(%d, %v, %d, %s) %d...", fq.txid, typ, len(domain), domainSig, len(fq.packet))
  891. }
  892. resc := make(chan []byte, 1) // it's fine buffered or not
  893. errc := make(chan error, 1) // it's fine buffered or not too
  894. for i := range resolvers {
  895. go func(rr *resolverAndDelay) {
  896. if rr.startDelay > 0 {
  897. timer := time.NewTimer(rr.startDelay)
  898. select {
  899. case <-timer.C:
  900. case <-ctx.Done():
  901. timer.Stop()
  902. return
  903. }
  904. }
  905. resb, err := f.send(ctx, fq, *rr)
  906. if err != nil {
  907. err = fmt.Errorf("resolving using %q: %w", rr.name.Addr, err)
  908. select {
  909. case errc <- err:
  910. case <-ctx.Done():
  911. }
  912. return
  913. }
  914. select {
  915. case resc <- resb:
  916. case <-ctx.Done():
  917. }
  918. }(&resolvers[i])
  919. }
  920. var firstErr error
  921. var numErr int
  922. for {
  923. select {
  924. case v := <-resc:
  925. select {
  926. case <-ctx.Done():
  927. metricDNSFwdErrorContext.Add(1)
  928. return fmt.Errorf("waiting to send response: %w", ctx.Err())
  929. case responseChan <- packet{v, query.family, query.addr}:
  930. if f.verboseFwd {
  931. f.logf("response(%d, %v, %d) = %d, nil", fq.txid, typ, len(domain), len(v))
  932. }
  933. metricDNSFwdSuccess.Add(1)
  934. f.health.SetHealthy(dnsForwarderFailing)
  935. return nil
  936. }
  937. case err := <-errc:
  938. if firstErr == nil {
  939. firstErr = err
  940. }
  941. numErr++
  942. if numErr == len(resolvers) {
  943. if errors.Is(firstErr, errServerFailure) {
  944. res, err := servfailResponse(query)
  945. if err != nil {
  946. f.logf("building servfail response: %v", err)
  947. return firstErr
  948. }
  949. select {
  950. case <-ctx.Done():
  951. metricDNSFwdErrorContext.Add(1)
  952. metricDNSFwdErrorContextGotError.Add(1)
  953. var resolverAddrs []string
  954. for _, rr := range resolvers {
  955. resolverAddrs = append(resolverAddrs, rr.name.Addr)
  956. }
  957. f.health.SetUnhealthy(dnsForwarderFailing, health.Args{health.ArgDNSServers: strings.Join(resolverAddrs, ",")})
  958. case responseChan <- res:
  959. if f.verboseFwd {
  960. f.logf("forwarder response(%d, %v, %d) = %d, %v", fq.txid, typ, len(domain), len(res.bs), firstErr)
  961. }
  962. return nil
  963. }
  964. }
  965. return firstErr
  966. }
  967. case <-ctx.Done():
  968. metricDNSFwdErrorContext.Add(1)
  969. if firstErr != nil {
  970. metricDNSFwdErrorContextGotError.Add(1)
  971. return firstErr
  972. }
  973. // If we haven't got an error or a successful response,
  974. // include all resolvers in the error message so we can
  975. // at least see what what servers we're trying to
  976. // query.
  977. var resolverAddrs []string
  978. for _, rr := range resolvers {
  979. resolverAddrs = append(resolverAddrs, rr.name.Addr)
  980. }
  981. f.health.SetUnhealthy(dnsForwarderFailing, health.Args{health.ArgDNSServers: strings.Join(resolverAddrs, ",")})
  982. return fmt.Errorf("waiting for response or error from %v: %w", resolverAddrs, ctx.Err())
  983. }
  984. }
  985. }
  986. var initListenConfig func(_ *net.ListenConfig, _ *netmon.Monitor, tunName string) error
  987. // nameFromQuery extracts the normalized query name from bs.
  988. func nameFromQuery(bs []byte) (dnsname.FQDN, dns.Type, error) {
  989. var parser dns.Parser
  990. hdr, err := parser.Start(bs)
  991. if err != nil {
  992. return "", 0, err
  993. }
  994. if hdr.Response {
  995. return "", 0, errNotQuery
  996. }
  997. q, err := parser.Question()
  998. if err != nil {
  999. return "", 0, err
  1000. }
  1001. n := q.Name.Data[:q.Name.Length]
  1002. fqdn, err := dnsname.ToFQDN(rawNameToLower(n))
  1003. if err != nil {
  1004. return "", 0, err
  1005. }
  1006. return fqdn, q.Type, nil
  1007. }
  1008. // nxDomainResponse returns an NXDomain DNS reply for the provided request.
  1009. func nxDomainResponse(req packet) (res packet, err error) {
  1010. p := dnsParserPool.Get().(*dnsParser)
  1011. defer dnsParserPool.Put(p)
  1012. if err := p.parseQuery(req.bs); err != nil {
  1013. return packet{}, err
  1014. }
  1015. h := p.Header
  1016. h.Response = true
  1017. h.RecursionAvailable = h.RecursionDesired
  1018. h.RCode = dns.RCodeNameError
  1019. b := dns.NewBuilder(nil, h)
  1020. // TODO(bradfitz): should we add an SOA record in the Authority
  1021. // section too? (for the nxdomain negative caching TTL)
  1022. // For which zone? Does iOS care?
  1023. b.StartQuestions()
  1024. b.Question(p.Question)
  1025. res.bs, err = b.Finish()
  1026. res.addr = req.addr
  1027. return res, err
  1028. }
  1029. // servfailResponse returns a SERVFAIL error reply for the provided request.
  1030. func servfailResponse(req packet) (res packet, err error) {
  1031. p := dnsParserPool.Get().(*dnsParser)
  1032. defer dnsParserPool.Put(p)
  1033. if err := p.parseQuery(req.bs); err != nil {
  1034. return packet{}, err
  1035. }
  1036. h := p.Header
  1037. h.Response = true
  1038. h.Authoritative = true
  1039. h.RCode = dns.RCodeServerFailure
  1040. b := dns.NewBuilder(nil, h)
  1041. b.StartQuestions()
  1042. b.Question(p.Question)
  1043. res.bs, err = b.Finish()
  1044. res.addr = req.addr
  1045. return res, err
  1046. }
  1047. // closePool is a dynamic set of io.Closers to close as a group.
  1048. // It's intended to be Closed at most once.
  1049. //
  1050. // The zero value is ready for use.
  1051. type closePool struct {
  1052. mu sync.Mutex
  1053. m map[io.Closer]bool
  1054. closed bool
  1055. }
  1056. func (p *closePool) Add(c io.Closer) {
  1057. p.mu.Lock()
  1058. defer p.mu.Unlock()
  1059. if p.closed {
  1060. c.Close()
  1061. return
  1062. }
  1063. if p.m == nil {
  1064. p.m = map[io.Closer]bool{}
  1065. }
  1066. p.m[c] = true
  1067. }
  1068. func (p *closePool) Remove(c io.Closer) {
  1069. p.mu.Lock()
  1070. defer p.mu.Unlock()
  1071. if p.closed {
  1072. return
  1073. }
  1074. delete(p.m, c)
  1075. }
  1076. func (p *closePool) Close() error {
  1077. p.mu.Lock()
  1078. defer p.mu.Unlock()
  1079. if p.closed {
  1080. return nil
  1081. }
  1082. p.closed = true
  1083. for c := range p.m {
  1084. c.Close()
  1085. }
  1086. return nil
  1087. }