Skip to content

Commit 639ac5c

Browse files
committed
Merge pull request #352 from fjl/no-enc-handshake
p2p: disable encryption handshake, enable log events
2 parents 765740b + 3719db3 commit 639ac5c

File tree

10 files changed

+333
-342
lines changed

10 files changed

+333
-342
lines changed

cmd/mist/assets/qml/main.qml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -931,7 +931,8 @@ ApplicationWindow {
931931
model: peerModel
932932
TableViewColumn{width: 180; role: "addr" ; title: "Remote Address" }
933933
TableViewColumn{width: 280; role: "nodeID" ; title: "Node ID" }
934-
TableViewColumn{width: 180; role: "caps" ; title: "Capabilities" }
934+
TableViewColumn{width: 100; role: "name" ; title: "Name" }
935+
TableViewColumn{width: 40; role: "caps" ; title: "Capabilities" }
935936
}
936937
}
937938
}

cmd/mist/gui.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ NumGC: %d
466466
))
467467
}
468468

469-
type qmlpeer struct{ Addr, NodeID, Caps string }
469+
type qmlpeer struct{ Addr, NodeID, Name, Caps string }
470470

471471
type peersByID []*qmlpeer
472472

@@ -481,6 +481,7 @@ func (gui *Gui) setPeerInfo() {
481481
qpeers[i] = &qmlpeer{
482482
NodeID: p.ID().String(),
483483
Addr: p.RemoteAddr().String(),
484+
Name: p.Name(),
484485
Caps: fmt.Sprint(p.Caps()),
485486
}
486487
}

logger/types.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,16 @@ func (l *P2PConnected) EventName() string {
4242
return "p2p.connected"
4343
}
4444

