Client disconnected due to malformed packet

Hi all,

I’m new to the community. I’m trying to reverse engineer the MQTT messaging of an IOT device (an Air Purifier in this case). It seems fairly straight forward MQTT messaging after a HTTP discussion to determine MQTT server information.

I spun up a local Mosquitto instance in Docker, redirected requests from the internet based MQTT broker to my instance and watched the discussion by doing some packet sniffing in Wireshark.

Unfortunately, something strange happens. The IOT device successfully connects to my local broker (using user/password auth - unencrypted TCP) but SUBSCRIBE requests are failing with a “malformed packet” error message. Here is some log messaging:

2024-03-17 14:41:00 1710646860: New connection from 192.168.65.1:56821 on port 1883.
2024-03-17 14:41:00 1710646860: New client connected from 192.168.65.1:56821 as 2F067766A3003C82 (p2, c1, k10, u'device').
2024-03-17 14:41:00 1710646860: No will message specified.
2024-03-17 14:41:00 1710646860: Sending CONNACK to 2F067766A3003C82 (0, 0)
2024-03-17 14:41:00 1710646860: Received SUBSCRIBE from 2F067766A3003C82
2024-03-17 14:41:00 1710646860: Client 2F067766A3003C82 disconnected due to malformed packet.

I’ve compared the packets between the SUBSCRIBE request to my server VS the IOT providers instance and the requests are identical (naturally). The Connect Command uses v3.1.1 of the protocol.

Before I start seriously yak -shaving and compiling my own Docker container to add to the logging - are there any MQTT experts that could suggest a better way to debug this issue? Looking at the source code for handing SUBSCRIBE requests there are a number of areas this could be - but I can’t change anything about the IOT device and the client it runs.

I’ve also tested redirecting the IOT device to test.mosquitto.org which behaves the same as my local mosquitto instance (here’s a screenshot of wireshark).

Any suggestions? Is there any independent way to validate the SUBSCRIBE TCP packet (I had ChatGPT decode and review it and it thinks it is valid - but in practice we know that’s false). Wireshark appears to decode it as MQTT successfully, but for the “official” server the response is a SUBSCRIBE ACK. On Mosquitto it’s a TCP packet. What have this device maker done to make their device only work with their broker?

If it helps, here’s the SUBSCRIBE TCP frame

0000   82 2d 14 17 4f ec f0 fe 6b b1 cb 7c 08 00 45 00   .-..O...k..|..E.
0010   00 48 00 21 00 00 ff 06 8b 2d c0 a8 02 98 0a 0a   .H.!.....-......
0020   63 17 44 eb 07 5b 00 00 19 ab 81 14 84 d2 50 18   c.D..[........P.
0030   05 d8 30 52 00 00 82 1e 00 00 00 19 64 65 76 69   ..0R........devi
0040   63 65 2f 32 46 30 36 37 37 36 36 41 33 30 30 33   ce/2F067766A3003
0050   43 38 32 2f 2b 01                                 C82/+.

Hi,
Dissecting your packet, we have this part as the MQTT subscribe

82 1e 00 00 00 19 64 65
76 69 63 65 2f 32 46 30
36 37 37 36 36 41 33 30
30 33 43 38 32 2f 2b 01

82: SUBSCRIBE command
1e: Remaining length of the packet = 30, which is correct
0000: The message ID of this packet
0019: The length of the subscription topic = 25, which is correct
64…2b: The topic
01: The requested QoS = 1

The problem is that the message ID is set to zero, which is forbidden by the protocol spec, with the instruction that any clients that do that should be disconnected. You could fix this for your case by removing the if(mid == 0) return MOSQ_ERR_MALFORMED_PACKET; line in src/handle_subscribe.c file.

If you’re using docker, then it’s easy to get a new image with this in, run ./docker.sh from the root of a checked out copy of the mosquitto repo.

Cheers,

Roger

Thanks for the detailed response @roger.light

FWIW, I swapped a container instance of EMQX and it handles the same requests without an error, so I guess they are more lenient or less strict on the spec. As I can’t manage the client implementation in this case - is my only option a custom compile if I prefer to use Mosquitto?