Skip to content

Commit eca3d39

Browse files
authored
p2p/discover: pass invalid discv5 packets to Unhandled channel (#26699)
This makes it possible to run another protocol alongside discv5, by reading unhandled packets from the channel.
1 parent c8a6b71 commit eca3d39

File tree

2 files changed

+26
-2
lines changed

2 files changed

+26
-2
lines changed

p2p/discover/v5_udp.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ type UDPv5 struct {
8383
callCh chan *callV5
8484
callDoneCh chan *callV5
8585
respTimeoutCh chan *callTimeout
86+
unhandled chan<- ReadPacket
8687

8788
// state of dispatch
8889
codec codecV5
@@ -156,6 +157,7 @@ func newUDPv5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) {
156157
callCh: make(chan *callV5),
157158
callDoneCh: make(chan *callV5),
158159
respTimeoutCh: make(chan *callTimeout),
160+
unhandled: cfg.Unhandled,
159161
// state of dispatch
160162
codec: v5wire.NewCodec(ln, cfg.PrivateKey, cfg.Clock, cfg.V5ProtocolID),
161163
activeCallByNode: make(map[enode.ID]*callV5),
@@ -657,6 +659,14 @@ func (t *UDPv5) handlePacket(rawpacket []byte, fromAddr *net.UDPAddr) error {
657659
addr := fromAddr.String()
658660
fromID, fromNode, packet, err := t.codec.Decode(rawpacket, addr)
659661
if err != nil {
662+
if t.unhandled != nil && v5wire.IsInvalidHeader(err) {
663+
// The packet seems unrelated to discv5, send it to the next protocol.
664+
// t.log.Trace("Unhandled discv5 packet", "id", fromID, "addr", addr, "err", err)
665+
up := ReadPacket{Data: make([]byte, len(rawpacket)), Addr: fromAddr}
666+
copy(up.Data, rawpacket)
667+
t.unhandled <- up
668+
return nil
669+
}
660670
t.log.Debug("Bad discv5 packet", "id", fromID, "addr", addr, "err", err)
661671
return err
662672
}

p2p/discover/v5wire/encoding.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ const (
9494
// Should reject packets smaller than minPacketSize.
9595
minPacketSize = 63
9696

97+
maxPacketSize = 1280
98+
9799
minMessageSize = 48 // this refers to data after static headers
98100
randomPacketMsgSize = 20
99101
)
@@ -122,6 +124,13 @@ var (
122124
ErrInvalidReqID = errors.New("request ID larger than 8 bytes")
123125
)
124126

127+
// IsInvalidHeader reports whether 'err' is related to an invalid packet header. When it
128+
// returns false, it is pretty certain that the packet causing the error does not belong
129+
// to discv5.
130+
func IsInvalidHeader(err error) bool {
131+
return err == errTooShort || err == errInvalidHeader || err == errMsgTooShort
132+
}
133+
125134
// Packet sizes.
126135
var (
127136
sizeofStaticHeader = binary.Size(StaticHeader{})
@@ -147,6 +156,7 @@ type Codec struct {
147156
msgctbuf []byte // message data ciphertext
148157

149158
// decoder buffer
159+
decbuf []byte
150160
reader bytes.Reader
151161
}
152162

@@ -158,6 +168,7 @@ func NewCodec(ln *enode.LocalNode, key *ecdsa.PrivateKey, clock mclock.Clock, pr
158168
privkey: key,
159169
sc: NewSessionCache(1024, clock),
160170
protocolID: DefaultProtocolID,
171+
decbuf: make([]byte, maxPacketSize),
161172
}
162173
if protocolID != nil {
163174
c.protocolID = *protocolID
@@ -424,10 +435,13 @@ func (c *Codec) encryptMessage(s *session, p Packet, head *Header, headerData []
424435
}
425436

426437
// Decode decodes a discovery packet.
427-
func (c *Codec) Decode(input []byte, addr string) (src enode.ID, n *enode.Node, p Packet, err error) {
428-
if len(input) < minPacketSize {
438+
func (c *Codec) Decode(inputData []byte, addr string) (src enode.ID, n *enode.Node, p Packet, err error) {
439+
if len(inputData) < minPacketSize {
429440
return enode.ID{}, nil, nil, errTooShort
430441
}
442+
// Copy the packet to a tmp buffer to avoid modifying it.
443+
c.decbuf = append(c.decbuf[:0], inputData...)
444+
input := c.decbuf
431445
// Unmask the static header.
432446
var head Header
433447
copy(head.IV[:], input[:sizeofMaskingIV])

0 commit comments

Comments
 (0)