45+
type P2PDisconnected struct {
46+
NumConnections int `json:"num_connections"`
47+
RemoteId string `json:"remote_id"`
48+
LogEvent
49+
}
50+
51+
func (l *P2PDisconnected) EventName() string {
52+
return "p2p.disconnected"
53+
}
54+
4555
type EthMinerNewBlock struct {
4656
BlockHash string `json:"block_hash"`
4757
BlockNumber int `json:"block_number"`
@@ -117,16 +127,6 @@ func (l *EthTxReceived) EventName() string {
117127
// return "p2p.handshaked"
118128
// }
119129

120-
// type P2PDisconnected struct {
121-
// NumConnections int `json:"num_connections"`
122-
// RemoteId string `json:"remote_id"`
123-
// LogEvent
124-
// }
125-
126-
// func (l *P2PDisconnected) EventName() string {
127-
// return "p2p.disconnected"
128-
// }
129-
130130
// type P2PDisconnecting struct {
131131
// Reason string `json:"reason"`
132132
// RemoteId string `json:"remote_id"`

p2p/crypto.go renamed to p2p/handshake.go

Lines changed: 104 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
11
package p2p
22

33
import (
4-
// "binary"
54
"crypto/ecdsa"
65
"crypto/rand"
6+
"errors"
77
"fmt"
88
"io"
9+
"net"
910

1011
"github.com/ethereum/go-ethereum/crypto"
1112
"github.com/ethereum/go-ethereum/crypto/ecies"
1213
"github.com/ethereum/go-ethereum/crypto/secp256k1"
13-
ethlogger "github.com/ethereum/go-ethereum/logger"
1414
"github.com/ethereum/go-ethereum/p2p/discover"
15+
"github.com/ethereum/go-ethereum/rlp"
1516
)
1617

17-
var clogger = ethlogger.NewLogger("CRYPTOID")
18-
1918
const (
2019
sskLen = 16 // ecies.MaxSharedKeyLength(pubKey) / 2
2120
sigLen = 65 // elliptic S256
@@ -30,26 +29,76 @@ const (
3029
rHSLen = authRespLen + eciesBytes // size of the final ECIES payload sent as receiver's handshake
3130
)
3231

33-
type hexkey []byte
32+
type conn struct {
33+
*frameRW
34+
*protoHandshake
35+
}
3436

35-
func (self hexkey) String() string {
36-
return fmt.Sprintf("(%d) %x", len(self), []byte(self))
37+
func newConn(fd net.Conn, hs *protoHandshake) *conn {
38+
return &conn{newFrameRW(fd, msgWriteTimeout), hs}
3739
}
3840

39-
func encHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, dial *discover.Node) (
40-
remoteID discover.NodeID,
41-
sessionToken []byte,
42-
err error,
43-
) {
41+
// encHandshake represents information about the remote end
42+
// of a connection that is negotiated during the encryption handshake.
43+
type encHandshake struct {
44+
ID discover.NodeID
45+
IngressMAC []byte
46+
EgressMAC []byte
47+
Token []byte
48+
}
49+
50+
// protoHandshake is the RLP structure of the protocol handshake.
51+
type protoHandshake struct {
52+
Version uint64
53+
Name string
54+
Caps []Cap
55+
ListenPort uint64
56+
ID discover.NodeID
57+
}
58+
59+
// setupConn starts a protocol session on the given connection.
60+
// It runs the encryption handshake and the protocol handshake.
61+
// If dial is non-nil, the connection the local node is the initiator.
62+
func setupConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake, dial *discover.Node) (*conn, error) {
4463
if dial == nil {
45-
var remotePubkey []byte
46-
sessionToken, remotePubkey, err = inboundEncHandshake(conn, prv, nil)
47-
copy(remoteID[:], remotePubkey)
64+
return setupInboundConn(fd, prv, our)
4865
} else {
49-
remoteID = dial.ID
50-
sessionToken, err = outboundEncHandshake(conn, prv, remoteID[:], nil)
66+
return setupOutboundConn(fd, prv, our, dial)
67+
}
68+
}
69+
70+
func setupInboundConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake) (*conn, error) {
71+
// var remotePubkey []byte
72+
// sessionToken, remotePubkey, err = inboundEncHandshake(fd, prv, nil)
73+
// copy(remoteID[:], remotePubkey)
74+
75+
rw := newFrameRW(fd, msgWriteTimeout)
76+
rhs, err := readProtocolHandshake(rw, our)
77+
if err != nil {
78+
return nil, err
79+
}
80+
if err := writeProtocolHandshake(rw, our); err != nil {
81+
return nil, fmt.Errorf("protocol write error: %v", err)
82+
}
83+
return &conn{rw, rhs}, nil
84+
}
85+
86+
func setupOutboundConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake, dial *discover.Node) (*conn, error) {
87+
// remoteID = dial.ID
88+
// sessionToken, err = outboundEncHandshake(fd, prv, remoteID[:], nil)
89+
90+
rw := newFrameRW(fd, msgWriteTimeout)
91+
if err := writeProtocolHandshake(rw, our); err != nil {
92+
return nil, fmt.Errorf("protocol write error: %v", err)
5193
}
52-
return remoteID, sessionToken, err
94+
rhs, err := readProtocolHandshake(rw, our)
95+
if err != nil {
96+
return nil, fmt.Errorf("protocol handshake read error: %v", err)
97+
}
98+
if rhs.ID != dial.ID {
99+
return nil, errors.New("dialed node id mismatch")
100+
}
101+
return &conn{rw, rhs}, nil
53102
}
54103

55104
// outboundEncHandshake negotiates a session token on conn.
@@ -66,18 +115,9 @@ func outboundEncHandshake(conn io.ReadWriter, prvKey *ecdsa.PrivateKey, remotePu
66115
if err != nil {
67116
return nil, err
68117
}
69-
if sessionToken != nil {
70-
clogger.Debugf("session-token: %v", hexkey(sessionToken))
71-
}
72-
73-
clogger.Debugf("initiator-nonce: %v", hexkey(initNonce))
74-
clogger.Debugf("initiator-random-private-key: %v", hexkey(crypto.FromECDSA(randomPrivKey)))
75-
randomPublicKeyS, _ := exportPublicKey(&randomPrivKey.PublicKey)
76-
clogger.Debugf("initiator-random-public-key: %v", hexkey(randomPublicKeyS))
77118
if _, err = conn.Write(auth); err != nil {
78119
return nil, err
79120
}
80-
clogger.Debugf("initiator handshake: %v", hexkey(auth))
81121

82122
response := make([]byte, rHSLen)
83123
if _, err = io.ReadFull(conn, response); err != nil {
@@ -88,9 +128,6 @@ func outboundEncHandshake(conn io.ReadWriter, prvKey *ecdsa.PrivateKey, remotePu
88128
return nil, err
89129
}
90130

91-
clogger.Debugf("receiver-nonce: %v", hexkey(recNonce))
92-
remoteRandomPubKeyS, _ := exportPublicKey(remoteRandomPubKey)
93-
clogger.Debugf("receiver-random-public-key: %v", hexkey(remoteRandomPubKeyS))
94131
return newSession(initNonce, recNonce, randomPrivKey, remoteRandomPubKey)
95132
}
96133

@@ -221,12 +258,9 @@ func inboundEncHandshake(conn io.ReadWriter, prvKey *ecdsa.PrivateKey, sessionTo
221258
if err != nil {
222259
return nil, nil, err
223260
}
224-
clogger.Debugf("receiver-nonce: %v", hexkey(recNonce))
225-
clogger.Debugf("receiver-random-priv-key: %v", hexkey(crypto.FromECDSA(randomPrivKey)))
226261
if _, err = conn.Write(response); err != nil {
227262
return nil, nil, err
228263
}
229-
clogger.Debugf("receiver handshake:\n%v", hexkey(response))
230264
token, err = newSession(initNonce, recNonce, randomPrivKey, remoteRandomPubKey)
231265
return token, remotePubKey, err
232266
}
@@ -361,3 +395,40 @@ func xor(one, other []byte) (xor []byte) {
361395
}
362396
return xor
363397
}
398+
399+
func writeProtocolHandshake(w MsgWriter, our *protoHandshake) error {
400+
return EncodeMsg(w, handshakeMsg, our.Version, our.Name, our.Caps, our.ListenPort, our.ID[:])
401+
}
402+
403+
func readProtocolHandshake(r MsgReader, our *protoHandshake) (*protoHandshake, error) {
404+
// read and handle remote handshake
405+
msg, err := r.ReadMsg()
406+
if err != nil {
407+
return nil, err
408+
}
409+
if msg.Code == discMsg {
410+
// disconnect before protocol handshake is valid according to the
411+
// spec and we send it ourself if Server.addPeer fails.
412+
var reason DiscReason
413+
rlp.Decode(msg.Payload, &reason)
414+
return nil, discRequestedError(reason)
415+
}
416+
if msg.Code != handshakeMsg {
417+
return nil, fmt.Errorf("expected handshake, got %x", msg.Code)
418+
}
419+
if msg.Size > baseProtocolMaxMsgSize {
420+
return nil, fmt.Errorf("message too big (%d > %d)", msg.Size, baseProtocolMaxMsgSize)
421+
}
422+
var hs protoHandshake
423+
if err := msg.Decode(&hs); err != nil {
424+
return nil, err
425+
}
426+
// validate handshake info
427+
if hs.Version != our.Version {
428+
return nil, newPeerError(errP2PVersionMismatch, "required version %d, received %d\n", baseProtocolVersion, hs.Version)
429+
}
430+
if (hs.ID == discover.NodeID{}) {
431+
return nil, newPeerError(errPubkeyInvalid, "missing")
432+
}
433+
return &hs, nil
434+
}

p2p/crypto_test.go renamed to p2p/handshake_test.go

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import (
55
"crypto/ecdsa"
66
"crypto/rand"
77
"net"
8+
"reflect"
89
"testing"
910

1011
"github.com/ethereum/go-ethereum/crypto"
1112
"github.com/ethereum/go-ethereum/crypto/ecies"
13+
"github.com/ethereum/go-ethereum/p2p/discover"
1214
)
1315

1416
func TestPublicKeyEncoding(t *testing.T) {
@@ -91,14 +93,14 @@ func testCryptoHandshake(prv0, prv1 *ecdsa.PrivateKey, sessionToken []byte, t *t
9193
if err != nil {
9294
t.Errorf("%v", err)
9395
}
94-
t.Logf("-> %v", hexkey(auth))
96+
// t.Logf("-> %v", hexkey(auth))
9597

9698
// receiver reads auth and responds with response
9799
response, remoteRecNonce, remoteInitNonce, _, remoteRandomPrivKey, remoteInitRandomPubKey, err := authResp(auth, sessionToken, prv1)
98100
if err != nil {
99101
t.Errorf("%v", err)
100102
}
101-
t.Logf("<- %v\n", hexkey(response))
103+
// t.Logf("<- %v\n", hexkey(response))
102104

103105
// initiator reads receiver's response and the key exchange completes
104106
recNonce, remoteRandomPubKey, _, err := completeHandshake(response, prv0)
@@ -132,7 +134,7 @@ func testCryptoHandshake(prv0, prv1 *ecdsa.PrivateKey, sessionToken []byte, t *t
132134
}
133135
}
134136

135-
func TestHandshake(t *testing.T) {
137+
func TestEncHandshake(t *testing.T) {
136138
defer testlog(t).detach()
137139

138140
prv0, _ := crypto.GenerateKey()
@@ -165,3 +167,58 @@ func TestHandshake(t *testing.T) {
165167
t.Error("session token mismatch")
166168
}
167169
}
170+
171+
func TestSetupConn(t *testing.T) {
172+
prv0, _ := crypto.GenerateKey()
173+
prv1, _ := crypto.GenerateKey()
174+
node0 := &discover.Node{
175+
ID: discover.PubkeyID(&prv0.PublicKey),
176+
IP: net.IP{1, 2, 3, 4},
177+
TCPPort: 33,
178+
}
179+
node1 := &discover.Node{
180+
ID: discover.PubkeyID(&prv1.PublicKey),
181+
IP: net.IP{5, 6, 7, 8},
182+
TCPPort: 44,
183+
}
184+
hs0 := &protoHandshake{
185+
Version: baseProtocolVersion,
186+
ID: node0.ID,
187+
Caps: []Cap{{"a", 0}, {"b", 2}},
188+
}
189+
hs1 := &protoHandshake{
190+
Version: baseProtocolVersion,
191+
ID: node1.ID,
192+
Caps: []Cap{{"c", 1}, {"d", 3}},
193+
}
194+
fd0, fd1 := net.Pipe()
195+
196+
done := make(chan struct{})
197+
go func() {
198+
defer close(done)
199+
conn0, err := setupConn(fd0, prv0, hs0, node1)
200+
if err != nil {
201+
t.Errorf("outbound side error: %v", err)
202+
return
203+
}
204+
if conn0.ID != node1.ID {
205+
t.Errorf("outbound conn id mismatch: got %v, want %v", conn0.ID, node1.ID)
206+
}
207+
if !reflect.DeepEqual(conn0.Caps, hs1.Caps) {
208+
t.Errorf("outbound caps mismatch: got %v, want %v", conn0.Caps, hs1.Caps)
209+
}
210+
}()
211+
212+
conn1, err := setupConn(fd1, prv1, hs1, nil)
213+
if err != nil {
214+
t.Fatalf("inbound side error: %v", err)
215+
}
216+
if conn1.ID != node0.ID {
217+
t.Errorf("inbound conn id mismatch: got %v, want %v", conn1.ID, node0.ID)
218+
}
219+
if !reflect.DeepEqual(conn1.Caps, hs0.Caps) {
220+
t.Errorf("inbound caps mismatch: got %v, want %v", conn1.Caps, hs0.Caps)
221+
}
222+
223+
<-done
224+
}

p2p/message.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ func (rw *frameRW) ReadMsg() (msg Msg, err error) {
197197
return msg, err
198198
}
199199
if !bytes.HasPrefix(start, magicToken) {
200-
return msg, fmt.Errorf("bad magic token %x", start[:4], magicToken)
200+
return msg, fmt.Errorf("bad magic token %x", start[:4])
201201
}
202202
size := binary.BigEndian.Uint32(start[4:])
203203

0 commit comments

Comments
 (0)