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:
Lucas Vieira
2021-02-26 04:44:01 -03:00
committed by GitHub
parent afe62e0a7d
commit 7cc3949bbe
2 changed files with 80 additions and 0 deletions

View File

@@ -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)