p2p/discover: new endpoint format
This commit changes the discovery protocol to use the new "v4" endpoint format, which allows for separate UDP and TCP ports and makes it possible to discover the UDP address after NAT.
This commit is contained in:
parent
3fef601903
commit
fc747ef4a6
@ -277,8 +277,8 @@ func (s *Ethereum) NodeInfo() *NodeInfo {
|
||||
NodeUrl: node.String(),
|
||||
NodeID: node.ID.String(),
|
||||
IP: node.IP.String(),
|
||||
DiscPort: node.DiscPort,
|
||||
TCPPort: node.TCPPort,
|
||||
DiscPort: int(node.UDP),
|
||||
TCPPort: int(node.TCP),
|
||||
ListenAddr: s.net.ListenAddr,
|
||||
Td: s.ChainManager().Td().String(),
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@ -86,9 +87,10 @@ func TestNodeDBInt64(t *testing.T) {
|
||||
|
||||
func TestNodeDBFetchStore(t *testing.T) {
|
||||
node := &Node{
|
||||
ID: MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||
IP: net.IP([]byte{192, 168, 0, 1}),
|
||||
TCPPort: 30303,
|
||||
ID: MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||
IP: net.IP([]byte{192, 168, 0, 1}),
|
||||
UDP: 30303,
|
||||
TCP: 30303,
|
||||
}
|
||||
inst := time.Now()
|
||||
|
||||
@ -124,7 +126,7 @@ func TestNodeDBFetchStore(t *testing.T) {
|
||||
}
|
||||
if stored := db.node(node.ID); stored == nil {
|
||||
t.Errorf("node: not found")
|
||||
} else if !bytes.Equal(stored.ID[:], node.ID[:]) || !stored.IP.Equal(node.IP) || stored.TCPPort != node.TCPPort {
|
||||
} else if !reflect.DeepEqual(stored, node) {
|
||||
t.Errorf("node: data mismatch: have %v, want %v", stored, node)
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"net"
|
||||
@ -16,49 +15,45 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
const nodeIDBits = 512
|
||||
|
||||
// Node represents a host on the network.
|
||||
type Node struct {
|
||||
ID NodeID
|
||||
IP net.IP
|
||||
|
||||
DiscPort int // UDP listening port for discovery protocol
|
||||
TCPPort int // TCP listening port for RLPx
|
||||
IP net.IP // len 4 for IPv4 or 16 for IPv6
|
||||
UDP, TCP uint16 // port numbers
|
||||
ID NodeID
|
||||
}
|
||||
|
||||
func newNode(id NodeID, addr *net.UDPAddr) *Node {
|
||||
ip := addr.IP.To4()
|
||||
if ip == nil {
|
||||
ip = addr.IP.To16()
|
||||
}
|
||||
return &Node{
|
||||
ID: id,
|
||||
IP: addr.IP,
|
||||
DiscPort: addr.Port,
|
||||
TCPPort: addr.Port,
|
||||
IP: ip,
|
||||
UDP: uint16(addr.Port),
|
||||
TCP: uint16(addr.Port),
|
||||
ID: id,
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Node) isValid() bool {
|
||||
// TODO: don't accept localhost, LAN addresses from internet hosts
|
||||
return !n.IP.IsMulticast() && !n.IP.IsUnspecified() && n.TCPPort != 0 && n.DiscPort != 0
|
||||
}
|
||||
|
||||
func (n *Node) addr() *net.UDPAddr {
|
||||
return &net.UDPAddr{IP: n.IP, Port: n.DiscPort}
|
||||
return &net.UDPAddr{IP: n.IP, Port: int(n.UDP)}
|
||||
}
|
||||
|
||||
// The string representation of a Node is a URL.
|
||||
// Please see ParseNode for a description of the format.
|
||||
func (n *Node) String() string {
|
||||
addr := net.TCPAddr{IP: n.IP, Port: n.TCPPort}
|
||||
addr := net.TCPAddr{IP: n.IP, Port: int(n.TCP)}
|
||||
u := url.URL{
|
||||
Scheme: "enode",
|
||||
User: url.User(fmt.Sprintf("%x", n.ID[:])),
|
||||
Host: addr.String(),
|
||||
}
|
||||
if n.DiscPort != n.TCPPort {
|
||||
u.RawQuery = "discport=" + strconv.Itoa(n.DiscPort)
|
||||
if n.UDP != n.TCP {
|
||||
u.RawQuery = "discport=" + strconv.Itoa(int(n.UDP))
|
||||
}
|
||||
return u.String()
|
||||
}
|
||||
@ -98,16 +93,20 @@ func ParseNode(rawurl string) (*Node, error) {
|
||||
if n.IP = net.ParseIP(ip); n.IP == nil {
|
||||
return nil, errors.New("invalid IP address")
|
||||
}
|
||||
if n.TCPPort, err = strconv.Atoi(port); err != nil {
|
||||
tcp, err := strconv.ParseUint(port, 10, 16)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid port")
|
||||
}
|
||||
n.TCP = uint16(tcp)
|
||||
qv := u.Query()
|
||||
if qv.Get("discport") == "" {
|
||||
n.DiscPort = n.TCPPort
|
||||
n.UDP = n.TCP
|
||||
} else {
|
||||
if n.DiscPort, err = strconv.Atoi(qv.Get("discport")); err != nil {
|
||||
udp, err := strconv.ParseUint(qv.Get("discport"), 10, 16)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid discport in query")
|
||||
}
|
||||
n.UDP = uint16(udp)
|
||||
}
|
||||
return &n, nil
|
||||
}
|
||||
@ -121,22 +120,6 @@ func MustParseNode(rawurl string) *Node {
|
||||
return n
|
||||
}
|
||||
|
||||
func (n Node) EncodeRLP(w io.Writer) error {
|
||||
return rlp.Encode(w, rpcNode{IP: n.IP.String(), Port: uint16(n.TCPPort), ID: n.ID})
|
||||
}
|
||||
func (n *Node) DecodeRLP(s *rlp.Stream) (err error) {
|
||||
var ext rpcNode
|
||||
if err = s.Decode(&ext); err == nil {
|
||||
n.TCPPort = int(ext.Port)
|
||||
n.DiscPort = int(ext.Port)
|
||||
n.ID = ext.ID
|
||||
if n.IP = net.ParseIP(ext.IP); n.IP == nil {
|
||||
return errors.New("invalid IP string")
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// NodeID is a unique identifier for each node.
|
||||
// The node identifier is a marshaled elliptic curve public key.
|
||||
type NodeID [nodeIDBits / 8]byte
|
||||
|
@ -49,28 +49,28 @@ var parseNodeTests = []struct {
|
||||
{
|
||||
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150",
|
||||
wantResult: &Node{
|
||||
ID: MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||
IP: net.ParseIP("127.0.0.1"),
|
||||
DiscPort: 52150,
|
||||
TCPPort: 52150,
|
||||
ID: MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||
IP: net.ParseIP("127.0.0.1"),
|
||||
UDP: 52150,
|
||||
TCP: 52150,
|
||||
},
|
||||
},
|
||||
{
|
||||
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150",
|
||||
wantResult: &Node{
|
||||
ID: MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||
IP: net.ParseIP("::"),
|
||||
DiscPort: 52150,
|
||||
TCPPort: 52150,
|
||||
ID: MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||
IP: net.ParseIP("::"),
|
||||
UDP: 52150,
|
||||
TCP: 52150,
|
||||
},
|
||||
},
|
||||
{
|
||||
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=223344",
|
||||
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334",
|
||||
wantResult: &Node{
|
||||
ID: MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||
IP: net.ParseIP("127.0.0.1"),
|
||||
DiscPort: 223344,
|
||||
TCPPort: 52150,
|
||||
ID: MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||
IP: net.ParseIP("127.0.0.1"),
|
||||
UDP: 22334,
|
||||
TCP: 52150,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ func (tab *Table) bondall(nodes []*Node) (result []*Node) {
|
||||
rc := make(chan *Node, len(nodes))
|
||||
for i := range nodes {
|
||||
go func(n *Node) {
|
||||
nn, _ := tab.bond(false, n.ID, n.addr(), uint16(n.TCPPort))
|
||||
nn, _ := tab.bond(false, n.ID, n.addr(), uint16(n.TCP))
|
||||
rc <- nn
|
||||
}(nodes[i])
|
||||
}
|
||||
@ -299,12 +299,7 @@ func (tab *Table) pingpong(w *bondproc, pinged bool, id NodeID, addr *net.UDPAdd
|
||||
tab.net.waitping(id)
|
||||
}
|
||||
// Bonding succeeded, update the node database
|
||||
w.n = &Node{
|
||||
ID: id,
|
||||
IP: addr.IP,
|
||||
DiscPort: addr.Port,
|
||||
TCPPort: int(tcpPort),
|
||||
}
|
||||
w.n = &Node{ID: id, IP: addr.IP, UDP: uint16(addr.Port), TCP: tcpPort}
|
||||
tab.db.updateNode(w.n)
|
||||
close(w.done)
|
||||
}
|
||||
|
@ -261,9 +261,9 @@ func (t findnodeOracle) findnode(toid NodeID, toaddr *net.UDPAddr, target NodeID
|
||||
panic("query to node at distance 0")
|
||||
default:
|
||||
// TODO: add more randomness to distances
|
||||
next := toaddr.Port - 1
|
||||
next := uint16(toaddr.Port) - 1
|
||||
for i := 0; i < bucketSize; i++ {
|
||||
result = append(result, &Node{ID: randomID(t.target, next), DiscPort: next})
|
||||
result = append(result, &Node{ID: randomID(t.target, int(next)), UDP: next})
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
|
@ -49,16 +49,20 @@ const (
|
||||
// RPC request structures
|
||||
type (
|
||||
ping struct {
|
||||
Version uint // must match Version
|
||||
IP string // our IP
|
||||
Port uint16 // our port
|
||||
Version uint
|
||||
From, To rpcEndpoint
|
||||
Expiration uint64
|
||||
}
|
||||
|
||||
// reply to Ping
|
||||
// pong is the reply to ping.
|
||||
pong struct {
|
||||
ReplyTok []byte
|
||||
Expiration uint64
|
||||
// This field should mirror the UDP envelope address
|
||||
// of the ping packet, which provides a way to discover the
|
||||
// the external address (after NAT).
|
||||
To rpcEndpoint
|
||||
|
||||
ReplyTok []byte // This contains the hash of the ping packet.
|
||||
Expiration uint64 // Absolute timestamp at which the packet becomes invalid.
|
||||
}
|
||||
|
||||
findnode struct {
|
||||
@ -73,12 +77,25 @@ type (
|
||||
Nodes []*Node
|
||||
Expiration uint64
|
||||
}
|
||||
|
||||
rpcEndpoint struct {
|
||||
IP net.IP // len 4 for IPv4 or 16 for IPv6
|
||||
UDP uint16 // for discovery protocol
|
||||
TCP uint16 // for RLPx protocol
|
||||
}
|
||||
)
|
||||
|
||||
type rpcNode struct {
|
||||
IP string
|
||||
Port uint16
|
||||
ID NodeID
|
||||
func makeEndpoint(addr *net.UDPAddr, tcpPort uint16) rpcEndpoint {
|
||||
ip := addr.IP.To4()
|
||||
if ip == nil {
|
||||
ip = addr.IP.To16()
|
||||
}
|
||||
return rpcEndpoint{IP: ip, UDP: uint16(addr.Port), TCP: tcpPort}
|
||||
}
|
||||
|
||||
func validNode(n *Node) bool {
|
||||
// TODO: don't accept localhost, LAN addresses from internet hosts
|
||||
return !n.IP.IsMulticast() && !n.IP.IsUnspecified() && n.UDP != 0
|
||||
}
|
||||
|
||||
type packet interface {
|
||||
@ -94,8 +111,9 @@ type conn interface {
|
||||
|
||||
// udp implements the RPC protocol.
|
||||
type udp struct {
|
||||
conn conn
|
||||
priv *ecdsa.PrivateKey
|
||||
conn conn
|
||||
priv *ecdsa.PrivateKey
|
||||
ourEndpoint rpcEndpoint
|
||||
|
||||
addpending chan *pending
|
||||
gotreply chan reply
|
||||
@ -176,6 +194,8 @@ func newUDP(priv *ecdsa.PrivateKey, c conn, natm nat.Interface, nodeDBPath strin
|
||||
realaddr = &net.UDPAddr{IP: ext, Port: realaddr.Port}
|
||||
}
|
||||
}
|
||||
// TODO: separate TCP port
|
||||
udp.ourEndpoint = makeEndpoint(realaddr, uint16(realaddr.Port))
|
||||
udp.Table = newTable(udp, PubkeyID(&priv.PublicKey), realaddr, nodeDBPath)
|
||||
go udp.loop()
|
||||
go udp.readLoop()
|
||||
@ -194,8 +214,8 @@ func (t *udp) ping(toid NodeID, toaddr *net.UDPAddr) error {
|
||||
errc := t.pending(toid, pongPacket, func(interface{}) bool { return true })
|
||||
t.send(toaddr, pingPacket, ping{
|
||||
Version: Version,
|
||||
IP: t.self.IP.String(),
|
||||
Port: uint16(t.self.TCPPort),
|
||||
From: t.ourEndpoint,
|
||||
To: makeEndpoint(toaddr, 0), // TODO: maybe use known TCP port from DB
|
||||
Expiration: uint64(time.Now().Add(expiration).Unix()),
|
||||
})
|
||||
return <-errc
|
||||
@ -214,7 +234,7 @@ func (t *udp) findnode(toid NodeID, toaddr *net.UDPAddr, target NodeID) ([]*Node
|
||||
reply := r.(*neighbors)
|
||||
for _, n := range reply.Nodes {
|
||||
nreceived++
|
||||
if n.isValid() {
|
||||
if validNode(n) {
|
||||
nodes = append(nodes, n)
|
||||
}
|
||||
}
|
||||
@ -374,19 +394,24 @@ func (t *udp) readLoop() {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
packet, fromID, hash, err := decodePacket(buf[:nbytes])
|
||||
if err != nil {
|
||||
glog.V(logger.Debug).Infof("Bad packet from %v: %v\n", from, err)
|
||||
continue
|
||||
}
|
||||
status := "ok"
|
||||
if err := packet.handle(t, from, fromID, hash); err != nil {
|
||||
status = err.Error()
|
||||
}
|
||||
glog.V(logger.Detail).Infof("<<< %v %T: %s\n", from, packet, status)
|
||||
t.handlePacket(from, buf[:nbytes])
|
||||
}
|
||||
}
|
||||
|
||||
func (t *udp) handlePacket(from *net.UDPAddr, buf []byte) error {
|
||||
packet, fromID, hash, err := decodePacket(buf)
|
||||
if err != nil {
|
||||
glog.V(logger.Debug).Infof("Bad packet from %v: %v\n", from, err)
|
||||
return err
|
||||
}
|
||||
status := "ok"
|
||||
if err = packet.handle(t, from, fromID, hash); err != nil {
|
||||
status = err.Error()
|
||||
}
|
||||
glog.V(logger.Detail).Infof("<<< %v %T: %s\n", from, packet, status)
|
||||
return err
|
||||
}
|
||||
|
||||
func decodePacket(buf []byte) (packet, NodeID, []byte, error) {
|
||||
if len(buf) < headSize+1 {
|
||||
return nil, NodeID{}, nil, errPacketTooSmall
|
||||
@ -425,12 +450,13 @@ func (req *ping) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) er
|
||||
return errBadVersion
|
||||
}
|
||||
t.send(from, pongPacket, pong{
|
||||
To: makeEndpoint(from, req.From.TCP),
|
||||
ReplyTok: mac,
|
||||
Expiration: uint64(time.Now().Add(expiration).Unix()),
|
||||
})
|
||||
if !t.handleReply(fromID, pingPacket, req) {
|
||||
// Note: we're ignoring the provided IP address right now
|
||||
go t.bond(true, fromID, from, req.Port)
|
||||
go t.bond(true, fromID, from, req.From.TCP)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -23,6 +23,15 @@ func init() {
|
||||
logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, logpkg.LstdFlags, logger.ErrorLevel))
|
||||
}
|
||||
|
||||
// shared test variables
|
||||
var (
|
||||
futureExp = uint64(time.Now().Add(10 * time.Hour).Unix())
|
||||
testTarget = MustHexID("01010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101")
|
||||
testRemote = rpcEndpoint{IP: net.ParseIP("1.1.1.1").To4(), UDP: 1, TCP: 2}
|
||||
testLocalAnnounced = rpcEndpoint{IP: net.ParseIP("2.2.2.2").To4(), UDP: 3, TCP: 4}
|
||||
testLocal = rpcEndpoint{IP: net.ParseIP("3.3.3.3").To4(), UDP: 5, TCP: 6}
|
||||
)
|
||||
|
||||
type udpTest struct {
|
||||
t *testing.T
|
||||
pipe *dgramPipe
|
||||
@ -52,8 +61,7 @@ func (test *udpTest) packetIn(wantError error, ptype byte, data packet) error {
|
||||
return test.errorf("packet (%d) encode error: %v", err)
|
||||
}
|
||||
test.sent = append(test.sent, enc)
|
||||
err = data.handle(test.udp, test.remoteaddr, PubkeyID(&test.remotekey.PublicKey), enc[:macSize])
|
||||
if err != wantError {
|
||||
if err = test.udp.handlePacket(test.remoteaddr, enc); err != wantError {
|
||||
return test.errorf("error mismatch: got %q, want %q", err, wantError)
|
||||
}
|
||||
return nil
|
||||
@ -90,18 +98,12 @@ func (test *udpTest) errorf(format string, args ...interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// shared test variables
|
||||
var (
|
||||
futureExp = uint64(time.Now().Add(10 * time.Hour).Unix())
|
||||
testTarget = MustHexID("01010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101")
|
||||
)
|
||||
|
||||
func TestUDP_packetErrors(t *testing.T) {
|
||||
test := newUDPTest(t)
|
||||
defer test.table.Close()
|
||||
|
||||
test.packetIn(errExpired, pingPacket, &ping{IP: "foo", Port: 99, Version: Version})
|
||||
test.packetIn(errBadVersion, pingPacket, &ping{IP: "foo", Port: 99, Version: 99, Expiration: futureExp})
|
||||
test.packetIn(errExpired, pingPacket, &ping{From: testRemote, To: testLocalAnnounced, Version: Version})
|
||||
test.packetIn(errBadVersion, pingPacket, &ping{From: testRemote, To: testLocalAnnounced, Version: 99, Expiration: futureExp})
|
||||
test.packetIn(errUnsolicitedReply, pongPacket, &pong{ReplyTok: []byte{}, Expiration: futureExp})
|
||||
test.packetIn(errUnknownNode, findnodePacket, &findnode{Expiration: futureExp})
|
||||
test.packetIn(errUnsolicitedReply, neighborsPacket, &neighbors{Expiration: futureExp})
|
||||
@ -147,10 +149,10 @@ func TestUDP_findnode(t *testing.T) {
|
||||
nodes := &nodesByDistance{target: target}
|
||||
for i := 0; i < bucketSize; i++ {
|
||||
nodes.push(&Node{
|
||||
IP: net.IP{1, 2, 3, byte(i)},
|
||||
DiscPort: i + 2,
|
||||
TCPPort: i + 2,
|
||||
ID: randomID(test.table.self.ID, i+2),
|
||||
IP: net.IP{1, 2, 3, byte(i)},
|
||||
UDP: uint16(i + 2),
|
||||
TCP: uint16(i + 3),
|
||||
ID: randomID(test.table.self.ID, i+2),
|
||||
}, bucketSize)
|
||||
}
|
||||
test.table.add(nodes.entries)
|
||||
@ -158,10 +160,10 @@ func TestUDP_findnode(t *testing.T) {
|
||||
// ensure there's a bond with the test node,
|
||||
// findnode won't be accepted otherwise.
|
||||
test.table.db.updateNode(&Node{
|
||||
ID: PubkeyID(&test.remotekey.PublicKey),
|
||||
IP: test.remoteaddr.IP,
|
||||
DiscPort: test.remoteaddr.Port,
|
||||
TCPPort: 99,
|
||||
ID: PubkeyID(&test.remotekey.PublicKey),
|
||||
IP: test.remoteaddr.IP,
|
||||
UDP: uint16(test.remoteaddr.Port),
|
||||
TCP: 99,
|
||||
})
|
||||
// check that closest neighbors are returned.
|
||||
test.packetIn(nil, findnodePacket, &findnode{Target: testTarget, Expiration: futureExp})
|
||||
@ -204,9 +206,9 @@ func TestUDP_findnodeMultiReply(t *testing.T) {
|
||||
|
||||
// send the reply as two packets.
|
||||
list := []*Node{
|
||||
MustParseNode("enode://ba85011c70bcc5c04d8607d3a0ed29aa6179c092cbdda10d5d32684fb33ed01bd94f588ca8f91ac48318087dcb02eaf36773a7a453f0eedd6742af668097b29c@10.0.1.16:30303"),
|
||||
MustParseNode("enode://ba85011c70bcc5c04d8607d3a0ed29aa6179c092cbdda10d5d32684fb33ed01bd94f588ca8f91ac48318087dcb02eaf36773a7a453f0eedd6742af668097b29c@10.0.1.16:30303?discport=30304"),
|
||||
MustParseNode("enode://81fa361d25f157cd421c60dcc28d8dac5ef6a89476633339c5df30287474520caca09627da18543d9079b5b288698b542d56167aa5c09111e55acdbbdf2ef799@10.0.1.16:30303"),
|
||||
MustParseNode("enode://9bffefd833d53fac8e652415f4973bee289e8b1a5c6c4cbe70abf817ce8a64cee11b823b66a987f51aaa9fba0d6a91b3e6bf0d5a5d1042de8e9eeea057b217f8@10.0.1.36:30301"),
|
||||
MustParseNode("enode://9bffefd833d53fac8e652415f4973bee289e8b1a5c6c4cbe70abf817ce8a64cee11b823b66a987f51aaa9fba0d6a91b3e6bf0d5a5d1042de8e9eeea057b217f8@10.0.1.36:30301?discport=17"),
|
||||
MustParseNode("enode://1b5b4aa662d7cb44a7221bfba67302590b643028197a7d5214790f3bac7aaa4a3241be9e83c09cf1f6c69d007c634faae3dc1b1221793e8446c0b3a09de65960@10.0.1.16:30303"),
|
||||
}
|
||||
test.packetIn(nil, neighborsPacket, &neighbors{Expiration: futureExp, Nodes: list[:2]})
|
||||
@ -231,7 +233,8 @@ func TestUDP_successfulPing(t *testing.T) {
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
test.packetIn(nil, pingPacket, &ping{IP: "foo", Port: 99, Version: Version, Expiration: futureExp})
|
||||
// The remote side sends a ping packet to initiate the exchange.
|
||||
test.packetIn(nil, pingPacket, &ping{From: testRemote, To: testLocalAnnounced, Version: Version, Expiration: futureExp})
|
||||
close(done)
|
||||
}()
|
||||
|
||||
@ -239,12 +242,34 @@ func TestUDP_successfulPing(t *testing.T) {
|
||||
test.waitPacketOut(func(p *pong) {
|
||||
pinghash := test.sent[0][:macSize]
|
||||
if !bytes.Equal(p.ReplyTok, pinghash) {
|
||||
t.Errorf("got ReplyTok %x, want %x", p.ReplyTok, pinghash)
|
||||
t.Errorf("got pong.ReplyTok %x, want %x", p.ReplyTok, pinghash)
|
||||
}
|
||||
wantTo := rpcEndpoint{
|
||||
// The mirrored UDP address is the UDP packet sender
|
||||
IP: test.remoteaddr.IP, UDP: uint16(test.remoteaddr.Port),
|
||||
// The mirrored TCP port is the one from the ping packet
|
||||
TCP: testRemote.TCP,
|
||||
}
|
||||
if !reflect.DeepEqual(p.To, wantTo) {
|
||||
t.Errorf("got pong.To %v, want %v", p.To, wantTo)
|
||||
}
|
||||
})
|
||||
|
||||
// remote is unknown, the table pings back.
|
||||
test.waitPacketOut(func(p *ping) error { return nil })
|
||||
test.waitPacketOut(func(p *ping) error {
|
||||
if !reflect.DeepEqual(p.From, test.udp.ourEndpoint) {
|
||||
t.Errorf("got ping.From %v, want %v", p.From, test.udp.ourEndpoint)
|
||||
}
|
||||
wantTo := rpcEndpoint{
|
||||
// The mirrored UDP address is the UDP packet sender.
|
||||
IP: test.remoteaddr.IP, UDP: uint16(test.remoteaddr.Port),
|
||||
TCP: 0,
|
||||
}
|
||||
if !reflect.DeepEqual(p.To, wantTo) {
|
||||
t.Errorf("got ping.To %v, want %v", p.To, wantTo)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
test.packetIn(nil, pongPacket, &pong{Expiration: futureExp})
|
||||
|
||||
// ping should return shortly after getting the pong packet.
|
||||
@ -259,11 +284,11 @@ func TestUDP_successfulPing(t *testing.T) {
|
||||
if !bytes.Equal(rnode.IP, test.remoteaddr.IP) {
|
||||
t.Errorf("node has wrong IP: got %v, want: %v", rnode.IP, test.remoteaddr.IP)
|
||||
}
|
||||
if rnode.DiscPort != test.remoteaddr.Port {
|
||||
t.Errorf("node has wrong Port: got %v, want: %v", rnode.DiscPort, test.remoteaddr.Port)
|
||||
if int(rnode.UDP) != test.remoteaddr.Port {
|
||||
t.Errorf("node has wrong UDP port: got %v, want: %v", rnode.UDP, test.remoteaddr.Port)
|
||||
}
|
||||
if rnode.TCPPort != 99 {
|
||||
t.Errorf("node has wrong Port: got %v, want: %v", rnode.TCPPort, 99)
|
||||
if rnode.TCP != testRemote.TCP {
|
||||
t.Errorf("node has wrong TCP port: got %v, want: %v", rnode.TCP, testRemote.TCP)
|
||||
}
|
||||
}
|
||||
|
||||
@ -327,7 +352,7 @@ func (c *dgramPipe) Close() error {
|
||||
}
|
||||
|
||||
func (c *dgramPipe) LocalAddr() net.Addr {
|
||||
return &net.UDPAddr{}
|
||||
return &net.UDPAddr{IP: testLocal.IP, Port: int(testLocal.UDP)}
|
||||
}
|
||||
|
||||
func (c *dgramPipe) waitPacketOut() []byte {
|
||||
|
@ -119,14 +119,14 @@ func TestSetupConn(t *testing.T) {
|
||||
prv0, _ := crypto.GenerateKey()
|
||||
prv1, _ := crypto.GenerateKey()
|
||||
node0 := &discover.Node{
|
||||
ID: discover.PubkeyID(&prv0.PublicKey),
|
||||
IP: net.IP{1, 2, 3, 4},
|
||||
TCPPort: 33,
|
||||
ID: discover.PubkeyID(&prv0.PublicKey),
|
||||
IP: net.IP{1, 2, 3, 4},
|
||||
TCP: 33,
|
||||
}
|
||||
node1 := &discover.Node{
|
||||
ID: discover.PubkeyID(&prv1.PublicKey),
|
||||
IP: net.IP{5, 6, 7, 8},
|
||||
TCPPort: 44,
|
||||
ID: discover.PubkeyID(&prv1.PublicKey),
|
||||
IP: net.IP{5, 6, 7, 8},
|
||||
TCP: 44,
|
||||
}
|
||||
hs0 := &protoHandshake{
|
||||
Version: baseProtocolVersion,
|
||||
|
@ -394,7 +394,7 @@ func (srv *Server) dialLoop() {
|
||||
}
|
||||
|
||||
func (srv *Server) dialNode(dest *discover.Node) {
|
||||
addr := &net.TCPAddr{IP: dest.IP, Port: dest.TCPPort}
|
||||
addr := &net.TCPAddr{IP: dest.IP, Port: int(dest.TCP)}
|
||||
glog.V(logger.Debug).Infof("Dialing %v\n", dest)
|
||||
conn, err := srv.Dialer.Dial("tcp", addr.String())
|
||||
if err != nil {
|
||||
|
@ -102,7 +102,7 @@ func TestServerDial(t *testing.T) {
|
||||
|
||||
// tell the server to connect
|
||||
tcpAddr := listener.Addr().(*net.TCPAddr)
|
||||
srv.SuggestPeer(&discover.Node{IP: tcpAddr.IP, TCPPort: tcpAddr.Port})
|
||||
srv.SuggestPeer(&discover.Node{IP: tcpAddr.IP, TCP: uint16(tcpAddr.Port)})
|
||||
|
||||
select {
|
||||
case conn := <-accepted:
|
||||
|
Loading…
Reference in New Issue
Block a user