Skip to content

Commit 8b774d2

Browse files
committed
Issue #540 - Validating Reserved Bits on incoming Messages
Signed-off-by: James Sutton <james.sutton@uk.ibm.com>
1 parent 77cba83 commit 8b774d2

2 files changed

Lines changed: 44 additions & 14 deletions

File tree

  • org.eclipse.paho.mqttv5.client/src/main/java/org/eclipse/paho/mqttv5/client/wire
  • org.eclipse.paho.mqttv5.common/src/main/java/org/eclipse/paho/mqttv5/common/packet

org.eclipse.paho.mqttv5.client/src/main/java/org/eclipse/paho/mqttv5/client/wire/MqttInputStream.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,12 @@ public MqttWireMessage readMqttWireMessage() throws IOException, MqttException {
102102
// Invalid MQTT message type...
103103
throw ExceptionHelper.createMqttException(MqttClientException.REASON_CODE_INVALID_MESSAGE);
104104
}
105+
106+
byte reserved = (byte) (first & 0x0F);
107+
MqttWireMessage.validateReservedBits(type, reserved);
108+
105109
remLen = MqttDataTypes.readVariableByteInteger(in).getValue();
106110
bais.write(first);
107-
// bit silly, we decode it then encode it
108-
// TODO - Should this be a long or an int?
109111
bais.write(MqttWireMessage.encodeVariableByteInteger((int)remLen));
110112
packet = new byte[(int)(bais.size()+remLen)];
111113
packetLen = 0;

org.eclipse.paho.mqttv5.common/src/main/java/org/eclipse/paho/mqttv5/common/packet/MqttWireMessage.java

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,13 @@ public abstract class MqttWireMessage {
5959
"PUBREL", "PUBCOMP", "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK", "PINGREQ", "PINGRESP", "DISCONNECT",
6060
"AUTH" };
6161

62+
private static final byte[] PACKET_RESERVED_MASKS = { 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0 };
63+
6264
// The type of the message (e.g CONNECT, PUBLISH, SUBSCRIBE)
6365
private byte type;
6466

6567
MqttProperties properties = new MqttProperties();
66-
68+
6769
// The MQTT Message ID
6870
protected int msgId;
6971
protected int[] reasonCodes = null; // Multiple Reason Codes (SUBACK, UNSUBACK)
@@ -92,7 +94,7 @@ public MqttWireMessage(byte type) {
9294
* @throws MqttException
9395
* if an exception occurs whilst getting the payload.
9496
*/
95-
public byte[] getPayload() throws MqttException{
97+
public byte[] getPayload() throws MqttException {
9698
return new byte[0];
9799
}
98100

@@ -170,7 +172,8 @@ public boolean isMessageIdRequired() {
170172
*
171173
* @throws MqttException
172174
* if an error occurred whilst creating the WireMessage
173-
* @param data the MqttPersistable to create the message from
175+
* @param data
176+
* the MqttPersistable to create the message from
174177
* @return MqttWireMessage the de-persisted message
175178
*/
176179
public static MqttWireMessage createWireMessage(MqttPersistable data) throws MqttException {
@@ -238,7 +241,7 @@ private static MqttWireMessage createWireMessage(InputStream inputStream) throws
238241
result = new MqttPubComp(data);
239242
break;
240243
case MqttWireMessage.MESSAGE_TYPE_SUBSCRIBE:
241-
result = new MqttSubscribe( data);
244+
result = new MqttSubscribe(data);
242245
break;
243246
case MqttWireMessage.MESSAGE_TYPE_SUBACK:
244247
result = new MqttSubAck(data);
@@ -288,7 +291,31 @@ public static byte[] encodeVariableByteInteger(int number) {
288291
return baos.toByteArray();
289292
}
290293

291-
294+
/**
295+
* Validates that the reserved bits set on an MQTT packet conform to the MQTT
296+
* specification.
297+
*
298+
* @param type
299+
* - The Message Type
300+
* @param reserved
301+
* - The Reserved Bits
302+
* @throws MqttException
303+
* If the set reserved bits do not match the specification.
304+
* @throws IllegalArgumentException
305+
* If the message type does not exist.
306+
*/
307+
public static void validateReservedBits(byte type, byte reserved) throws MqttException, IllegalArgumentException {
308+
if (type == MESSAGE_TYPE_PUBLISH) {
309+
// Publish can vary, but will be parsed separately.
310+
return;
311+
}
312+
if (type > MESSAGE_TYPE_AUTH) {
313+
throw new IllegalArgumentException("Unrecognised Message Type.");
314+
}
315+
if (reserved != PACKET_RESERVED_MASKS[type]) {
316+
throw new MqttException(MqttException.REASON_CODE_MALFORMED_PACKET);
317+
}
318+
}
292319

293320
protected byte[] encodeMessageId() throws MqttException {
294321
try {
@@ -317,7 +344,7 @@ public boolean isDuplicate() {
317344
public MqttProperties getProperties() {
318345
return properties;
319346
}
320-
347+
321348
public void setProperties(MqttProperties properties) {
322349
this.properties = properties;
323350
}
@@ -345,11 +372,11 @@ protected void validateReturnCode(int returnCode, int[] validReturnCodes) throws
345372
}
346373
throw new MqttException(MqttException.REASON_CODE_INVALID_RETURN_CODE);
347374
}
348-
375+
349376
/**
350377
*
351-
* Returns the reason codes from the MqttWireMessage.
352-
* These will be present if the messages is of the following types:
378+
* Returns the reason codes from the MqttWireMessage. These will be present if
379+
* the messages is of the following types:
353380
* <ul>
354381
* <li>CONNACK - 1 Reason Code Max.</li>
355382
* <li>PUBACK - 1 Reason Code Max.</li>
@@ -364,16 +391,17 @@ protected void validateReturnCode(int returnCode, int[] validReturnCodes) throws
364391
* Warning: This method may be removed in favour of Token.getReasonCodes()
365392
*
366393
* May be null if this message does not contain any Reason Codes.
394+
*
367395
* @return An array of return codes, or null.
368396
*/
369397
public int[] getReasonCodes() {
370-
if(this.reasonCodes != null) {
398+
if (this.reasonCodes != null) {
371399
return this.reasonCodes;
372400
} else if (this.reasonCode != -1) {
373-
return new int[] {this.reasonCode};
401+
return new int[] { this.reasonCode };
374402
} else {
375403
return null;
376404
}
377405
}
378-
406+
379407
}

0 commit comments

Comments
 (0)