Skip to content

Commit 3e4fbce

Browse files
thinkAfCodfjl
andauthored
p2p/discover: repeat exact encoding when resending WHOAREYOU packet (ethereum#31543)
When resending the WHOAREYOU packet, a new nonce and random IV should not be generated. The sent packet needs to match the previously-sent one exactly in order to make the handshake retry work. --------- Co-authored-by: Felix Lange <fjl@twurst.com>
1 parent ee30681 commit 3e4fbce

File tree

3 files changed

+45
-14
lines changed

3 files changed

+45
-14
lines changed

p2p/discover/v5_udp_test.go

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -181,29 +181,35 @@ func TestUDPv5_handshakeRepeatChallenge(t *testing.T) {
181181
nonce1 := v5wire.Nonce{1}
182182
nonce2 := v5wire.Nonce{2}
183183
nonce3 := v5wire.Nonce{3}
184-
check := func(p *v5wire.Whoareyou, wantNonce v5wire.Nonce) {
184+
var firstAuthTag *v5wire.Nonce
185+
check := func(p *v5wire.Whoareyou, authTag, wantNonce v5wire.Nonce) {
185186
t.Helper()
186187
if p.Nonce != wantNonce {
187-
t.Error("wrong nonce in WHOAREYOU:", p.Nonce, wantNonce)
188+
t.Error("wrong nonce in WHOAREYOU:", p.Nonce, "want:", wantNonce)
189+
}
190+
if firstAuthTag == nil {
191+
firstAuthTag = &authTag
192+
} else if authTag != *firstAuthTag {
193+
t.Error("wrong auth tag in WHOAREYOU header:", authTag, "want:", *firstAuthTag)
188194
}
189195
}
190196

191197
// Unknown packet from unknown node.
192198
test.packetIn(&v5wire.Unknown{Nonce: nonce1})
193-
test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, _ v5wire.Nonce) {
194-
check(p, nonce1)
199+
test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, authTag v5wire.Nonce) {
200+
check(p, authTag, nonce1)
195201
})
196202

197203
// Second unknown packet. Here we expect the response to reference the
198204
// first unknown packet.
199205
test.packetIn(&v5wire.Unknown{Nonce: nonce2})
200-
test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, _ v5wire.Nonce) {
201-
check(p, nonce1)
206+
test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, authTag v5wire.Nonce) {
207+
check(p, authTag, nonce1)
202208
})
203209
// Third unknown packet. This should still return the first nonce.
204210
test.packetIn(&v5wire.Unknown{Nonce: nonce3})
205-
test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, _ v5wire.Nonce) {
206-
check(p, nonce1)
211+
test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, authTag v5wire.Nonce) {
212+
check(p, authTag, nonce1)
207213
})
208214
}
209215

@@ -766,20 +772,30 @@ type testCodecFrame struct {
766772
}
767773

768774
func (c *testCodec) Encode(toID enode.ID, addr string, p v5wire.Packet, _ *v5wire.Whoareyou) ([]byte, v5wire.Nonce, error) {
775+
// To match the behavior of v5wire.Codec, we return the cached encoding of
776+
// WHOAREYOU challenges.
777+
if wp, ok := p.(*v5wire.Whoareyou); ok && len(wp.Encoded) > 0 {
778+
return wp.Encoded, wp.Nonce, nil
779+
}
780+
769781
c.ctr++
770782
var authTag v5wire.Nonce
771783
binary.BigEndian.PutUint64(authTag[:], c.ctr)
784+
penc, _ := rlp.EncodeToBytes(p)
785+
frame, err := rlp.EncodeToBytes(testCodecFrame{c.id, authTag, p.Kind(), penc})
786+
if err != nil {
787+
return frame, authTag, err
788+
}
772789

790+
// Store recently sent challenges.
773791
if w, ok := p.(*v5wire.Whoareyou); ok {
774-
// Store recently sent Whoareyou challenges.
792+
w.Nonce = authTag
793+
w.Encoded = frame
775794
if c.sentChallenges == nil {
776795
c.sentChallenges = make(map[enode.ID]*v5wire.Whoareyou)
777796
}
778797
c.sentChallenges[toID] = w
779798
}
780-
781-
penc, _ := rlp.EncodeToBytes(p)
782-
frame, err := rlp.EncodeToBytes(testCodecFrame{c.id, authTag, p.Kind(), penc})
783799
return frame, authTag, err
784800
}
785801

p2p/discover/v5wire/encoding.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,11 @@ func (c *Codec) Encode(id enode.ID, addr string, packet Packet, challenge *Whoar
189189
)
190190
switch {
191191
case packet.Kind() == WhoareyouPacket:
192+
// just send the WHOAREYOU packet raw again, rather than the re-encoded challenge data
193+
w := packet.(*Whoareyou)
194+
if len(w.Encoded) > 0 {
195+
return w.Encoded, w.Nonce, nil
196+
}
192197
head, err = c.encodeWhoareyou(id, packet.(*Whoareyou))
193198
case challenge != nil:
194199
// We have an unanswered challenge, send handshake.
@@ -218,15 +223,22 @@ func (c *Codec) Encode(id enode.ID, addr string, packet Packet, challenge *Whoar
218223
// Store sent WHOAREYOU challenges.
219224
if challenge, ok := packet.(*Whoareyou); ok {
220225
challenge.ChallengeData = bytesCopy(&c.buf)
226+
enc, err := c.EncodeRaw(id, head, msgData)
227+
if err != nil {
228+
return nil, Nonce{}, err
229+
}
230+
challenge.Encoded = bytes.Clone(enc)
221231
c.sc.storeSentHandshake(id, addr, challenge)
222-
} else if msgData == nil {
232+
return enc, head.Nonce, err
233+
}
234+
235+
if msgData == nil {
223236
headerData := c.buf.Bytes()
224237
msgData, err = c.encryptMessage(session, packet, &head, headerData)
225238
if err != nil {
226239
return nil, Nonce{}, err
227240
}
228241
}
229-
230242
enc, err := c.EncodeRaw(id, head, msgData)
231243
return enc, head.Nonce, err
232244
}

p2p/discover/v5wire/msg.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ type (
7373
Node *enode.Node
7474

7575
sent mclock.AbsTime // for handshake GC.
76+
77+
// Encoded is packet raw data for sending out, but should not be include in the RLP encoding.
78+
Encoded []byte `rlp:"-"`
7679
}
7780

7881
// PING is sent during liveness checks.

0 commit comments

Comments
 (0)