Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

p2p/discover: pass invalid discv5 packets to Unhandled channel #26699

Merged
merged 1 commit into from
Mar 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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