lookup_unix.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. // Copyright 2011 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. //go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
  5. package net
  6. import (
  7. "context"
  8. "internal/bytealg"
  9. "sync"
  10. "syscall"
  11. "golang.org/x/net/dns/dnsmessage"
  12. )
  13. var onceReadProtocols sync.Once
  14. // readProtocols loads contents of /etc/protocols into protocols map
  15. // for quick access.
  16. func readProtocols() {
  17. file, err := open("/etc/protocols")
  18. if err != nil {
  19. return
  20. }
  21. defer file.close()
  22. for line, ok := file.readLine(); ok; line, ok = file.readLine() {
  23. // tcp 6 TCP # transmission control protocol
  24. if i := bytealg.IndexByteString(line, '#'); i >= 0 {
  25. line = line[0:i]
  26. }
  27. f := getFields(line)
  28. if len(f) < 2 {
  29. continue
  30. }
  31. if proto, _, ok := dtoi(f[1]); ok {
  32. if _, ok := protocols[f[0]]; !ok {
  33. protocols[f[0]] = proto
  34. }
  35. for _, alias := range f[2:] {
  36. if _, ok := protocols[alias]; !ok {
  37. protocols[alias] = proto
  38. }
  39. }
  40. }
  41. }
  42. }
  43. // lookupProtocol looks up IP protocol name in /etc/protocols and
  44. // returns correspondent protocol number.
  45. func lookupProtocol(_ context.Context, name string) (int, error) {
  46. onceReadProtocols.Do(readProtocols)
  47. return lookupProtocolMap(name)
  48. }
  49. func (r *Resolver) dial(ctx context.Context, network, server string) (Conn, error) {
  50. // Calling Dial here is scary -- we have to be sure not to
  51. // dial a name that will require a DNS lookup, or Dial will
  52. // call back here to translate it. The DNS config parser has
  53. // already checked that all the cfg.servers are IP
  54. // addresses, which Dial will use without a DNS lookup.
  55. var c Conn
  56. var err error
  57. if r != nil && r.Dial != nil {
  58. c, err = r.Dial(ctx, network, server)
  59. } else {
  60. var d Dialer
  61. c, err = d.DialContext(ctx, network, server)
  62. }
  63. if err != nil {
  64. return nil, mapErr(err)
  65. }
  66. return c, nil
  67. }
  68. func (r *Resolver) lookupHost(ctx context.Context, host string) (addrs []string, err error) {
  69. order := systemConf().hostLookupOrder(r, host)
  70. if !r.preferGo() && order == hostLookupCgo {
  71. if addrs, err, ok := cgoLookupHost(ctx, host); ok {
  72. return addrs, err
  73. }
  74. // cgo not available (or netgo); fall back to Go's DNS resolver
  75. order = hostLookupFilesDNS
  76. }
  77. return r.goLookupHostOrder(ctx, host, order)
  78. }
  79. func (r *Resolver) lookupIP(ctx context.Context, network, host string) (addrs []IPAddr, err error) {
  80. if r.preferGo() {
  81. return r.goLookupIP(ctx, network, host)
  82. }
  83. order := systemConf().hostLookupOrder(r, host)
  84. if order == hostLookupCgo {
  85. if addrs, err, ok := cgoLookupIP(ctx, network, host); ok {
  86. return addrs, err
  87. }
  88. // cgo not available (or netgo); fall back to Go's DNS resolver
  89. order = hostLookupFilesDNS
  90. }
  91. ips, _, err := r.goLookupIPCNAMEOrder(ctx, network, host, order)
  92. return ips, err
  93. }
  94. func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int, error) {
  95. if !r.preferGo() && systemConf().canUseCgo() {
  96. if port, err, ok := cgoLookupPort(ctx, network, service); ok {
  97. if err != nil {
  98. // Issue 18213: if cgo fails, first check to see whether we
  99. // have the answer baked-in to the net package.
  100. if port, err := goLookupPort(network, service); err == nil {
  101. return port, nil
  102. }
  103. }
  104. return port, err
  105. }
  106. }
  107. return goLookupPort(network, service)
  108. }
  109. func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error) {
  110. if !r.preferGo() && systemConf().canUseCgo() {
  111. if cname, err, ok := cgoLookupCNAME(ctx, name); ok {
  112. return cname, err
  113. }
  114. }
  115. return r.goLookupCNAME(ctx, name)
  116. }
  117. func (r *Resolver) lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
  118. var target string
  119. if service == "" && proto == "" {
  120. target = name
  121. } else {
  122. target = "_" + service + "._" + proto + "." + name
  123. }
  124. p, server, err := r.lookup(ctx, target, dnsmessage.TypeSRV)
  125. if err != nil {
  126. return "", nil, err
  127. }
  128. var srvs []*SRV
  129. var cname dnsmessage.Name
  130. for {
  131. h, err := p.AnswerHeader()
  132. if err == dnsmessage.ErrSectionDone {
  133. break
  134. }
  135. if err != nil {
  136. return "", nil, &DNSError{
  137. Err: "cannot unmarshal DNS message",
  138. Name: name,
  139. Server: server,
  140. }
  141. }
  142. if h.Type != dnsmessage.TypeSRV {
  143. if err := p.SkipAnswer(); err != nil {
  144. return "", nil, &DNSError{
  145. Err: "cannot unmarshal DNS message",
  146. Name: name,
  147. Server: server,
  148. }
  149. }
  150. continue
  151. }
  152. if cname.Length == 0 && h.Name.Length != 0 {
  153. cname = h.Name
  154. }
  155. srv, err := p.SRVResource()
  156. if err != nil {
  157. return "", nil, &DNSError{
  158. Err: "cannot unmarshal DNS message",
  159. Name: name,
  160. Server: server,
  161. }
  162. }
  163. srvs = append(srvs, &SRV{Target: srv.Target.String(), Port: srv.Port, Priority: srv.Priority, Weight: srv.Weight})
  164. }
  165. byPriorityWeight(srvs).sort()
  166. return cname.String(), srvs, nil
  167. }
  168. func (r *Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) {
  169. p, server, err := r.lookup(ctx, name, dnsmessage.TypeMX)
  170. if err != nil {
  171. return nil, err
  172. }
  173. var mxs []*MX
  174. for {
  175. h, err := p.AnswerHeader()
  176. if err == dnsmessage.ErrSectionDone {
  177. break
  178. }
  179. if err != nil {
  180. return nil, &DNSError{
  181. Err: "cannot unmarshal DNS message",
  182. Name: name,
  183. Server: server,
  184. }
  185. }
  186. if h.Type != dnsmessage.TypeMX {
  187. if err := p.SkipAnswer(); err != nil {
  188. return nil, &DNSError{
  189. Err: "cannot unmarshal DNS message",
  190. Name: name,
  191. Server: server,
  192. }
  193. }
  194. continue
  195. }
  196. mx, err := p.MXResource()
  197. if err != nil {
  198. return nil, &DNSError{
  199. Err: "cannot unmarshal DNS message",
  200. Name: name,
  201. Server: server,
  202. }
  203. }
  204. mxs = append(mxs, &MX{Host: mx.MX.String(), Pref: mx.Pref})
  205. }
  206. byPref(mxs).sort()
  207. return mxs, nil
  208. }
  209. func (r *Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) {
  210. p, server, err := r.lookup(ctx, name, dnsmessage.TypeNS)
  211. if err != nil {
  212. return nil, err
  213. }
  214. var nss []*NS
  215. for {
  216. h, err := p.AnswerHeader()
  217. if err == dnsmessage.ErrSectionDone {
  218. break
  219. }
  220. if err != nil {
  221. return nil, &DNSError{
  222. Err: "cannot unmarshal DNS message",
  223. Name: name,
  224. Server: server,
  225. }
  226. }
  227. if h.Type != dnsmessage.TypeNS {
  228. if err := p.SkipAnswer(); err != nil {
  229. return nil, &DNSError{
  230. Err: "cannot unmarshal DNS message",
  231. Name: name,
  232. Server: server,
  233. }
  234. }
  235. continue
  236. }
  237. ns, err := p.NSResource()
  238. if err != nil {
  239. return nil, &DNSError{
  240. Err: "cannot unmarshal DNS message",
  241. Name: name,
  242. Server: server,
  243. }
  244. }
  245. nss = append(nss, &NS{Host: ns.NS.String()})
  246. }
  247. return nss, nil
  248. }
  249. func (r *Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) {
  250. p, server, err := r.lookup(ctx, name, dnsmessage.TypeTXT)
  251. if err != nil {
  252. return nil, err
  253. }
  254. var txts []string
  255. for {
  256. h, err := p.AnswerHeader()
  257. if err == dnsmessage.ErrSectionDone {
  258. break
  259. }
  260. if err != nil {
  261. return nil, &DNSError{
  262. Err: "cannot unmarshal DNS message",
  263. Name: name,
  264. Server: server,
  265. }
  266. }
  267. if h.Type != dnsmessage.TypeTXT {
  268. if err := p.SkipAnswer(); err != nil {
  269. return nil, &DNSError{
  270. Err: "cannot unmarshal DNS message",
  271. Name: name,
  272. Server: server,
  273. }
  274. }
  275. continue
  276. }
  277. txt, err := p.TXTResource()
  278. if err != nil {
  279. return nil, &DNSError{
  280. Err: "cannot unmarshal DNS message",
  281. Name: name,
  282. Server: server,
  283. }
  284. }
  285. // Multiple strings in one TXT record need to be
  286. // concatenated without separator to be consistent
  287. // with previous Go resolver.
  288. n := 0
  289. for _, s := range txt.TXT {
  290. n += len(s)
  291. }
  292. txtJoin := make([]byte, 0, n)
  293. for _, s := range txt.TXT {
  294. txtJoin = append(txtJoin, s...)
  295. }
  296. if len(txts) == 0 {
  297. txts = make([]string, 0, 1)
  298. }
  299. txts = append(txts, string(txtJoin))
  300. }
  301. return txts, nil
  302. }
  303. func (r *Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error) {
  304. if !r.preferGo() && systemConf().canUseCgo() {
  305. if ptrs, err, ok := cgoLookupPTR(ctx, addr); ok {
  306. return ptrs, err
  307. }
  308. }
  309. return r.goLookupPTR(ctx, addr)
  310. }
  311. // concurrentThreadsLimit returns the number of threads we permit to
  312. // run concurrently doing DNS lookups via cgo. A DNS lookup may use a
  313. // file descriptor so we limit this to less than the number of
  314. // permitted open files. On some systems, notably Darwin, if
  315. // getaddrinfo is unable to open a file descriptor it simply returns
  316. // EAI_NONAME rather than a useful error. Limiting the number of
  317. // concurrent getaddrinfo calls to less than the permitted number of
  318. // file descriptors makes that error less likely. We don't bother to
  319. // apply the same limit to DNS lookups run directly from Go, because
  320. // there we will return a meaningful "too many open files" error.
  321. func concurrentThreadsLimit() int {
  322. var rlim syscall.Rlimit
  323. if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlim); err != nil {
  324. return 500
  325. }
  326. r := int(rlim.Cur)
  327. if r > 500 {
  328. r = 500
  329. } else if r > 30 {
  330. r -= 30
  331. }
  332. return r
  333. }