2011-07-04 18:18:51 +00:00
|
|
|
package dns
|
|
|
|
|
|
|
|
import (
|
2017-06-30 11:44:44 +00:00
|
|
|
"context"
|
2016-01-08 13:34:08 +00:00
|
|
|
"crypto/tls"
|
Ignore responses with unexpected IDs (#1155)
* Ignore replies with unexpected IDs
This fixes the following problem:
At time 0, we send a query with ID X from port P.
At time T, we time out the query due to lack of response, and then send
a different query with ID Y. By coincidence, the new query is sent from
the same port number P (since port numbers are only 16 bits, this can happen
with non-negligible probability when making queries at a high rate).
At time T+epsilon, we receive a response to the original query.
Since the ID in this response is X, not Y, we would previously return
ErrId, preventing the second query from succeeding.
With this commit, we simply ignore the response with the mismatched ID
and return once we receive the response with the correct ID.
* Update test for bad ID
The new test sends two replies: the first one has a bad ID, which should
be ignored, and the second one has the correct ID.
* Add test to ensure query times out when server returns bad ID
* Avoid use of error string matching in test case
* Check for mismatched query IDs when using TCP
* Reduce timeout in TestClientSyncBadID
2020-10-18 05:55:24 +00:00
|
|
|
"errors"
|
2015-11-01 20:46:57 +00:00
|
|
|
"fmt"
|
|
|
|
"net"
|
2021-12-28 13:52:38 +00:00
|
|
|
"path/filepath"
|
2015-03-18 19:12:53 +00:00
|
|
|
"strconv"
|
2017-11-08 10:01:19 +00:00
|
|
|
"strings"
|
2011-07-04 18:18:51 +00:00
|
|
|
"testing"
|
2011-07-23 21:43:43 +00:00
|
|
|
"time"
|
2011-07-04 18:18:51 +00:00
|
|
|
)
|
|
|
|
|
2021-12-28 13:52:38 +00:00
|
|
|
func TestIsPacketConn(t *testing.T) {
|
|
|
|
// UDP
|
|
|
|
s, addrstr, _, err := RunLocalUDPServer(":0")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to run test server: %v", err)
|
|
|
|
}
|
|
|
|
defer s.Shutdown()
|
|
|
|
c, err := net.Dial("udp", addrstr)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to dial: %v", err)
|
|
|
|
}
|
|
|
|
defer c.Close()
|
|
|
|
if !isPacketConn(c) {
|
|
|
|
t.Error("UDP connection should be a packet conn")
|
|
|
|
}
|
|
|
|
if !isPacketConn(struct{ *net.UDPConn }{c.(*net.UDPConn)}) {
|
|
|
|
t.Error("UDP connection (wrapped type) should be a packet conn")
|
|
|
|
}
|
|
|
|
|
|
|
|
// TCP
|
|
|
|
s, addrstr, _, err = RunLocalTCPServer(":0")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to run test server: %v", err)
|
|
|
|
}
|
|
|
|
defer s.Shutdown()
|
|
|
|
c, err = net.Dial("tcp", addrstr)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to dial: %v", err)
|
|
|
|
}
|
|
|
|
defer c.Close()
|
|
|
|
if isPacketConn(c) {
|
|
|
|
t.Error("TCP connection should not be a packet conn")
|
|
|
|
}
|
|
|
|
if isPacketConn(struct{ *net.TCPConn }{c.(*net.TCPConn)}) {
|
|
|
|
t.Error("TCP connection (wrapped type) should not be a packet conn")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unix datagram
|
|
|
|
s, addrstr, _, err = RunLocalUnixGramServer(filepath.Join(t.TempDir(), "unixgram.sock"))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to run test server: %v", err)
|
|
|
|
}
|
|
|
|
defer s.Shutdown()
|
|
|
|
c, err = net.Dial("unixgram", addrstr)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to dial: %v", err)
|
|
|
|
}
|
|
|
|
defer c.Close()
|
|
|
|
if !isPacketConn(c) {
|
|
|
|
t.Error("Unix datagram connection should be a packet conn")
|
|
|
|
}
|
|
|
|
if !isPacketConn(struct{ *net.UnixConn }{c.(*net.UnixConn)}) {
|
|
|
|
t.Error("Unix datagram connection (wrapped type) should be a packet conn")
|
|
|
|
}
|
|
|
|
|
2022-06-08 12:03:24 +00:00
|
|
|
// Unix Seqpacket
|
|
|
|
shutChan, addrstr, err := RunLocalUnixSeqPacketServer(filepath.Join(t.TempDir(), "unixpacket.sock"))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to run test server: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
shutChan <- &struct{}{}
|
|
|
|
}()
|
|
|
|
c, err = net.Dial("unixpacket", addrstr)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to dial: %v", err)
|
|
|
|
}
|
|
|
|
defer c.Close()
|
|
|
|
if !isPacketConn(c) {
|
|
|
|
t.Error("Unix datagram connection should be a packet conn")
|
|
|
|
}
|
|
|
|
if !isPacketConn(struct{ *net.UnixConn }{c.(*net.UnixConn)}) {
|
|
|
|
t.Error("Unix datagram connection (wrapped type) should be a packet conn")
|
|
|
|
}
|
|
|
|
|
2021-12-28 13:52:38 +00:00
|
|
|
// Unix stream
|
|
|
|
s, addrstr, _, err = RunLocalUnixServer(filepath.Join(t.TempDir(), "unixstream.sock"))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to run test server: %v", err)
|
|
|
|
}
|
|
|
|
defer s.Shutdown()
|
|
|
|
c, err = net.Dial("unix", addrstr)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to dial: %v", err)
|
|
|
|
}
|
|
|
|
defer c.Close()
|
|
|
|
if isPacketConn(c) {
|
|
|
|
t.Error("Unix stream connection should not be a packet conn")
|
|
|
|
}
|
|
|
|
if isPacketConn(struct{ *net.UnixConn }{c.(*net.UnixConn)}) {
|
|
|
|
t.Error("Unix stream connection (wrapped type) should not be a packet conn")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-29 09:52:01 +00:00
|
|
|
func TestDialUDP(t *testing.T) {
|
|
|
|
HandleFunc("miek.nl.", HelloServer)
|
|
|
|
defer HandleRemove("miek.nl.")
|
|
|
|
|
2020-10-24 15:53:01 +00:00
|
|
|
s, addrstr, _, err := RunLocalUDPServer(":0")
|
2017-09-29 09:52:01 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to run test server: %v", err)
|
|
|
|
}
|
|
|
|
defer s.Shutdown()
|
|
|
|
|
|
|
|
m := new(Msg)
|
|
|
|
m.SetQuestion("miek.nl.", TypeSOA)
|
|
|
|
|
|
|
|
c := new(Client)
|
|
|
|
conn, err := c.Dial(addrstr)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to dial: %v", err)
|
|
|
|
}
|
|
|
|
if conn == nil {
|
|
|
|
t.Fatalf("conn is nil")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-29 12:59:19 +00:00
|
|
|
func TestClientSync(t *testing.T) {
|
2014-02-15 08:03:40 +00:00
|
|
|
HandleFunc("miek.nl.", HelloServer)
|
2014-08-30 13:45:30 +00:00
|
|
|
defer HandleRemove("miek.nl.")
|
2014-02-15 08:03:40 +00:00
|
|
|
|
2020-10-24 15:53:01 +00:00
|
|
|
s, addrstr, _, err := RunLocalUDPServer(":0")
|
2014-08-29 12:59:19 +00:00
|
|
|
if err != nil {
|
2015-11-26 14:12:38 +00:00
|
|
|
t.Fatalf("unable to run test server: %v", err)
|
2014-08-29 12:59:19 +00:00
|
|
|
}
|
|
|
|
defer s.Shutdown()
|
|
|
|
|
2011-07-04 18:18:51 +00:00
|
|
|
m := new(Msg)
|
2012-01-08 14:34:42 +00:00
|
|
|
m.SetQuestion("miek.nl.", TypeSOA)
|
2011-07-04 18:18:51 +00:00
|
|
|
|
2012-05-26 08:28:32 +00:00
|
|
|
c := new(Client)
|
2015-02-26 06:14:21 +00:00
|
|
|
r, _, err := c.Exchange(m, addrstr)
|
|
|
|
if err != nil {
|
2017-09-29 09:52:01 +00:00
|
|
|
t.Fatalf("failed to exchange: %v", err)
|
2014-08-29 12:59:19 +00:00
|
|
|
}
|
2017-09-29 09:52:01 +00:00
|
|
|
if r == nil {
|
|
|
|
t.Fatal("response is nil")
|
|
|
|
}
|
|
|
|
if r.Rcode != RcodeSuccess {
|
2015-02-26 06:14:21 +00:00
|
|
|
t.Errorf("failed to get an valid answer\n%v", r)
|
2011-07-04 18:18:51 +00:00
|
|
|
}
|
2014-08-30 14:06:20 +00:00
|
|
|
// And now with plain Exchange().
|
2015-02-26 06:14:21 +00:00
|
|
|
r, err = Exchange(m, addrstr)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("failed to exchange: %v", err)
|
2014-08-30 14:06:20 +00:00
|
|
|
}
|
2015-06-24 19:09:46 +00:00
|
|
|
if r == nil || r.Rcode != RcodeSuccess {
|
2015-02-26 06:14:21 +00:00
|
|
|
t.Errorf("failed to get an valid answer\n%v", r)
|
2014-08-30 14:06:20 +00:00
|
|
|
}
|
2011-07-04 18:18:51 +00:00
|
|
|
}
|
|
|
|
|
2017-09-29 09:52:01 +00:00
|
|
|
func TestClientLocalAddress(t *testing.T) {
|
|
|
|
HandleFunc("miek.nl.", HelloServerEchoAddrPort)
|
|
|
|
defer HandleRemove("miek.nl.")
|
|
|
|
|
2020-10-24 15:53:01 +00:00
|
|
|
s, addrstr, _, err := RunLocalUDPServer(":0")
|
2017-09-29 09:52:01 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to run test server: %v", err)
|
|
|
|
}
|
|
|
|
defer s.Shutdown()
|
|
|
|
|
|
|
|
m := new(Msg)
|
|
|
|
m.SetQuestion("miek.nl.", TypeSOA)
|
|
|
|
|
|
|
|
c := new(Client)
|
2017-11-08 10:01:19 +00:00
|
|
|
laddr := net.UDPAddr{IP: net.ParseIP("0.0.0.0"), Port: 12345, Zone: ""}
|
2017-09-29 09:52:01 +00:00
|
|
|
c.Dialer = &net.Dialer{LocalAddr: &laddr}
|
|
|
|
r, _, err := c.Exchange(m, addrstr)
|
|
|
|
if err != nil {
|
2017-11-08 10:01:19 +00:00
|
|
|
t.Fatalf("failed to exchange: %v", err)
|
2017-09-29 09:52:01 +00:00
|
|
|
}
|
|
|
|
if r != nil && r.Rcode != RcodeSuccess {
|
|
|
|
t.Errorf("failed to get an valid answer\n%v", r)
|
|
|
|
}
|
|
|
|
if len(r.Extra) != 1 {
|
2018-12-02 08:23:35 +00:00
|
|
|
t.Fatalf("failed to get additional answers\n%v", r)
|
2017-09-29 09:52:01 +00:00
|
|
|
}
|
|
|
|
txt := r.Extra[0].(*TXT)
|
|
|
|
if txt == nil {
|
|
|
|
t.Errorf("invalid TXT response\n%v", txt)
|
|
|
|
}
|
2017-11-08 10:01:19 +00:00
|
|
|
if len(txt.Txt) != 1 || !strings.Contains(txt.Txt[0], ":12345") {
|
2017-09-29 09:52:01 +00:00
|
|
|
t.Errorf("invalid TXT response\n%v", txt.Txt)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestClientTLSSyncV4(t *testing.T) {
|
2016-01-08 13:34:08 +00:00
|
|
|
HandleFunc("miek.nl.", HelloServer)
|
|
|
|
defer HandleRemove("miek.nl.")
|
|
|
|
|
|
|
|
cert, err := tls.X509KeyPair(CertPEMBlock, KeyPEMBlock)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to build certificate: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
config := tls.Config{
|
|
|
|
Certificates: []tls.Certificate{cert},
|
|
|
|
}
|
|
|
|
|
2020-10-24 15:53:01 +00:00
|
|
|
s, addrstr, _, err := RunLocalTLSServer(":0", &config)
|
2016-01-08 13:34:08 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to run test server: %v", err)
|
|
|
|
}
|
|
|
|
defer s.Shutdown()
|
|
|
|
|
|
|
|
m := new(Msg)
|
|
|
|
m.SetQuestion("miek.nl.", TypeSOA)
|
|
|
|
|
|
|
|
c := new(Client)
|
2017-09-29 09:52:01 +00:00
|
|
|
|
|
|
|
// test tcp-tls
|
2016-01-08 13:34:08 +00:00
|
|
|
c.Net = "tcp-tls"
|
|
|
|
c.TLSConfig = &tls.Config{
|
|
|
|
InsecureSkipVerify: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
r, _, err := c.Exchange(m, addrstr)
|
|
|
|
if err != nil {
|
2017-09-29 09:52:01 +00:00
|
|
|
t.Fatalf("failed to exchange: %v", err)
|
2016-01-08 13:34:08 +00:00
|
|
|
}
|
2017-09-29 09:52:01 +00:00
|
|
|
if r == nil {
|
|
|
|
t.Fatal("response is nil")
|
|
|
|
}
|
|
|
|
if r.Rcode != RcodeSuccess {
|
|
|
|
t.Errorf("failed to get an valid answer\n%v", r)
|
|
|
|
}
|
|
|
|
|
|
|
|
// test tcp4-tls
|
|
|
|
c.Net = "tcp4-tls"
|
|
|
|
c.TLSConfig = &tls.Config{
|
|
|
|
InsecureSkipVerify: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
r, _, err = c.Exchange(m, addrstr)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to exchange: %v", err)
|
|
|
|
}
|
|
|
|
if r == nil {
|
|
|
|
t.Fatal("response is nil")
|
|
|
|
}
|
|
|
|
if r.Rcode != RcodeSuccess {
|
|
|
|
t.Errorf("failed to get an valid answer\n%v", r)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Ignore responses with unexpected IDs (#1155)
* Ignore replies with unexpected IDs
This fixes the following problem:
At time 0, we send a query with ID X from port P.
At time T, we time out the query due to lack of response, and then send
a different query with ID Y. By coincidence, the new query is sent from
the same port number P (since port numbers are only 16 bits, this can happen
with non-negligible probability when making queries at a high rate).
At time T+epsilon, we receive a response to the original query.
Since the ID in this response is X, not Y, we would previously return
ErrId, preventing the second query from succeeding.
With this commit, we simply ignore the response with the mismatched ID
and return once we receive the response with the correct ID.
* Update test for bad ID
The new test sends two replies: the first one has a bad ID, which should
be ignored, and the second one has the correct ID.
* Add test to ensure query times out when server returns bad ID
* Avoid use of error string matching in test case
* Check for mismatched query IDs when using TCP
* Reduce timeout in TestClientSyncBadID
2020-10-18 05:55:24 +00:00
|
|
|
func isNetworkTimeout(err error) bool {
|
|
|
|
// TODO: when Go 1.14 support is dropped, do this: https://golang.org/doc/go1.15#net
|
|
|
|
var netError net.Error
|
|
|
|
return errors.As(err, &netError) && netError.Timeout()
|
|
|
|
}
|
|
|
|
|
2017-02-15 20:40:16 +00:00
|
|
|
func TestClientSyncBadID(t *testing.T) {
|
|
|
|
HandleFunc("miek.nl.", HelloServerBadID)
|
2015-05-06 05:56:42 +00:00
|
|
|
defer HandleRemove("miek.nl.")
|
|
|
|
|
2020-10-24 15:53:01 +00:00
|
|
|
s, addrstr, _, err := RunLocalUDPServer(":0")
|
2015-05-06 05:56:42 +00:00
|
|
|
if err != nil {
|
2015-11-26 14:12:38 +00:00
|
|
|
t.Fatalf("unable to run test server: %v", err)
|
2015-05-06 05:56:42 +00:00
|
|
|
}
|
|
|
|
defer s.Shutdown()
|
|
|
|
|
|
|
|
m := new(Msg)
|
|
|
|
m.SetQuestion("miek.nl.", TypeSOA)
|
|
|
|
|
2022-03-02 12:52:49 +00:00
|
|
|
// Test with client.Exchange, the plain Exchange function is just a wrapper, so
|
|
|
|
// we don't need to test that separately.
|
Ignore responses with unexpected IDs (#1155)
* Ignore replies with unexpected IDs
This fixes the following problem:
At time 0, we send a query with ID X from port P.
At time T, we time out the query due to lack of response, and then send
a different query with ID Y. By coincidence, the new query is sent from
the same port number P (since port numbers are only 16 bits, this can happen
with non-negligible probability when making queries at a high rate).
At time T+epsilon, we receive a response to the original query.
Since the ID in this response is X, not Y, we would previously return
ErrId, preventing the second query from succeeding.
With this commit, we simply ignore the response with the mismatched ID
and return once we receive the response with the correct ID.
* Update test for bad ID
The new test sends two replies: the first one has a bad ID, which should
be ignored, and the second one has the correct ID.
* Add test to ensure query times out when server returns bad ID
* Avoid use of error string matching in test case
* Check for mismatched query IDs when using TCP
* Reduce timeout in TestClientSyncBadID
2020-10-18 05:55:24 +00:00
|
|
|
c := &Client{
|
2022-03-02 12:52:49 +00:00
|
|
|
Timeout: 10 * time.Millisecond,
|
Ignore responses with unexpected IDs (#1155)
* Ignore replies with unexpected IDs
This fixes the following problem:
At time 0, we send a query with ID X from port P.
At time T, we time out the query due to lack of response, and then send
a different query with ID Y. By coincidence, the new query is sent from
the same port number P (since port numbers are only 16 bits, this can happen
with non-negligible probability when making queries at a high rate).
At time T+epsilon, we receive a response to the original query.
Since the ID in this response is X, not Y, we would previously return
ErrId, preventing the second query from succeeding.
With this commit, we simply ignore the response with the mismatched ID
and return once we receive the response with the correct ID.
* Update test for bad ID
The new test sends two replies: the first one has a bad ID, which should
be ignored, and the second one has the correct ID.
* Add test to ensure query times out when server returns bad ID
* Avoid use of error string matching in test case
* Check for mismatched query IDs when using TCP
* Reduce timeout in TestClientSyncBadID
2020-10-18 05:55:24 +00:00
|
|
|
}
|
|
|
|
if _, _, err := c.Exchange(m, addrstr); err == nil || !isNetworkTimeout(err) {
|
|
|
|
t.Errorf("query did not time out")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestClientSyncBadThenGoodID(t *testing.T) {
|
|
|
|
HandleFunc("miek.nl.", HelloServerBadThenGoodID)
|
|
|
|
defer HandleRemove("miek.nl.")
|
|
|
|
|
2020-10-24 15:53:01 +00:00
|
|
|
s, addrstr, _, err := RunLocalUDPServer(":0")
|
Ignore responses with unexpected IDs (#1155)
* Ignore replies with unexpected IDs
This fixes the following problem:
At time 0, we send a query with ID X from port P.
At time T, we time out the query due to lack of response, and then send
a different query with ID Y. By coincidence, the new query is sent from
the same port number P (since port numbers are only 16 bits, this can happen
with non-negligible probability when making queries at a high rate).
At time T+epsilon, we receive a response to the original query.
Since the ID in this response is X, not Y, we would previously return
ErrId, preventing the second query from succeeding.
With this commit, we simply ignore the response with the mismatched ID
and return once we receive the response with the correct ID.
* Update test for bad ID
The new test sends two replies: the first one has a bad ID, which should
be ignored, and the second one has the correct ID.
* Add test to ensure query times out when server returns bad ID
* Avoid use of error string matching in test case
* Check for mismatched query IDs when using TCP
* Reduce timeout in TestClientSyncBadID
2020-10-18 05:55:24 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to run test server: %v", err)
|
|
|
|
}
|
|
|
|
defer s.Shutdown()
|
|
|
|
|
|
|
|
m := new(Msg)
|
|
|
|
m.SetQuestion("miek.nl.", TypeSOA)
|
|
|
|
|
2015-05-06 05:56:42 +00:00
|
|
|
c := new(Client)
|
Ignore responses with unexpected IDs (#1155)
* Ignore replies with unexpected IDs
This fixes the following problem:
At time 0, we send a query with ID X from port P.
At time T, we time out the query due to lack of response, and then send
a different query with ID Y. By coincidence, the new query is sent from
the same port number P (since port numbers are only 16 bits, this can happen
with non-negligible probability when making queries at a high rate).
At time T+epsilon, we receive a response to the original query.
Since the ID in this response is X, not Y, we would previously return
ErrId, preventing the second query from succeeding.
With this commit, we simply ignore the response with the mismatched ID
and return once we receive the response with the correct ID.
* Update test for bad ID
The new test sends two replies: the first one has a bad ID, which should
be ignored, and the second one has the correct ID.
* Add test to ensure query times out when server returns bad ID
* Avoid use of error string matching in test case
* Check for mismatched query IDs when using TCP
* Reduce timeout in TestClientSyncBadID
2020-10-18 05:55:24 +00:00
|
|
|
r, _, err := c.Exchange(m, addrstr)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("failed to exchange: %v", err)
|
|
|
|
}
|
|
|
|
if r.Id != m.Id {
|
|
|
|
t.Errorf("failed to get response with expected Id")
|
2015-05-06 05:56:42 +00:00
|
|
|
}
|
Ignore responses with unexpected IDs (#1155)
* Ignore replies with unexpected IDs
This fixes the following problem:
At time 0, we send a query with ID X from port P.
At time T, we time out the query due to lack of response, and then send
a different query with ID Y. By coincidence, the new query is sent from
the same port number P (since port numbers are only 16 bits, this can happen
with non-negligible probability when making queries at a high rate).
At time T+epsilon, we receive a response to the original query.
Since the ID in this response is X, not Y, we would previously return
ErrId, preventing the second query from succeeding.
With this commit, we simply ignore the response with the mismatched ID
and return once we receive the response with the correct ID.
* Update test for bad ID
The new test sends two replies: the first one has a bad ID, which should
be ignored, and the second one has the correct ID.
* Add test to ensure query times out when server returns bad ID
* Avoid use of error string matching in test case
* Check for mismatched query IDs when using TCP
* Reduce timeout in TestClientSyncBadID
2020-10-18 05:55:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestClientSyncTCPBadID(t *testing.T) {
|
|
|
|
HandleFunc("miek.nl.", HelloServerBadID)
|
|
|
|
defer HandleRemove("miek.nl.")
|
|
|
|
|
2020-10-24 15:53:01 +00:00
|
|
|
s, addrstr, _, err := RunLocalTCPServer(":0")
|
Ignore responses with unexpected IDs (#1155)
* Ignore replies with unexpected IDs
This fixes the following problem:
At time 0, we send a query with ID X from port P.
At time T, we time out the query due to lack of response, and then send
a different query with ID Y. By coincidence, the new query is sent from
the same port number P (since port numbers are only 16 bits, this can happen
with non-negligible probability when making queries at a high rate).
At time T+epsilon, we receive a response to the original query.
Since the ID in this response is X, not Y, we would previously return
ErrId, preventing the second query from succeeding.
With this commit, we simply ignore the response with the mismatched ID
and return once we receive the response with the correct ID.
* Update test for bad ID
The new test sends two replies: the first one has a bad ID, which should
be ignored, and the second one has the correct ID.
* Add test to ensure query times out when server returns bad ID
* Avoid use of error string matching in test case
* Check for mismatched query IDs when using TCP
* Reduce timeout in TestClientSyncBadID
2020-10-18 05:55:24 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to run test server: %v", err)
|
|
|
|
}
|
|
|
|
defer s.Shutdown()
|
|
|
|
|
|
|
|
m := new(Msg)
|
|
|
|
m.SetQuestion("miek.nl.", TypeSOA)
|
|
|
|
|
|
|
|
c := &Client{
|
|
|
|
Net: "tcp",
|
|
|
|
}
|
|
|
|
if _, _, err := c.Exchange(m, addrstr); err != ErrId {
|
2015-05-06 05:56:42 +00:00
|
|
|
t.Errorf("did not find a bad Id")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-06 06:51:51 +00:00
|
|
|
func TestClientEDNS0(t *testing.T) {
|
2014-08-29 12:59:19 +00:00
|
|
|
HandleFunc("miek.nl.", HelloServer)
|
2014-08-30 13:45:30 +00:00
|
|
|
defer HandleRemove("miek.nl.")
|
2014-08-29 12:59:19 +00:00
|
|
|
|
2020-10-24 15:53:01 +00:00
|
|
|
s, addrstr, _, err := RunLocalUDPServer(":0")
|
2014-08-29 12:59:19 +00:00
|
|
|
if err != nil {
|
2015-11-26 14:12:38 +00:00
|
|
|
t.Fatalf("unable to run test server: %v", err)
|
2014-08-29 12:59:19 +00:00
|
|
|
}
|
|
|
|
defer s.Shutdown()
|
|
|
|
|
2011-07-06 06:51:51 +00:00
|
|
|
m := new(Msg)
|
2012-01-08 14:34:42 +00:00
|
|
|
m.SetQuestion("miek.nl.", TypeDNSKEY)
|
2011-07-04 18:18:51 +00:00
|
|
|
|
2011-11-28 05:03:21 +00:00
|
|
|
m.SetEdns0(2048, true)
|
2011-07-04 18:18:51 +00:00
|
|
|
|
2012-05-26 08:28:40 +00:00
|
|
|
c := new(Client)
|
2015-02-26 06:14:21 +00:00
|
|
|
r, _, err := c.Exchange(m, addrstr)
|
|
|
|
if err != nil {
|
2017-09-29 09:52:01 +00:00
|
|
|
t.Fatalf("failed to exchange: %v", err)
|
2014-08-29 12:59:19 +00:00
|
|
|
}
|
2011-07-06 06:51:51 +00:00
|
|
|
|
|
|
|
if r != nil && r.Rcode != RcodeSuccess {
|
2017-09-29 09:52:01 +00:00
|
|
|
t.Errorf("failed to get a valid answer\n%v", r)
|
2011-07-04 18:18:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-18 19:12:53 +00:00
|
|
|
// Validates the transmission and parsing of local EDNS0 options.
|
|
|
|
func TestClientEDNS0Local(t *testing.T) {
|
|
|
|
optStr1 := "1979:0x0707"
|
|
|
|
optStr2 := strconv.Itoa(EDNS0LOCALSTART) + ":0x0601"
|
|
|
|
|
2015-03-17 17:41:55 +00:00
|
|
|
handler := func(w ResponseWriter, req *Msg) {
|
|
|
|
m := new(Msg)
|
|
|
|
m.SetReply(req)
|
|
|
|
|
|
|
|
m.Extra = make([]RR, 1, 2)
|
2015-03-18 19:12:53 +00:00
|
|
|
m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello local edns"}}
|
2015-03-17 17:41:55 +00:00
|
|
|
|
2015-03-18 19:12:53 +00:00
|
|
|
// If the local options are what we expect, then reflect them back.
|
|
|
|
ec1 := req.Extra[0].(*OPT).Option[0].(*EDNS0_LOCAL).String()
|
|
|
|
ec2 := req.Extra[0].(*OPT).Option[1].(*EDNS0_LOCAL).String()
|
|
|
|
if ec1 == optStr1 && ec2 == optStr2 {
|
2015-03-17 17:41:55 +00:00
|
|
|
m.Extra = append(m.Extra, req.Extra[0])
|
|
|
|
}
|
|
|
|
|
|
|
|
w.WriteMsg(m)
|
|
|
|
}
|
|
|
|
|
|
|
|
HandleFunc("miek.nl.", handler)
|
|
|
|
defer HandleRemove("miek.nl.")
|
|
|
|
|
2020-10-24 15:53:01 +00:00
|
|
|
s, addrstr, _, err := RunLocalUDPServer(":0")
|
2015-03-17 17:41:55 +00:00
|
|
|
if err != nil {
|
2015-11-26 14:12:38 +00:00
|
|
|
t.Fatalf("unable to run test server: %s", err)
|
2015-03-17 17:41:55 +00:00
|
|
|
}
|
|
|
|
defer s.Shutdown()
|
|
|
|
|
|
|
|
m := new(Msg)
|
|
|
|
m.SetQuestion("miek.nl.", TypeTXT)
|
|
|
|
|
2015-03-18 19:12:53 +00:00
|
|
|
// Add two local edns options to the query.
|
|
|
|
ec1 := &EDNS0_LOCAL{Code: 1979, Data: []byte{7, 7}}
|
|
|
|
ec2 := &EDNS0_LOCAL{Code: EDNS0LOCALSTART, Data: []byte{6, 1}}
|
2015-03-17 17:41:55 +00:00
|
|
|
o := &OPT{Hdr: RR_Header{Name: ".", Rrtype: TypeOPT}, Option: []EDNS0{ec1, ec2}}
|
|
|
|
m.Extra = append(m.Extra, o)
|
|
|
|
|
|
|
|
c := new(Client)
|
2016-06-09 06:00:08 +00:00
|
|
|
r, _, err := c.Exchange(m, addrstr)
|
|
|
|
if err != nil {
|
2017-09-29 09:52:01 +00:00
|
|
|
t.Fatalf("failed to exchange: %s", err)
|
2015-03-17 17:41:55 +00:00
|
|
|
}
|
|
|
|
|
2017-09-29 09:52:01 +00:00
|
|
|
if r == nil {
|
|
|
|
t.Fatal("response is nil")
|
|
|
|
}
|
|
|
|
if r.Rcode != RcodeSuccess {
|
|
|
|
t.Fatal("failed to get a valid answer")
|
2015-03-17 17:41:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
txt := r.Extra[0].(*TXT).Txt[0]
|
2015-03-18 19:12:53 +00:00
|
|
|
if txt != "Hello local edns" {
|
2016-06-09 06:00:08 +00:00
|
|
|
t.Error("Unexpected result for miek.nl", txt, "!= Hello local edns")
|
2015-03-17 17:41:55 +00:00
|
|
|
}
|
|
|
|
|
2015-03-18 19:12:53 +00:00
|
|
|
// Validate the local options in the reply.
|
|
|
|
got := r.Extra[1].(*OPT).Option[0].(*EDNS0_LOCAL).String()
|
|
|
|
if got != optStr1 {
|
2016-06-09 06:00:08 +00:00
|
|
|
t.Errorf("failed to get local edns0 answer; got %s, expected %s", got, optStr1)
|
2015-03-17 17:41:55 +00:00
|
|
|
}
|
|
|
|
|
2015-03-18 19:12:53 +00:00
|
|
|
got = r.Extra[1].(*OPT).Option[1].(*EDNS0_LOCAL).String()
|
|
|
|
if got != optStr2 {
|
2016-06-09 06:00:08 +00:00
|
|
|
t.Errorf("failed to get local edns0 answer; got %s, expected %s", got, optStr2)
|
2012-10-15 17:37:19 +00:00
|
|
|
}
|
|
|
|
}
|
2015-06-24 19:09:46 +00:00
|
|
|
|
|
|
|
func TestClientConn(t *testing.T) {
|
|
|
|
HandleFunc("miek.nl.", HelloServer)
|
|
|
|
defer HandleRemove("miek.nl.")
|
|
|
|
|
|
|
|
// This uses TCP just to make it slightly different than TestClientSync
|
2020-10-24 15:53:01 +00:00
|
|
|
s, addrstr, _, err := RunLocalTCPServer(":0")
|
2015-06-24 19:09:46 +00:00
|
|
|
if err != nil {
|
2015-11-26 14:12:38 +00:00
|
|
|
t.Fatalf("unable to run test server: %v", err)
|
2015-06-24 19:09:46 +00:00
|
|
|
}
|
|
|
|
defer s.Shutdown()
|
|
|
|
|
|
|
|
m := new(Msg)
|
|
|
|
m.SetQuestion("miek.nl.", TypeSOA)
|
|
|
|
|
|
|
|
cn, err := Dial("tcp", addrstr)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("failed to dial %s: %v", addrstr, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = cn.WriteMsg(m)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("failed to exchange: %v", err)
|
|
|
|
}
|
|
|
|
r, err := cn.ReadMsg()
|
2017-07-09 06:56:13 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("failed to get a valid answer: %v", err)
|
|
|
|
}
|
2015-06-24 19:09:46 +00:00
|
|
|
if r == nil || r.Rcode != RcodeSuccess {
|
|
|
|
t.Errorf("failed to get an valid answer\n%v", r)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = cn.WriteMsg(m)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("failed to exchange: %v", err)
|
|
|
|
}
|
|
|
|
h := new(Header)
|
2015-07-03 08:34:46 +00:00
|
|
|
buf, err := cn.ReadMsgHeader(h)
|
2015-06-24 19:09:46 +00:00
|
|
|
if buf == nil {
|
|
|
|
t.Errorf("failed to get an valid answer\n%v", r)
|
|
|
|
}
|
2017-07-09 06:56:13 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("failed to get a valid answer: %v", err)
|
|
|
|
}
|
2015-06-24 19:09:46 +00:00
|
|
|
if int(h.Bits&0xF) != RcodeSuccess {
|
2015-07-03 08:34:46 +00:00
|
|
|
t.Errorf("failed to get an valid answer in ReadMsgHeader\n%v", r)
|
2015-06-24 19:09:46 +00:00
|
|
|
}
|
|
|
|
if h.Ancount != 0 || h.Qdcount != 1 || h.Nscount != 0 || h.Arcount != 1 {
|
|
|
|
t.Errorf("expected to have question and additional in response; got something else: %+v", h)
|
|
|
|
}
|
|
|
|
if err = r.Unpack(buf); err != nil {
|
|
|
|
t.Errorf("unable to unpack message fully: %v", err)
|
|
|
|
}
|
|
|
|
}
|
2015-11-01 20:46:57 +00:00
|
|
|
|
2021-02-13 18:49:02 +00:00
|
|
|
func TestClientConnWriteSinglePacket(t *testing.T) {
|
|
|
|
c := &countingConn{}
|
|
|
|
conn := Conn{
|
|
|
|
Conn: c,
|
|
|
|
}
|
|
|
|
m := new(Msg)
|
|
|
|
m.SetQuestion("miek.nl.", TypeTXT)
|
|
|
|
err := conn.WriteMsg(m)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to write: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.writes != 1 {
|
|
|
|
t.Fatalf("incorrect number of Write calls")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-01 20:46:57 +00:00
|
|
|
func TestTruncatedMsg(t *testing.T) {
|
|
|
|
m := new(Msg)
|
|
|
|
m.SetQuestion("miek.nl.", TypeSRV)
|
|
|
|
cnt := 10
|
|
|
|
for i := 0; i < cnt; i++ {
|
|
|
|
r := &SRV{
|
|
|
|
Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeSRV, Class: ClassINET, Ttl: 0},
|
|
|
|
Port: uint16(i + 8000),
|
|
|
|
Target: "target.miek.nl.",
|
|
|
|
}
|
|
|
|
m.Answer = append(m.Answer, r)
|
|
|
|
|
|
|
|
re := &A{
|
|
|
|
Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeA, Class: ClassINET, Ttl: 0},
|
|
|
|
A: net.ParseIP(fmt.Sprintf("127.0.0.%d", i)).To4(),
|
|
|
|
}
|
|
|
|
m.Extra = append(m.Extra, re)
|
|
|
|
}
|
|
|
|
buf, err := m.Pack()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("failed to pack: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
r := new(Msg)
|
|
|
|
if err = r.Unpack(buf); err != nil {
|
|
|
|
t.Errorf("unable to unpack message: %v", err)
|
|
|
|
}
|
|
|
|
if len(r.Answer) != cnt {
|
2016-06-09 06:00:08 +00:00
|
|
|
t.Errorf("answer count after regular unpack doesn't match: %d", len(r.Answer))
|
2015-11-01 20:46:57 +00:00
|
|
|
}
|
|
|
|
if len(r.Extra) != cnt {
|
2016-06-09 06:00:08 +00:00
|
|
|
t.Errorf("extra count after regular unpack doesn't match: %d", len(r.Extra))
|
2015-11-01 20:46:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
m.Truncated = true
|
|
|
|
buf, err = m.Pack()
|
|
|
|
if err != nil {
|
2018-11-27 14:26:11 +00:00
|
|
|
t.Errorf("failed to pack truncated message: %v", err)
|
2015-11-01 20:46:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
r = new(Msg)
|
2018-11-27 14:26:11 +00:00
|
|
|
if err = r.Unpack(buf); err != nil {
|
|
|
|
t.Errorf("failed to unpack truncated message: %v", err)
|
2015-11-01 20:46:57 +00:00
|
|
|
}
|
|
|
|
if !r.Truncated {
|
2016-06-09 06:00:08 +00:00
|
|
|
t.Errorf("truncated message wasn't unpacked as truncated")
|
2015-11-01 20:46:57 +00:00
|
|
|
}
|
|
|
|
if len(r.Answer) != cnt {
|
2016-06-09 06:00:08 +00:00
|
|
|
t.Errorf("answer count after truncated unpack doesn't match: %d", len(r.Answer))
|
2015-11-01 20:46:57 +00:00
|
|
|
}
|
|
|
|
if len(r.Extra) != cnt {
|
2016-06-09 06:00:08 +00:00
|
|
|
t.Errorf("extra count after truncated unpack doesn't match: %d", len(r.Extra))
|
2015-11-01 20:46:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now we want to remove almost all of the extra records
|
|
|
|
// We're going to loop over the extra to get the count of the size of all
|
|
|
|
// of them
|
|
|
|
off := 0
|
|
|
|
buf1 := make([]byte, m.Len())
|
|
|
|
for i := 0; i < len(m.Extra); i++ {
|
|
|
|
off, err = PackRR(m.Extra[i], buf1, off, nil, m.Compress)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("failed to pack extra: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove all of the extra bytes but 10 bytes from the end of buf
|
|
|
|
off -= 10
|
|
|
|
buf1 = buf[:len(buf)-off]
|
|
|
|
|
|
|
|
r = new(Msg)
|
2018-11-27 14:26:11 +00:00
|
|
|
if err = r.Unpack(buf1); err == nil {
|
|
|
|
t.Error("cutoff message should have failed to unpack")
|
2015-11-01 20:46:57 +00:00
|
|
|
}
|
2018-11-27 14:26:11 +00:00
|
|
|
// r's header might be still usable.
|
2015-11-01 20:46:57 +00:00
|
|
|
if !r.Truncated {
|
2016-06-09 06:00:08 +00:00
|
|
|
t.Error("truncated cutoff message wasn't unpacked as truncated")
|
2015-11-01 20:46:57 +00:00
|
|
|
}
|
|
|
|
if len(r.Answer) != cnt {
|
2016-06-09 06:00:08 +00:00
|
|
|
t.Errorf("answer count after cutoff unpack doesn't match: %d", len(r.Answer))
|
2015-11-01 20:46:57 +00:00
|
|
|
}
|
|
|
|
if len(r.Extra) != 0 {
|
2016-06-09 06:00:08 +00:00
|
|
|
t.Errorf("extra count after cutoff unpack is not zero: %d", len(r.Extra))
|
2015-11-01 20:46:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now we want to remove almost all of the answer records too
|
|
|
|
buf1 = make([]byte, m.Len())
|
|
|
|
as := 0
|
|
|
|
for i := 0; i < len(m.Extra); i++ {
|
|
|
|
off1 := off
|
|
|
|
off, err = PackRR(m.Extra[i], buf1, off, nil, m.Compress)
|
|
|
|
as = off - off1
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("failed to pack extra: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Keep exactly one answer left
|
|
|
|
// This should still cause Answer to be nil
|
|
|
|
off -= as
|
|
|
|
buf1 = buf[:len(buf)-off]
|
|
|
|
|
|
|
|
r = new(Msg)
|
2018-11-27 14:26:11 +00:00
|
|
|
if err = r.Unpack(buf1); err == nil {
|
|
|
|
t.Error("cutoff message should have failed to unpack")
|
2015-11-01 20:46:57 +00:00
|
|
|
}
|
|
|
|
if !r.Truncated {
|
2016-06-09 06:00:08 +00:00
|
|
|
t.Error("truncated cutoff message wasn't unpacked as truncated")
|
2015-11-01 20:46:57 +00:00
|
|
|
}
|
|
|
|
if len(r.Answer) != 0 {
|
2016-06-09 06:00:08 +00:00
|
|
|
t.Errorf("answer count after second cutoff unpack is not zero: %d", len(r.Answer))
|
2015-11-01 20:46:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now leave only 1 byte of the question
|
|
|
|
// Since the header is always 12 bytes, we just need to keep 13
|
|
|
|
buf1 = buf[:13]
|
|
|
|
|
|
|
|
r = new(Msg)
|
|
|
|
err = r.Unpack(buf1)
|
2018-11-27 14:26:11 +00:00
|
|
|
if err == nil {
|
|
|
|
t.Errorf("error should be nil after question cutoff unpack: %v", err)
|
2015-11-01 20:46:57 +00:00
|
|
|
}
|
|
|
|
|
2017-12-20 10:51:13 +00:00
|
|
|
// Finally, if we only have the header, we don't return an error.
|
2015-11-01 20:46:57 +00:00
|
|
|
buf1 = buf[:12]
|
|
|
|
|
|
|
|
r = new(Msg)
|
2017-12-20 10:51:13 +00:00
|
|
|
if err = r.Unpack(buf1); err != nil {
|
|
|
|
t.Errorf("from header-only unpack should not return an error: %v", err)
|
2015-11-01 20:46:57 +00:00
|
|
|
}
|
|
|
|
}
|
2016-04-19 10:29:51 +00:00
|
|
|
|
|
|
|
func TestTimeout(t *testing.T) {
|
|
|
|
// Set up a dummy UDP server that won't respond
|
2017-11-08 10:01:19 +00:00
|
|
|
addr, err := net.ResolveUDPAddr("udp", ":0")
|
2016-04-19 10:29:51 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to resolve local udp address: %v", err)
|
|
|
|
}
|
|
|
|
conn, err := net.ListenUDP("udp", addr)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to run test server: %v", err)
|
|
|
|
}
|
|
|
|
defer conn.Close()
|
|
|
|
addrstr := conn.LocalAddr().String()
|
|
|
|
|
|
|
|
// Message to send
|
|
|
|
m := new(Msg)
|
|
|
|
m.SetQuestion("miek.nl.", TypeTXT)
|
|
|
|
|
2018-12-03 07:40:52 +00:00
|
|
|
runTest := func(name string, exchange func(m *Msg, addr string, timeout time.Duration) (*Msg, time.Duration, error)) {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
start := time.Now()
|
2016-04-19 10:29:51 +00:00
|
|
|
|
2018-12-03 07:40:52 +00:00
|
|
|
timeout := time.Millisecond
|
|
|
|
allowable := timeout + 10*time.Millisecond
|
2016-04-19 10:29:51 +00:00
|
|
|
|
2018-12-03 07:40:52 +00:00
|
|
|
_, _, err := exchange(m, addrstr, timeout)
|
|
|
|
if err == nil {
|
|
|
|
t.Errorf("no timeout using Client.%s", name)
|
|
|
|
}
|
2016-04-19 10:29:51 +00:00
|
|
|
|
2018-12-03 07:40:52 +00:00
|
|
|
length := time.Since(start)
|
|
|
|
if length > allowable {
|
|
|
|
t.Errorf("exchange took longer %v than specified Timeout %v", length, allowable)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
runTest("Exchange", func(m *Msg, addr string, timeout time.Duration) (*Msg, time.Duration, error) {
|
2016-04-19 10:29:51 +00:00
|
|
|
c := &Client{Timeout: timeout}
|
2018-12-03 07:40:52 +00:00
|
|
|
return c.Exchange(m, addr)
|
|
|
|
})
|
|
|
|
runTest("ExchangeContext", func(m *Msg, addr string, timeout time.Duration) (*Msg, time.Duration, error) {
|
2017-06-30 11:44:44 +00:00
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
|
|
|
defer cancel()
|
2016-04-19 10:29:51 +00:00
|
|
|
|
2018-12-03 07:40:52 +00:00
|
|
|
return new(Client).ExchangeContext(ctx, m, addrstr)
|
|
|
|
})
|
2016-04-19 10:29:51 +00:00
|
|
|
}
|
2017-02-17 11:38:00 +00:00
|
|
|
|
|
|
|
// Check that responses from deduplicated requests aren't shared between callers
|
|
|
|
func TestConcurrentExchanges(t *testing.T) {
|
|
|
|
cases := make([]*Msg, 2)
|
|
|
|
cases[0] = new(Msg)
|
|
|
|
cases[1] = new(Msg)
|
|
|
|
cases[1].Truncated = true
|
|
|
|
|
2018-12-04 07:29:08 +00:00
|
|
|
for _, m := range cases {
|
2018-10-04 06:24:09 +00:00
|
|
|
mm := m // redeclare m so as not to trip the race detector
|
2017-02-17 11:38:00 +00:00
|
|
|
handler := func(w ResponseWriter, req *Msg) {
|
2018-10-04 06:24:09 +00:00
|
|
|
r := mm.Copy()
|
2017-02-17 11:38:00 +00:00
|
|
|
r.SetReply(req)
|
|
|
|
|
|
|
|
w.WriteMsg(r)
|
|
|
|
}
|
|
|
|
|
|
|
|
HandleFunc("miek.nl.", handler)
|
|
|
|
defer HandleRemove("miek.nl.")
|
|
|
|
|
2020-10-24 15:53:01 +00:00
|
|
|
s, addrstr, _, err := RunLocalUDPServer(":0")
|
2017-02-17 11:38:00 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to run test server: %s", err)
|
|
|
|
}
|
|
|
|
defer s.Shutdown()
|
|
|
|
|
|
|
|
m := new(Msg)
|
|
|
|
m.SetQuestion("miek.nl.", TypeSRV)
|
2018-12-04 07:29:08 +00:00
|
|
|
|
2017-02-17 11:38:00 +00:00
|
|
|
c := &Client{
|
|
|
|
SingleInflight: true,
|
|
|
|
}
|
2018-12-04 07:29:08 +00:00
|
|
|
// Force this client to always return the same request,
|
|
|
|
// even though we're querying sequentially. Running the
|
|
|
|
// Exchange calls below concurrently can fail due to
|
|
|
|
// goroutine scheduling, but this simulates the same
|
|
|
|
// outcome.
|
|
|
|
c.group.dontDeleteForTesting = true
|
2017-02-17 11:38:00 +00:00
|
|
|
|
2018-12-04 07:29:08 +00:00
|
|
|
r := make([]*Msg, 2)
|
|
|
|
for i := range r {
|
|
|
|
r[i], _, _ = c.Exchange(m.Copy(), addrstr)
|
|
|
|
if r[i] == nil {
|
|
|
|
t.Errorf("response %d is nil", i)
|
|
|
|
}
|
2017-02-17 11:38:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if r[0] == r[1] {
|
2017-11-10 10:11:23 +00:00
|
|
|
t.Errorf("got same response, expected non-shared responses")
|
2017-02-17 11:38:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-05-04 08:22:21 +00:00
|
|
|
|
|
|
|
func TestExchangeWithConn(t *testing.T) {
|
|
|
|
HandleFunc("miek.nl.", HelloServer)
|
|
|
|
defer HandleRemove("miek.nl.")
|
|
|
|
|
2020-10-24 15:53:01 +00:00
|
|
|
s, addrstr, _, err := RunLocalUDPServer(":0")
|
2020-05-04 08:22:21 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to run test server: %v", err)
|
|
|
|
}
|
|
|
|
defer s.Shutdown()
|
|
|
|
|
|
|
|
m := new(Msg)
|
|
|
|
m.SetQuestion("miek.nl.", TypeSOA)
|
|
|
|
|
|
|
|
c := new(Client)
|
|
|
|
conn, err := c.Dial(addrstr)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to dial: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
r, _, err := c.ExchangeWithConn(m, conn)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to exchange: %v", err)
|
|
|
|
}
|
|
|
|
if r == nil {
|
|
|
|
t.Fatal("response is nil")
|
|
|
|
}
|
|
|
|
if r.Rcode != RcodeSuccess {
|
|
|
|
t.Errorf("failed to get an valid answer\n%v", r)
|
|
|
|
}
|
|
|
|
}
|