dns_resolver.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /*
  2. *
  3. * Copyright 2017 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. package naming
  19. import (
  20. "context"
  21. "errors"
  22. "fmt"
  23. "net"
  24. "strconv"
  25. "time"
  26. "google.golang.org/grpc/grpclog"
  27. )
  28. const (
  29. defaultPort = "443"
  30. defaultFreq = time.Minute * 30
  31. )
  32. var (
  33. errMissingAddr = errors.New("missing address")
  34. errWatcherClose = errors.New("watcher has been closed")
  35. lookupHost = net.DefaultResolver.LookupHost
  36. lookupSRV = net.DefaultResolver.LookupSRV
  37. )
  38. // NewDNSResolverWithFreq creates a DNS Resolver that can resolve DNS names, and
  39. // create watchers that poll the DNS server using the frequency set by freq.
  40. func NewDNSResolverWithFreq(freq time.Duration) (Resolver, error) {
  41. return &dnsResolver{freq: freq}, nil
  42. }
  43. // NewDNSResolver creates a DNS Resolver that can resolve DNS names, and create
  44. // watchers that poll the DNS server using the default frequency defined by defaultFreq.
  45. func NewDNSResolver() (Resolver, error) {
  46. return NewDNSResolverWithFreq(defaultFreq)
  47. }
  48. // dnsResolver handles name resolution for names following the DNS scheme
  49. type dnsResolver struct {
  50. // frequency of polling the DNS server that the watchers created by this resolver will use.
  51. freq time.Duration
  52. }
  53. // formatIP returns ok = false if addr is not a valid textual representation of an IP address.
  54. // If addr is an IPv4 address, return the addr and ok = true.
  55. // If addr is an IPv6 address, return the addr enclosed in square brackets and ok = true.
  56. func formatIP(addr string) (addrIP string, ok bool) {
  57. ip := net.ParseIP(addr)
  58. if ip == nil {
  59. return "", false
  60. }
  61. if ip.To4() != nil {
  62. return addr, true
  63. }
  64. return "[" + addr + "]", true
  65. }
  66. // parseTarget takes the user input target string, returns formatted host and port info.
  67. // If target doesn't specify a port, set the port to be the defaultPort.
  68. // If target is in IPv6 format and host-name is enclosed in sqarue brackets, brackets
  69. // are strippd when setting the host.
  70. // examples:
  71. // target: "www.google.com" returns host: "www.google.com", port: "443"
  72. // target: "ipv4-host:80" returns host: "ipv4-host", port: "80"
  73. // target: "[ipv6-host]" returns host: "ipv6-host", port: "443"
  74. // target: ":80" returns host: "localhost", port: "80"
  75. // target: ":" returns host: "localhost", port: "443"
  76. func parseTarget(target string) (host, port string, err error) {
  77. if target == "" {
  78. return "", "", errMissingAddr
  79. }
  80. if ip := net.ParseIP(target); ip != nil {
  81. // target is an IPv4 or IPv6(without brackets) address
  82. return target, defaultPort, nil
  83. }
  84. if host, port, err := net.SplitHostPort(target); err == nil {
  85. // target has port, i.e ipv4-host:port, [ipv6-host]:port, host-name:port
  86. if host == "" {
  87. // Keep consistent with net.Dial(): If the host is empty, as in ":80", the local system is assumed.
  88. host = "localhost"
  89. }
  90. if port == "" {
  91. // If the port field is empty(target ends with colon), e.g. "[::1]:", defaultPort is used.
  92. port = defaultPort
  93. }
  94. return host, port, nil
  95. }
  96. if host, port, err := net.SplitHostPort(target + ":" + defaultPort); err == nil {
  97. // target doesn't have port
  98. return host, port, nil
  99. }
  100. return "", "", fmt.Errorf("invalid target address %v", target)
  101. }
  102. // Resolve creates a watcher that watches the name resolution of the target.
  103. func (r *dnsResolver) Resolve(target string) (Watcher, error) {
  104. host, port, err := parseTarget(target)
  105. if err != nil {
  106. return nil, err
  107. }
  108. if net.ParseIP(host) != nil {
  109. ipWatcher := &ipWatcher{
  110. updateChan: make(chan *Update, 1),
  111. }
  112. host, _ = formatIP(host)
  113. ipWatcher.updateChan <- &Update{Op: Add, Addr: host + ":" + port}
  114. return ipWatcher, nil
  115. }
  116. ctx, cancel := context.WithCancel(context.Background())
  117. return &dnsWatcher{
  118. r: r,
  119. host: host,
  120. port: port,
  121. ctx: ctx,
  122. cancel: cancel,
  123. t: time.NewTimer(0),
  124. }, nil
  125. }
  126. // dnsWatcher watches for the name resolution update for a specific target
  127. type dnsWatcher struct {
  128. r *dnsResolver
  129. host string
  130. port string
  131. // The latest resolved address set
  132. curAddrs map[string]*Update
  133. ctx context.Context
  134. cancel context.CancelFunc
  135. t *time.Timer
  136. }
  137. // ipWatcher watches for the name resolution update for an IP address.
  138. type ipWatcher struct {
  139. updateChan chan *Update
  140. }
  141. // Next returns the address resolution Update for the target. For IP address,
  142. // the resolution is itself, thus polling name server is unnecessary. Therefore,
  143. // Next() will return an Update the first time it is called, and will be blocked
  144. // for all following calls as no Update exists until watcher is closed.
  145. func (i *ipWatcher) Next() ([]*Update, error) {
  146. u, ok := <-i.updateChan
  147. if !ok {
  148. return nil, errWatcherClose
  149. }
  150. return []*Update{u}, nil
  151. }
  152. // Close closes the ipWatcher.
  153. func (i *ipWatcher) Close() {
  154. close(i.updateChan)
  155. }
  156. // AddressType indicates the address type returned by name resolution.
  157. type AddressType uint8
  158. const (
  159. // Backend indicates the server is a backend server.
  160. Backend AddressType = iota
  161. // GRPCLB indicates the server is a grpclb load balancer.
  162. GRPCLB
  163. )
  164. // AddrMetadataGRPCLB contains the information the name resolver for grpclb should provide. The
  165. // name resolver used by the grpclb balancer is required to provide this type of metadata in
  166. // its address updates.
  167. type AddrMetadataGRPCLB struct {
  168. // AddrType is the type of server (grpc load balancer or backend).
  169. AddrType AddressType
  170. // ServerName is the name of the grpc load balancer. Used for authentication.
  171. ServerName string
  172. }
  173. // compileUpdate compares the old resolved addresses and newly resolved addresses,
  174. // and generates an update list
  175. func (w *dnsWatcher) compileUpdate(newAddrs map[string]*Update) []*Update {
  176. var res []*Update
  177. for a, u := range w.curAddrs {
  178. if _, ok := newAddrs[a]; !ok {
  179. u.Op = Delete
  180. res = append(res, u)
  181. }
  182. }
  183. for a, u := range newAddrs {
  184. if _, ok := w.curAddrs[a]; !ok {
  185. res = append(res, u)
  186. }
  187. }
  188. return res
  189. }
  190. func (w *dnsWatcher) lookupSRV() map[string]*Update {
  191. newAddrs := make(map[string]*Update)
  192. _, srvs, err := lookupSRV(w.ctx, "grpclb", "tcp", w.host)
  193. if err != nil {
  194. grpclog.Infof("grpc: failed dns SRV record lookup due to %v.\n", err)
  195. return nil
  196. }
  197. for _, s := range srvs {
  198. lbAddrs, err := lookupHost(w.ctx, s.Target)
  199. if err != nil {
  200. grpclog.Warningf("grpc: failed load banlacer address dns lookup due to %v.\n", err)
  201. continue
  202. }
  203. for _, a := range lbAddrs {
  204. a, ok := formatIP(a)
  205. if !ok {
  206. grpclog.Errorf("grpc: failed IP parsing due to %v.\n", err)
  207. continue
  208. }
  209. addr := a + ":" + strconv.Itoa(int(s.Port))
  210. newAddrs[addr] = &Update{Addr: addr,
  211. Metadata: AddrMetadataGRPCLB{AddrType: GRPCLB, ServerName: s.Target}}
  212. }
  213. }
  214. return newAddrs
  215. }
  216. func (w *dnsWatcher) lookupHost() map[string]*Update {
  217. newAddrs := make(map[string]*Update)
  218. addrs, err := lookupHost(w.ctx, w.host)
  219. if err != nil {
  220. grpclog.Warningf("grpc: failed dns A record lookup due to %v.\n", err)
  221. return nil
  222. }
  223. for _, a := range addrs {
  224. a, ok := formatIP(a)
  225. if !ok {
  226. grpclog.Errorf("grpc: failed IP parsing due to %v.\n", err)
  227. continue
  228. }
  229. addr := a + ":" + w.port
  230. newAddrs[addr] = &Update{Addr: addr}
  231. }
  232. return newAddrs
  233. }
  234. func (w *dnsWatcher) lookup() []*Update {
  235. newAddrs := w.lookupSRV()
  236. if newAddrs == nil {
  237. // If failed to get any balancer address (either no corresponding SRV for the
  238. // target, or caused by failure during resolution/parsing of the balancer target),
  239. // return any A record info available.
  240. newAddrs = w.lookupHost()
  241. }
  242. result := w.compileUpdate(newAddrs)
  243. w.curAddrs = newAddrs
  244. return result
  245. }
  246. // Next returns the resolved address update(delta) for the target. If there's no
  247. // change, it will sleep for 30 mins and try to resolve again after that.
  248. func (w *dnsWatcher) Next() ([]*Update, error) {
  249. for {
  250. select {
  251. case <-w.ctx.Done():
  252. return nil, errWatcherClose
  253. case <-w.t.C:
  254. }
  255. result := w.lookup()
  256. // Next lookup should happen after an interval defined by w.r.freq.
  257. w.t.Reset(w.r.freq)
  258. if len(result) > 0 {
  259. return result, nil
  260. }
  261. }
  262. }
  263. func (w *dnsWatcher) Close() {
  264. w.cancel()
  265. }