github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/p2p/discover/udp_test.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package discover
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/ecdsa"
    22  	"encoding/binary"
    23  	"encoding/hex"
    24  	"errors"
    25  	"fmt"
    26  	"io"
    27  	"math/rand"
    28  	"net"
    29  	"path/filepath"
    30  	"reflect"
    31  	"runtime"
    32  	"sync"
    33  	"testing"
    34  	"time"
    35  
    36  	"github.com/davecgh/go-spew/spew"
    37  	"github.com/ethereumproject/go-ethereum/common"
    38  	"github.com/ethereumproject/go-ethereum/crypto"
    39  	"github.com/ethereumproject/go-ethereum/rlp"
    40  )
    41  
    42  func init() {
    43  	spew.Config.DisableMethods = true
    44  }
    45  
    46  // This test checks that isPacketTooBig correctly identifies
    47  // errors that result from receiving a UDP packet larger
    48  // than the supplied receive buffer.
    49  func TestIsPacketTooBig(t *testing.T) {
    50  	listener, err := net.ListenPacket("udp", "127.0.0.1:0")
    51  	if err != nil {
    52  		t.Fatal(err)
    53  	}
    54  	defer listener.Close()
    55  	sender, err := net.Dial("udp", listener.LocalAddr().String())
    56  	if err != nil {
    57  		t.Fatal(err)
    58  	}
    59  	defer sender.Close()
    60  
    61  	sendN := 1800
    62  	recvN := 300
    63  	for i := 0; i < 20; i++ {
    64  		go func() {
    65  			buf := make([]byte, sendN)
    66  			for i := range buf {
    67  				buf[i] = byte(i)
    68  			}
    69  			sender.Write(buf)
    70  		}()
    71  
    72  		buf := make([]byte, recvN)
    73  		listener.SetDeadline(time.Now().Add(1 * time.Second))
    74  		n, _, err := listener.ReadFrom(buf)
    75  		if err != nil {
    76  			if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
    77  				continue
    78  			}
    79  			if !isPacketTooBig(err) {
    80  				t.Fatal("unexpected read error:", spew.Sdump(err))
    81  			}
    82  			continue
    83  		}
    84  		if n != recvN {
    85  			t.Fatalf("short read: %d, want %d", n, recvN)
    86  		}
    87  		for i := range buf {
    88  			if buf[i] != byte(i) {
    89  				t.Fatalf("error in pattern")
    90  				break
    91  			}
    92  		}
    93  	}
    94  }
    95  
    96  // shared test variables
    97  var (
    98  	futureExp          = uint64(time.Now().Add(10 * time.Hour).Unix())
    99  	testTarget         = NodeID{0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}
   100  	testRemote         = rpcEndpoint{IP: net.ParseIP("1.1.1.1").To4(), UDP: 1, TCP: 2}
   101  	testLocalAnnounced = rpcEndpoint{IP: net.ParseIP("2.2.2.2").To4(), UDP: 3, TCP: 4}
   102  	testLocal          = rpcEndpoint{IP: net.ParseIP("3.3.3.3").To4(), UDP: 5, TCP: 6}
   103  )
   104  
   105  type udpTest struct {
   106  	t                   *testing.T
   107  	pipe                *dgramPipe
   108  	table               *Table
   109  	udp                 *udp
   110  	sent                [][]byte
   111  	localkey, remotekey *ecdsa.PrivateKey
   112  	remoteaddr          *net.UDPAddr
   113  }
   114  
   115  func newUDPTest(t *testing.T) *udpTest {
   116  	test := &udpTest{
   117  		t:          t,
   118  		pipe:       newpipe(),
   119  		localkey:   newkey(),
   120  		remotekey:  newkey(),
   121  		remoteaddr: &net.UDPAddr{IP: net.IP{10, 2, 3, 4}, Port: 30303}, // must come from "reserved" address to be valid since findNode tests use reserved address enodes
   122  	}
   123  	test.table, test.udp, _ = newUDP(test.localkey, test.pipe, nil, "")
   124  	<-test.table.initDone
   125  	return test
   126  }
   127  
   128  // handles a packet as if it had been sent to the transport.
   129  func (test *udpTest) packetIn(wantError error, ptype byte, data packet) error {
   130  	enc, err := encodePacket(test.remotekey, ptype, data)
   131  	if err != nil {
   132  		return test.errorf("packet (%d) encode error: %v", ptype, err)
   133  	}
   134  	test.sent = append(test.sent, enc)
   135  	if err = test.udp.handlePacket(test.remoteaddr, enc); err != wantError {
   136  		return test.errorf("error mismatch: got %q, want %q", err, wantError)
   137  	}
   138  	return nil
   139  }
   140  
   141  // waits for a packet to be sent by the transport.
   142  // validate should have type func(*udpTest, X) error, where X is a packet type.
   143  func (test *udpTest) waitPacketOut(validate interface{}) error {
   144  	dgram := test.pipe.waitPacketOut()
   145  	p, _, _, err := decodePacket(dgram)
   146  	if err != nil {
   147  		return test.errorf("sent packet decode error: %v", err)
   148  	}
   149  	fn := reflect.ValueOf(validate)
   150  	exptype := fn.Type().In(0)
   151  	if reflect.TypeOf(p) != exptype {
   152  		return test.errorf("sent packet type mismatch, got: %v, want: %v", reflect.TypeOf(p), exptype)
   153  	}
   154  	fn.Call([]reflect.Value{reflect.ValueOf(p)})
   155  	return nil
   156  }
   157  
   158  func (test *udpTest) errorf(format string, args ...interface{}) error {
   159  	_, file, line, ok := runtime.Caller(2) // errorf + waitPacketOut
   160  	if ok {
   161  		file = filepath.Base(file)
   162  	} else {
   163  		file = "???"
   164  		line = 1
   165  	}
   166  	err := fmt.Errorf(format, args...)
   167  	fmt.Printf("\t%s:%d: %v\n", file, line, err)
   168  	test.t.Fail()
   169  	return err
   170  }
   171  
   172  func TestUDP_packetErrors(t *testing.T) {
   173  	test := newUDPTest(t)
   174  	defer test.table.Close()
   175  
   176  	test.packetIn(errExpired, pingPacket, &ping{From: testRemote, To: testLocalAnnounced, Version: Version})
   177  	test.packetIn(errUnsolicitedReply, pongPacket, &pong{ReplyTok: []byte{}, Expiration: futureExp})
   178  	test.packetIn(errUnknownNode, findnodePacket, &findnode{Expiration: futureExp})
   179  	test.packetIn(errUnsolicitedReply, neighborsPacket, &neighbors{Expiration: futureExp})
   180  }
   181  
   182  func TestUDP_pingTimeout(t *testing.T) {
   183  	t.Parallel()
   184  	test := newUDPTest(t)
   185  	defer test.table.Close()
   186  
   187  	toaddr := &net.UDPAddr{IP: net.ParseIP("1.2.3.4"), Port: 2222}
   188  	toid := NodeID{1, 2, 3, 4}
   189  	if err := test.udp.ping(toid, toaddr); err != errTimeout {
   190  		t.Error("expected timeout error, got", err)
   191  	}
   192  }
   193  
   194  func TestUDP_responseTimeouts(t *testing.T) {
   195  	t.Parallel()
   196  	test := newUDPTest(t)
   197  	defer test.table.Close()
   198  
   199  	rand.Seed(time.Now().UnixNano())
   200  	randomDuration := func(max time.Duration) time.Duration {
   201  		return time.Duration(rand.Int63n(int64(max)))
   202  	}
   203  
   204  	var (
   205  		nReqs      = 200
   206  		nTimeouts  = 0                       // number of requests with ptype > 128
   207  		nilErr     = make(chan error, nReqs) // for requests that get a reply
   208  		timeoutErr = make(chan error, nReqs) // for requests that time out
   209  	)
   210  	for i := 0; i < nReqs; i++ {
   211  		// Create a matcher for a random request in udp.loop. Requests
   212  		// with ptype <= 128 will not get a reply and should time out.
   213  		// For all other requests, a reply is scheduled to arrive
   214  		// within the timeout window.
   215  		p := &pending{
   216  			ptype:    byte(rand.Intn(255)),
   217  			callback: func(interface{}) bool { return true },
   218  		}
   219  		binary.BigEndian.PutUint64(p.from[:], uint64(i))
   220  		if p.ptype <= 128 {
   221  			p.errc = timeoutErr
   222  			test.udp.addpending <- p
   223  			nTimeouts++
   224  		} else {
   225  			p.errc = nilErr
   226  			test.udp.addpending <- p
   227  			time.AfterFunc(randomDuration(60*time.Millisecond), func() {
   228  				if !test.udp.handleReply(p.from, p.ptype, nil) {
   229  					t.Logf("not matched: %v", p)
   230  				}
   231  			})
   232  		}
   233  		time.Sleep(randomDuration(30 * time.Millisecond))
   234  	}
   235  
   236  	// Check that all timeouts were delivered and that the rest got nil errors.
   237  	// The replies must be delivered.
   238  	var (
   239  		recvDeadline        = time.After(20 * time.Second)
   240  		nTimeoutsRecv, nNil = 0, 0
   241  	)
   242  	for i := 0; i < nReqs; i++ {
   243  		select {
   244  		case err := <-timeoutErr:
   245  			if err != errTimeout {
   246  				t.Fatalf("got non-timeout error on timeoutErr %d: %v", i, err)
   247  			}
   248  			nTimeoutsRecv++
   249  		case err := <-nilErr:
   250  			if err != nil {
   251  				t.Fatalf("got non-nil error on nilErr %d: %v", i, err)
   252  			}
   253  			nNil++
   254  		case <-recvDeadline:
   255  			t.Fatalf("exceeded recv deadline")
   256  		}
   257  	}
   258  	if nTimeoutsRecv != nTimeouts {
   259  		t.Errorf("wrong number of timeout errors received: got %d, want %d", nTimeoutsRecv, nTimeouts)
   260  	}
   261  	if nNil != nReqs-nTimeouts {
   262  		t.Errorf("wrong number of successful replies: got %d, want %d", nNil, nReqs-nTimeouts)
   263  	}
   264  }
   265  
   266  func TestUDP_findnodeTimeout(t *testing.T) {
   267  	t.Parallel()
   268  	test := newUDPTest(t)
   269  	defer test.table.Close()
   270  
   271  	toaddr := &net.UDPAddr{IP: net.ParseIP("1.2.3.4"), Port: 2222}
   272  	toid := NodeID{1, 2, 3, 4}
   273  	target := NodeID{4, 5, 6, 7}
   274  	result, err := test.udp.findnode(toid, toaddr, target)
   275  	if err != errTimeout {
   276  		t.Error("expected timeout error, got", err)
   277  	}
   278  	if len(result) > 0 {
   279  		t.Error("expected empty result, got", result)
   280  	}
   281  }
   282  
   283  func TestUDP_findnode(t *testing.T) {
   284  	test := newUDPTest(t)
   285  	defer test.table.Close()
   286  
   287  	// put a few nodes into the table. their exact
   288  	// distribution shouldn't matter much, altough we need to
   289  	// take care not to overflow any bucket.
   290  	nodes := make([]*Node, bucketSize)
   291  	for i := range nodes {
   292  		nodes[i] = nodeAtDistance(test.table.self.sha, i+2)
   293  	}
   294  	test.table.stuff(nodes)
   295  
   296  	// ensure there's a bond with the test node,
   297  	// findnode won't be accepted otherwise.
   298  	test.table.db.updateNode(NewNode(
   299  		PubkeyID(&test.remotekey.PublicKey),
   300  		test.remoteaddr.IP,
   301  		uint16(test.remoteaddr.Port),
   302  		99,
   303  	))
   304  	// check that closest neighbors are returned.
   305  	test.packetIn(nil, findnodePacket, &findnode{Target: testTarget, Expiration: futureExp})
   306  	expected := test.table.closest(testTarget)
   307  
   308  	waitNeighbors := func(want []*Node) {
   309  		test.waitPacketOut(func(p *neighbors) {
   310  			if len(p.Nodes) != len(want) {
   311  				t.Errorf("wrong number of results: got %d, want %d", len(p.Nodes), bucketSize)
   312  			}
   313  			for i := range p.Nodes {
   314  				if p.Nodes[i].ID != want[i].ID {
   315  					t.Errorf("result mismatch at %d:\n  got:  %v\n  want: %v", i, p.Nodes[i], expected.Nodes[i])
   316  				}
   317  			}
   318  		})
   319  	}
   320  	waitNeighbors(expected.Nodes[:maxNeighbors])
   321  	waitNeighbors(expected.Nodes[maxNeighbors:])
   322  }
   323  
   324  func TestUDP_findnodeMultiReply(t *testing.T) {
   325  	test := newUDPTest(t)
   326  	defer test.table.Close()
   327  
   328  	// queue a pending findnode request
   329  	resultc, errc := make(chan []*Node), make(chan error)
   330  	go func() {
   331  		rid := PubkeyID(&test.remotekey.PublicKey)
   332  		ns, err := test.udp.findnode(rid, test.remoteaddr, testTarget)
   333  		if err != nil && len(ns) == 0 {
   334  			errc <- err
   335  		} else {
   336  			resultc <- ns
   337  		}
   338  	}()
   339  
   340  	// wait for the findnode to be sent.
   341  	// after it is sent, the transport is waiting for a reply
   342  	test.waitPacketOut(func(p *findnode) {
   343  		if p.Target != testTarget {
   344  			t.Errorf("wrong target: got %v, want %v", p.Target, testTarget)
   345  		}
   346  	})
   347  
   348  	// send the reply as two packets.
   349  	list := []*Node{
   350  		MustParseNode("enode://ba85011c70bcc5c04d8607d3a0ed29aa6179c092cbdda10d5d32684fb33ed01bd94f588ca8f91ac48318087dcb02eaf36773a7a453f0eedd6742af668097b29c@10.0.1.16:30303?discport=30304"),
   351  		MustParseNode("enode://81fa361d25f157cd421c60dcc28d8dac5ef6a89476633339c5df30287474520caca09627da18543d9079b5b288698b542d56167aa5c09111e55acdbbdf2ef799@10.0.1.16:30303"),
   352  		MustParseNode("enode://9bffefd833d53fac8e652415f4973bee289e8b1a5c6c4cbe70abf817ce8a64cee11b823b66a987f51aaa9fba0d6a91b3e6bf0d5a5d1042de8e9eeea057b217f8@10.0.1.36:30301?discport=17"),
   353  		MustParseNode("enode://1b5b4aa662d7cb44a7221bfba67302590b643028197a7d5214790f3bac7aaa4a3241be9e83c09cf1f6c69d007c634faae3dc1b1221793e8446c0b3a09de65960@10.0.1.16:30303"),
   354  	}
   355  	rpclist := make([]rpcNode, len(list))
   356  	for i := range list {
   357  		rpclist[i] = nodeToRPC(list[i])
   358  	}
   359  	test.packetIn(nil, neighborsPacket, &neighbors{Expiration: futureExp, Nodes: rpclist[:2]})
   360  	test.packetIn(nil, neighborsPacket, &neighbors{Expiration: futureExp, Nodes: rpclist[2:]})
   361  
   362  	// check that the sent neighbors are all returned by findnode
   363  	select {
   364  	case result := <-resultc:
   365  		want := append(list[:2], list[3:]...)
   366  		if !reflect.DeepEqual(result, want) {
   367  			t.Errorf("neighbors mismatch:\n  got:  %v\n  want: %v", result, want)
   368  		}
   369  	case err := <-errc:
   370  		t.Errorf("findnode error: %v", err)
   371  	case <-time.After(5 * time.Second):
   372  		t.Error("findnode did not return within 5 seconds")
   373  	}
   374  }
   375  
   376  func TestUDP_successfulPing(t *testing.T) {
   377  	test := newUDPTest(t)
   378  	added := make(chan *Node, 1)
   379  	test.table.nodeAddedHook = func(n *Node) { added <- n }
   380  	defer test.table.Close()
   381  
   382  	// The remote side sends a ping packet to initiate the exchange.
   383  	go test.packetIn(nil, pingPacket, &ping{From: testRemote, To: testLocalAnnounced, Version: Version, Expiration: futureExp})
   384  
   385  	// the ping is replied to.
   386  	test.waitPacketOut(func(p *pong) {
   387  		pinghash := test.sent[0][:macSize]
   388  		if !bytes.Equal(p.ReplyTok, pinghash) {
   389  			t.Errorf("got pong.ReplyTok %x, want %x", p.ReplyTok, pinghash)
   390  		}
   391  		wantTo := rpcEndpoint{
   392  			// The mirrored UDP address is the UDP packet sender
   393  			IP: test.remoteaddr.IP, UDP: uint16(test.remoteaddr.Port),
   394  			// The mirrored TCP port is the one from the ping packet
   395  			TCP: testRemote.TCP,
   396  		}
   397  		if !reflect.DeepEqual(p.To, wantTo) {
   398  			t.Errorf("got pong.To %v, want %v", p.To, wantTo)
   399  		}
   400  	})
   401  
   402  	// remote is unknown, the table pings back.
   403  	test.waitPacketOut(func(p *ping) error {
   404  		if !reflect.DeepEqual(p.From, test.udp.ourEndpoint) {
   405  			t.Errorf("got ping.From %v, want %v", p.From, test.udp.ourEndpoint)
   406  		}
   407  		wantTo := rpcEndpoint{
   408  			// The mirrored UDP address is the UDP packet sender.
   409  			IP: test.remoteaddr.IP, UDP: uint16(test.remoteaddr.Port),
   410  			TCP: 0,
   411  		}
   412  		if !reflect.DeepEqual(p.To, wantTo) {
   413  			t.Errorf("got ping.To %v, want %v", p.To, wantTo)
   414  		}
   415  		return nil
   416  	})
   417  	test.packetIn(nil, pongPacket, &pong{Expiration: futureExp})
   418  
   419  	// the node should be added to the table shortly after getting the
   420  	// pong packet.
   421  	select {
   422  	case n := <-added:
   423  		rid := PubkeyID(&test.remotekey.PublicKey)
   424  		if n.ID != rid {
   425  			t.Errorf("node has wrong ID: got %v, want %v", n.ID, rid)
   426  		}
   427  		if !bytes.Equal(n.IP, test.remoteaddr.IP) {
   428  			t.Errorf("node has wrong IP: got %v, want: %v", n.IP, test.remoteaddr.IP)
   429  		}
   430  		if int(n.UDP) != test.remoteaddr.Port {
   431  			t.Errorf("node has wrong UDP port: got %v, want: %v", n.UDP, test.remoteaddr.Port)
   432  		}
   433  		if n.TCP != testRemote.TCP {
   434  			t.Errorf("node has wrong TCP port: got %v, want: %v", n.TCP, testRemote.TCP)
   435  		}
   436  	case <-time.After(2 * time.Second):
   437  		t.Errorf("node was not added within 2 seconds")
   438  	}
   439  }
   440  
   441  var testPackets = []struct {
   442  	input      string
   443  	wantPacket interface{}
   444  }{
   445  	{
   446  		input: "71dbda3a79554728d4f94411e42ee1f8b0d561c10e1e5f5893367948c6a7d70bb87b235fa28a77070271b6c164a2dce8c7e13a5739b53b5e96f2e5acb0e458a02902f5965d55ecbeb2ebb6cabb8b2b232896a36b737666c55265ad0a68412f250001ea04cb847f000001820cfa8215a8d790000000000000000000000000000000018208ae820d058443b9a355",
   447  		wantPacket: &ping{
   448  			Version:    4,
   449  			From:       rpcEndpoint{net.ParseIP("127.0.0.1").To4(), 3322, 5544},
   450  			To:         rpcEndpoint{net.ParseIP("::1"), 2222, 3333},
   451  			Expiration: 1136239445,
   452  			Rest:       []rlp.RawValue{},
   453  		},
   454  	},
   455  	{
   456  		input: "e9614ccfd9fc3e74360018522d30e1419a143407ffcce748de3e22116b7e8dc92ff74788c0b6663aaa3d67d641936511c8f8d6ad8698b820a7cf9e1be7155e9a241f556658c55428ec0563514365799a4be2be5a685a80971ddcfa80cb422cdd0101ec04cb847f000001820cfa8215a8d790000000000000000000000000000000018208ae820d058443b9a3550102",
   457  		wantPacket: &ping{
   458  			Version:    4,
   459  			From:       rpcEndpoint{net.ParseIP("127.0.0.1").To4(), 3322, 5544},
   460  			To:         rpcEndpoint{net.ParseIP("::1"), 2222, 3333},
   461  			Expiration: 1136239445,
   462  			Rest:       []rlp.RawValue{{0x01}, {0x02}},
   463  		},
   464  	},
   465  	{
   466  		input: "577be4349c4dd26768081f58de4c6f375a7a22f3f7adda654d1428637412c3d7fe917cadc56d4e5e7ffae1dbe3efffb9849feb71b262de37977e7c7a44e677295680e9e38ab26bee2fcbae207fba3ff3d74069a50b902a82c9903ed37cc993c50001f83e82022bd79020010db83c4d001500000000abcdef12820cfa8215a8d79020010db885a308d313198a2e037073488208ae82823a8443b9a355c5010203040531b9019afde696e582a78fa8d95ea13ce3297d4afb8ba6433e4154caa5ac6431af1b80ba76023fa4090c408f6b4bc3701562c031041d4702971d102c9ab7fa5eed4cd6bab8f7af956f7d565ee1917084a95398b6a21eac920fe3dd1345ec0a7ef39367ee69ddf092cbfe5b93e5e568ebc491983c09c76d922dc3",
   467  		wantPacket: &ping{
   468  			Version:    555,
   469  			From:       rpcEndpoint{net.ParseIP("2001:db8:3c4d:15::abcd:ef12"), 3322, 5544},
   470  			To:         rpcEndpoint{net.ParseIP("2001:db8:85a3:8d3:1319:8a2e:370:7348"), 2222, 33338},
   471  			Expiration: 1136239445,
   472  			Rest:       []rlp.RawValue{{0xC5, 0x01, 0x02, 0x03, 0x04, 0x05}},
   473  		},
   474  	},
   475  	{
   476  		input: "09b2428d83348d27cdf7064ad9024f526cebc19e4958f0fdad87c15eb598dd61d08423e0bf66b2069869e1724125f820d851c136684082774f870e614d95a2855d000f05d1648b2d5945470bc187c2d2216fbe870f43ed0909009882e176a46b0102f846d79020010db885a308d313198a2e037073488208ae82823aa0fbc914b16819237dcd8801d7e53f69e9719adecb3cc0e790c57e91ca4461c9548443b9a355c6010203c2040506a0c969a58f6f9095004c0177a6b47f451530cab38966a25cca5cb58f055542124e",
   477  		wantPacket: &pong{
   478  			To:         rpcEndpoint{net.ParseIP("2001:db8:85a3:8d3:1319:8a2e:370:7348"), 2222, 33338},
   479  			ReplyTok:   common.Hex2Bytes("fbc914b16819237dcd8801d7e53f69e9719adecb3cc0e790c57e91ca4461c954"),
   480  			Expiration: 1136239445,
   481  			Rest:       []rlp.RawValue{{0xC6, 0x01, 0x02, 0x03, 0xC2, 0x04, 0x05}, {0x06}},
   482  		},
   483  	},
   484  	{
   485  		input: "c7c44041b9f7c7e41934417ebac9a8e1a4c6298f74553f2fcfdcae6ed6fe53163eb3d2b52e39fe91831b8a927bf4fc222c3902202027e5e9eb812195f95d20061ef5cd31d502e47ecb61183f74a504fe04c51e73df81f25c4d506b26db4517490103f84eb840ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd31387574077f301b421bc84df7266c44e9e6d569fc56be00812904767bf5ccd1fc7f8443b9a35582999983999999280dc62cc8255c73471e0a61da0c89acdc0e035e260add7fc0c04ad9ebf3919644c91cb247affc82b69bd2ca235c71eab8e49737c937a2c396",
   486  		wantPacket: &findnode{
   487  			Target:     MustHexID("ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd31387574077f301b421bc84df7266c44e9e6d569fc56be00812904767bf5ccd1fc7f"),
   488  			Expiration: 1136239445,
   489  			Rest:       []rlp.RawValue{{0x82, 0x99, 0x99}, {0x83, 0x99, 0x99, 0x99}},
   490  		},
   491  	},
   492  	{
   493  		input: "c679fc8fe0b8b12f06577f2e802d34f6fa257e6137a995f6f4cbfc9ee50ed3710faf6e66f932c4c8d81d64343f429651328758b47d3dbc02c4042f0fff6946a50f4a49037a72bb550f3a7872363a83e1b9ee6469856c24eb4ef80b7535bcf99c0004f9015bf90150f84d846321163782115c82115db8403155e1427f85f10a5c9a7755877748041af1bcd8d474ec065eb33df57a97babf54bfd2103575fa829115d224c523596b401065a97f74010610fce76382c0bf32f84984010203040101b840312c55512422cf9b8a4097e9a6ad79402e87a15ae909a4bfefa22398f03d20951933beea1e4dfa6f968212385e829f04c2d314fc2d4e255e0d3bc08792b069dbf8599020010db83c4d001500000000abcdef12820d05820d05b84038643200b172dcfef857492156971f0e6aa2c538d8b74010f8e140811d53b98c765dd2d96126051913f44582e8c199ad7c6d6819e9a56483f637feaac9448aacf8599020010db885a308d313198a2e037073488203e78203e8b8408dcab8618c3253b558d459da53bd8fa68935a719aff8b811197101a4b2b47dd2d47295286fc00cc081bb542d760717d1bdd6bec2c37cd72eca367d6dd3b9df738443b9a355010203b525a138aa34383fec3d2719a0",
   494  		wantPacket: &neighbors{
   495  			Nodes: []rpcNode{
   496  				{
   497  					ID:  MustHexID("3155e1427f85f10a5c9a7755877748041af1bcd8d474ec065eb33df57a97babf54bfd2103575fa829115d224c523596b401065a97f74010610fce76382c0bf32"),
   498  					IP:  net.ParseIP("99.33.22.55").To4(),
   499  					UDP: 4444,
   500  					TCP: 4445,
   501  				},
   502  				{
   503  					ID:  MustHexID("312c55512422cf9b8a4097e9a6ad79402e87a15ae909a4bfefa22398f03d20951933beea1e4dfa6f968212385e829f04c2d314fc2d4e255e0d3bc08792b069db"),
   504  					IP:  net.ParseIP("1.2.3.4").To4(),
   505  					UDP: 1,
   506  					TCP: 1,
   507  				},
   508  				{
   509  					ID:  MustHexID("38643200b172dcfef857492156971f0e6aa2c538d8b74010f8e140811d53b98c765dd2d96126051913f44582e8c199ad7c6d6819e9a56483f637feaac9448aac"),
   510  					IP:  net.ParseIP("2001:db8:3c4d:15::abcd:ef12"),
   511  					UDP: 3333,
   512  					TCP: 3333,
   513  				},
   514  				{
   515  					ID:  MustHexID("8dcab8618c3253b558d459da53bd8fa68935a719aff8b811197101a4b2b47dd2d47295286fc00cc081bb542d760717d1bdd6bec2c37cd72eca367d6dd3b9df73"),
   516  					IP:  net.ParseIP("2001:db8:85a3:8d3:1319:8a2e:370:7348"),
   517  					UDP: 999,
   518  					TCP: 1000,
   519  				},
   520  			},
   521  			Expiration: 1136239445,
   522  			Rest:       []rlp.RawValue{{0x01}, {0x02}, {0x03}},
   523  		},
   524  	},
   525  }
   526  
   527  func TestForwardCompatibility(t *testing.T) {
   528  	testkey, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
   529  	wantNodeID := PubkeyID(&testkey.PublicKey)
   530  
   531  	for _, test := range testPackets {
   532  		input, err := hex.DecodeString(test.input)
   533  		if err != nil {
   534  			t.Fatalf("invalid hex: %s", test.input)
   535  		}
   536  		packet, nodeid, _, err := decodePacket(input)
   537  		if err != nil {
   538  			t.Errorf("did not accept packet %s\n%v", test.input, err)
   539  			continue
   540  		}
   541  		if !reflect.DeepEqual(packet, test.wantPacket) {
   542  			t.Errorf("got %s\nwant %s", spew.Sdump(packet), spew.Sdump(test.wantPacket))
   543  		}
   544  		if nodeid != wantNodeID {
   545  			t.Errorf("got id %v\nwant id %v", nodeid, wantNodeID)
   546  		}
   547  	}
   548  }
   549  
   550  func TestIPBetween(t *testing.T) {
   551  	HandleIpBetween(t, "0.0.0.0", "255.255.255.255", "128.128.128.128", true)
   552  	HandleIpBetween(t, "0.0.0.0", "128.128.128.128", "255.255.255.255", false)
   553  	HandleIpBetween(t, "74.50.153.0", "74.50.153.4", "74.50.153.0", true)
   554  	HandleIpBetween(t, "74.50.153.0", "74.50.153.4", "74.50.153.4", true)
   555  	HandleIpBetween(t, "74.50.153.0", "74.50.153.4", "74.50.153.5", false)
   556  	HandleIpBetween(t, "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "74.50.153.4", "74.50.153.2", false)
   557  	HandleIpBetween(t, "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:0db8:85a3:0000:0000:8a2e:0370:8334", "2001:0db8:85a3:0000:0000:8a2e:0370:7334", true)
   558  	HandleIpBetween(t, "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:0db8:85a3:0000:0000:8a2e:0370:8334", "2001:0db8:85a3:0000:0000:8a2e:0370:7350", true)
   559  	HandleIpBetween(t, "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:0db8:85a3:0000:0000:8a2e:0370:8334", "2001:0db8:85a3:0000:0000:8a2e:0370:8334", true)
   560  	HandleIpBetween(t, "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:0db8:85a3:0000:0000:8a2e:0370:8334", "2001:0db8:85a3:0000:0000:8a2e:0370:8335", false)
   561  	HandleIpBetween(t, "::ffff:192.0.2.128", "::ffff:192.0.2.250", "::ffff:192.0.2.127", false)
   562  	HandleIpBetween(t, "::ffff:192.0.2.128", "::ffff:192.0.2.250", "::ffff:192.0.2.128", true)
   563  	HandleIpBetween(t, "::ffff:192.0.2.128", "::ffff:192.0.2.250", "::ffff:192.0.2.129", true)
   564  	HandleIpBetween(t, "::ffff:192.0.2.128", "::ffff:192.0.2.250", "::ffff:192.0.2.250", true)
   565  	HandleIpBetween(t, "::ffff:192.0.2.128", "::ffff:192.0.2.250", "::ffff:192.0.2.251", false)
   566  	HandleIpBetween(t, "::ffff:192.0.2.128", "::ffff:192.0.2.250", "192.0.2.130", true)
   567  	HandleIpBetween(t, "192.0.2.128", "192.0.2.250", "::ffff:192.0.2.130", true)
   568  	HandleIpBetween(t, "idonotparse", "192.0.2.250", "::ffff:192.0.2.130", false)
   569  }
   570  
   571  func HandleIpBetween(t *testing.T, from string, to string, test string, assert bool) {
   572  	res, e := IpBetween(net.ParseIP(from), net.ParseIP(to), net.ParseIP(test))
   573  	// If there is an error and we expected truth.
   574  	if e != nil && assert {
   575  		t.Errorf("Assertion (have: %t should be: %t) failed on range %s-%s with test %s: error: %v", res, assert, from, to, test, e)
   576  	}
   577  	if res != assert {
   578  		t.Errorf("Assertion (have: %t should be: %t) failed on range %s-%s with test %s", res, assert, from, to, test)
   579  	}
   580  }
   581  
   582  func TestIsReserved(t *testing.T) {
   583  	table := []struct {
   584  		ip       string
   585  		reserved bool
   586  	}{
   587  		{"0.1.1.1", true},
   588  		{"10.0.0.1", true},
   589  		{"127.12.13.14", true},
   590  		{"128.1.1.12", false},
   591  	}
   592  	for _, tt := range table {
   593  		if got := isReserved(net.ParseIP(tt.ip)); got != tt.reserved {
   594  			t.Errorf("unexpected: ip: %v, notReserved? -> want: %v, got: %v", tt.ip, tt.reserved, got)
   595  		}
   596  	}
   597  }
   598  
   599  // dgramPipe is a fake UDP socket. It queues all sent datagrams.
   600  type dgramPipe struct {
   601  	mu      *sync.Mutex
   602  	cond    *sync.Cond
   603  	closing chan struct{}
   604  	closed  bool
   605  	queue   [][]byte
   606  }
   607  
   608  func newpipe() *dgramPipe {
   609  	mu := new(sync.Mutex)
   610  	return &dgramPipe{
   611  		closing: make(chan struct{}),
   612  		cond:    &sync.Cond{L: mu},
   613  		mu:      mu,
   614  	}
   615  }
   616  
   617  // WriteToUDP queues a datagram.
   618  func (c *dgramPipe) WriteToUDP(b []byte, to *net.UDPAddr) (n int, err error) {
   619  	msg := make([]byte, len(b))
   620  	copy(msg, b)
   621  	c.mu.Lock()
   622  	defer c.mu.Unlock()
   623  	if c.closed {
   624  		return 0, errors.New("closed")
   625  	}
   626  	c.queue = append(c.queue, msg)
   627  	c.cond.Signal()
   628  	return len(b), nil
   629  }
   630  
   631  // ReadFromUDP just hangs until the pipe is closed.
   632  func (c *dgramPipe) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) {
   633  	<-c.closing
   634  	return 0, nil, io.EOF
   635  }
   636  
   637  func (c *dgramPipe) Close() error {
   638  	c.mu.Lock()
   639  	defer c.mu.Unlock()
   640  	if !c.closed {
   641  		close(c.closing)
   642  		c.closed = true
   643  	}
   644  	return nil
   645  }
   646  
   647  func (c *dgramPipe) LocalAddr() net.Addr {
   648  	return &net.UDPAddr{IP: testLocal.IP, Port: int(testLocal.UDP)}
   649  }
   650  
   651  func (c *dgramPipe) waitPacketOut() []byte {
   652  	c.mu.Lock()
   653  	defer c.mu.Unlock()
   654  	for len(c.queue) == 0 {
   655  		c.cond.Wait()
   656  	}
   657  	p := c.queue[0]
   658  	copy(c.queue, c.queue[1:])
   659  	c.queue = c.queue[:len(c.queue)-1]
   660  	return p
   661  }