Skip to content

Commit 6c59eef

Browse files
authored
MQTTSubscribe now supports multiple topic subscriptions in the payload. (#2759)
1 parent 22d15fd commit 6c59eef

File tree

2 files changed

+53
-34
lines changed

2 files changed

+53
-34
lines changed

scapy/contrib/mqtt.py

+17-26
Original file line numberDiff line numberDiff line change
@@ -220,14 +220,26 @@ class MQTTPubcomp(Packet):
220220
]
221221

222222

223+
class MQTTTopic(Packet):
224+
name = "MQTT topic"
225+
fields_desc = [
226+
FieldLenField("length", None, length_of="topic"),
227+
StrLenField("topic", "", length_from=lambda pkt:pkt.length)
228+
]
229+
230+
def guess_payload_class(self, payload):
231+
return conf.padding_layer
232+
233+
234+
class MQTTTopicQOS(MQTTTopic):
235+
fields_desc = MQTTTopic.fields_desc + [ByteEnumField("QOS", 0, QOS_LEVEL)]
236+
237+
223238
class MQTTSubscribe(Packet):
224239
name = "MQTT subscribe"
225240
fields_desc = [
226241
ShortField("msgid", None),
227-
FieldLenField("length", None, length_of="topic"),
228-
StrLenField("topic", "",
229-
length_from=lambda pkt: pkt.length),
230-
ByteEnumField("QOS", 0, QOS_LEVEL),
242+
PacketListField("topics", [], cls=MQTTTopicQOS)
231243
]
232244

233245

@@ -247,32 +259,11 @@ class MQTTSuback(Packet):
247259
]
248260

249261

250-
class MQTTTopic(Packet):
251-
name = "MQTT topic"
252-
fields_desc = [
253-
FieldLenField("len", None, length_of="topic"),
254-
StrLenField("topic", "", length_from=lambda pkt:pkt.len)
255-
]
256-
257-
def guess_payload_class(self, payload):
258-
return conf.padding_layer
259-
260-
261-
def cb_topic(pkt, lst, cur, remain):
262-
"""
263-
Decode the remaining bytes as a MQTT topic
264-
"""
265-
if len(remain) > 3:
266-
return MQTTTopic
267-
else:
268-
return conf.raw_layer
269-
270-
271262
class MQTTUnsubscribe(Packet):
272263
name = "MQTT unsubscribe"
273264
fields_desc = [
274265
ShortField("msgid", None),
275-
PacketListField("topics", [], next_cls_cb=cb_topic)
266+
PacketListField("topics", [], cls=MQTTTopic)
276267
]
277268

278269

test/contrib/mqtt.uts

+36-8
Original file line numberDiff line numberDiff line change
@@ -70,20 +70,20 @@ assert(connack.retcode == 0)
7070

7171

7272
= MQTTSubscribe, packet instantiation
73-
sb = MQTT()/MQTTSubscribe(msgid=1,topic='newtopic',QOS=0,length=0)
73+
sb = MQTT()/MQTTSubscribe(msgid=1, topics=[MQTTTopicQOS(topic='newtopic', QOS=1, length=0)])
7474
assert(sb.type == 8)
7575
assert(sb.msgid == 1)
76-
assert(sb.topic == b'newtopic')
77-
assert(sb.length == 0)
78-
assert(sb[MQTTSubscribe].QOS == 0)
76+
assert(sb.topics[0].topic == b'newtopic')
77+
assert(sb.topics[0].length == 0)
78+
assert(sb[MQTTSubscribe][MQTTTopicQOS].QOS == 1)
7979

8080
= MQTTSubscribe, packet dissection
81-
s = b'\x82\t\x00\x01\x00\x04test\x00'
81+
s = b'\x82\t\x00\x01\x00\x04test\x01'
8282
subscribe = MQTT(s)
8383
assert(subscribe.msgid == 1)
84-
assert(subscribe.length == 4)
85-
assert(subscribe.topic == b'test')
86-
assert(subscribe.QOS == 1)
84+
assert(subscribe.topics[0].length == 4)
85+
assert(subscribe.topics[0].topic == b'test')
86+
assert(subscribe.topics[0].QOS == 1)
8787

8888

8989
= MQTTSuback, packet instantiation
@@ -98,6 +98,30 @@ suback = MQTT(s)
9898
assert(suback.msgid == 1)
9999
assert(suback.retcode == 0)
100100

101+
= MQTTUnsubscribe, packet instantiation
102+
unsb = MQTT()/MQTTUnsubscribe(msgid=1, topics=[MQTTTopic(topic='newtopic',length=0)])
103+
assert(unsb.type == 10)
104+
assert(unsb.msgid == 1)
105+
assert(unsb.topics[0].topic == b'newtopic')
106+
assert(unsb.topics[0].length == 0)
107+
108+
= MQTTUnsubscribe, packet dissection
109+
u = b'\xA2\x09\x00\x01\x00\x03\x61\x2F\x62'
110+
unsubscribe = MQTT(u)
111+
assert(unsubscribe.msgid == 1)
112+
assert(unsubscribe.topics[0].length == 3)
113+
assert(unsubscribe.topics[0].topic == b'a/b')
114+
115+
= MQTTUnsuback, packet instantiation
116+
unsk = MQTT()/MQTTUnsuback(msgid=1)
117+
assert(unsk.type == 11)
118+
assert(unsk.msgid == 1)
119+
120+
= MQTTUnsuback, packet dissection
121+
u = b'\xb0\x02\x00\x01'
122+
unsuback = MQTT(u)
123+
assert(unsuback.type == 11)
124+
assert(unsuback.msgid == 1)
101125

102126
= MQTTPubrec, packet instantiation
103127
pc = MQTT()/MQTTPubrec(msgid=1)
@@ -129,3 +153,7 @@ assert(type(MQTT().fieldtype['len'].randval() + 0) == int)
129153
= MQTTUnsubscribe
130154
u = MQTT(b'\xA2\x0C\x00\x01\x00\x03\x61\x2F\x62\x00\x03\x63\x2F\x64')
131155
assert MQTTUnsubscribe in u and len(u.topics) == 2 and u.topics[1].topic == b"c/d"
156+
157+
= MQTTSubscribe
158+
u = MQTT(b'\x82\x10\x00\x01\x00\x03\x61\x2F\x62\x02\x00\x03\x63\x2F\x64\x00')
159+
assert MQTTSubscribe in u and len(u.topics) == 2 and u.topics[1].topic == b"c/d"

0 commit comments

Comments
 (0)