2013-08-13 10:44:12 -06:00
|
|
|
// Copyright 2013 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2014-04-30 08:26:07 -06:00
|
|
|
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
|
2013-08-13 14:44:57 -06:00
|
|
|
|
2013-08-13 10:44:12 -06:00
|
|
|
package net
|
|
|
|
|
|
|
|
import (
|
2016-04-14 18:47:25 -06:00
|
|
|
"context"
|
2017-06-08 14:19:28 -06:00
|
|
|
"errors"
|
2015-06-10 21:46:01 -06:00
|
|
|
"fmt"
|
2017-02-10 15:59:38 -07:00
|
|
|
"internal/poll"
|
2014-05-14 18:11:00 -06:00
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"path"
|
|
|
|
"reflect"
|
2015-06-10 21:46:01 -06:00
|
|
|
"strings"
|
|
|
|
"sync"
|
2013-08-13 10:44:12 -06:00
|
|
|
"testing"
|
2014-05-14 18:11:00 -06:00
|
|
|
"time"
|
2013-08-13 10:44:12 -06:00
|
|
|
)
|
|
|
|
|
2017-02-20 06:58:55 -07:00
|
|
|
var goResolver = Resolver{PreferGo: true}
|
|
|
|
|
2016-04-25 14:09:11 -06:00
|
|
|
// Test address from 192.0.2.0/24 block, reserved by RFC 5737 for documentation.
|
|
|
|
const TestAddr uint32 = 0xc0000201
|
|
|
|
|
2016-11-01 22:01:08 -06:00
|
|
|
// Test address from 2001:db8::/32 block, reserved by RFC 3849 for documentation.
|
|
|
|
var TestAddr6 = [16]byte{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
|
|
|
|
|
2014-08-05 18:58:47 -06:00
|
|
|
var dnsTransportFallbackTests = []struct {
|
|
|
|
server string
|
|
|
|
name string
|
|
|
|
qtype uint16
|
|
|
|
timeout int
|
|
|
|
rcode int
|
|
|
|
}{
|
|
|
|
// Querying "com." with qtype=255 usually makes an answer
|
|
|
|
// which requires more than 512 bytes.
|
|
|
|
{"8.8.8.8:53", "com.", dnsTypeALL, 2, dnsRcodeSuccess},
|
|
|
|
{"8.8.4.4:53", "com.", dnsTypeALL, 4, dnsRcodeSuccess},
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDNSTransportFallback(t *testing.T) {
|
2017-02-20 06:58:55 -07:00
|
|
|
fake := fakeDNSServer{
|
2017-06-08 14:19:28 -06:00
|
|
|
rh: func(n, _ string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
|
2017-02-20 06:58:55 -07:00
|
|
|
r := &dnsMsg{
|
|
|
|
dnsMsgHdr: dnsMsgHdr{
|
2017-06-08 14:19:28 -06:00
|
|
|
id: q.id,
|
|
|
|
response: true,
|
|
|
|
rcode: dnsRcodeSuccess,
|
2017-02-20 06:58:55 -07:00
|
|
|
},
|
2017-06-08 14:19:28 -06:00
|
|
|
question: q.question,
|
2017-02-20 06:58:55 -07:00
|
|
|
}
|
|
|
|
if n == "udp" {
|
|
|
|
r.truncated = true
|
|
|
|
}
|
|
|
|
return r, nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
r := Resolver{PreferGo: true, Dial: fake.DialContext}
|
2014-08-05 18:58:47 -06:00
|
|
|
for _, tt := range dnsTransportFallbackTests {
|
2016-08-29 14:53:32 -06:00
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
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 15:17:40 -06:00
|
|
|
defer cancel()
|
2017-02-20 06:58:55 -07:00
|
|
|
msg, err := r.exchange(ctx, tt.server, tt.name, tt.qtype, time.Second)
|
2014-08-05 18:58:47 -06:00
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
switch msg.rcode {
|
2017-02-20 06:58:55 -07:00
|
|
|
case tt.rcode:
|
2014-08-05 18:58:47 -06:00
|
|
|
default:
|
|
|
|
t.Errorf("got %v from %v; want %v", msg.rcode, tt.server, tt.rcode)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// See RFC 6761 for further information about the reserved, pseudo
|
|
|
|
// domain names.
|
|
|
|
var specialDomainNameTests = []struct {
|
|
|
|
name string
|
|
|
|
qtype uint16
|
|
|
|
rcode int
|
|
|
|
}{
|
2015-01-14 22:25:26 -07:00
|
|
|
// Name resolution APIs and libraries should not recognize the
|
2014-08-05 18:58:47 -06:00
|
|
|
// followings as special.
|
|
|
|
{"1.0.168.192.in-addr.arpa.", dnsTypePTR, dnsRcodeNameError},
|
|
|
|
{"test.", dnsTypeALL, dnsRcodeNameError},
|
|
|
|
{"example.com.", dnsTypeALL, dnsRcodeSuccess},
|
|
|
|
|
2015-01-14 22:25:26 -07:00
|
|
|
// Name resolution APIs and libraries should recognize the
|
2014-08-05 18:58:47 -06:00
|
|
|
// followings as special and should not send any queries.
|
2016-02-24 03:55:20 -07:00
|
|
|
// Though, we test those names here for verifying negative
|
2014-08-05 18:58:47 -06:00
|
|
|
// answers at DNS query-response interaction level.
|
|
|
|
{"localhost.", dnsTypeALL, dnsRcodeNameError},
|
|
|
|
{"invalid.", dnsTypeALL, dnsRcodeNameError},
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSpecialDomainName(t *testing.T) {
|
2017-02-20 06:58:55 -07:00
|
|
|
fake := fakeDNSServer{func(_, _ string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
|
|
|
|
r := &dnsMsg{
|
|
|
|
dnsMsgHdr: dnsMsgHdr{
|
2017-06-08 14:19:28 -06:00
|
|
|
id: q.id,
|
|
|
|
response: true,
|
2017-02-20 06:58:55 -07:00
|
|
|
},
|
2017-06-08 14:19:28 -06:00
|
|
|
question: q.question,
|
2017-02-20 06:58:55 -07:00
|
|
|
}
|
2014-08-05 18:58:47 -06:00
|
|
|
|
2017-02-20 06:58:55 -07:00
|
|
|
switch q.question[0].Name {
|
|
|
|
case "example.com.":
|
|
|
|
r.rcode = dnsRcodeSuccess
|
|
|
|
default:
|
|
|
|
r.rcode = dnsRcodeNameError
|
|
|
|
}
|
|
|
|
|
|
|
|
return r, nil
|
|
|
|
}}
|
|
|
|
r := Resolver{PreferGo: true, Dial: fake.DialContext}
|
2014-08-05 18:58:47 -06:00
|
|
|
server := "8.8.8.8:53"
|
|
|
|
for _, tt := range specialDomainNameTests {
|
2016-08-29 14:53:32 -06:00
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
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 15:17:40 -06:00
|
|
|
defer cancel()
|
2017-02-20 06:58:55 -07:00
|
|
|
msg, err := r.exchange(ctx, server, tt.name, tt.qtype, 3*time.Second)
|
2014-08-05 18:58:47 -06:00
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
switch msg.rcode {
|
|
|
|
case tt.rcode, dnsRcodeServerFailure:
|
|
|
|
default:
|
|
|
|
t.Errorf("got %v from %v; want %v", msg.rcode, server, tt.rcode)
|
|
|
|
continue
|
|
|
|
}
|
2013-08-13 10:44:12 -06:00
|
|
|
}
|
|
|
|
}
|
2014-05-14 18:11:00 -06:00
|
|
|
|
2016-03-31 00:08:44 -06:00
|
|
|
// Issue 13705: don't try to resolve onion addresses, etc
|
|
|
|
func TestAvoidDNSName(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
avoid bool
|
|
|
|
}{
|
|
|
|
{"foo.com", false},
|
|
|
|
{"foo.com.", false},
|
|
|
|
|
|
|
|
{"foo.onion.", true},
|
|
|
|
{"foo.onion", true},
|
|
|
|
{"foo.ONION", true},
|
|
|
|
{"foo.ONION.", true},
|
|
|
|
|
2016-08-17 03:13:03 -06:00
|
|
|
// But do resolve *.local address; Issue 16739
|
|
|
|
{"foo.local.", false},
|
|
|
|
{"foo.local", false},
|
|
|
|
{"foo.LOCAL", false},
|
|
|
|
{"foo.LOCAL.", false},
|
2016-03-31 00:08:44 -06:00
|
|
|
|
|
|
|
{"", true}, // will be rejected earlier too
|
|
|
|
|
|
|
|
// Without stuff before onion/local, they're fine to
|
|
|
|
// use DNS. With a search path,
|
|
|
|
// "onion.vegegtables.com" can use DNS. Without a
|
|
|
|
// search path (or with a trailing dot), the queries
|
|
|
|
// are just kinda useless, but don't reveal anything
|
|
|
|
// private.
|
|
|
|
{"local", false},
|
|
|
|
{"onion", false},
|
|
|
|
{"local.", false},
|
|
|
|
{"onion.", false},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
got := avoidDNS(tt.name)
|
|
|
|
if got != tt.avoid {
|
|
|
|
t.Errorf("avoidDNS(%q) = %v; want %v", tt.name, got, tt.avoid)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-20 06:58:55 -07:00
|
|
|
var fakeDNSServerSuccessful = fakeDNSServer{func(_, _ string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
|
|
|
|
r := &dnsMsg{
|
|
|
|
dnsMsgHdr: dnsMsgHdr{
|
|
|
|
id: q.id,
|
|
|
|
response: true,
|
|
|
|
},
|
|
|
|
question: q.question,
|
|
|
|
}
|
|
|
|
if len(q.question) == 1 && q.question[0].Qtype == dnsTypeA {
|
|
|
|
r.answer = []dnsRR{
|
|
|
|
&dnsRR_A{
|
|
|
|
Hdr: dnsRR_Header{
|
|
|
|
Name: q.question[0].Name,
|
|
|
|
Rrtype: dnsTypeA,
|
|
|
|
Class: dnsClassINET,
|
|
|
|
Rdlength: 4,
|
|
|
|
},
|
|
|
|
A: TestAddr,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r, nil
|
|
|
|
}}
|
|
|
|
|
2016-03-31 00:08:44 -06:00
|
|
|
// Issue 13705: don't try to resolve onion addresses, etc
|
|
|
|
func TestLookupTorOnion(t *testing.T) {
|
2017-02-20 06:58:55 -07:00
|
|
|
r := Resolver{PreferGo: true, Dial: fakeDNSServerSuccessful.DialContext}
|
|
|
|
addrs, err := r.LookupIPAddr(context.Background(), "foo.onion")
|
2016-03-31 00:08:44 -06:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("lookup = %v; want nil", err)
|
|
|
|
}
|
2017-02-20 06:58:55 -07:00
|
|
|
if len(addrs) > 0 {
|
|
|
|
t.Errorf("unexpected addresses: %v", addrs)
|
|
|
|
}
|
2016-03-31 00:08:44 -06:00
|
|
|
}
|
|
|
|
|
2014-05-14 18:11:00 -06:00
|
|
|
type resolvConfTest struct {
|
2015-05-12 21:56:56 -06:00
|
|
|
dir string
|
|
|
|
path string
|
2015-06-10 21:46:01 -06:00
|
|
|
*resolverConfig
|
2014-05-14 18:11:00 -06:00
|
|
|
}
|
|
|
|
|
2015-06-10 21:46:01 -06:00
|
|
|
func newResolvConfTest() (*resolvConfTest, error) {
|
2015-05-05 19:41:01 -06:00
|
|
|
dir, err := ioutil.TempDir("", "go-resolvconftest")
|
2014-05-14 18:11:00 -06:00
|
|
|
if err != nil {
|
2015-06-10 21:46:01 -06:00
|
|
|
return nil, err
|
2014-05-14 18:11:00 -06:00
|
|
|
}
|
2015-06-10 21:46:01 -06:00
|
|
|
conf := &resolvConfTest{
|
|
|
|
dir: dir,
|
|
|
|
path: path.Join(dir, "resolv.conf"),
|
|
|
|
resolverConfig: &resolvConf,
|
2014-05-14 18:11:00 -06:00
|
|
|
}
|
2015-06-10 21:46:01 -06:00
|
|
|
conf.initOnce.Do(conf.init)
|
|
|
|
return conf, nil
|
2014-05-14 18:11:00 -06:00
|
|
|
}
|
|
|
|
|
2015-06-10 21:46:01 -06:00
|
|
|
func (conf *resolvConfTest) writeAndUpdate(lines []string) error {
|
|
|
|
f, err := os.OpenFile(conf.path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
|
2014-05-14 18:11:00 -06:00
|
|
|
if err != nil {
|
2015-06-10 21:46:01 -06:00
|
|
|
return err
|
2014-05-14 18:11:00 -06:00
|
|
|
}
|
2015-06-10 21:46:01 -06:00
|
|
|
if _, err := f.WriteString(strings.Join(lines, "\n")); err != nil {
|
2014-05-14 18:11:00 -06:00
|
|
|
f.Close()
|
2015-06-10 21:46:01 -06:00
|
|
|
return err
|
2014-05-14 18:11:00 -06:00
|
|
|
}
|
|
|
|
f.Close()
|
2016-02-20 21:33:34 -07:00
|
|
|
if err := conf.forceUpdate(conf.path, time.Now().Add(time.Hour)); err != nil {
|
2015-06-10 21:46:01 -06:00
|
|
|
return err
|
2014-05-14 18:11:00 -06:00
|
|
|
}
|
2015-06-10 21:46:01 -06:00
|
|
|
return nil
|
2014-05-14 18:11:00 -06:00
|
|
|
}
|
|
|
|
|
2016-02-20 21:33:34 -07:00
|
|
|
func (conf *resolvConfTest) forceUpdate(name string, lastChecked time.Time) error {
|
2015-06-10 21:46:01 -06:00
|
|
|
dnsConf := dnsReadConfig(name)
|
|
|
|
conf.mu.Lock()
|
|
|
|
conf.dnsConfig = dnsConf
|
|
|
|
conf.mu.Unlock()
|
|
|
|
for i := 0; i < 5; i++ {
|
|
|
|
if conf.tryAcquireSema() {
|
2016-02-20 21:33:34 -07:00
|
|
|
conf.lastChecked = lastChecked
|
2015-06-10 21:46:01 -06:00
|
|
|
conf.releaseSema()
|
|
|
|
return nil
|
|
|
|
}
|
2014-05-14 18:11:00 -06:00
|
|
|
}
|
2015-06-10 21:46:01 -06:00
|
|
|
return fmt.Errorf("tryAcquireSema for %s failed", name)
|
2014-05-14 18:11:00 -06:00
|
|
|
}
|
|
|
|
|
2015-06-10 21:46:01 -06:00
|
|
|
func (conf *resolvConfTest) servers() []string {
|
|
|
|
conf.mu.RLock()
|
|
|
|
servers := conf.dnsConfig.servers
|
|
|
|
conf.mu.RUnlock()
|
|
|
|
return servers
|
|
|
|
}
|
2015-04-25 18:50:21 -06:00
|
|
|
|
2015-06-10 21:46:01 -06:00
|
|
|
func (conf *resolvConfTest) teardown() error {
|
2016-02-20 21:33:34 -07:00
|
|
|
err := conf.forceUpdate("/etc/resolv.conf", time.Time{})
|
2015-06-10 21:46:01 -06:00
|
|
|
os.RemoveAll(conf.dir)
|
|
|
|
return err
|
|
|
|
}
|
2015-04-25 18:50:21 -06:00
|
|
|
|
2015-06-10 21:46:01 -06:00
|
|
|
var updateResolvConfTests = []struct {
|
|
|
|
name string // query name
|
|
|
|
lines []string // resolver configuration lines
|
|
|
|
servers []string // expected name servers
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "golang.org",
|
|
|
|
lines: []string{"nameserver 8.8.8.8"},
|
2016-04-28 12:15:44 -06:00
|
|
|
servers: []string{"8.8.8.8:53"},
|
2015-06-10 21:46:01 -06:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "",
|
|
|
|
lines: nil, // an empty resolv.conf should use defaultNS as name servers
|
|
|
|
servers: defaultNS,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "www.example.com",
|
|
|
|
lines: []string{"nameserver 8.8.4.4"},
|
2016-04-28 12:15:44 -06:00
|
|
|
servers: []string{"8.8.4.4:53"},
|
2015-06-10 21:46:01 -06:00
|
|
|
},
|
2014-05-14 18:11:00 -06:00
|
|
|
}
|
|
|
|
|
2015-06-10 21:46:01 -06:00
|
|
|
func TestUpdateResolvConf(t *testing.T) {
|
2017-02-20 06:58:55 -07:00
|
|
|
r := Resolver{PreferGo: true, Dial: fakeDNSServerSuccessful.DialContext}
|
2014-05-14 18:11:00 -06:00
|
|
|
|
2015-06-10 21:46:01 -06:00
|
|
|
conf, err := newResolvConfTest()
|
|
|
|
if err != nil {
|
2015-04-30 21:38:42 -06:00
|
|
|
t.Fatal(err)
|
2014-05-14 18:11:00 -06:00
|
|
|
}
|
2015-06-10 21:46:01 -06:00
|
|
|
defer conf.teardown()
|
2014-05-14 18:11:00 -06:00
|
|
|
|
2015-06-10 21:46:01 -06:00
|
|
|
for i, tt := range updateResolvConfTests {
|
|
|
|
if err := conf.writeAndUpdate(tt.lines); err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if tt.name != "" {
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
const N = 10
|
|
|
|
wg.Add(N)
|
|
|
|
for j := 0; j < N; j++ {
|
|
|
|
go func(name string) {
|
|
|
|
defer wg.Done()
|
2017-02-20 06:58:55 -07:00
|
|
|
ips, err := r.LookupIPAddr(context.Background(), name)
|
2015-06-10 21:46:01 -06:00
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if len(ips) == 0 {
|
|
|
|
t.Errorf("no records for %s", name)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}(tt.name)
|
|
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
}
|
|
|
|
servers := conf.servers()
|
|
|
|
if !reflect.DeepEqual(servers, tt.servers) {
|
|
|
|
t.Errorf("#%d: got %v; want %v", i, servers, tt.servers)
|
|
|
|
continue
|
2015-04-25 18:50:21 -06:00
|
|
|
}
|
2014-05-14 18:11:00 -06:00
|
|
|
}
|
|
|
|
}
|
2014-08-29 16:50:50 -06:00
|
|
|
|
2015-06-09 02:30:00 -06:00
|
|
|
var goLookupIPWithResolverConfigTests = []struct {
|
|
|
|
name string
|
|
|
|
lines []string // resolver configuration lines
|
|
|
|
error
|
|
|
|
a, aaaa bool // whether response contains A, AAAA-record
|
|
|
|
}{
|
|
|
|
// no records, transport timeout
|
|
|
|
{
|
|
|
|
"jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j",
|
|
|
|
[]string{
|
|
|
|
"options timeout:1 attempts:1",
|
|
|
|
"nameserver 255.255.255.255", // please forgive us for abuse of limited broadcast address
|
|
|
|
},
|
|
|
|
&DNSError{Name: "jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j", Server: "255.255.255.255:53", IsTimeout: true},
|
|
|
|
false, false,
|
|
|
|
},
|
|
|
|
|
|
|
|
// no records, non-existent domain
|
|
|
|
{
|
|
|
|
"jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j",
|
|
|
|
[]string{
|
|
|
|
"options timeout:3 attempts:1",
|
|
|
|
"nameserver 8.8.8.8",
|
|
|
|
},
|
|
|
|
&DNSError{Name: "jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j", Server: "8.8.8.8:53", IsTimeout: false},
|
|
|
|
false, false,
|
|
|
|
},
|
|
|
|
|
|
|
|
// a few A records, no AAAA records
|
|
|
|
{
|
|
|
|
"ipv4.google.com.",
|
|
|
|
[]string{
|
|
|
|
"nameserver 8.8.8.8",
|
|
|
|
"nameserver 2001:4860:4860::8888",
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
true, false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"ipv4.google.com",
|
|
|
|
[]string{
|
|
|
|
"domain golang.org",
|
|
|
|
"nameserver 2001:4860:4860::8888",
|
|
|
|
"nameserver 8.8.8.8",
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
true, false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"ipv4.google.com",
|
|
|
|
[]string{
|
|
|
|
"search x.golang.org y.golang.org",
|
|
|
|
"nameserver 2001:4860:4860::8888",
|
|
|
|
"nameserver 8.8.8.8",
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
true, false,
|
|
|
|
},
|
|
|
|
|
|
|
|
// no A records, a few AAAA records
|
|
|
|
{
|
|
|
|
"ipv6.google.com.",
|
|
|
|
[]string{
|
|
|
|
"nameserver 2001:4860:4860::8888",
|
|
|
|
"nameserver 8.8.8.8",
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
false, true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"ipv6.google.com",
|
|
|
|
[]string{
|
|
|
|
"domain golang.org",
|
|
|
|
"nameserver 8.8.8.8",
|
|
|
|
"nameserver 2001:4860:4860::8888",
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
false, true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"ipv6.google.com",
|
|
|
|
[]string{
|
|
|
|
"search x.golang.org y.golang.org",
|
|
|
|
"nameserver 8.8.8.8",
|
|
|
|
"nameserver 2001:4860:4860::8888",
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
false, true,
|
|
|
|
},
|
|
|
|
|
|
|
|
// both A and AAAA records
|
|
|
|
{
|
|
|
|
"hostname.as112.net", // see RFC 7534
|
|
|
|
[]string{
|
|
|
|
"domain golang.org",
|
|
|
|
"nameserver 2001:4860:4860::8888",
|
|
|
|
"nameserver 8.8.8.8",
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
true, true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"hostname.as112.net", // see RFC 7534
|
|
|
|
[]string{
|
|
|
|
"search x.golang.org y.golang.org",
|
|
|
|
"nameserver 2001:4860:4860::8888",
|
|
|
|
"nameserver 8.8.8.8",
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
true, true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGoLookupIPWithResolverConfig(t *testing.T) {
|
2017-02-20 06:58:55 -07:00
|
|
|
fake := fakeDNSServer{func(n, s string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
|
|
|
|
switch s {
|
|
|
|
case "[2001:4860:4860::8888]:53", "8.8.8.8:53":
|
|
|
|
break
|
|
|
|
default:
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
return nil, poll.ErrTimeout
|
|
|
|
}
|
|
|
|
r := &dnsMsg{
|
|
|
|
dnsMsgHdr: dnsMsgHdr{
|
|
|
|
id: q.id,
|
|
|
|
response: true,
|
|
|
|
},
|
|
|
|
question: q.question,
|
|
|
|
}
|
|
|
|
for _, question := range q.question {
|
|
|
|
switch question.Qtype {
|
|
|
|
case dnsTypeA:
|
|
|
|
switch question.Name {
|
|
|
|
case "hostname.as112.net.":
|
|
|
|
break
|
|
|
|
case "ipv4.google.com.":
|
|
|
|
r.answer = append(r.answer, &dnsRR_A{
|
|
|
|
Hdr: dnsRR_Header{
|
|
|
|
Name: q.question[0].Name,
|
|
|
|
Rrtype: dnsTypeA,
|
|
|
|
Class: dnsClassINET,
|
|
|
|
Rdlength: 4,
|
|
|
|
},
|
|
|
|
A: TestAddr,
|
|
|
|
})
|
|
|
|
default:
|
|
|
|
|
|
|
|
}
|
|
|
|
case dnsTypeAAAA:
|
|
|
|
switch question.Name {
|
|
|
|
case "hostname.as112.net.":
|
|
|
|
break
|
|
|
|
case "ipv6.google.com.":
|
|
|
|
r.answer = append(r.answer, &dnsRR_AAAA{
|
|
|
|
Hdr: dnsRR_Header{
|
|
|
|
Name: q.question[0].Name,
|
|
|
|
Rrtype: dnsTypeAAAA,
|
|
|
|
Class: dnsClassINET,
|
|
|
|
Rdlength: 16,
|
|
|
|
},
|
|
|
|
AAAA: TestAddr6,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r, nil
|
|
|
|
}}
|
|
|
|
r := Resolver{PreferGo: true, Dial: fake.DialContext}
|
2015-06-09 02:30:00 -06:00
|
|
|
|
|
|
|
conf, err := newResolvConfTest()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer conf.teardown()
|
|
|
|
|
|
|
|
for _, tt := range goLookupIPWithResolverConfigTests {
|
|
|
|
if err := conf.writeAndUpdate(tt.lines); err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
continue
|
|
|
|
}
|
2017-02-20 06:58:55 -07:00
|
|
|
addrs, err := r.LookupIPAddr(context.Background(), tt.name)
|
2015-06-09 02:30:00 -06:00
|
|
|
if err != nil {
|
2016-02-23 19:59:49 -07:00
|
|
|
if err, ok := err.(*DNSError); !ok || tt.error != nil && (err.Name != tt.error.(*DNSError).Name || err.Server != tt.error.(*DNSError).Server || err.IsTimeout != tt.error.(*DNSError).IsTimeout) {
|
2015-06-09 02:30:00 -06:00
|
|
|
t.Errorf("got %v; want %v", err, tt.error)
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if len(addrs) == 0 {
|
|
|
|
t.Errorf("no records for %s", tt.name)
|
|
|
|
}
|
|
|
|
if !tt.a && !tt.aaaa && len(addrs) > 0 {
|
|
|
|
t.Errorf("unexpected %v for %s", addrs, tt.name)
|
|
|
|
}
|
|
|
|
for _, addr := range addrs {
|
|
|
|
if !tt.a && addr.IP.To4() != nil {
|
|
|
|
t.Errorf("got %v; must not be IPv4 address", addr)
|
|
|
|
}
|
|
|
|
if !tt.aaaa && addr.IP.To16() != nil && addr.IP.To4() == nil {
|
|
|
|
t.Errorf("got %v; must not be IPv6 address", addr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-29 22:08:46 -07:00
|
|
|
// Test that goLookupIPOrder falls back to the host file when no DNS servers are available.
|
|
|
|
func TestGoLookupIPOrderFallbackToFile(t *testing.T) {
|
2017-02-20 06:58:55 -07:00
|
|
|
fake := fakeDNSServer{func(n, s string, q *dnsMsg, tm time.Time) (*dnsMsg, error) {
|
|
|
|
r := &dnsMsg{
|
|
|
|
dnsMsgHdr: dnsMsgHdr{
|
|
|
|
id: q.id,
|
|
|
|
response: true,
|
|
|
|
},
|
|
|
|
question: q.question,
|
|
|
|
}
|
|
|
|
return r, nil
|
|
|
|
}}
|
|
|
|
r := Resolver{PreferGo: true, Dial: fake.DialContext}
|
2015-11-29 22:08:46 -07:00
|
|
|
|
|
|
|
// Add a config that simulates no dns servers being available.
|
|
|
|
conf, err := newResolvConfTest()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if err := conf.writeAndUpdate([]string{}); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
// Redirect host file lookups.
|
|
|
|
defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
|
|
|
|
testHookHostsPath = "testdata/hosts"
|
|
|
|
|
|
|
|
for _, order := range []hostLookupOrder{hostLookupFilesDNS, hostLookupDNSFiles} {
|
|
|
|
name := fmt.Sprintf("order %v", order)
|
|
|
|
|
2016-02-24 03:55:20 -07:00
|
|
|
// First ensure that we get an error when contacting a non-existent host.
|
2017-02-20 06:58:55 -07:00
|
|
|
_, _, err := r.goLookupIPCNAMEOrder(context.Background(), "notarealhost", order)
|
2015-11-29 22:08:46 -07:00
|
|
|
if err == nil {
|
|
|
|
t.Errorf("%s: expected error while looking up name not in hosts file", name)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now check that we get an address when the name appears in the hosts file.
|
2017-02-20 06:58:55 -07:00
|
|
|
addrs, _, err := r.goLookupIPCNAMEOrder(context.Background(), "thor", order) // entry is in "testdata/hosts"
|
2015-11-29 22:08:46 -07:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("%s: expected to successfully lookup host entry", name)
|
|
|
|
continue
|
|
|
|
}
|
2015-12-01 20:02:04 -07:00
|
|
|
if len(addrs) != 1 {
|
|
|
|
t.Errorf("%s: expected exactly one result, but got %v", name, addrs)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if got, want := addrs[0].String(), "127.1.1.1"; got != want {
|
2015-11-29 22:08:46 -07:00
|
|
|
t.Errorf("%s: address doesn't match expectation. got %v, want %v", name, got, want)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
defer conf.teardown()
|
|
|
|
}
|
|
|
|
|
2015-11-19 12:24:42 -07:00
|
|
|
// Issue 12712.
|
|
|
|
// When using search domains, return the error encountered
|
|
|
|
// querying the original name instead of an error encountered
|
|
|
|
// querying a generated name.
|
|
|
|
func TestErrorForOriginalNameWhenSearching(t *testing.T) {
|
|
|
|
const fqdn = "doesnotexist.domain"
|
|
|
|
|
|
|
|
conf, err := newResolvConfTest()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer conf.teardown()
|
|
|
|
|
|
|
|
if err := conf.writeAndUpdate([]string{"search servfail"}); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2017-02-20 06:58:55 -07:00
|
|
|
fake := fakeDNSServer{func(_, _ string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
|
2015-11-19 12:24:42 -07:00
|
|
|
r := &dnsMsg{
|
|
|
|
dnsMsgHdr: dnsMsgHdr{
|
2017-06-08 14:19:28 -06:00
|
|
|
id: q.id,
|
|
|
|
response: true,
|
2015-11-19 12:24:42 -07:00
|
|
|
},
|
2017-06-08 14:19:28 -06:00
|
|
|
question: q.question,
|
2015-11-19 12:24:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
switch q.question[0].Name {
|
|
|
|
case fqdn + ".servfail.":
|
|
|
|
r.rcode = dnsRcodeServerFailure
|
|
|
|
default:
|
|
|
|
r.rcode = dnsRcodeNameError
|
|
|
|
}
|
|
|
|
|
|
|
|
return r, nil
|
2017-02-20 06:58:55 -07:00
|
|
|
}}
|
2015-11-19 12:24:42 -07:00
|
|
|
|
2016-11-01 22:01:08 -06:00
|
|
|
cases := []struct {
|
|
|
|
strictErrors bool
|
|
|
|
wantErr *DNSError
|
|
|
|
}{
|
|
|
|
{true, &DNSError{Name: fqdn, Err: "server misbehaving", IsTemporary: true}},
|
|
|
|
{false, &DNSError{Name: fqdn, Err: errNoSuchHost.Error()}},
|
2015-11-19 12:24:42 -07:00
|
|
|
}
|
2016-11-01 22:01:08 -06:00
|
|
|
for _, tt := range cases {
|
2017-02-20 06:58:55 -07:00
|
|
|
r := Resolver{PreferGo: true, StrictErrors: tt.strictErrors, Dial: fake.DialContext}
|
|
|
|
_, err = r.LookupIPAddr(context.Background(), fqdn)
|
2016-11-01 22:01:08 -06:00
|
|
|
if err == nil {
|
|
|
|
t.Fatal("expected an error")
|
|
|
|
}
|
2015-11-19 12:24:42 -07:00
|
|
|
|
2016-11-01 22:01:08 -06:00
|
|
|
want := tt.wantErr
|
|
|
|
if err, ok := err.(*DNSError); !ok || err.Name != want.Name || err.Err != want.Err || err.IsTemporary != want.IsTemporary {
|
|
|
|
t.Errorf("got %v; want %v", err, want)
|
|
|
|
}
|
2015-11-19 12:24:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-25 14:09:11 -06:00
|
|
|
// Issue 15434. If a name server gives a lame referral, continue to the next.
|
|
|
|
func TestIgnoreLameReferrals(t *testing.T) {
|
|
|
|
conf, err := newResolvConfTest()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer conf.teardown()
|
|
|
|
|
2016-08-29 14:53:32 -06:00
|
|
|
if err := conf.writeAndUpdate([]string{"nameserver 192.0.2.1", // the one that will give a lame referral
|
|
|
|
"nameserver 192.0.2.2"}); err != nil {
|
2016-04-25 14:09:11 -06:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2017-02-20 06:58:55 -07:00
|
|
|
fake := fakeDNSServer{func(_, s string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
|
2016-04-25 14:09:11 -06:00
|
|
|
t.Log(s, q)
|
|
|
|
r := &dnsMsg{
|
|
|
|
dnsMsgHdr: dnsMsgHdr{
|
|
|
|
id: q.id,
|
|
|
|
response: true,
|
|
|
|
},
|
|
|
|
question: q.question,
|
|
|
|
}
|
|
|
|
|
|
|
|
if s == "192.0.2.2:53" {
|
|
|
|
r.recursion_available = true
|
|
|
|
if q.question[0].Qtype == dnsTypeA {
|
|
|
|
r.answer = []dnsRR{
|
|
|
|
&dnsRR_A{
|
|
|
|
Hdr: dnsRR_Header{
|
|
|
|
Name: q.question[0].Name,
|
|
|
|
Rrtype: dnsTypeA,
|
|
|
|
Class: dnsClassINET,
|
|
|
|
Rdlength: 4,
|
|
|
|
},
|
|
|
|
A: TestAddr,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return r, nil
|
2017-02-20 06:58:55 -07:00
|
|
|
}}
|
|
|
|
r := Resolver{PreferGo: true, Dial: fake.DialContext}
|
2016-04-25 14:09:11 -06:00
|
|
|
|
2017-02-20 06:58:55 -07:00
|
|
|
addrs, err := r.LookupIPAddr(context.Background(), "www.golang.org")
|
2016-04-25 14:09:11 -06:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if got := len(addrs); got != 1 {
|
2016-05-10 22:04:22 -06:00
|
|
|
t.Fatalf("got %d addresses, want 1", got)
|
2016-04-25 14:09:11 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if got, want := addrs[0].String(), "192.0.2.1"; got != want {
|
2016-05-10 22:04:22 -06:00
|
|
|
t.Fatalf("got address %v, want %v", got, want)
|
2016-04-25 14:09:11 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-29 22:12:28 -06:00
|
|
|
func BenchmarkGoLookupIP(b *testing.B) {
|
2015-05-13 18:25:24 -06:00
|
|
|
testHookUninstaller.Do(uninstallTestHooks)
|
2016-04-14 18:47:25 -06:00
|
|
|
ctx := context.Background()
|
net: add socket system call hooks for testing
This change adds socket system call hooks to existing test cases for
simulating a bit complicated network conditions to help making timeout
and dual IP stack test cases work more properly in followup changes.
Also test cases print debugging information in non-short mode like the
following:
Leaked goroutines:
net.TestWriteTimeout.func2(0xc20802a5a0, 0xc20801d000, 0x1000, 0x1000, 0xc2081d2ae0)
/go/src/net/timeout_test.go:170 +0x98
created by net.TestWriteTimeout
/go/src/net/timeout_test.go:173 +0x745
net.runDatagramPacketConnServer(0xc2080730e0, 0x2bd270, 0x3, 0x2c1770, 0xb, 0xc2081d2ba0, 0xc2081d2c00)
/go/src/net/server_test.go:398 +0x667
created by net.TestTimeoutUDP
/go/src/net/timeout_test.go:247 +0xc9
(snip)
Leaked sockets:
3: {Cookie:615726511685632 Err:<nil> SocketErr:0}
5: {Cookie:7934075906097152 Err:<nil> SocketErr:0}
Socket statistical information:
{Family:1 Type:805306370 Protocol:0 Opened:17 Accepted:0 Connected:5 Closed:17}
{Family:2 Type:805306369 Protocol:0 Opened:450 Accepted:234 Connected:279 Closed:636}
{Family:1 Type:805306369 Protocol:0 Opened:11 Accepted:5 Connected:5 Closed:16}
{Family:28 Type:805306369 Protocol:0 Opened:95 Accepted:22 Connected:16 Closed:116}
{Family:2 Type:805306370 Protocol:0 Opened:84 Accepted:0 Connected:34 Closed:83}
{Family:28 Type:805306370 Protocol:0 Opened:52 Accepted:0 Connected:4 Closed:52}
Change-Id: I0e84be59a0699bc31245c78e2249423459b8cdda
Reviewed-on: https://go-review.googlesource.com/6390
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2015-02-28 20:27:01 -07:00
|
|
|
|
2014-08-29 22:12:28 -06:00
|
|
|
for i := 0; i < b.N; i++ {
|
2017-02-20 06:58:55 -07:00
|
|
|
goResolver.LookupIPAddr(ctx, "www.example.com")
|
2014-08-29 22:12:28 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-29 16:50:50 -06:00
|
|
|
func BenchmarkGoLookupIPNoSuchHost(b *testing.B) {
|
2015-05-13 18:25:24 -06:00
|
|
|
testHookUninstaller.Do(uninstallTestHooks)
|
2016-04-14 18:47:25 -06:00
|
|
|
ctx := context.Background()
|
net: add socket system call hooks for testing
This change adds socket system call hooks to existing test cases for
simulating a bit complicated network conditions to help making timeout
and dual IP stack test cases work more properly in followup changes.
Also test cases print debugging information in non-short mode like the
following:
Leaked goroutines:
net.TestWriteTimeout.func2(0xc20802a5a0, 0xc20801d000, 0x1000, 0x1000, 0xc2081d2ae0)
/go/src/net/timeout_test.go:170 +0x98
created by net.TestWriteTimeout
/go/src/net/timeout_test.go:173 +0x745
net.runDatagramPacketConnServer(0xc2080730e0, 0x2bd270, 0x3, 0x2c1770, 0xb, 0xc2081d2ba0, 0xc2081d2c00)
/go/src/net/server_test.go:398 +0x667
created by net.TestTimeoutUDP
/go/src/net/timeout_test.go:247 +0xc9
(snip)
Leaked sockets:
3: {Cookie:615726511685632 Err:<nil> SocketErr:0}
5: {Cookie:7934075906097152 Err:<nil> SocketErr:0}
Socket statistical information:
{Family:1 Type:805306370 Protocol:0 Opened:17 Accepted:0 Connected:5 Closed:17}
{Family:2 Type:805306369 Protocol:0 Opened:450 Accepted:234 Connected:279 Closed:636}
{Family:1 Type:805306369 Protocol:0 Opened:11 Accepted:5 Connected:5 Closed:16}
{Family:28 Type:805306369 Protocol:0 Opened:95 Accepted:22 Connected:16 Closed:116}
{Family:2 Type:805306370 Protocol:0 Opened:84 Accepted:0 Connected:34 Closed:83}
{Family:28 Type:805306370 Protocol:0 Opened:52 Accepted:0 Connected:4 Closed:52}
Change-Id: I0e84be59a0699bc31245c78e2249423459b8cdda
Reviewed-on: https://go-review.googlesource.com/6390
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2015-02-28 20:27:01 -07:00
|
|
|
|
2014-08-29 16:50:50 -06:00
|
|
|
for i := 0; i < b.N; i++ {
|
2017-02-20 06:58:55 -07:00
|
|
|
goResolver.LookupIPAddr(ctx, "some.nonexistent")
|
2014-08-29 16:50:50 -06:00
|
|
|
}
|
|
|
|
}
|
2014-08-29 22:12:28 -06:00
|
|
|
|
|
|
|
func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) {
|
2015-05-13 18:25:24 -06:00
|
|
|
testHookUninstaller.Do(uninstallTestHooks)
|
net: add socket system call hooks for testing
This change adds socket system call hooks to existing test cases for
simulating a bit complicated network conditions to help making timeout
and dual IP stack test cases work more properly in followup changes.
Also test cases print debugging information in non-short mode like the
following:
Leaked goroutines:
net.TestWriteTimeout.func2(0xc20802a5a0, 0xc20801d000, 0x1000, 0x1000, 0xc2081d2ae0)
/go/src/net/timeout_test.go:170 +0x98
created by net.TestWriteTimeout
/go/src/net/timeout_test.go:173 +0x745
net.runDatagramPacketConnServer(0xc2080730e0, 0x2bd270, 0x3, 0x2c1770, 0xb, 0xc2081d2ba0, 0xc2081d2c00)
/go/src/net/server_test.go:398 +0x667
created by net.TestTimeoutUDP
/go/src/net/timeout_test.go:247 +0xc9
(snip)
Leaked sockets:
3: {Cookie:615726511685632 Err:<nil> SocketErr:0}
5: {Cookie:7934075906097152 Err:<nil> SocketErr:0}
Socket statistical information:
{Family:1 Type:805306370 Protocol:0 Opened:17 Accepted:0 Connected:5 Closed:17}
{Family:2 Type:805306369 Protocol:0 Opened:450 Accepted:234 Connected:279 Closed:636}
{Family:1 Type:805306369 Protocol:0 Opened:11 Accepted:5 Connected:5 Closed:16}
{Family:28 Type:805306369 Protocol:0 Opened:95 Accepted:22 Connected:16 Closed:116}
{Family:2 Type:805306370 Protocol:0 Opened:84 Accepted:0 Connected:34 Closed:83}
{Family:28 Type:805306370 Protocol:0 Opened:52 Accepted:0 Connected:4 Closed:52}
Change-Id: I0e84be59a0699bc31245c78e2249423459b8cdda
Reviewed-on: https://go-review.googlesource.com/6390
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2015-02-28 20:27:01 -07:00
|
|
|
|
2015-06-10 21:46:01 -06:00
|
|
|
conf, err := newResolvConfTest()
|
|
|
|
if err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
defer conf.teardown()
|
|
|
|
|
|
|
|
lines := []string{
|
|
|
|
"nameserver 203.0.113.254", // use TEST-NET-3 block, see RFC 5737
|
|
|
|
"nameserver 8.8.8.8",
|
|
|
|
}
|
|
|
|
if err := conf.writeAndUpdate(lines); err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
2016-04-14 18:47:25 -06:00
|
|
|
ctx := context.Background()
|
2015-06-10 21:46:01 -06:00
|
|
|
|
2014-08-29 22:12:28 -06:00
|
|
|
for i := 0; i < b.N; i++ {
|
2017-02-20 06:58:55 -07:00
|
|
|
goResolver.LookupIPAddr(ctx, "www.example.com")
|
2014-08-29 22:12:28 -06:00
|
|
|
}
|
|
|
|
}
|
2015-11-19 12:24:42 -07:00
|
|
|
|
2017-02-20 06:58:55 -07:00
|
|
|
type fakeDNSServer struct {
|
|
|
|
rh func(n, s string, q *dnsMsg, t time.Time) (*dnsMsg, error)
|
2015-11-19 12:24:42 -07:00
|
|
|
}
|
|
|
|
|
2017-02-20 06:58:55 -07:00
|
|
|
func (server *fakeDNSServer) DialContext(_ context.Context, n, s string) (Conn, error) {
|
2017-06-08 14:19:28 -06:00
|
|
|
return &fakeDNSConn{nil, server, n, s, nil, time.Time{}}, nil
|
2016-04-25 14:09:11 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
type fakeDNSConn struct {
|
2017-02-20 06:58:55 -07:00
|
|
|
Conn
|
|
|
|
server *fakeDNSServer
|
|
|
|
n string
|
|
|
|
s string
|
2017-06-08 14:19:28 -06:00
|
|
|
q *dnsMsg
|
2017-02-20 06:58:55 -07:00
|
|
|
t time.Time
|
2015-11-19 12:24:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeDNSConn) Close() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-06-08 14:19:28 -06:00
|
|
|
func (f *fakeDNSConn) Read(b []byte) (int, error) {
|
|
|
|
resp, err := f.server.rh(f.n, f.s, f.q, f.t)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
bb, ok := resp.Pack()
|
|
|
|
if !ok {
|
|
|
|
return 0, errors.New("cannot marshal DNS message")
|
|
|
|
}
|
|
|
|
if len(b) < len(bb) {
|
|
|
|
return 0, errors.New("read would fragment DNS message")
|
|
|
|
}
|
|
|
|
|
|
|
|
copy(b, bb)
|
|
|
|
return len(bb), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeDNSConn) ReadFrom(b []byte) (int, Addr, error) {
|
|
|
|
return 0, nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeDNSConn) Write(b []byte) (int, error) {
|
|
|
|
f.q = new(dnsMsg)
|
|
|
|
if !f.q.Unpack(b) {
|
|
|
|
return 0, errors.New("cannot unmarshal DNS message")
|
|
|
|
}
|
|
|
|
return len(b), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeDNSConn) WriteTo(b []byte, addr Addr) (int, error) {
|
|
|
|
return 0, nil
|
|
|
|
}
|
|
|
|
|
2016-08-29 14:53:32 -06:00
|
|
|
func (f *fakeDNSConn) SetDeadline(t time.Time) error {
|
|
|
|
f.t = t
|
2015-11-19 12:24:42 -07:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-04-15 20:19:58 -06:00
|
|
|
// UDP round-tripper algorithm should ignore invalid DNS responses (issue 13281).
|
|
|
|
func TestIgnoreDNSForgeries(t *testing.T) {
|
|
|
|
c, s := Pipe()
|
|
|
|
go func() {
|
|
|
|
b := make([]byte, 512)
|
|
|
|
n, err := s.Read(b)
|
|
|
|
if err != nil {
|
2016-11-14 22:34:58 -07:00
|
|
|
t.Error(err)
|
|
|
|
return
|
2016-04-15 20:19:58 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
msg := &dnsMsg{}
|
|
|
|
if !msg.Unpack(b[:n]) {
|
2016-11-14 22:34:58 -07:00
|
|
|
t.Error("invalid DNS query")
|
|
|
|
return
|
2016-04-15 20:19:58 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
s.Write([]byte("garbage DNS response packet"))
|
|
|
|
|
|
|
|
msg.response = true
|
|
|
|
msg.id++ // make invalid ID
|
|
|
|
b, ok := msg.Pack()
|
|
|
|
if !ok {
|
2016-11-14 22:34:58 -07:00
|
|
|
t.Error("failed to pack DNS response")
|
|
|
|
return
|
2016-04-15 20:19:58 -06:00
|
|
|
}
|
|
|
|
s.Write(b)
|
|
|
|
|
|
|
|
msg.id-- // restore original ID
|
|
|
|
msg.answer = []dnsRR{
|
|
|
|
&dnsRR_A{
|
|
|
|
Hdr: dnsRR_Header{
|
|
|
|
Name: "www.example.com.",
|
|
|
|
Rrtype: dnsTypeA,
|
|
|
|
Class: dnsClassINET,
|
|
|
|
Rdlength: 4,
|
|
|
|
},
|
|
|
|
A: TestAddr,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
b, ok = msg.Pack()
|
|
|
|
if !ok {
|
2016-11-14 22:34:58 -07:00
|
|
|
t.Error("failed to pack DNS response")
|
|
|
|
return
|
2016-04-15 20:19:58 -06:00
|
|
|
}
|
|
|
|
s.Write(b)
|
|
|
|
}()
|
|
|
|
|
|
|
|
msg := &dnsMsg{
|
|
|
|
dnsMsgHdr: dnsMsgHdr{
|
|
|
|
id: 42,
|
|
|
|
},
|
|
|
|
question: []dnsQuestion{
|
|
|
|
{
|
|
|
|
Name: "www.example.com.",
|
|
|
|
Qtype: dnsTypeA,
|
|
|
|
Qclass: dnsClassINET,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2017-06-08 14:19:28 -06:00
|
|
|
dc := &dnsPacketConn{c}
|
|
|
|
resp, err := dc.dnsRoundTrip(msg)
|
2016-04-15 20:19:58 -06:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("dnsRoundTripUDP failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if got := resp.answer[0].(*dnsRR_A).A; got != TestAddr {
|
2016-05-10 22:04:22 -06:00
|
|
|
t.Errorf("got address %v, want %v", got, TestAddr)
|
2016-04-15 20:19:58 -06:00
|
|
|
}
|
2015-11-19 12:24:42 -07:00
|
|
|
}
|
2016-08-29 14:53:32 -06:00
|
|
|
|
|
|
|
// Issue 16865. If a name server times out, continue to the next.
|
|
|
|
func TestRetryTimeout(t *testing.T) {
|
|
|
|
conf, err := newResolvConfTest()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer conf.teardown()
|
|
|
|
|
2016-12-19 14:05:53 -07:00
|
|
|
testConf := []string{
|
|
|
|
"nameserver 192.0.2.1", // the one that will timeout
|
|
|
|
"nameserver 192.0.2.2",
|
|
|
|
}
|
|
|
|
if err := conf.writeAndUpdate(testConf); err != nil {
|
2016-08-29 14:53:32 -06:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var deadline0 time.Time
|
|
|
|
|
2017-02-20 06:58:55 -07:00
|
|
|
fake := fakeDNSServer{func(_, s string, q *dnsMsg, deadline time.Time) (*dnsMsg, error) {
|
2016-08-29 14:53:32 -06:00
|
|
|
t.Log(s, q, deadline)
|
|
|
|
|
|
|
|
if deadline.IsZero() {
|
|
|
|
t.Error("zero deadline")
|
|
|
|
}
|
|
|
|
|
|
|
|
if s == "192.0.2.1:53" {
|
|
|
|
deadline0 = deadline
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
2017-02-10 15:59:38 -07:00
|
|
|
return nil, poll.ErrTimeout
|
2016-08-29 14:53:32 -06:00
|
|
|
}
|
|
|
|
|
2017-05-04 09:05:33 -06:00
|
|
|
if deadline.Equal(deadline0) {
|
2016-08-29 14:53:32 -06:00
|
|
|
t.Error("deadline didn't change")
|
|
|
|
}
|
|
|
|
|
2016-12-19 14:05:53 -07:00
|
|
|
return mockTXTResponse(q), nil
|
2017-02-20 06:58:55 -07:00
|
|
|
}}
|
|
|
|
r := &Resolver{PreferGo: true, Dial: fake.DialContext}
|
2016-08-29 14:53:32 -06:00
|
|
|
|
2017-02-20 06:58:55 -07:00
|
|
|
_, err = r.LookupTXT(context.Background(), "www.golang.org")
|
2016-08-29 14:53:32 -06:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if deadline0.IsZero() {
|
|
|
|
t.Error("deadline0 still zero", deadline0)
|
|
|
|
}
|
|
|
|
}
|
2016-09-15 14:24:42 -06:00
|
|
|
|
|
|
|
func TestRotate(t *testing.T) {
|
|
|
|
// without rotation, always uses the first server
|
|
|
|
testRotate(t, false, []string{"192.0.2.1", "192.0.2.2"}, []string{"192.0.2.1:53", "192.0.2.1:53", "192.0.2.1:53"})
|
|
|
|
|
|
|
|
// with rotation, rotates through back to first
|
|
|
|
testRotate(t, true, []string{"192.0.2.1", "192.0.2.2"}, []string{"192.0.2.1:53", "192.0.2.2:53", "192.0.2.1:53"})
|
|
|
|
}
|
|
|
|
|
|
|
|
func testRotate(t *testing.T, rotate bool, nameservers, wantServers []string) {
|
|
|
|
conf, err := newResolvConfTest()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer conf.teardown()
|
|
|
|
|
|
|
|
var confLines []string
|
|
|
|
for _, ns := range nameservers {
|
|
|
|
confLines = append(confLines, "nameserver "+ns)
|
|
|
|
}
|
|
|
|
if rotate {
|
|
|
|
confLines = append(confLines, "options rotate")
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := conf.writeAndUpdate(confLines); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var usedServers []string
|
2017-02-20 06:58:55 -07:00
|
|
|
fake := fakeDNSServer{func(_, s string, q *dnsMsg, deadline time.Time) (*dnsMsg, error) {
|
2016-09-15 14:24:42 -06:00
|
|
|
usedServers = append(usedServers, s)
|
2016-12-19 14:05:53 -07:00
|
|
|
return mockTXTResponse(q), nil
|
2017-02-20 06:58:55 -07:00
|
|
|
}}
|
|
|
|
r := Resolver{PreferGo: true, Dial: fake.DialContext}
|
2016-09-15 14:24:42 -06:00
|
|
|
|
|
|
|
// len(nameservers) + 1 to allow rotation to get back to start
|
|
|
|
for i := 0; i < len(nameservers)+1; i++ {
|
2017-02-20 06:58:55 -07:00
|
|
|
if _, err := r.LookupTXT(context.Background(), "www.golang.org"); err != nil {
|
2016-09-15 14:24:42 -06:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(usedServers, wantServers) {
|
2016-12-19 14:05:53 -07:00
|
|
|
t.Errorf("rotate=%t got used servers:\n%v\nwant:\n%v", rotate, usedServers, wantServers)
|
2016-09-15 14:24:42 -06:00
|
|
|
}
|
|
|
|
}
|
2016-12-19 14:05:53 -07:00
|
|
|
|
|
|
|
func mockTXTResponse(q *dnsMsg) *dnsMsg {
|
|
|
|
r := &dnsMsg{
|
|
|
|
dnsMsgHdr: dnsMsgHdr{
|
|
|
|
id: q.id,
|
|
|
|
response: true,
|
|
|
|
recursion_available: true,
|
|
|
|
},
|
|
|
|
question: q.question,
|
|
|
|
answer: []dnsRR{
|
|
|
|
&dnsRR_TXT{
|
|
|
|
Hdr: dnsRR_Header{
|
|
|
|
Name: q.question[0].Name,
|
|
|
|
Rrtype: dnsTypeTXT,
|
|
|
|
Class: dnsClassINET,
|
|
|
|
},
|
|
|
|
Txt: "ok",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
return r
|
|
|
|
}
|
2016-11-01 22:01:08 -06:00
|
|
|
|
|
|
|
// Issue 17448. With StrictErrors enabled, temporary errors should make
|
|
|
|
// LookupIP fail rather than return a partial result.
|
|
|
|
func TestStrictErrorsLookupIP(t *testing.T) {
|
|
|
|
conf, err := newResolvConfTest()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer conf.teardown()
|
|
|
|
|
|
|
|
confData := []string{
|
|
|
|
"nameserver 192.0.2.53",
|
|
|
|
"search x.golang.org y.golang.org",
|
|
|
|
}
|
|
|
|
if err := conf.writeAndUpdate(confData); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2017-03-17 14:34:56 -06:00
|
|
|
const name = "test-issue19592"
|
2016-11-01 22:01:08 -06:00
|
|
|
const server = "192.0.2.53:53"
|
2017-03-17 14:34:56 -06:00
|
|
|
const searchX = "test-issue19592.x.golang.org."
|
|
|
|
const searchY = "test-issue19592.y.golang.org."
|
2016-11-01 22:01:08 -06:00
|
|
|
const ip4 = "192.0.2.1"
|
|
|
|
const ip6 = "2001:db8::1"
|
|
|
|
|
|
|
|
type resolveWhichEnum int
|
|
|
|
const (
|
|
|
|
resolveOK resolveWhichEnum = iota
|
|
|
|
resolveOpError
|
|
|
|
resolveServfail
|
|
|
|
resolveTimeout
|
|
|
|
)
|
|
|
|
|
|
|
|
makeTempError := func(err string) error {
|
|
|
|
return &DNSError{
|
|
|
|
Err: err,
|
|
|
|
Name: name,
|
|
|
|
Server: server,
|
|
|
|
IsTemporary: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
makeTimeout := func() error {
|
|
|
|
return &DNSError{
|
|
|
|
Err: poll.ErrTimeout.Error(),
|
|
|
|
Name: name,
|
|
|
|
Server: server,
|
|
|
|
IsTimeout: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
makeNxDomain := func() error {
|
|
|
|
return &DNSError{
|
|
|
|
Err: errNoSuchHost.Error(),
|
|
|
|
Name: name,
|
|
|
|
Server: server,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cases := []struct {
|
|
|
|
desc string
|
|
|
|
resolveWhich func(quest *dnsQuestion) resolveWhichEnum
|
|
|
|
wantStrictErr error
|
|
|
|
wantLaxErr error
|
|
|
|
wantIPs []string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
desc: "No errors",
|
|
|
|
resolveWhich: func(quest *dnsQuestion) resolveWhichEnum {
|
|
|
|
return resolveOK
|
|
|
|
},
|
|
|
|
wantIPs: []string{ip4, ip6},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "searchX error fails in strict mode",
|
|
|
|
resolveWhich: func(quest *dnsQuestion) resolveWhichEnum {
|
|
|
|
if quest.Name == searchX {
|
|
|
|
return resolveTimeout
|
|
|
|
}
|
|
|
|
return resolveOK
|
|
|
|
},
|
|
|
|
wantStrictErr: makeTimeout(),
|
|
|
|
wantIPs: []string{ip4, ip6},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "searchX IPv4-only timeout fails in strict mode",
|
|
|
|
resolveWhich: func(quest *dnsQuestion) resolveWhichEnum {
|
|
|
|
if quest.Name == searchX && quest.Qtype == dnsTypeA {
|
|
|
|
return resolveTimeout
|
|
|
|
}
|
|
|
|
return resolveOK
|
|
|
|
},
|
|
|
|
wantStrictErr: makeTimeout(),
|
|
|
|
wantIPs: []string{ip4, ip6},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "searchX IPv6-only servfail fails in strict mode",
|
|
|
|
resolveWhich: func(quest *dnsQuestion) resolveWhichEnum {
|
|
|
|
if quest.Name == searchX && quest.Qtype == dnsTypeAAAA {
|
|
|
|
return resolveServfail
|
|
|
|
}
|
|
|
|
return resolveOK
|
|
|
|
},
|
|
|
|
wantStrictErr: makeTempError("server misbehaving"),
|
|
|
|
wantIPs: []string{ip4, ip6},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "searchY error always fails",
|
|
|
|
resolveWhich: func(quest *dnsQuestion) resolveWhichEnum {
|
|
|
|
if quest.Name == searchY {
|
|
|
|
return resolveTimeout
|
|
|
|
}
|
|
|
|
return resolveOK
|
|
|
|
},
|
|
|
|
wantStrictErr: makeTimeout(),
|
|
|
|
wantLaxErr: makeNxDomain(), // This one reaches the "test." FQDN.
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "searchY IPv4-only socket error fails in strict mode",
|
|
|
|
resolveWhich: func(quest *dnsQuestion) resolveWhichEnum {
|
|
|
|
if quest.Name == searchY && quest.Qtype == dnsTypeA {
|
|
|
|
return resolveOpError
|
|
|
|
}
|
|
|
|
return resolveOK
|
|
|
|
},
|
|
|
|
wantStrictErr: makeTempError("write: socket on fire"),
|
|
|
|
wantIPs: []string{ip6},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "searchY IPv6-only timeout fails in strict mode",
|
|
|
|
resolveWhich: func(quest *dnsQuestion) resolveWhichEnum {
|
|
|
|
if quest.Name == searchY && quest.Qtype == dnsTypeAAAA {
|
|
|
|
return resolveTimeout
|
|
|
|
}
|
|
|
|
return resolveOK
|
|
|
|
},
|
|
|
|
wantStrictErr: makeTimeout(),
|
|
|
|
wantIPs: []string{ip4},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, tt := range cases {
|
2017-02-20 06:58:55 -07:00
|
|
|
fake := fakeDNSServer{func(_, s string, q *dnsMsg, deadline time.Time) (*dnsMsg, error) {
|
2016-11-01 22:01:08 -06:00
|
|
|
t.Log(s, q)
|
|
|
|
|
|
|
|
switch tt.resolveWhich(&q.question[0]) {
|
|
|
|
case resolveOK:
|
|
|
|
// Handle below.
|
|
|
|
case resolveOpError:
|
|
|
|
return nil, &OpError{Op: "write", Err: fmt.Errorf("socket on fire")}
|
|
|
|
case resolveServfail:
|
2017-06-08 14:19:28 -06:00
|
|
|
return &dnsMsg{
|
|
|
|
dnsMsgHdr: dnsMsgHdr{
|
|
|
|
id: q.id,
|
|
|
|
response: true,
|
|
|
|
rcode: dnsRcodeServerFailure,
|
|
|
|
},
|
|
|
|
question: q.question,
|
|
|
|
}, nil
|
2016-11-01 22:01:08 -06:00
|
|
|
case resolveTimeout:
|
|
|
|
return nil, poll.ErrTimeout
|
|
|
|
default:
|
|
|
|
t.Fatal("Impossible resolveWhich")
|
|
|
|
}
|
|
|
|
|
|
|
|
switch q.question[0].Name {
|
|
|
|
case searchX, name + ".":
|
|
|
|
// Return NXDOMAIN to utilize the search list.
|
2017-06-08 14:19:28 -06:00
|
|
|
return &dnsMsg{
|
|
|
|
dnsMsgHdr: dnsMsgHdr{
|
|
|
|
id: q.id,
|
|
|
|
response: true,
|
|
|
|
rcode: dnsRcodeNameError,
|
|
|
|
},
|
|
|
|
question: q.question,
|
|
|
|
}, nil
|
2016-11-01 22:01:08 -06:00
|
|
|
case searchY:
|
|
|
|
// Return records below.
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("Unexpected Name: %v", q.question[0].Name)
|
|
|
|
}
|
|
|
|
|
|
|
|
r := &dnsMsg{
|
|
|
|
dnsMsgHdr: dnsMsgHdr{
|
|
|
|
id: q.id,
|
|
|
|
response: true,
|
|
|
|
},
|
|
|
|
question: q.question,
|
|
|
|
}
|
|
|
|
switch q.question[0].Qtype {
|
|
|
|
case dnsTypeA:
|
|
|
|
r.answer = []dnsRR{
|
|
|
|
&dnsRR_A{
|
|
|
|
Hdr: dnsRR_Header{
|
|
|
|
Name: q.question[0].Name,
|
|
|
|
Rrtype: dnsTypeA,
|
|
|
|
Class: dnsClassINET,
|
|
|
|
Rdlength: 4,
|
|
|
|
},
|
|
|
|
A: TestAddr,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
case dnsTypeAAAA:
|
|
|
|
r.answer = []dnsRR{
|
|
|
|
&dnsRR_AAAA{
|
|
|
|
Hdr: dnsRR_Header{
|
|
|
|
Name: q.question[0].Name,
|
|
|
|
Rrtype: dnsTypeAAAA,
|
|
|
|
Class: dnsClassINET,
|
|
|
|
Rdlength: 16,
|
|
|
|
},
|
|
|
|
AAAA: TestAddr6,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("Unexpected Qtype: %v", q.question[0].Qtype)
|
|
|
|
}
|
|
|
|
return r, nil
|
2017-02-20 06:58:55 -07:00
|
|
|
}}
|
2016-11-01 22:01:08 -06:00
|
|
|
|
|
|
|
for _, strict := range []bool{true, false} {
|
2017-02-20 06:58:55 -07:00
|
|
|
r := Resolver{PreferGo: true, StrictErrors: strict, Dial: fake.DialContext}
|
|
|
|
ips, err := r.LookupIPAddr(context.Background(), name)
|
2016-11-01 22:01:08 -06:00
|
|
|
|
|
|
|
var wantErr error
|
|
|
|
if strict {
|
|
|
|
wantErr = tt.wantStrictErr
|
|
|
|
} else {
|
|
|
|
wantErr = tt.wantLaxErr
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(err, wantErr) {
|
|
|
|
t.Errorf("#%d (%s) strict=%v: got err %#v; want %#v", i, tt.desc, strict, err, wantErr)
|
|
|
|
}
|
|
|
|
|
|
|
|
gotIPs := map[string]struct{}{}
|
|
|
|
for _, ip := range ips {
|
|
|
|
gotIPs[ip.String()] = struct{}{}
|
|
|
|
}
|
|
|
|
wantIPs := map[string]struct{}{}
|
|
|
|
if wantErr == nil {
|
|
|
|
for _, ip := range tt.wantIPs {
|
|
|
|
wantIPs[ip] = struct{}{}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(gotIPs, wantIPs) {
|
|
|
|
t.Errorf("#%d (%s) strict=%v: got ips %v; want %v", i, tt.desc, strict, gotIPs, wantIPs)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Issue 17448. With StrictErrors enabled, temporary errors should make
|
|
|
|
// LookupTXT stop walking the search list.
|
|
|
|
func TestStrictErrorsLookupTXT(t *testing.T) {
|
|
|
|
conf, err := newResolvConfTest()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer conf.teardown()
|
|
|
|
|
|
|
|
confData := []string{
|
|
|
|
"nameserver 192.0.2.53",
|
|
|
|
"search x.golang.org y.golang.org",
|
|
|
|
}
|
|
|
|
if err := conf.writeAndUpdate(confData); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
const name = "test"
|
|
|
|
const server = "192.0.2.53:53"
|
|
|
|
const searchX = "test.x.golang.org."
|
|
|
|
const searchY = "test.y.golang.org."
|
|
|
|
const txt = "Hello World"
|
|
|
|
|
2017-02-20 06:58:55 -07:00
|
|
|
fake := fakeDNSServer{func(_, s string, q *dnsMsg, deadline time.Time) (*dnsMsg, error) {
|
2016-11-01 22:01:08 -06:00
|
|
|
t.Log(s, q)
|
|
|
|
|
|
|
|
switch q.question[0].Name {
|
|
|
|
case searchX:
|
|
|
|
return nil, poll.ErrTimeout
|
|
|
|
case searchY:
|
|
|
|
return mockTXTResponse(q), nil
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("Unexpected Name: %v", q.question[0].Name)
|
|
|
|
}
|
2017-02-20 06:58:55 -07:00
|
|
|
}}
|
2016-11-01 22:01:08 -06:00
|
|
|
|
|
|
|
for _, strict := range []bool{true, false} {
|
2017-02-20 06:58:55 -07:00
|
|
|
r := Resolver{StrictErrors: strict, Dial: fake.DialContext}
|
2016-11-01 22:01:08 -06:00
|
|
|
_, rrs, err := r.lookup(context.Background(), name, dnsTypeTXT)
|
|
|
|
var wantErr error
|
|
|
|
var wantRRs int
|
|
|
|
if strict {
|
|
|
|
wantErr = &DNSError{
|
|
|
|
Err: poll.ErrTimeout.Error(),
|
|
|
|
Name: name,
|
|
|
|
Server: server,
|
|
|
|
IsTimeout: true,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
wantRRs = 1
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(err, wantErr) {
|
|
|
|
t.Errorf("strict=%v: got err %#v; want %#v", strict, err, wantErr)
|
|
|
|
}
|
|
|
|
if len(rrs) != wantRRs {
|
|
|
|
t.Errorf("strict=%v: got %v; want %v", strict, len(rrs), wantRRs)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|