1 /*
2  * MQTT Protocol
3  *
4  * Copyright 2020 Baptiste Assmann <bedis9@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  *
11  */
12 
13 #include <haproxy/chunk.h>
14 #include <haproxy/mqtt.h>
15 
16 uint8_t mqtt_cpt_flags[MQTT_CPT_ENTRIES] = {
17 	[MQTT_CPT_INVALID]     = 0x00,
18 	[MQTT_CPT_CONNECT]     = 0x00,
19 	[MQTT_CPT_CONNACK]     = 0x00,
20 
21 	/* MQTT_CPT_PUBLISH flags can have different values (DUP, QoS, RETAIN), must be
22 	 * check more carefully
23 	 */
24 	[MQTT_CPT_PUBLISH]     = 0x0F,
25 
26 	[MQTT_CPT_PUBACK]      = 0x00,
27 	[MQTT_CPT_PUBREC]      = 0x00,
28 	[MQTT_CPT_PUBREL]      = 0x02,
29 	[MQTT_CPT_PUBCOMP]     = 0x00,
30 	[MQTT_CPT_SUBSCRIBE]   = 0x02,
31 	[MQTT_CPT_SUBACK]      = 0x00,
32 	[MQTT_CPT_UNSUBSCRIBE] = 0x02,
33 	[MQTT_CPT_UNSUBACK]    = 0x00,
34 	[MQTT_CPT_PINGREQ]     = 0x00,
35 	[MQTT_CPT_PINGRESP]    = 0x00,
36 	[MQTT_CPT_DISCONNECT]  = 0x00,
37 	[MQTT_CPT_AUTH]        = 0x00,
38 };
39 
40 const struct ist mqtt_fields_string[MQTT_FN_ENTRIES] = {
41 	[MQTT_FN_INVALID]                            = IST(""),
42 
43 	/* it's MQTT 3.1.1 and 5.0, those fields have no unique id, so we use strings */
44 	[MQTT_FN_FLAGS]                              = IST("flags"),
45 	[MQTT_FN_REASON_CODE]                        = IST("reason_code"),       /* MQTT 3.1.1: return_code */
46 	[MQTT_FN_PROTOCOL_NAME]                      = IST("protocol_name"),
47 	[MQTT_FN_PROTOCOL_VERSION]                   = IST("protocol_version"),  /* MQTT 3.1.1: protocol_level */
48 	[MQTT_FN_CLIENT_IDENTIFIER]                  = IST("client_identifier"),
49 	[MQTT_FN_WILL_TOPIC]                         = IST("will_topic"),
50 	[MQTT_FN_WILL_PAYLOAD]                       = IST("will_payload"),      /* MQTT 3.1.1: will_message */
51 	[MQTT_FN_USERNAME]                           = IST("username"),
52 	[MQTT_FN_PASSWORD]                           = IST("password"),
53 	[MQTT_FN_KEEPALIVE]                          = IST("keepalive"),
54 	/* from here, it's MQTT 5.0 only */
55 	[MQTT_FN_PAYLOAD_FORMAT_INDICATOR]           = IST("1"),
56 	[MQTT_FN_MESSAGE_EXPIRY_INTERVAL]            = IST("2"),
57 	[MQTT_FN_CONTENT_TYPE]                       = IST("3"),
58 	[MQTT_FN_RESPONSE_TOPIC]                     = IST("8"),
59 	[MQTT_FN_CORRELATION_DATA]                   = IST("9"),
60 	[MQTT_FN_SUBSCRIPTION_IDENTIFIER]            = IST("11"),
61 	[MQTT_FN_SESSION_EXPIRY_INTERVAL]            = IST("17"),
62 	[MQTT_FN_ASSIGNED_CLIENT_IDENTIFIER]         = IST("18"),
63 	[MQTT_FN_SERVER_KEEPALIVE]                   = IST("19"),
64 	[MQTT_FN_AUTHENTICATION_METHOD]              = IST("21"),
65 	[MQTT_FN_AUTHENTICATION_DATA]                = IST("22"),
66 	[MQTT_FN_REQUEST_PROBLEM_INFORMATION]        = IST("23"),
67 	[MQTT_FN_DELAY_INTERVAL]                     = IST("24"),
68 	[MQTT_FN_REQUEST_RESPONSE_INFORMATION]       = IST("25"),
69 	[MQTT_FN_RESPONSE_INFORMATION]               = IST("26"),
70 	[MQTT_FN_SERVER_REFERENCE]                   = IST("28"),
71 	[MQTT_FN_REASON_STRING]                      = IST("31"),
72 	[MQTT_FN_RECEIVE_MAXIMUM]                    = IST("33"),
73 	[MQTT_FN_TOPIC_ALIAS_MAXIMUM]                = IST("34"),
74 	[MQTT_FN_TOPIC_ALIAS]                        = IST("35"),
75 	[MQTT_FN_MAXIMUM_QOS]                        = IST("36"),
76 	[MQTT_FN_RETAIN_AVAILABLE]                   = IST("37"),
77 	[MQTT_FN_USER_PROPERTY]                      = IST("38"),
78 	[MQTT_FN_MAXIMUM_PACKET_SIZE]                = IST("39"),
79 	[MQTT_FN_WILDCARD_SUBSCRIPTION_AVAILABLE]    = IST("40"),
80 	[MQTT_FN_SUBSCRIPTION_IDENTIFIERS_AVAILABLE] = IST("41"),
81 	[MQTT_FN_SHARED_SUBSCRIPTION_AVAILABLE]      = IST("42"),
82 };
83 
84 /* list of supported capturable field names for each MQTT control packet type */
85 const uint64_t mqtt_fields_per_packet[MQTT_CPT_ENTRIES] = {
86 	[MQTT_CPT_INVALID]     = 0,
87 
88 	[MQTT_CPT_CONNECT]     = MQTT_FN_BIT_PROTOCOL_NAME                     | MQTT_FN_BIT_PROTOCOL_VERSION                   |
89 	                         MQTT_FN_BIT_FLAGS                             | MQTT_FN_BIT_KEEPALIVE                          |
90 	                         MQTT_FN_BIT_SESSION_EXPIRY_INTERVAL           | MQTT_FN_BIT_RECEIVE_MAXIMUM                    |
91 	                         MQTT_FN_BIT_MAXIMUM_PACKET_SIZE               | MQTT_FN_BIT_TOPIC_ALIAS_MAXIMUM                |
92 	                         MQTT_FN_BIT_REQUEST_RESPONSE_INFORMATION      | MQTT_FN_BIT_REQUEST_PROBLEM_INFORMATION        |
93 	                         MQTT_FN_BIT_USER_PROPERTY                     | MQTT_FN_BIT_AUTHENTICATION_METHOD              |
94 	                         MQTT_FN_BIT_AUTHENTICATION_DATA               | MQTT_FN_BIT_CLIENT_IDENTIFIER                  |
95 	                         MQTT_FN_BIT_DELAY_INTERVAL                    | MQTT_FN_BIT_PAYLOAD_FORMAT_INDICATOR           |
96 	                         MQTT_FN_BIT_MESSAGE_EXPIRY_INTERVAL           | MQTT_FN_BIT_CONTENT_TYPE                       |
97 	                         MQTT_FN_BIT_RESPONSE_TOPIC                    | MQTT_FN_BIT_CORRELATION_DATA                   |
98 	                         MQTT_FN_BIT_USER_PROPERTY                     | MQTT_FN_BIT_WILL_TOPIC                         |
99 	                         MQTT_FN_BIT_WILL_PAYLOAD                      | MQTT_FN_BIT_USERNAME                           |
100 	                         MQTT_FN_BIT_PASSWORD,
101 
102 	[MQTT_CPT_CONNACK]     = MQTT_FN_BIT_FLAGS                             | MQTT_FN_BIT_PROTOCOL_VERSION                   |
103 	                         MQTT_FN_BIT_REASON_CODE                       | MQTT_FN_BIT_SESSION_EXPIRY_INTERVAL            |
104 	                         MQTT_FN_BIT_RECEIVE_MAXIMUM                   | MQTT_FN_BIT_MAXIMUM_QOS                        |
105 	                         MQTT_FN_BIT_RETAIN_AVAILABLE                  | MQTT_FN_BIT_MAXIMUM_PACKET_SIZE                |
106 	                         MQTT_FN_BIT_ASSIGNED_CLIENT_IDENTIFIER        | MQTT_FN_BIT_TOPIC_ALIAS_MAXIMUM                |
107 	                         MQTT_FN_BIT_REASON_STRING                     | MQTT_FN_BIT_WILDCARD_SUBSCRIPTION_AVAILABLE    |
108 	                         MQTT_FN_BIT_SUBSCRIPTION_IDENTIFIERS_AVAILABLE| MQTT_FN_BIT_SHARED_SUBSCRIPTION_AVAILABLE      |
109 	                         MQTT_FN_BIT_SERVER_KEEPALIVE                  | MQTT_FN_BIT_RESPONSE_INFORMATION               |
110 	                         MQTT_FN_BIT_SERVER_REFERENCE                  | MQTT_FN_BIT_USER_PROPERTY                      |
111 	                         MQTT_FN_BIT_AUTHENTICATION_METHOD             | MQTT_FN_BIT_AUTHENTICATION_DATA,
112 
113 	[MQTT_CPT_PUBLISH]     = MQTT_FN_BIT_PAYLOAD_FORMAT_INDICATOR          | MQTT_FN_BIT_MESSAGE_EXPIRY_INTERVAL            |
114 	                         MQTT_FN_BIT_CONTENT_TYPE                      | MQTT_FN_BIT_RESPONSE_TOPIC                     |
115 	                         MQTT_FN_BIT_CORRELATION_DATA                  | MQTT_FN_BIT_SUBSCRIPTION_IDENTIFIER            |
116 	                         MQTT_FN_BIT_TOPIC_ALIAS                       | MQTT_FN_BIT_USER_PROPERTY,
117 
118 	[MQTT_CPT_PUBACK]      = MQTT_FN_BIT_REASON_CODE | MQTT_FN_BIT_REASON_STRING | MQTT_FN_BIT_USER_PROPERTY,
119 
120 	[MQTT_CPT_PUBREC]      = MQTT_FN_BIT_REASON_CODE | MQTT_FN_BIT_REASON_STRING | MQTT_FN_BIT_USER_PROPERTY,
121 
122 	[MQTT_CPT_PUBREL]      = MQTT_FN_BIT_REASON_CODE | MQTT_FN_BIT_REASON_STRING | MQTT_FN_BIT_USER_PROPERTY,
123 
124 	[MQTT_CPT_PUBCOMP]     = MQTT_FN_BIT_REASON_CODE | MQTT_FN_BIT_REASON_STRING | MQTT_FN_BIT_USER_PROPERTY,
125 
126 	[MQTT_CPT_SUBSCRIBE]   = MQTT_FN_BIT_SUBSCRIPTION_IDENTIFIER | MQTT_FN_BIT_USER_PROPERTY,
127 
128 	[MQTT_CPT_SUBACK]      = MQTT_FN_BIT_REASON_STRING | MQTT_FN_BIT_USER_PROPERTY,
129 
130 	[MQTT_CPT_UNSUBSCRIBE] = MQTT_FN_BIT_USER_PROPERTY,
131 
132 	[MQTT_CPT_UNSUBACK]    = MQTT_FN_BIT_REASON_STRING | MQTT_FN_BIT_USER_PROPERTY,
133 
134 	[MQTT_CPT_PINGREQ]     = 0,
135 
136 	[MQTT_CPT_PINGRESP]    = 0,
137 
138 	[MQTT_CPT_DISCONNECT]  = MQTT_FN_BIT_REASON_CODE                       | MQTT_FN_BIT_SESSION_EXPIRY_INTERVAL            |
139 	                         MQTT_FN_BIT_SERVER_REFERENCE                  | MQTT_FN_BIT_REASON_STRING                      |
140 	                         MQTT_FN_BIT_USER_PROPERTY,
141 
142 	[MQTT_CPT_AUTH]        = MQTT_FN_BIT_AUTHENTICATION_METHOD             | MQTT_FN_BIT_AUTHENTICATION_DATA                |
143 	                         MQTT_FN_BIT_REASON_STRING                     | MQTT_FN_BIT_USER_PROPERTY,
144 };
145 
146 /* Checks the first byte of a message to read the fixed header and extract the
147  * packet type and flags. <parser> is supposed to point to the fix header byte.
148  *
149  * Fix header looks like:
150  * +-------+-----------+-----------+-----------+---------+----------+----------+---------+------------+
151  * |  bit  |    7      |     6     |    5      |    4    |     3    |     2    |     1   |     0      |
152  * +-------+-----------+-----------+-----------+---------+----------+----------+---------+------------+
153  * | field |          MQTT Control Packet Type           | Flags specific to each Control Packet type |
154  * +-------+---------------------------------------------+--------------------------------------------+
155  *
156  * On success, <ptk> is updated with the packet type and flags and the new parser
157  * state is returned. On error, IST_NULL is returned.
158  */
mqtt_read_fixed_hdr(struct ist parser,struct mqtt_pkt * pkt)159 static inline struct ist mqtt_read_fixed_hdr(struct ist parser, struct mqtt_pkt *pkt)
160 {
161 	uint8_t type  = (uint8_t)*istptr(parser);
162 	uint8_t ptype = (type & 0xF0) >> 4;
163 	uint8_t flags = type & 0x0F;
164 
165 	if (ptype == MQTT_CPT_INVALID || ptype >= MQTT_CPT_ENTRIES || flags != mqtt_cpt_flags[ptype])
166 		return IST_NULL;
167 
168 	pkt->fixed_hdr.type = ptype;
169 	pkt->fixed_hdr.flags = flags;
170 	return istnext(parser);
171 }
172 
173 /* Reads a one byte integer. more information here :
174  *     https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901007
175  *
176  * <parser> is supposed to point to the first byte of the integer. On success
177  * the integer is stored in <*i>, if provided, and the new parser state is returned. On
178  * error, IST_NULL is returned.
179 */
mqtt_read_1byte_int(struct ist parser,uint8_t * i)180 static inline struct ist mqtt_read_1byte_int(struct ist parser, uint8_t *i)
181 {
182 	if (istlen(parser) < 1)
183 		return IST_NULL;
184 	if (i)
185 		*i = (uint8_t)*istptr(parser);
186 	parser = istadv(parser, 1);
187 	return parser;
188 }
189 
190 /* Reads a two byte integer. more information here :
191  *     https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901008
192  *
193  * <parser> is supposed to point to the first byte of the integer. On success
194  * the integer is stored in <*i>, if provided, and the new parser state is returned. On
195  * error, IST_NULL is returned.
196 */
mqtt_read_2byte_int(struct ist parser,uint16_t * i)197 static inline struct ist mqtt_read_2byte_int(struct ist parser, uint16_t *i)
198 {
199 	if (istlen(parser) < 2)
200 		return IST_NULL;
201 	if (i) {
202 		*i  = (uint8_t)*istptr(parser) << 8;
203 		*i += (uint8_t)*(istptr(parser) + 1);
204 	}
205 	parser = istadv(parser, 2);
206 	return parser;
207 }
208 
209 /* Reads a four byte integer. more information here :
210  *     https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901009
211  *
212  * <parser> is supposed to point to the first byte of the integer. On success
213  * the integer is stored in <*i>, if provided, and the new parser state is returned. On
214  * error, IST_NULL is returned.
215 */
mqtt_read_4byte_int(struct ist parser,uint32_t * i)216 static inline struct ist mqtt_read_4byte_int(struct ist parser, uint32_t *i)
217 {
218 	if (istlen(parser) < 4)
219 		return IST_NULL;
220 	if (i) {
221 		*i  = (uint8_t)*istptr(parser) << 24;
222 		*i += (uint8_t)*(istptr(parser) + 1) << 16;
223 		*i += (uint8_t)*(istptr(parser) + 2) << 8;
224 		*i += (uint8_t)*(istptr(parser) + 3);
225 	}
226 	parser = istadv(parser, 4);
227 	return parser;
228 }
229 
230 /* Reads a variable byte integer. more information here :
231  *   https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718023
232  *   https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901011
233  *
234  * It is encoded using a variable length encoding scheme which uses a single
235  * byte for values up to 127.  Larger values are handled as follows. The least
236  * significant seven bits of each byte encode the data, and the most significant
237  * bit is used to indicate that there are following bytes in the representation.
238  * Thus each byte encodes 128 values and a "continuation bit".
239  *
240  * The maximum number of bytes in the Remaining Length field is four
241  * (MQTT_REMAINING_LENGHT_MAX_SIZE).
242  *
243  * <parser> is supposed to point to the first byte of the integer. On success
244  * the integer is stored in <*i> and the new parser state is returned. On
245  * error, IST_NULL is returned.
246  */
mqtt_read_varint(struct ist parser,uint32_t * i)247 static inline struct ist mqtt_read_varint(struct ist parser, uint32_t *i)
248 {
249 	int off, m;
250 
251 	off = m = 0;
252 	if (i)
253 		*i = 0;
254 	for (off = 0; off < MQTT_REMAINING_LENGHT_MAX_SIZE && istlen(parser); off++) {
255 		uint8_t byte = (uint8_t)*istptr(parser);
256 
257 		if (i) {
258 			*i += (byte & 127) << m;
259 			m += 7; /* preparing <m> for next byte */
260 		}
261 		parser = istnext(parser);
262 
263 		/* we read the latest byte for the remaining length field */
264 		if (byte <= 127)
265 			break;
266 	}
267 
268 	if (off == MQTT_REMAINING_LENGHT_MAX_SIZE)
269 		return IST_NULL;
270 	return parser;
271 }
272 
273 /* Reads a MQTT string. more information here :
274  *   http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718016
275  *   https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901010
276  *
277  * In MQTT, strings are prefixed by their size, encoded over 2 bytes:
278  *   byte 1:  length MSB
279  *   byte 2:  length LSB
280  *   byte 3:  string
281  *   ...
282  *
283  *   string size is MSB * 256 + LSB
284  *
285  * <parser> is supposed to point to the first byte of the string. On success the
286  * string is stored in <*str>, if provided, and the new parser state is
287  * returned. On error, IST_NULL is returned.
288  */
mqtt_read_string(struct ist parser,struct ist * str)289 static inline struct ist mqtt_read_string(struct ist parser, struct ist *str)
290 {
291 	uint16_t len = 0;
292 
293 	/* read and compute the string length */
294 	if (istlen(parser) < 2)
295 		goto error;
296 
297 	parser = mqtt_read_2byte_int(parser, &len);
298 	if (!isttest(parser) || istlen(parser) < len)
299 		goto error;
300 
301 	if (str) {
302 		str->ptr = istptr(parser);
303 		str->len = len;
304 	}
305 
306 	return istadv(parser, len);
307 
308   error:
309 	return IST_NULL;
310 }
311 
312 /* Helper function to convert a unsigned integer to a string. The result is
313  * written in <buf>. On success, the written size is returned, otherwise, on
314  * error, 0 is returned.
315  */
mqtt_uint2str(struct buffer * buf,uint32_t i)316 static inline size_t mqtt_uint2str(struct buffer *buf, uint32_t i)
317 {
318 	char *end;
319 
320 	end = ultoa_o(i, buf->area, buf->size);
321 	if (!end)
322 		return 0;
323 	buf->data = end - buf->area;
324 	return buf->data;
325 }
326 
327 /* Extracts the value of a <fieldname_id> of type <type> from a given MQTT
328  * message <msg>.  IST_NULL is returned if an error occurred while parsing or if
329  * the field could not be found. If more data are required, the message with a
330  * length set to 0 is returned. If the field is found, the response is returned
331  * as a struct ist.
332  */
mqtt_field_value(struct ist msg,int type,int fieldname_id)333 struct ist mqtt_field_value(struct ist msg, int type, int fieldname_id)
334 {
335 	struct buffer *trash = get_trash_chunk();
336 	struct mqtt_pkt mpkt;
337 	struct ist res;
338 
339 	switch (mqtt_validate_message(msg, &mpkt)) {
340 	case MQTT_VALID_MESSAGE:
341 		if (mpkt.fixed_hdr.type != type)
342 			goto not_found_or_invalid;
343 		break;
344 	case MQTT_NEED_MORE_DATA:
345 	     goto need_more;
346 	case MQTT_INVALID_MESSAGE:
347 		goto not_found_or_invalid;
348 	}
349 
350 	switch (type) {
351 	case MQTT_CPT_CONNECT:
352 		switch (fieldname_id) {
353 		case MQTT_FN_FLAGS:
354 			if (!mqtt_uint2str(trash, mpkt.data.connect.var_hdr.flags))
355 				goto not_found_or_invalid;
356 			res = ist2(trash->area, trash->data);
357 			goto end;
358 
359 		case MQTT_FN_PROTOCOL_NAME:
360 			if (!istlen(mpkt.data.connect.var_hdr.protocol_name))
361 				goto not_found_or_invalid;
362 			res = mpkt.data.connect.var_hdr.protocol_name;
363 			goto end;
364 
365 		case MQTT_FN_PROTOCOL_VERSION:
366 			if (!mqtt_uint2str(trash, mpkt.data.connect.var_hdr.protocol_version))
367 				goto not_found_or_invalid;
368 			res = ist2(trash->area, trash->data);
369 			goto end;
370 
371 		case MQTT_FN_CLIENT_IDENTIFIER:
372 			if (!istlen(mpkt.data.connect.payload.client_identifier))
373 				goto not_found_or_invalid;
374 			res = mpkt.data.connect.payload.client_identifier;
375 			goto end;
376 
377 		case MQTT_FN_WILL_TOPIC:
378 			if (!istlen(mpkt.data.connect.payload.will_topic))
379 				goto not_found_or_invalid;
380 			res = mpkt.data.connect.payload.will_topic;
381 			goto end;
382 
383 		case MQTT_FN_WILL_PAYLOAD:
384 			if (!istlen(mpkt.data.connect.payload.will_payload))
385 				goto not_found_or_invalid;
386 			res = mpkt.data.connect.payload.will_payload;
387 			goto end;
388 
389 		case MQTT_FN_USERNAME:
390 			if (!istlen(mpkt.data.connect.payload.username))
391 				goto not_found_or_invalid;
392 			res = mpkt.data.connect.payload.username;
393 			goto end;
394 
395 		case MQTT_FN_PASSWORD:
396 			if (!istlen(mpkt.data.connect.payload.password))
397 				goto not_found_or_invalid;
398 			res = mpkt.data.connect.payload.password;
399 			goto end;
400 
401 		case MQTT_FN_KEEPALIVE:
402 			    if (!mqtt_uint2str(trash, mpkt.data.connect.var_hdr.keepalive))
403 				    goto not_found_or_invalid;
404 			    res = ist2(trash->area, trash->data);
405 			    goto end;
406 
407 		case MQTT_FN_PAYLOAD_FORMAT_INDICATOR:
408 			if ((mpkt.data.connect.var_hdr.protocol_version != MQTT_VERSION_5_0) ||
409 			    !(mpkt.data.connect.var_hdr.flags & MQTT_CONNECT_FL_WILL))
410 				goto not_found_or_invalid;
411 			if (!mqtt_uint2str(trash, mpkt.data.connect.payload.will_props.payload_format_indicator))
412 				goto not_found_or_invalid;
413 			res = ist2(trash->area, trash->data);
414 			goto end;
415 
416 		case MQTT_FN_MESSAGE_EXPIRY_INTERVAL:
417 			if ((mpkt.data.connect.var_hdr.protocol_version != MQTT_VERSION_5_0) ||
418 			    !(mpkt.data.connect.var_hdr.flags & MQTT_CONNECT_FL_WILL))
419 				goto not_found_or_invalid;
420 			if (!mqtt_uint2str(trash, mpkt.data.connect.payload.will_props.message_expiry_interval))
421 				goto not_found_or_invalid;
422 			res = ist2(trash->area, trash->data);
423 			goto end;
424 
425 		case MQTT_FN_CONTENT_TYPE:
426 			if ((mpkt.data.connect.var_hdr.protocol_version != MQTT_VERSION_5_0) ||
427 			    !(mpkt.data.connect.var_hdr.flags & MQTT_CONNECT_FL_WILL))
428 				goto not_found_or_invalid;
429 			if (!istlen(mpkt.data.connect.payload.will_props.content_type))
430 				goto not_found_or_invalid;
431 			res = mpkt.data.connect.payload.will_props.content_type;
432 			goto end;
433 
434 		case MQTT_FN_RESPONSE_TOPIC:
435 			if ((mpkt.data.connect.var_hdr.protocol_version != MQTT_VERSION_5_0) ||
436 			    !(mpkt.data.connect.var_hdr.flags & MQTT_CONNECT_FL_WILL))
437 				goto not_found_or_invalid;
438 			if (!istlen(mpkt.data.connect.payload.will_props.response_topic))
439 				goto not_found_or_invalid;
440 			res = mpkt.data.connect.payload.will_props.response_topic;
441 			goto end;
442 
443 		case MQTT_FN_CORRELATION_DATA:
444 			if ((mpkt.data.connect.var_hdr.protocol_version != MQTT_VERSION_5_0) ||
445 			    !(mpkt.data.connect.var_hdr.flags & MQTT_CONNECT_FL_WILL))
446 				goto not_found_or_invalid;
447 			if (!istlen(mpkt.data.connect.payload.will_props.correlation_data))
448 				goto not_found_or_invalid;
449 			res = mpkt.data.connect.payload.will_props.correlation_data;
450 			goto end;
451 
452 		case MQTT_FN_SESSION_EXPIRY_INTERVAL:
453 			if (mpkt.data.connect.var_hdr.protocol_version != MQTT_VERSION_5_0)
454 				goto not_found_or_invalid;
455 			if (!mqtt_uint2str(trash, mpkt.data.connect.var_hdr.props.session_expiry_interval))
456 				goto not_found_or_invalid;
457 			res = ist2(trash->area, trash->data);
458 			goto end;
459 
460 		case MQTT_FN_AUTHENTICATION_METHOD:
461 			if (mpkt.data.connect.var_hdr.protocol_version != MQTT_VERSION_5_0)
462 				goto not_found_or_invalid;
463 			if (!istlen(mpkt.data.connect.var_hdr.props.authentication_method))
464 				goto not_found_or_invalid;
465 			res = mpkt.data.connect.var_hdr.props.authentication_method;
466 			goto end;
467 
468 		case MQTT_FN_AUTHENTICATION_DATA:
469 			if (mpkt.data.connect.var_hdr.protocol_version != MQTT_VERSION_5_0)
470 				goto not_found_or_invalid;
471 			if (!istlen(mpkt.data.connect.var_hdr.props.authentication_data))
472 				goto not_found_or_invalid;
473 			res = mpkt.data.connect.var_hdr.props.authentication_data;
474 			goto end;
475 
476 		case MQTT_FN_REQUEST_PROBLEM_INFORMATION:
477 			if (mpkt.data.connect.var_hdr.protocol_version != MQTT_VERSION_5_0)
478 				goto not_found_or_invalid;
479 			if (!mqtt_uint2str(trash, mpkt.data.connect.var_hdr.props.request_problem_information))
480 				goto not_found_or_invalid;
481 			res = ist2(trash->area, trash->data);
482 			goto end;
483 
484 		case MQTT_FN_DELAY_INTERVAL:
485 			if ((mpkt.data.connect.var_hdr.protocol_version != MQTT_VERSION_5_0) ||
486 			    !(mpkt.data.connect.var_hdr.flags & MQTT_CONNECT_FL_WILL))
487 				goto not_found_or_invalid;
488 			if (!mqtt_uint2str(trash, mpkt.data.connect.payload.will_props.delay_interval))
489 				goto not_found_or_invalid;
490 			res = ist2(trash->area, trash->data);
491 			goto end;
492 
493 		case MQTT_FN_REQUEST_RESPONSE_INFORMATION:
494 			if (mpkt.data.connect.var_hdr.protocol_version != MQTT_VERSION_5_0)
495 				goto not_found_or_invalid;
496 			if (!mqtt_uint2str(trash, mpkt.data.connect.var_hdr.props.request_response_information))
497 				goto not_found_or_invalid;
498 			res = ist2(trash->area, trash->data);
499 			goto end;
500 
501 		case MQTT_FN_RECEIVE_MAXIMUM:
502 			if (mpkt.data.connect.var_hdr.protocol_version != MQTT_VERSION_5_0)
503 				goto not_found_or_invalid;
504 			if (!mqtt_uint2str(trash, mpkt.data.connect.var_hdr.props.receive_maximum))
505 				goto not_found_or_invalid;
506 			res = ist2(trash->area, trash->data);
507 			goto end;
508 
509 		case MQTT_FN_TOPIC_ALIAS_MAXIMUM:
510 			if (mpkt.data.connect.var_hdr.protocol_version != MQTT_VERSION_5_0)
511 				goto not_found_or_invalid;
512 			if (!mqtt_uint2str(trash, mpkt.data.connect.var_hdr.props.topic_alias_maximum))
513 				goto not_found_or_invalid;
514 			res = ist2(trash->area, trash->data);
515 			goto end;
516 
517 		case MQTT_FN_MAXIMUM_PACKET_SIZE:
518 			if (mpkt.data.connect.var_hdr.protocol_version != MQTT_VERSION_5_0)
519 				goto not_found_or_invalid;
520 			if (!mqtt_uint2str(trash, mpkt.data.connect.var_hdr.props.maximum_packet_size))
521 				goto not_found_or_invalid;
522 			res = ist2(trash->area, trash->data);
523 			goto end;
524 
525 		default:
526 			goto not_found_or_invalid;
527 		}
528 		break;
529 
530 	case MQTT_CPT_CONNACK:
531 		switch (fieldname_id) {
532 		case MQTT_FN_FLAGS:
533 			if (!mqtt_uint2str(trash, mpkt.data.connack.var_hdr.flags))
534 				goto not_found_or_invalid;
535 			res = ist2(trash->area, trash->data);
536 			goto end;
537 
538 		case MQTT_FN_REASON_CODE:
539 			if (!mqtt_uint2str(trash, mpkt.data.connack.var_hdr.reason_code))
540 				goto not_found_or_invalid;
541 			res = ist2(trash->area, trash->data);
542 			goto end;
543 
544 		case MQTT_FN_PROTOCOL_VERSION:
545 			if (!mqtt_uint2str(trash, mpkt.data.connack.var_hdr.protocol_version))
546 				goto not_found_or_invalid;
547 			res = ist2(trash->area, trash->data);
548 			goto end;
549 
550 		case MQTT_FN_SESSION_EXPIRY_INTERVAL:
551 			if (mpkt.data.connack.var_hdr.protocol_version != MQTT_VERSION_5_0)
552 				goto not_found_or_invalid;
553 			if (!mqtt_uint2str(trash, mpkt.data.connack.var_hdr.props.session_expiry_interval))
554 				goto not_found_or_invalid;
555 			res = ist2(trash->area, trash->data);
556 			goto end;
557 
558 		case MQTT_FN_ASSIGNED_CLIENT_IDENTIFIER:
559 			if (mpkt.data.connack.var_hdr.protocol_version != MQTT_VERSION_5_0)
560 				goto not_found_or_invalid;
561 			if (!istlen(mpkt.data.connack.var_hdr.props.assigned_client_identifier))
562 				goto not_found_or_invalid;
563 			res = mpkt.data.connack.var_hdr.props.assigned_client_identifier;
564 			goto end;
565 
566 		case MQTT_FN_SERVER_KEEPALIVE:
567 			if (mpkt.data.connack.var_hdr.protocol_version != MQTT_VERSION_5_0)
568 				goto not_found_or_invalid;
569 			if (!mqtt_uint2str(trash, mpkt.data.connack.var_hdr.props.server_keepalive))
570 				goto not_found_or_invalid;
571 			res = ist2(trash->area, trash->data);
572 			goto end;
573 
574 		case MQTT_FN_AUTHENTICATION_METHOD:
575 			if (mpkt.data.connack.var_hdr.protocol_version != MQTT_VERSION_5_0)
576 				goto not_found_or_invalid;
577 			if (!istlen(mpkt.data.connack.var_hdr.props.authentication_method))
578 				goto not_found_or_invalid;
579 			res = mpkt.data.connack.var_hdr.props.authentication_method;
580 			goto end;
581 
582 		case MQTT_FN_AUTHENTICATION_DATA:
583 			if (mpkt.data.connack.var_hdr.protocol_version != MQTT_VERSION_5_0)
584 				goto not_found_or_invalid;
585 			if (!istlen(mpkt.data.connack.var_hdr.props.authentication_data))
586 				goto not_found_or_invalid;
587 			res = mpkt.data.connack.var_hdr.props.authentication_data;
588 			goto end;
589 
590 		case MQTT_FN_RESPONSE_INFORMATION:
591 			if (mpkt.data.connack.var_hdr.protocol_version != MQTT_VERSION_5_0)
592 				goto not_found_or_invalid;
593 			if (!istlen(mpkt.data.connack.var_hdr.props.response_information))
594 				goto not_found_or_invalid;
595 			res = mpkt.data.connack.var_hdr.props.response_information;
596 			goto end;
597 
598 		case MQTT_FN_SERVER_REFERENCE:
599 			if (mpkt.data.connack.var_hdr.protocol_version != MQTT_VERSION_5_0)
600 				goto not_found_or_invalid;
601 			if (!istlen(mpkt.data.connack.var_hdr.props.server_reference))
602 				goto not_found_or_invalid;
603 			res = mpkt.data.connack.var_hdr.props.server_reference;
604 			goto end;
605 
606 		case MQTT_FN_REASON_STRING:
607 			if (mpkt.data.connack.var_hdr.protocol_version != MQTT_VERSION_5_0)
608 				goto not_found_or_invalid;
609 			if (!istlen(mpkt.data.connack.var_hdr.props.reason_string))
610 				goto not_found_or_invalid;
611 			res = mpkt.data.connack.var_hdr.props.reason_string;
612 			goto end;
613 
614 		case MQTT_FN_RECEIVE_MAXIMUM:
615 			if (mpkt.data.connack.var_hdr.protocol_version != MQTT_VERSION_5_0)
616 				goto not_found_or_invalid;
617 			if (!mqtt_uint2str(trash, mpkt.data.connack.var_hdr.props.receive_maximum))
618 				goto not_found_or_invalid;
619 			res = ist2(trash->area, trash->data);
620 			goto end;
621 
622 		case MQTT_FN_TOPIC_ALIAS_MAXIMUM:
623 			if (mpkt.data.connack.var_hdr.protocol_version != MQTT_VERSION_5_0)
624 				goto not_found_or_invalid;
625 			if (!mqtt_uint2str(trash, mpkt.data.connack.var_hdr.props.topic_alias_maximum))
626 				goto not_found_or_invalid;
627 			res = ist2(trash->area, trash->data);
628 			goto end;
629 
630 		case MQTT_FN_MAXIMUM_QOS:
631 			if (mpkt.data.connack.var_hdr.protocol_version != MQTT_VERSION_5_0)
632 				goto not_found_or_invalid;
633 			if (!mqtt_uint2str(trash, mpkt.data.connack.var_hdr.props.maximum_qos))
634 				goto not_found_or_invalid;
635 			res = ist2(trash->area, trash->data);
636 			goto end;
637 
638 		case MQTT_FN_RETAIN_AVAILABLE:
639 			if (mpkt.data.connack.var_hdr.protocol_version != MQTT_VERSION_5_0)
640 				goto not_found_or_invalid;
641 			if (!mqtt_uint2str(trash, mpkt.data.connack.var_hdr.props.retain_available))
642 				goto not_found_or_invalid;
643 			res = ist2(trash->area, trash->data);
644 			goto end;
645 
646 		case MQTT_FN_MAXIMUM_PACKET_SIZE:
647 			if (mpkt.data.connack.var_hdr.protocol_version != MQTT_VERSION_5_0)
648 				goto not_found_or_invalid;
649 			if (!mqtt_uint2str(trash, mpkt.data.connack.var_hdr.props.maximum_packet_size))
650 				goto not_found_or_invalid;
651 			res = ist2(trash->area, trash->data);
652 			goto end;
653 
654 		case MQTT_FN_WILDCARD_SUBSCRIPTION_AVAILABLE:
655 			if (mpkt.data.connack.var_hdr.protocol_version != MQTT_VERSION_5_0)
656 				goto not_found_or_invalid;
657 			if (!mqtt_uint2str(trash, mpkt.data.connack.var_hdr.props.wildcard_subscription_available))
658 				goto not_found_or_invalid;
659 			res = ist2(trash->area, trash->data);
660 			goto end;
661 
662 		case MQTT_FN_SUBSCRIPTION_IDENTIFIERS_AVAILABLE:
663 			if (mpkt.data.connack.var_hdr.protocol_version != MQTT_VERSION_5_0)
664 				goto not_found_or_invalid;
665 			if (!mqtt_uint2str(trash, mpkt.data.connack.var_hdr.props.subscription_identifiers_available))
666 				goto not_found_or_invalid;
667 			res = ist2(trash->area, trash->data);
668 			goto end;
669 
670 		case MQTT_FN_SHARED_SUBSCRIPTION_AVAILABLE:
671 			if (mpkt.data.connack.var_hdr.protocol_version != MQTT_VERSION_5_0)
672 				goto not_found_or_invalid;
673 			if (!mqtt_uint2str(trash, mpkt.data.connack.var_hdr.props.shared_subsription_available))
674 				goto not_found_or_invalid;
675 			res = ist2(trash->area, trash->data);
676 			goto end;
677 
678 		default:
679 			goto not_found_or_invalid;
680 		}
681 		break;
682 
683 	default:
684 		goto not_found_or_invalid;
685 	}
686 
687   end:
688 	return res;
689 
690   need_more:
691 	return ist2(istptr(msg), 0);
692 
693   not_found_or_invalid:
694 	return IST_NULL;
695 }
696 
697 /* Parses a CONNECT packet :
698  *   https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718028
699  *   https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901033
700  *
701  * <parser> should point right after the MQTT fixed header. The remaining length
702  * was already checked, thus missing data is an error. On success, the result of
703  * the parsing is stored in <mpkt>.
704  *
705  * Returns:
706  *  MQTT_INVALID_MESSAGE if the CONNECT message is invalid
707  *  MQTT_VALID_MESSAGE   if the CONNECT message looks valid
708  */
mqtt_parse_connect(struct ist parser,struct mqtt_pkt * mpkt)709 static int mqtt_parse_connect(struct ist parser, struct mqtt_pkt *mpkt)
710 {
711 	/* The parser length is stored to be sure exactly consumed the announced
712 	 * remaining length. */
713 	size_t orig_len = istlen(parser);
714 	int ret = MQTT_INVALID_MESSAGE;
715 
716 	/*
717 	 * parsing variable header
718 	 */
719 	/* read protocol_name */
720 	parser = mqtt_read_string(parser, &mpkt->data.connect.var_hdr.protocol_name);
721 	if (!isttest(parser) || !isteqi(mpkt->data.connect.var_hdr.protocol_name, ist("MQTT")))
722 		goto end;
723 
724 	/* read protocol_version */
725 	parser = mqtt_read_1byte_int(parser, &mpkt->data.connect.var_hdr.protocol_version);
726 	if (!isttest(parser))
727 		goto end;
728 	if (mpkt->data.connect.var_hdr.protocol_version != MQTT_VERSION_3_1_1 &&
729 	    mpkt->data.connect.var_hdr.protocol_version != MQTT_VERSION_5_0)
730 		goto end;
731 
732 	/* read flags */
733 	/* bit 1 is 'reserved' and must be set to 0 in CONNECT message flags */
734 	parser = mqtt_read_1byte_int(parser, &mpkt->data.connect.var_hdr.flags);
735 	if (!isttest(parser) || (mpkt->data.connect.var_hdr.flags & MQTT_CONNECT_FL_RESERVED))
736 		goto end;
737 
738 	/* if WILL flag must be set to have WILL_QOS flag or WILL_RETAIN set */
739 	if ((mpkt->data.connect.var_hdr.flags & (MQTT_CONNECT_FL_WILL|MQTT_CONNECT_FL_WILL_QOS|MQTT_CONNECT_FL_WILL_RETAIN)) == MQTT_CONNECT_FL_WILL_QOS)
740 	    goto end;
741 
742 	/* read keepalive */
743 	parser = mqtt_read_2byte_int(parser, &mpkt->data.connect.var_hdr.keepalive);
744 	if (!isttest(parser))
745 		goto end;
746 
747 	/* read properties, only available in MQTT_VERSION_5_0 */
748 	if (mpkt->data.connect.var_hdr.protocol_version == MQTT_VERSION_5_0) {
749 		struct ist props;
750 		unsigned int user_prop_idx = 0;
751 		uint64_t fields = 0;
752 		uint32_t plen = 0;
753 
754 		parser = mqtt_read_varint(parser, &plen);
755 		if (!isttest(parser) || istlen(parser) < plen)
756 			goto end;
757 		props  = ist2(istptr(parser), plen);
758 		parser = istadv(parser, props.len);
759 
760 		while (istlen(props) > 0) {
761 			switch (*istptr(props)) {
762 			case MQTT_PROP_SESSION_EXPIRY_INTERVAL:
763 				if (fields & MQTT_FN_BIT_SESSION_EXPIRY_INTERVAL)
764 					goto end;
765 				props = mqtt_read_4byte_int(istnext(props), &mpkt->data.connect.var_hdr.props.session_expiry_interval);
766 				fields |= MQTT_FN_BIT_SESSION_EXPIRY_INTERVAL;
767 				break;
768 
769 			case MQTT_PROP_RECEIVE_MAXIMUM:
770 				if (fields & MQTT_FN_BIT_RECEIVE_MAXIMUM)
771 					goto end;
772 				props = mqtt_read_2byte_int(istnext(props), &mpkt->data.connect.var_hdr.props.receive_maximum);
773 				/* cannot be 0 */
774 				if (!mpkt->data.connect.var_hdr.props.receive_maximum)
775 					goto end;
776 				fields |= MQTT_FN_BIT_RECEIVE_MAXIMUM;
777 				break;
778 
779 			case MQTT_PROP_MAXIMUM_PACKET_SIZE:
780 				if (fields & MQTT_FN_BIT_MAXIMUM_PACKET_SIZE)
781 					goto end;
782 				props = mqtt_read_4byte_int(istnext(props), &mpkt->data.connect.var_hdr.props.maximum_packet_size);
783 				/* cannot be 0 */
784 				if (!mpkt->data.connect.var_hdr.props.maximum_packet_size)
785 					goto end;
786 				fields |= MQTT_FN_BIT_MAXIMUM_PACKET_SIZE;
787 				break;
788 
789 			case MQTT_PROP_TOPIC_ALIAS_MAXIMUM:
790 				if (fields & MQTT_FN_BIT_TOPIC_ALIAS)
791 					goto end;
792 				props = mqtt_read_2byte_int(istnext(props), &mpkt->data.connect.var_hdr.props.topic_alias_maximum);
793 				fields |= MQTT_FN_BIT_TOPIC_ALIAS;
794 				break;
795 
796 			case MQTT_PROP_REQUEST_RESPONSE_INFORMATION:
797 				if (fields & MQTT_FN_BIT_REQUEST_RESPONSE_INFORMATION)
798 					goto end;
799 				props = mqtt_read_1byte_int(istnext(props), &mpkt->data.connect.var_hdr.props.request_response_information);
800 				/* can have only 2 values: 0 or 1 */
801 				if (mpkt->data.connect.var_hdr.props.request_response_information > 1)
802 					goto end;
803 				fields |= MQTT_FN_BIT_REQUEST_RESPONSE_INFORMATION;
804 				break;
805 
806 			case MQTT_PROP_REQUEST_PROBLEM_INFORMATION:
807 				if (fields & MQTT_FN_BIT_REQUEST_PROBLEM_INFORMATION)
808 					goto end;
809 				props = mqtt_read_1byte_int(istnext(props), &mpkt->data.connect.var_hdr.props.request_problem_information);
810 				/* can have only 2 values: 0 or 1 */
811 				if (mpkt->data.connect.var_hdr.props.request_problem_information > 1)
812 					goto end;
813 				fields |= MQTT_FN_BIT_REQUEST_PROBLEM_INFORMATION;
814 				break;
815 
816 			case MQTT_PROP_USER_PROPERTIES:
817 				/* if we reached MQTT_PROP_USER_PROPERTY_ENTRIES already, then
818 				 * we start writing over the first property */
819 				if (user_prop_idx >= MQTT_PROP_USER_PROPERTY_ENTRIES)
820 					user_prop_idx = 0;
821 
822 				/* read user property name and value */
823 				props = mqtt_read_string(istnext(props), &mpkt->data.connect.var_hdr.props.user_props[user_prop_idx].name);
824 				if (!isttest(props))
825 					goto end;
826 				props = mqtt_read_string(props, &mpkt->data.connect.var_hdr.props.user_props[user_prop_idx].value);
827 				++user_prop_idx;
828 				break;
829 
830 			case MQTT_PROP_AUTHENTICATION_METHOD:
831 				if (fields & MQTT_FN_BIT_AUTHENTICATION_METHOD)
832 					goto end;
833 				props = mqtt_read_string(istnext(props), &mpkt->data.connect.var_hdr.props.authentication_method);
834 				fields |= MQTT_FN_BIT_AUTHENTICATION_METHOD;
835 				break;
836 
837 			case MQTT_PROP_AUTHENTICATION_DATA:
838 				if (fields & MQTT_FN_BIT_AUTHENTICATION_DATA)
839 					goto end;
840 				props = mqtt_read_string(istnext(props), &mpkt->data.connect.var_hdr.props.authentication_data);
841 				fields |= MQTT_FN_BIT_AUTHENTICATION_DATA;
842 				break;
843 
844 			default:
845 				goto end;
846 			}
847 
848 			if (!isttest(props))
849 				goto end;
850 		}
851 	}
852 
853 	/* cannot have auth data without auth method */
854 	if (!istlen(mpkt->data.connect.var_hdr.props.authentication_method) &&
855 	    istlen(mpkt->data.connect.var_hdr.props.authentication_data))
856 	    goto end;
857 
858 	/* parsing payload
859 	 *
860 	 * Content of payload is related to flags parsed above and the field order is pre-defined:
861 	 *   Client Identifier, Will Topic, Will Message, User Name, Password
862 	 */
863 	/* read client identifier */
864 	parser = mqtt_read_string(parser, &mpkt->data.connect.payload.client_identifier);
865 	if (!isttest(parser))
866 		goto end;
867 
868 	/* read Will Properties, for MQTT v5 only
869 	 * https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901060
870 	 */
871 	if ((mpkt->data.connect.var_hdr.protocol_version == MQTT_VERSION_5_0) &&
872 	    (mpkt->data.connect.var_hdr.flags & MQTT_CONNECT_FL_WILL)) {
873 		struct ist props;
874 		unsigned int user_prop_idx = 0;
875 		uint64_t fields = 0;
876 		uint32_t plen = 0;
877 
878 		parser = mqtt_read_varint(parser, &plen);
879 		if (!isttest(parser) || istlen(parser) < plen)
880 			goto end;
881 		props  = ist2(istptr(parser), plen);
882 		parser = istadv(parser, props.len);
883 
884 		while (istlen(props) > 0) {
885 			switch (*istptr(props)) {
886 			case MQTT_PROP_WILL_DELAY_INTERVAL:
887 				if (fields & MQTT_FN_BIT_DELAY_INTERVAL)
888 					goto end;
889 				props = mqtt_read_4byte_int(istnext(props), &mpkt->data.connect.payload.will_props.delay_interval);
890 				fields |= MQTT_FN_BIT_DELAY_INTERVAL;
891 				break;
892 
893 			case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR:
894 				if (fields & MQTT_FN_BIT_PAYLOAD_FORMAT_INDICATOR)
895 					goto end;
896 				props = mqtt_read_1byte_int(istnext(props), &mpkt->data.connect.payload.will_props.payload_format_indicator);
897 				/* can have only 2 values: 0 or 1 */
898 				if (mpkt->data.connect.payload.will_props.payload_format_indicator > 1)
899 					goto end;
900 				fields |= MQTT_FN_BIT_PAYLOAD_FORMAT_INDICATOR;
901 				break;
902 
903 			case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL:
904 				if (fields & MQTT_FN_BIT_MESSAGE_EXPIRY_INTERVAL)
905 					goto end;
906 				props = mqtt_read_4byte_int(istnext(props), &mpkt->data.connect.payload.will_props.message_expiry_interval);
907 				fields |= MQTT_FN_BIT_MESSAGE_EXPIRY_INTERVAL;
908 				break;
909 
910 			case MQTT_PROP_CONTENT_TYPE:
911 				if (fields & MQTT_FN_BIT_CONTENT_TYPE)
912 					goto end;
913 				props = mqtt_read_string(istnext(props), &mpkt->data.connect.payload.will_props.content_type);
914 				fields |= MQTT_FN_BIT_CONTENT_TYPE;
915 				break;
916 
917 			case MQTT_PROP_RESPONSE_TOPIC:
918 				if (fields & MQTT_FN_BIT_RESPONSE_TOPIC)
919 					goto end;
920 				props = mqtt_read_string(istnext(props), &mpkt->data.connect.payload.will_props.response_topic);
921 				fields |= MQTT_FN_BIT_RESPONSE_TOPIC;
922 				break;
923 
924 			case MQTT_PROP_CORRELATION_DATA:
925 				if (fields & MQTT_FN_BIT_CORRELATION_DATA)
926 					goto end;
927 				props = mqtt_read_string(istnext(props), &mpkt->data.connect.payload.will_props.correlation_data);
928 				fields |= MQTT_FN_BIT_CORRELATION_DATA;
929 				break;
930 
931 			case MQTT_PROP_USER_PROPERTIES:
932 				/* if we reached MQTT_PROP_USER_PROPERTY_ENTRIES already, then
933 				 * we start writing over the first property */
934 				if (user_prop_idx >= MQTT_PROP_USER_PROPERTY_ENTRIES)
935 					user_prop_idx = 0;
936 
937 				/* read user property name and value */
938 				props = mqtt_read_string(istnext(props), &mpkt->data.connect.payload.will_props.user_props[user_prop_idx].name);
939 				if (!isttest(props))
940 					goto end;
941 				props = mqtt_read_string(props, &mpkt->data.connect.payload.will_props.user_props[user_prop_idx].value);
942 				++user_prop_idx;
943 				break;
944 
945 			default:
946 				goto end;
947 			}
948 
949 			if (!isttest(props))
950 				goto end;
951 		}
952 	}
953 
954 	/* read Will Topic and Will Message (MQTT 3.1.1) or Payload (MQTT 5.0) */
955 	if (mpkt->data.connect.var_hdr.flags & MQTT_CONNECT_FL_WILL) {
956 		parser = mqtt_read_string(parser, &mpkt->data.connect.payload.will_topic);
957 		if (!isttest(parser))
958 			goto end;
959 		parser = mqtt_read_string(parser, &mpkt->data.connect.payload.will_payload);
960 		if (!isttest(parser))
961 			goto end;
962 	}
963 
964 	/* read User Name */
965 	if (mpkt->data.connect.var_hdr.flags & MQTT_CONNECT_FL_USERNAME) {
966 		parser = mqtt_read_string(parser, &mpkt->data.connect.payload.username);
967 		if (!isttest(parser))
968 			goto end;
969 	}
970 
971 	/* read Password */
972 	if (mpkt->data.connect.var_hdr.flags & MQTT_CONNECT_FL_PASSWORD) {
973 		parser = mqtt_read_string(parser, &mpkt->data.connect.payload.password);
974 		if (!isttest(parser))
975 			goto end;
976 	}
977 
978 	if ((orig_len - istlen(parser)) == mpkt->fixed_hdr.remaining_length)
979 		ret = MQTT_VALID_MESSAGE;
980 
981   end:
982 	return ret;
983 }
984 
985 /* Parses a CONNACK packet :
986  *   https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718033
987  *   https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901074
988  *
989  * <parser> should point right after the MQTT fixed header. The remaining length
990  * was already checked, thus missing data is an error. On success, the result of
991  * the parsing is stored in <mpkt>.
992  *
993  * Returns:
994  *  MQTT_INVALID_MESSAGE if the CONNECT message is invalid
995  *  MQTT_VALID_MESSAGE   if the CONNECT message looks valid
996  */
mqtt_parse_connack(struct ist parser,struct mqtt_pkt * mpkt)997 static int mqtt_parse_connack(struct ist parser, struct mqtt_pkt *mpkt)
998 {
999 	/* The parser length is stored to be sure exactly consumed the announced
1000 	 * remaining length. */
1001 	size_t orig_len = istlen(parser);
1002 	int ret = MQTT_INVALID_MESSAGE;
1003 
1004 	if (istlen(parser) < 2)
1005 		goto end;
1006 	else if (istlen(parser) == 2)
1007 		mpkt->data.connack.var_hdr.protocol_version = MQTT_VERSION_3_1_1;
1008 	else
1009 		mpkt->data.connack.var_hdr.protocol_version = MQTT_VERSION_5_0;
1010 
1011 	/*
1012 	 * parsing variable header
1013 	 */
1014 	/* read flags */
1015 	/* bits 7 to 1 on flags are reserved and must be 0 */
1016 	parser = mqtt_read_1byte_int(parser, &mpkt->data.connack.var_hdr.flags);
1017 	if (!isttest(parser) || (mpkt->data.connack.var_hdr.flags & 0xFE))
1018 		goto end;
1019 
1020 	/* read reason_code */
1021 	parser = mqtt_read_1byte_int(parser, &mpkt->data.connack.var_hdr.reason_code);
1022 	if (!isttest(parser))
1023 		goto end;
1024 
1025 	/* we can leave here for MQTT 3.1.1 */
1026 	if (mpkt->data.connack.var_hdr.protocol_version == MQTT_VERSION_3_1_1) {
1027 		if ((orig_len - istlen(parser)) == mpkt->fixed_hdr.remaining_length)
1028 			ret = MQTT_VALID_MESSAGE;
1029 		goto end;
1030 	}
1031 
1032 	/* read properties, only available in MQTT_VERSION_5_0 */
1033 	if (mpkt->data.connack.var_hdr.protocol_version == MQTT_VERSION_5_0) {
1034 		struct ist props;
1035 		unsigned int user_prop_idx = 0;
1036 		uint64_t fields = 0;
1037 		uint32_t plen = 0;
1038 
1039 		parser = mqtt_read_varint(parser, &plen);
1040 		if (!isttest(parser) || istlen(parser) < plen)
1041 			goto end;
1042 		props  = ist2(istptr(parser), plen);
1043 		parser = istadv(parser, props.len);
1044 
1045 		while (istlen(props) > 0) {
1046 			switch (*istptr(props)) {
1047 			case MQTT_PROP_SESSION_EXPIRY_INTERVAL:
1048 				if (fields & MQTT_FN_BIT_SESSION_EXPIRY_INTERVAL)
1049 					goto end;
1050 				props = mqtt_read_4byte_int(istnext(props), &mpkt->data.connack.var_hdr.props.session_expiry_interval);
1051 				fields |= MQTT_FN_BIT_SESSION_EXPIRY_INTERVAL;
1052 				break;
1053 
1054 			case MQTT_PROP_RECEIVE_MAXIMUM:
1055 				if (fields & MQTT_FN_BIT_RECEIVE_MAXIMUM)
1056 					goto end;
1057 				props = mqtt_read_2byte_int(istnext(props), &mpkt->data.connack.var_hdr.props.receive_maximum);
1058 				/* cannot be 0 */
1059 				if (!mpkt->data.connack.var_hdr.props.receive_maximum)
1060 					goto end;
1061 				fields |= MQTT_FN_BIT_RECEIVE_MAXIMUM;
1062 				break;
1063 
1064 			case MQTT_PROP_MAXIMUM_QOS:
1065 				if (fields & MQTT_FN_BIT_MAXIMUM_QOS)
1066 					goto end;
1067 				props = mqtt_read_1byte_int(istnext(props), &mpkt->data.connack.var_hdr.props.maximum_qos);
1068 				/* can have only 2 values: 0 or 1 */
1069 				if (mpkt->data.connack.var_hdr.props.maximum_qos > 1)
1070 					goto end;
1071 				fields |= MQTT_FN_BIT_MAXIMUM_QOS;
1072 				break;
1073 
1074 			case MQTT_PROP_RETAIN_AVAILABLE:
1075 				if (fields & MQTT_FN_BIT_RETAIN_AVAILABLE)
1076 					goto end;
1077 				props = mqtt_read_1byte_int(istnext(props), &mpkt->data.connack.var_hdr.props.retain_available);
1078 				/* can have only 2 values: 0 or 1 */
1079 				if (mpkt->data.connack.var_hdr.props.retain_available > 1)
1080 					goto end;
1081 				fields |= MQTT_FN_BIT_RETAIN_AVAILABLE;
1082 				break;
1083 
1084 			case MQTT_PROP_MAXIMUM_PACKET_SIZE:
1085 				if (fields & MQTT_FN_BIT_MAXIMUM_PACKET_SIZE)
1086 					goto end;
1087 				props = mqtt_read_4byte_int(istnext(props), &mpkt->data.connack.var_hdr.props.maximum_packet_size);
1088 				/* cannot be 0 */
1089 				if (!mpkt->data.connack.var_hdr.props.maximum_packet_size)
1090 					goto end;
1091 				fields |= MQTT_FN_BIT_MAXIMUM_PACKET_SIZE;
1092 				break;
1093 
1094 			case MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER:
1095 				if (fields & MQTT_FN_BIT_ASSIGNED_CLIENT_IDENTIFIER)
1096 					goto end;
1097 				props = mqtt_read_string(istnext(props), &mpkt->data.connack.var_hdr.props.assigned_client_identifier);
1098 				if (!istlen(mpkt->data.connack.var_hdr.props.assigned_client_identifier))
1099 					goto end;
1100 				fields |= MQTT_FN_BIT_ASSIGNED_CLIENT_IDENTIFIER;
1101 				break;
1102 
1103 			case MQTT_PROP_TOPIC_ALIAS_MAXIMUM:
1104 				if (fields & MQTT_FN_BIT_TOPIC_ALIAS_MAXIMUM)
1105 					goto end;
1106 				props = mqtt_read_2byte_int(istnext(props), &mpkt->data.connack.var_hdr.props.topic_alias_maximum);
1107 				fields |= MQTT_FN_BIT_TOPIC_ALIAS_MAXIMUM;
1108 				break;
1109 
1110 			case MQTT_PROP_REASON_STRING:
1111 				if (fields & MQTT_FN_BIT_REASON_STRING)
1112 					goto end;
1113 				props = mqtt_read_string(istnext(props), &mpkt->data.connack.var_hdr.props.reason_string);
1114 				fields |= MQTT_FN_BIT_REASON_STRING;
1115 				break;
1116 
1117 			case MQTT_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE:
1118 				if (fields & MQTT_FN_BIT_WILDCARD_SUBSCRIPTION_AVAILABLE)
1119 					goto end;
1120 				props = mqtt_read_1byte_int(istnext(props), &mpkt->data.connack.var_hdr.props.wildcard_subscription_available);
1121 				/* can have only 2 values: 0 or 1 */
1122 				if (mpkt->data.connack.var_hdr.props.wildcard_subscription_available > 1)
1123 					goto end;
1124 				fields |= MQTT_FN_BIT_WILDCARD_SUBSCRIPTION_AVAILABLE;
1125 				break;
1126 
1127 			case MQTT_PROP_SUBSCRIPTION_IDENTIFIERS_AVAILABLE:
1128 				if (fields & MQTT_FN_BIT_SUBSCRIPTION_IDENTIFIER)
1129 					goto end;
1130 				props = mqtt_read_1byte_int(istnext(props), &mpkt->data.connack.var_hdr.props.subscription_identifiers_available);
1131 				/* can have only 2 values: 0 or 1 */
1132 				if (mpkt->data.connack.var_hdr.props.subscription_identifiers_available > 1)
1133 					goto end;
1134 				fields |= MQTT_FN_BIT_SUBSCRIPTION_IDENTIFIER;
1135 				break;
1136 
1137 			case MQTT_PROP_SHARED_SUBSRIPTION_AVAILABLE:
1138 				if (fields & MQTT_FN_BIT_SHARED_SUBSCRIPTION_AVAILABLE)
1139 					goto end;
1140 				props = mqtt_read_1byte_int(istnext(props), &mpkt->data.connack.var_hdr.props.shared_subsription_available);
1141 				/* can have only 2 values: 0 or 1 */
1142 				if (mpkt->data.connack.var_hdr.props.shared_subsription_available > 1)
1143 					goto end;
1144 				fields |= MQTT_FN_BIT_SHARED_SUBSCRIPTION_AVAILABLE;
1145 				break;
1146 
1147 			case MQTT_PROP_SERVER_KEEPALIVE:
1148 				if (fields & MQTT_FN_BIT_SERVER_KEEPALIVE)
1149 					goto end;
1150 				props = mqtt_read_2byte_int(istnext(props), &mpkt->data.connack.var_hdr.props.server_keepalive);
1151 				fields |= MQTT_FN_BIT_SERVER_KEEPALIVE;
1152 				break;
1153 
1154 			case MQTT_PROP_RESPONSE_INFORMATION:
1155 				if (fields & MQTT_FN_BIT_RESPONSE_INFORMATION)
1156 					goto end;
1157 				props = mqtt_read_string(istnext(props), &mpkt->data.connack.var_hdr.props.response_information);
1158 				fields |= MQTT_FN_BIT_RESPONSE_INFORMATION;
1159 				break;
1160 
1161 			case MQTT_PROP_SERVER_REFERENCE:
1162 				if (fields & MQTT_FN_BIT_SERVER_REFERENCE)
1163 					goto end;
1164 				props = mqtt_read_string(istnext(props), &mpkt->data.connack.var_hdr.props.server_reference);
1165 				fields |= MQTT_FN_BIT_SERVER_REFERENCE;
1166 				break;
1167 
1168 			case MQTT_PROP_USER_PROPERTIES:
1169 				/* if we reached MQTT_PROP_USER_PROPERTY_ENTRIES already, then
1170 				 * we start writing over the first property */
1171 				if (user_prop_idx >= MQTT_PROP_USER_PROPERTY_ENTRIES)
1172 					user_prop_idx = 0;
1173 
1174 				/* read user property name and value */
1175 				props = mqtt_read_string(istnext(props), &mpkt->data.connack.var_hdr.props.user_props[user_prop_idx].name);
1176 				if (!isttest(props))
1177 					goto end;
1178 				props = mqtt_read_string(props, &mpkt->data.connack.var_hdr.props.user_props[user_prop_idx].value);
1179 				++user_prop_idx;
1180 				break;
1181 
1182 			case MQTT_PROP_AUTHENTICATION_METHOD:
1183 				if (fields & MQTT_FN_BIT_AUTHENTICATION_METHOD)
1184 					goto end;
1185 				props = mqtt_read_string(istnext(props), &mpkt->data.connack.var_hdr.props.authentication_method);
1186 				fields |= MQTT_FN_BIT_AUTHENTICATION_METHOD;
1187 				break;
1188 
1189 			case MQTT_PROP_AUTHENTICATION_DATA:
1190 				if (fields & MQTT_FN_BIT_AUTHENTICATION_DATA)
1191 					goto end;
1192 				props = mqtt_read_string(istnext(props), &mpkt->data.connack.var_hdr.props.authentication_data);
1193 				fields |= MQTT_FN_BIT_AUTHENTICATION_DATA;
1194 				break;
1195 
1196 			default:
1197 				return 0;
1198 			}
1199 
1200 			if (!isttest(props))
1201 				goto end;
1202 		}
1203 	}
1204 
1205 	if ((orig_len - istlen(parser)) == mpkt->fixed_hdr.remaining_length)
1206 		ret = MQTT_VALID_MESSAGE;
1207   end:
1208 	return ret;
1209 }
1210 
1211 
1212 /* Parses and validates a MQTT packet
1213  *   https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718028
1214  *
1215  * For now, due to HAProxy limitation, only validation of CONNECT and CONNACK packets
1216  * are supported.
1217  *
1218  *   - check FIXED_HDR
1219  *   - check remaining length
1220  *   - check variable headers and payload
1221  *
1222  * if <mpkt> is not NULL, then this structure will be filled up as well. An
1223  * unsupported packet type is considered as invalid. It is not a problem for now
1224  * because only the first packet on each side can be parsed (CONNECT for the
1225  * client and CONNACK for the server).
1226  *
1227  * Returns:
1228  *  MQTT_INVALID_MESSAGE if the message is invalid
1229  *  MQTT_NEED_MORE_DATA  if we need more data to fully validate the message
1230  *  MQTT_VALID_MESSAGE   if the message looks valid
1231  */
mqtt_validate_message(const struct ist msg,struct mqtt_pkt * mpkt)1232 int mqtt_validate_message(const struct ist msg, struct mqtt_pkt *mpkt)
1233 {
1234 	struct ist parser;
1235 	struct mqtt_pkt tmp_mpkt;
1236 	int ret = MQTT_INVALID_MESSAGE;
1237 
1238 	if (!mpkt)
1239 		mpkt = &tmp_mpkt;
1240 	memset(mpkt, 0, sizeof(*mpkt));
1241 
1242 	parser = msg;
1243 	if (istlen(msg) < MQTT_MIN_PKT_SIZE) {
1244 		ret = MQTT_NEED_MORE_DATA;
1245 		goto end;
1246 	}
1247 
1248 	/* parse the MQTT fixed header */
1249 	parser = mqtt_read_fixed_hdr(parser, mpkt);
1250 	if (!isttest(parser)) {
1251 		ret = MQTT_INVALID_MESSAGE;
1252 		goto end;
1253 	}
1254 
1255 	/* Now parsing "remaining length" field */
1256 	parser = mqtt_read_varint(parser, &mpkt->fixed_hdr.remaining_length);
1257 	if (!isttest(parser)) {
1258 		ret = MQTT_INVALID_MESSAGE;
1259 		goto end;
1260 	}
1261 
1262 	if (istlen(parser) < mpkt->fixed_hdr.remaining_length)
1263 		return MQTT_NEED_MORE_DATA;
1264 
1265 	/* Now parsing the variable header and payload, which is based on the packet type */
1266 	switch (mpkt->fixed_hdr.type) {
1267 	case MQTT_CPT_CONNECT:
1268 		ret = mqtt_parse_connect(parser, mpkt);
1269 		break;
1270 	case MQTT_CPT_CONNACK:
1271 		ret = mqtt_parse_connack(parser, mpkt);
1272 		break;
1273 	default:
1274 		break;
1275 	}
1276 
1277   end:
1278 	return ret;
1279 }
1280