Skip to content

Commit

Permalink
p2p/discover: pass invalid discv5 packets to Unhandled channel (ether…
Browse files Browse the repository at this point in the history
…eum#26699)

This makes it possible to run another protocol alongside discv5, by reading 
unhandled packets from the channel.
  • Loading branch information
holiman authored and shekhirin committed Jun 6, 2023
1 parent 7a06e49 commit c719df5
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 2 deletions.
10 changes: 10 additions & 0 deletions p2p/discover/v5_udp.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ type UDPv5 struct {
callCh chan *callV5
callDoneCh chan *callV5
respTimeoutCh chan *callTimeout
unhandled chan<- ReadPacket

// state of dispatch
codec codecV5
Expand Down Expand Up @@ -156,6 +157,7 @@ func newUDPv5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) {
callCh: make(chan *callV5),
callDoneCh: make(chan *callV5),
respTimeoutCh: make(chan *callTimeout),
unhandled: cfg.Unhandled,
// state of dispatch
codec: v5wire.NewCodec(ln, cfg.PrivateKey, cfg.Clock, cfg.V5ProtocolID),
activeCallByNode: make(map[enode.ID]*callV5),
Expand Down Expand Up @@ -657,6 +659,14 @@ func (t *UDPv5) handlePacket(rawpacket []byte, fromAddr *net.UDPAddr) error {
addr := fromAddr.String()
fromID, fromNode, packet, err := t.codec.Decode(rawpacket, addr)
if err != nil {
if t.unhandled != nil && v5wire.IsInvalidHeader(err) {
// The packet seems unrelated to discv5, send it to the next protocol.
// t.log.Trace("Unhandled discv5 packet", "id", fromID, "addr", addr, "err", err)
up := ReadPacket{Data: make([]byte, len(rawpacket)), Addr: fromAddr}
copy(up.Data, rawpacket)
t.unhandled <- up
return nil
}
t.log.Debug("Bad discv5 packet", "id", fromID, "addr", addr, "err", err)
return err
}
Expand Down
18 changes: 16 additions & 2 deletions p2p/discover/v5wire/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ const (
// Should reject packets smaller than minPacketSize.
minPacketSize = 63

maxPacketSize = 1280

minMessageSize = 48 // this refers to data after static headers
randomPacketMsgSize = 20
)
Expand Down Expand Up @@ -122,6 +124,13 @@ var (
ErrInvalidReqID = errors.New("request ID larger than 8 bytes")
)

// IsInvalidHeader reports whether 'err' is related to an invalid packet header. When it
// returns false, it is pretty certain that the packet causing the error does not belong
// to discv5.
func IsInvalidHeader(err error) bool {
return err == errTooShort || err == errInvalidHeader || err == errMsgTooShort
}

// Packet sizes.
var (
sizeofStaticHeader = binary.Size(StaticHeader{})
Expand All @@ -147,6 +156,7 @@ type Codec struct {
msgctbuf []byte // message data ciphertext

// decoder buffer
decbuf []byte
reader bytes.Reader
}

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

// Decode decodes a discovery packet.
func (c *Codec) Decode(input []byte, addr string) (src enode.ID, n *enode.Node, p Packet, err error) {
if len(input) < minPacketSize {
func (c *Codec) Decode(inputData []byte, addr string) (src enode.ID, n *enode.Node, p Packet, err error) {
if len(inputData) < minPacketSize {
return enode.ID{}, nil, nil, errTooShort
}
// Copy the packet to a tmp buffer to avoid modifying it.
c.decbuf = append(c.decbuf[:0], inputData...)
input := c.decbuf
// Unmask the static header.
var head Header
copy(head.IV[:], input[:sizeofMaskingIV])
Expand Down

0 comments on commit c719df5

Please sign in to comment.