mirror of
https://github.com/fhmq/hmq.git
synced 2026-05-04 07:08:32 +00:00
Packet fields validation (#111)
* chore: ignore .pre-commit-config.yaml Signed-off-by: Lucas Vieira <lucas.engen.cc@gmail.com> * fix: 🐛 perform validation on control packet fields (fhmq/hmq#104) Signed-off-by: Lucas Vieira <lucas.engen@outlook.com> * feat: ❇️ add handling of null UTF-8 encoded character Signed-off-by: Lucas Vieira <lucas.engen@outlook.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package broker
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"math/rand"
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/eapache/queue"
|
||||
|
||||
@@ -188,6 +190,63 @@ func (c *client) readLoop() {
|
||||
|
||||
}
|
||||
|
||||
// extractPacketFields function reads a control packet and extracts only the fields
|
||||
// that needs to pass on UTF-8 validation
|
||||
func extractPacketFields(msgPacket packets.ControlPacket) []string {
|
||||
var fields []string
|
||||
|
||||
// Get packet type
|
||||
switch msgPacket.(type) {
|
||||
case *packets.ConnackPacket:
|
||||
case *packets.ConnectPacket:
|
||||
case *packets.PublishPacket:
|
||||
packet := msgPacket.(*packets.PublishPacket)
|
||||
fields = append(fields, packet.TopicName)
|
||||
break
|
||||
|
||||
case *packets.SubscribePacket:
|
||||
case *packets.SubackPacket:
|
||||
case *packets.UnsubscribePacket:
|
||||
packet := msgPacket.(*packets.UnsubscribePacket)
|
||||
fields = append(fields, packet.Topics...)
|
||||
break
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
// validatePacketFields function checks if any of control packets fields has ill-formed
|
||||
// UTF-8 string
|
||||
func validatePacketFields(msgPacket packets.ControlPacket) (validFields bool) {
|
||||
|
||||
// Extract just fields that needs validation
|
||||
fields := extractPacketFields(msgPacket)
|
||||
|
||||
for _, field := range fields {
|
||||
|
||||
// Perform the basic UTF-8 validation
|
||||
if !utf8.ValidString(field) {
|
||||
validFields = false
|
||||
return
|
||||
}
|
||||
|
||||
// A UTF-8 encoded string MUST NOT include an encoding of the null
|
||||
// character U+0000
|
||||
// If a receiver (Server or Client) receives a Control Packet containing U+0000
|
||||
// it MUST close the Network Connection
|
||||
// http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.pdf page 14
|
||||
if bytes.ContainsAny([]byte(field), "\u0000") {
|
||||
validFields = false
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// All fields has been validated successfully
|
||||
validFields = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func ProcessMessage(msg *Message) {
|
||||
c := msg.client
|
||||
ca := msg.packet
|
||||
@@ -199,11 +258,31 @@ func ProcessMessage(msg *Message) {
|
||||
log.Debug("Recv message:", zap.String("message type", reflect.TypeOf(msg.packet).String()[9:]), zap.String("ClientID", c.info.clientID))
|
||||
}
|
||||
|
||||
// Perform field validation
|
||||
if !validatePacketFields(ca) {
|
||||
|
||||
// http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.pdf
|
||||
// Page 14
|
||||
//
|
||||
// If a Server or Client receives a Control Packet
|
||||
// containing ill-formed UTF-8 it MUST close the Network Connection
|
||||
|
||||
c.conn.Close()
|
||||
|
||||
// Update client status
|
||||
//c.status = Disconnected
|
||||
|
||||
log.Error("Client disconnected due to malformed packet", zap.String("ClientID", c.info.clientID))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
switch ca.(type) {
|
||||
case *packets.ConnackPacket:
|
||||
case *packets.ConnectPacket:
|
||||
case *packets.PublishPacket:
|
||||
packet := ca.(*packets.PublishPacket)
|
||||
|
||||
c.ProcessPublish(packet)
|
||||
case *packets.PubackPacket:
|
||||
packet := ca.(*packets.PubackPacket)
|
||||
|
||||
Reference in New Issue
Block a user