2016-03-01 22:57:46 +00:00
|
|
|
// Copyright 2011 The Go Authors. All rights reserved.
|
2011-06-13 10:22:31 +10:00
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
2018-09-28 15:50:01 +02:00
|
|
|
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
build: add build comments to core packages
The go/build package already recognizes
system-specific file names like
mycode_darwin.go
mycode_darwin_386.go
mycode_386.s
However, it is also common to write files that
apply to multiple architectures, so a recent CL added
to go/build the ability to process comments
listing a set of conditions for building. For example:
// +build darwin freebsd openbsd/386
says that this file should be compiled only on
OS X, FreeBSD, or 32-bit x86 OpenBSD systems.
These conventions are not yet documented
(hence this long CL description).
This CL adds build comments to the multi-system
files in the core library, a step toward making it
possible to use go/build to build them.
With this change go/build can handle crypto/rand,
exec, net, path/filepath, os/user, and time.
os and syscall need additional adjustments.
R=golang-dev, r, gri, r, gustavo
CC=golang-dev
https://golang.org/cl/5011046
2011-09-15 16:48:57 -04:00
|
|
|
|
2011-06-13 10:22:31 +10:00
|
|
|
package net
|
|
|
|
|
|
2016-04-14 17:47:25 -07:00
|
|
|
import (
|
|
|
|
|
"context"
|
2018-08-21 14:50:48 -05:00
|
|
|
"internal/bytealg"
|
2016-04-14 17:47:25 -07:00
|
|
|
"sync"
|
2018-06-27 07:08:41 -07:00
|
|
|
"syscall"
|
2017-11-22 17:12:30 -08:00
|
|
|
|
2019-03-01 10:12:30 -05:00
|
|
|
"golang.org/x/net/dns/dnsmessage"
|
2016-04-14 17:47:25 -07:00
|
|
|
)
|
2011-06-13 10:22:31 +10:00
|
|
|
|
2013-08-22 10:33:37 +09:00
|
|
|
var onceReadProtocols sync.Once
|
2011-10-12 10:29:22 +11:00
|
|
|
|
|
|
|
|
// readProtocols loads contents of /etc/protocols into protocols map
|
|
|
|
|
// for quick access.
|
|
|
|
|
func readProtocols() {
|
2017-04-25 20:21:50 -06:00
|
|
|
file, err := open("/etc/protocols")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
defer file.close()
|
|
|
|
|
|
|
|
|
|
for line, ok := file.readLine(); ok; line, ok = file.readLine() {
|
|
|
|
|
// tcp 6 TCP # transmission control protocol
|
2018-08-21 14:50:48 -05:00
|
|
|
if i := bytealg.IndexByteString(line, '#'); i >= 0 {
|
2017-04-25 20:21:50 -06:00
|
|
|
line = line[0:i]
|
|
|
|
|
}
|
|
|
|
|
f := getFields(line)
|
|
|
|
|
if len(f) < 2 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if proto, _, ok := dtoi(f[1]); ok {
|
|
|
|
|
if _, ok := protocols[f[0]]; !ok {
|
|
|
|
|
protocols[f[0]] = proto
|
2011-10-12 10:29:22 +11:00
|
|
|
}
|
2017-04-25 20:21:50 -06:00
|
|
|
for _, alias := range f[2:] {
|
|
|
|
|
if _, ok := protocols[alias]; !ok {
|
|
|
|
|
protocols[alias] = proto
|
2011-10-12 10:29:22 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// lookupProtocol looks up IP protocol name in /etc/protocols and
|
|
|
|
|
// returns correspondent protocol number.
|
net: fix plan9 after context change, propagate contexts more
My previous https://golang.org/cl/22101 to add context throughout the
net package broke Plan 9, which isn't currently tested (#15251).
It also broke some old unsupported version of Windows (Windows 2000?)
which doesn't have the ConnectEx function, but that was only found
visually, since our minimum supported Windows version has ConnectEx.
This change simplifies the Windows and deletes the non-ConnectEx code
path. Windows 2000 will work even less now, if it even worked
before. Windows XP remains our minimum supported version.
Specifically, the previous CL stopped using the "dial" function, which
0intro noted:
https://github.com/golang/go/issues/15333#issuecomment-210842761
This CL removes the dial function instead and makes plan9's net
implementation respect contexts, which likely fixes a number of
t.Skipped tests. I'm leaving that to 0intro to investigate.
In the process of propagating and respecting contexts for plan9, I had
to change some signatures to add contexts to more places and ended up
pushing contexts down into the Go-based DNS resolution as well,
replacing the pure-Go DNS implementation's use of "timeout
time.Duration" with a context instead.
Updates #11932
Updates #15328
Fixes #15333
Change-Id: I6ad1e62f38271cdd86b3f40921f2d0f23374936a
Reviewed-on: https://go-review.googlesource.com/22144
Reviewed-by: David du Colombier <0intro@gmail.com>
Reviewed-by: Mikio Hara <mikioh.mikioh@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-04-16 14:17:40 -07:00
|
|
|
func lookupProtocol(_ context.Context, name string) (int, error) {
|
2011-10-12 10:29:22 +11:00
|
|
|
onceReadProtocols.Do(readProtocols)
|
2016-09-09 22:51:11 +00:00
|
|
|
return lookupProtocolMap(name)
|
2011-10-12 10:29:22 +11:00
|
|
|
}
|
|
|
|
|
|
2017-11-22 17:12:30 -08:00
|
|
|
func (r *Resolver) dial(ctx context.Context, network, server string) (Conn, error) {
|
2017-02-20 05:58:55 -08:00
|
|
|
// Calling Dial here is scary -- we have to be sure not to
|
|
|
|
|
// dial a name that will require a DNS lookup, or Dial will
|
|
|
|
|
// call back here to translate it. The DNS config parser has
|
|
|
|
|
// already checked that all the cfg.servers are IP
|
|
|
|
|
// addresses, which Dial will use without a DNS lookup.
|
|
|
|
|
var c Conn
|
|
|
|
|
var err error
|
2018-03-19 09:16:25 +03:00
|
|
|
if r != nil && r.Dial != nil {
|
2017-02-20 05:58:55 -08:00
|
|
|
c, err = r.Dial(ctx, network, server)
|
|
|
|
|
} else {
|
|
|
|
|
var d Dialer
|
|
|
|
|
c, err = d.DialContext(ctx, network, server)
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, mapErr(err)
|
|
|
|
|
}
|
2017-11-22 17:12:30 -08:00
|
|
|
return c, nil
|
2017-02-20 05:58:55 -08:00
|
|
|
}
|
|
|
|
|
|
2016-10-21 10:27:57 -07:00
|
|
|
func (r *Resolver) lookupHost(ctx context.Context, host string) (addrs []string, err error) {
|
2018-03-15 09:27:29 +03:00
|
|
|
order := systemConf().hostLookupOrder(r, host)
|
2018-03-19 09:16:25 +03:00
|
|
|
if !r.preferGo() && order == hostLookupCgo {
|
2016-05-08 18:17:59 -07:00
|
|
|
if addrs, err, ok := cgoLookupHost(ctx, host); ok {
|
2015-04-16 14:33:25 -07:00
|
|
|
return addrs, err
|
|
|
|
|
}
|
|
|
|
|
// cgo not available (or netgo); fall back to Go's DNS resolver
|
|
|
|
|
order = hostLookupFilesDNS
|
2011-06-13 10:22:31 +10:00
|
|
|
}
|
2016-11-01 21:01:08 -07:00
|
|
|
return r.goLookupHostOrder(ctx, host, order)
|
2011-06-13 10:22:31 +10:00
|
|
|
}
|
|
|
|
|
|
2018-06-21 01:23:37 +03:00
|
|
|
func (r *Resolver) lookupIP(ctx context.Context, network, host string) (addrs []IPAddr, err error) {
|
2018-03-19 09:16:25 +03:00
|
|
|
if r.preferGo() {
|
2016-11-01 21:01:08 -07:00
|
|
|
return r.goLookupIP(ctx, host)
|
2016-10-21 10:27:57 -07:00
|
|
|
}
|
2018-03-15 09:27:29 +03:00
|
|
|
order := systemConf().hostLookupOrder(r, host)
|
2015-04-16 14:33:25 -07:00
|
|
|
if order == hostLookupCgo {
|
2018-06-21 01:23:37 +03:00
|
|
|
if addrs, err, ok := cgoLookupIP(ctx, network, host); ok {
|
2015-04-16 14:33:25 -07:00
|
|
|
return addrs, err
|
|
|
|
|
}
|
|
|
|
|
// cgo not available (or netgo); fall back to Go's DNS resolver
|
|
|
|
|
order = hostLookupFilesDNS
|
2011-06-13 10:22:31 +10:00
|
|
|
}
|
2017-11-22 17:12:30 -08:00
|
|
|
ips, _, err := r.goLookupIPCNAMEOrder(ctx, host, order)
|
|
|
|
|
return ips, err
|
2011-06-13 10:22:31 +10:00
|
|
|
}
|
|
|
|
|
|
2016-10-21 10:27:57 -07:00
|
|
|
func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int, error) {
|
2018-03-19 09:16:25 +03:00
|
|
|
if !r.preferGo() && systemConf().canUseCgo() {
|
2016-05-08 18:17:59 -07:00
|
|
|
if port, err, ok := cgoLookupPort(ctx, network, service); ok {
|
2016-12-06 22:05:41 +00:00
|
|
|
if err != nil {
|
|
|
|
|
// Issue 18213: if cgo fails, first check to see whether we
|
|
|
|
|
// have the answer baked-in to the net package.
|
|
|
|
|
if port, err := goLookupPort(network, service); err == nil {
|
|
|
|
|
return port, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-08-18 22:50:12 -04:00
|
|
|
return port, err
|
|
|
|
|
}
|
2011-06-13 10:22:31 +10:00
|
|
|
}
|
2015-08-18 22:50:12 -04:00
|
|
|
return goLookupPort(network, service)
|
2011-06-13 10:22:31 +10:00
|
|
|
}
|
|
|
|
|
|
2016-10-21 10:27:57 -07:00
|
|
|
func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error) {
|
2018-03-19 09:16:25 +03:00
|
|
|
if !r.preferGo() && systemConf().canUseCgo() {
|
2016-05-08 18:17:59 -07:00
|
|
|
if cname, err, ok := cgoLookupCNAME(ctx, name); ok {
|
2015-08-18 22:50:12 -04:00
|
|
|
return cname, err
|
|
|
|
|
}
|
2011-06-13 10:22:31 +10:00
|
|
|
}
|
2016-11-01 21:01:08 -07:00
|
|
|
return r.goLookupCNAME(ctx, name)
|
2011-06-13 10:22:31 +10:00
|
|
|
}
|
|
|
|
|
|
2016-11-01 21:01:08 -07:00
|
|
|
func (r *Resolver) lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
|
2011-10-18 13:57:04 -04:00
|
|
|
var target string
|
|
|
|
|
if service == "" && proto == "" {
|
|
|
|
|
target = name
|
|
|
|
|
} else {
|
|
|
|
|
target = "_" + service + "._" + proto + "." + name
|
|
|
|
|
}
|
2017-11-22 17:12:30 -08:00
|
|
|
p, server, err := r.lookup(ctx, target, dnsmessage.TypeSRV)
|
2011-06-13 10:22:31 +10:00
|
|
|
if err != nil {
|
2015-04-19 20:54:01 +09:00
|
|
|
return "", nil, err
|
2011-06-13 10:22:31 +10:00
|
|
|
}
|
2017-11-22 17:12:30 -08:00
|
|
|
var srvs []*SRV
|
|
|
|
|
var cname dnsmessage.Name
|
|
|
|
|
for {
|
|
|
|
|
h, err := p.AnswerHeader()
|
|
|
|
|
if err == dnsmessage.ErrSectionDone {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", nil, &DNSError{
|
|
|
|
|
Err: "cannot unmarshal DNS message",
|
|
|
|
|
Name: name,
|
|
|
|
|
Server: server,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if h.Type != dnsmessage.TypeSRV {
|
|
|
|
|
if err := p.SkipAnswer(); err != nil {
|
|
|
|
|
return "", nil, &DNSError{
|
|
|
|
|
Err: "cannot unmarshal DNS message",
|
|
|
|
|
Name: name,
|
|
|
|
|
Server: server,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if cname.Length == 0 && h.Name.Length != 0 {
|
|
|
|
|
cname = h.Name
|
|
|
|
|
}
|
|
|
|
|
srv, err := p.SRVResource()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", nil, &DNSError{
|
|
|
|
|
Err: "cannot unmarshal DNS message",
|
|
|
|
|
Name: name,
|
|
|
|
|
Server: server,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
srvs = append(srvs, &SRV{Target: srv.Target.String(), Port: srv.Port, Priority: srv.Priority, Weight: srv.Weight})
|
2011-06-13 10:22:31 +10:00
|
|
|
}
|
2015-04-19 20:54:01 +09:00
|
|
|
byPriorityWeight(srvs).sort()
|
2017-11-22 17:12:30 -08:00
|
|
|
return cname.String(), srvs, nil
|
2011-06-13 10:22:31 +10:00
|
|
|
}
|
|
|
|
|
|
2016-11-01 21:01:08 -07:00
|
|
|
func (r *Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) {
|
2017-11-22 17:12:30 -08:00
|
|
|
p, server, err := r.lookup(ctx, name, dnsmessage.TypeMX)
|
2011-06-13 10:22:31 +10:00
|
|
|
if err != nil {
|
2015-04-19 20:54:01 +09:00
|
|
|
return nil, err
|
2011-06-13 10:22:31 +10:00
|
|
|
}
|
2017-11-22 17:12:30 -08:00
|
|
|
var mxs []*MX
|
|
|
|
|
for {
|
|
|
|
|
h, err := p.AnswerHeader()
|
|
|
|
|
if err == dnsmessage.ErrSectionDone {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, &DNSError{
|
|
|
|
|
Err: "cannot unmarshal DNS message",
|
|
|
|
|
Name: name,
|
|
|
|
|
Server: server,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if h.Type != dnsmessage.TypeMX {
|
|
|
|
|
if err := p.SkipAnswer(); err != nil {
|
|
|
|
|
return nil, &DNSError{
|
|
|
|
|
Err: "cannot unmarshal DNS message",
|
|
|
|
|
Name: name,
|
|
|
|
|
Server: server,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
mx, err := p.MXResource()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, &DNSError{
|
|
|
|
|
Err: "cannot unmarshal DNS message",
|
|
|
|
|
Name: name,
|
|
|
|
|
Server: server,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mxs = append(mxs, &MX{Host: mx.MX.String(), Pref: mx.Pref})
|
|
|
|
|
|
2011-06-13 10:22:31 +10:00
|
|
|
}
|
2015-04-19 20:54:01 +09:00
|
|
|
byPref(mxs).sort()
|
|
|
|
|
return mxs, nil
|
2011-06-13 10:22:31 +10:00
|
|
|
}
|
|
|
|
|
|
2016-11-01 21:01:08 -07:00
|
|
|
func (r *Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) {
|
2017-11-22 17:12:30 -08:00
|
|
|
p, server, err := r.lookup(ctx, name, dnsmessage.TypeNS)
|
2012-10-18 15:39:04 +09:00
|
|
|
if err != nil {
|
2015-04-19 20:54:01 +09:00
|
|
|
return nil, err
|
2012-10-18 15:39:04 +09:00
|
|
|
}
|
2017-11-22 17:12:30 -08:00
|
|
|
var nss []*NS
|
|
|
|
|
for {
|
|
|
|
|
h, err := p.AnswerHeader()
|
|
|
|
|
if err == dnsmessage.ErrSectionDone {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, &DNSError{
|
|
|
|
|
Err: "cannot unmarshal DNS message",
|
|
|
|
|
Name: name,
|
|
|
|
|
Server: server,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if h.Type != dnsmessage.TypeNS {
|
|
|
|
|
if err := p.SkipAnswer(); err != nil {
|
|
|
|
|
return nil, &DNSError{
|
|
|
|
|
Err: "cannot unmarshal DNS message",
|
|
|
|
|
Name: name,
|
|
|
|
|
Server: server,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
ns, err := p.NSResource()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, &DNSError{
|
|
|
|
|
Err: "cannot unmarshal DNS message",
|
|
|
|
|
Name: name,
|
|
|
|
|
Server: server,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
nss = append(nss, &NS{Host: ns.NS.String()})
|
2012-10-18 15:39:04 +09:00
|
|
|
}
|
2015-04-19 20:54:01 +09:00
|
|
|
return nss, nil
|
2012-10-18 15:39:04 +09:00
|
|
|
}
|
|
|
|
|
|
2016-10-21 10:27:57 -07:00
|
|
|
func (r *Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) {
|
2017-11-22 17:12:30 -08:00
|
|
|
p, server, err := r.lookup(ctx, name, dnsmessage.TypeTXT)
|
2011-09-13 13:05:33 +10:00
|
|
|
if err != nil {
|
2015-04-19 20:54:01 +09:00
|
|
|
return nil, err
|
2011-09-13 13:05:33 +10:00
|
|
|
}
|
2017-11-22 17:12:30 -08:00
|
|
|
var txts []string
|
|
|
|
|
for {
|
|
|
|
|
h, err := p.AnswerHeader()
|
|
|
|
|
if err == dnsmessage.ErrSectionDone {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, &DNSError{
|
|
|
|
|
Err: "cannot unmarshal DNS message",
|
|
|
|
|
Name: name,
|
|
|
|
|
Server: server,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if h.Type != dnsmessage.TypeTXT {
|
|
|
|
|
if err := p.SkipAnswer(); err != nil {
|
|
|
|
|
return nil, &DNSError{
|
|
|
|
|
Err: "cannot unmarshal DNS message",
|
|
|
|
|
Name: name,
|
|
|
|
|
Server: server,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
txt, err := p.TXTResource()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, &DNSError{
|
|
|
|
|
Err: "cannot unmarshal DNS message",
|
|
|
|
|
Name: name,
|
|
|
|
|
Server: server,
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-09-24 06:08:54 -04:00
|
|
|
// Multiple strings in one TXT record need to be
|
|
|
|
|
// concatenated without separator to be consistent
|
|
|
|
|
// with previous Go resolver.
|
|
|
|
|
n := 0
|
|
|
|
|
for _, s := range txt.TXT {
|
|
|
|
|
n += len(s)
|
|
|
|
|
}
|
|
|
|
|
txtJoin := make([]byte, 0, n)
|
|
|
|
|
for _, s := range txt.TXT {
|
|
|
|
|
txtJoin = append(txtJoin, s...)
|
|
|
|
|
}
|
2017-11-22 17:12:30 -08:00
|
|
|
if len(txts) == 0 {
|
2018-09-24 06:08:54 -04:00
|
|
|
txts = make([]string, 0, 1)
|
2017-11-22 17:12:30 -08:00
|
|
|
}
|
2018-09-24 06:08:54 -04:00
|
|
|
txts = append(txts, string(txtJoin))
|
2011-09-13 13:05:33 +10:00
|
|
|
}
|
2015-04-19 20:54:01 +09:00
|
|
|
return txts, nil
|
2011-09-13 13:05:33 +10:00
|
|
|
}
|
|
|
|
|
|
2016-10-21 10:27:57 -07:00
|
|
|
func (r *Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error) {
|
2018-03-19 09:16:25 +03:00
|
|
|
if !r.preferGo() && systemConf().canUseCgo() {
|
2016-05-08 18:17:59 -07:00
|
|
|
if ptrs, err, ok := cgoLookupPTR(ctx, addr); ok {
|
2015-08-18 22:50:12 -04:00
|
|
|
return ptrs, err
|
|
|
|
|
}
|
2011-06-13 10:22:31 +10:00
|
|
|
}
|
2016-11-01 21:01:08 -07:00
|
|
|
return r.goLookupPTR(ctx, addr)
|
2011-06-13 10:22:31 +10:00
|
|
|
}
|
2018-06-27 07:08:41 -07:00
|
|
|
|
|
|
|
|
// concurrentThreadsLimit returns the number of threads we permit to
|
|
|
|
|
// run concurrently doing DNS lookups via cgo. A DNS lookup may use a
|
|
|
|
|
// file descriptor so we limit this to less than the number of
|
|
|
|
|
// permitted open files. On some systems, notably Darwin, if
|
|
|
|
|
// getaddrinfo is unable to open a file descriptor it simply returns
|
|
|
|
|
// EAI_NONAME rather than a useful error. Limiting the number of
|
|
|
|
|
// concurrent getaddrinfo calls to less than the permitted number of
|
|
|
|
|
// file descriptors makes that error less likely. We don't bother to
|
|
|
|
|
// apply the same limit to DNS lookups run directly from Go, because
|
|
|
|
|
// there we will return a meaningful "too many open files" error.
|
|
|
|
|
func concurrentThreadsLimit() int {
|
|
|
|
|
var rlim syscall.Rlimit
|
|
|
|
|
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlim); err != nil {
|
|
|
|
|
return 500
|
|
|
|
|
}
|
|
|
|
|
r := int(rlim.Cur)
|
|
|
|
|
if r > 500 {
|
|
|
|
|
r = 500
|
|
|
|
|
} else if r > 30 {
|
|
|
|
|
r -= 30
|
|
|
|
|
}
|
|
|
|
|
return r
|
|
|
|
|
}
|