contrib: provide support for MQTT-SN#2131
Conversation
|
I did some testing locally, but did not integrate with your test framework yet. I will provide tests for that ASAP. |
scapy/contrib/mqttsn.py
Outdated
There was a problem hiding this comment.
This field also should manipulate the adjust of the len field of the MQTTSN wrapping packet, as the len for this packet type only signifies the length of the MQTTSNEncaps header without the encapsulated message (see section 5.5 of the spec). Is there a way to express this?
There was a problem hiding this comment.
Can't you use pkt.underlayer in the adjust ?
There was a problem hiding this comment.
In the adjust of this field you mean?
There was a problem hiding this comment.
If I see this correctly, StrLenField does not have an adjust parameter in its constructor.
There was a problem hiding this comment.
If I understand correctly, I meant
the adjust of the len field of the MQTTSN wrapping packet
It might be better if you clarify 😄 from what understand len in MQTTSN needs info from w_node_id. It can get this info during the adjust of the len
There was a problem hiding this comment.
It might be better if you clarify 😄
Ok, I'll try my best 😅:
For all packet types except this one the len field of MQTTSN (the underlayer of these packet types) denotes the total length of the packet. Only for this it denotes the length until the end of w_node_id (called "wireless node id" in the spec), and the length of the remainder is denoted by len field of a following MQTTSN packet (the encapsulated MQTT-SN datagram). So only for this I need to manipulate the len field of MQTTSN somehow to only go to the end of w_node_id string.
from what understand len in MQTTSN needs info from w_node_id. It can get this info during the adjust of the len
Do you mean something like this?
class MQTTSN(Packet):
name = "MQTT-SN header"
fields_desc = [
# …
VariableFieldLenField("len", None, length_of="len",
adjust=lambda pkt, x: x + len(pkt.payload))
if type(pkt.payload) is not MQTTSNEncaps
else x + len(pkt.payload.w_node_id) + 1,
# …
]There was a problem hiding this comment.
Ok, I somewhat did it like that :-)
Codecov Report
@@ Coverage Diff @@
## master #2131 +/- ##
==========================================
+ Coverage 87.25% 87.33% +0.07%
==========================================
Files 198 200 +2
Lines 44681 45384 +703
==========================================
+ Hits 38986 39635 +649
- Misses 5695 5749 +54
|
|
Fixed some errors I found during writing of the tests and provided tests. |
|
Let me know if I should squash, the checklist said, I should but the changes I fixed-up were done after I opened the PR, and I know from experience that the preferences of each reviewer can be different ;-). |
gpotter2
left a comment
There was a problem hiding this comment.
It's looking good.
Could you add a test that dissects a full packet, so that it tests the bindings with UDP ?
Will do |
|
And done. I used some dumps from some experiments of mine. The IPv6 prefix is an example prefix ( |
|
Fixed errors pointed out by travis. |
MQTT-SN is a sister protocol to MQTT that allows for MQTT-like traffic over UDP. It was designed to be as close as possible to MQTT but has some differences in its header format, so the MQTT layer of `scapy` can't be used to handle MQTT-SN packets.
|
And squashed |
Amend test to show that payload is parsed wrongly
Add 2 extra byte for >0xff length fields on adjust
Fix test for fixed length field calculation
|
While working with my implementation I noticed a bug in it. I fixed it and amended the tests to detect it. |
I provided a this also upstream [1] but it might take a while until there is a version of that one can install with `pip` etc. So for now I'd like to include this into our repo to provide some tests for our two MQTT-SN libraries, `emcute` and `asymcute`. [1]: secdev/scapy#2131
scapy/contrib/mqttsn.py
Outdated
|
|
||
| # Layer bindings | ||
| bind_layers(UDP, MQTTSN, sport=1883) | ||
| bind_layers(UDP, MQTTSN, dport=1883) |
There was a problem hiding this comment.
A better way of doing this is to use 2xbind_bottom_up and one bind_layers with both port set.
This makes sure that packets have the two ports set when building, therefore UDP doesn't by default fallback on DNS or some other thing
There was a problem hiding this comment.
Done and also provided a test for that case.
scapy/contrib/mqttsn.py
Outdated
| elif val > 0xff: | ||
| return s + b"".join([chb(0x01), chb(val >> 8), chb(val & 0xff)]) | ||
| else: | ||
| return s + b"".join([chb(val)]) |
scapy/contrib/mqttsn.py
Outdated
| raise Scapy_Exception("%s: invalid length field value" % | ||
| self.__class__.__name__) | ||
| elif val > 0xff: | ||
| return s + b"".join([chb(0x01), chb(val >> 8), chb(val & 0xff)]) |
There was a problem hiding this comment.
something like b"\x01" + struct.pack("!H", val) would probably be more appropriate
There was a problem hiding this comment.
Too used to C programming ^^
|
Thanks for the PR ! |
|
I did not squash yet :-/ |
|
It's alright, you can squash while merging a PR: (Though the messages will remain in the commit, but that's fine) |
MQTT-SN is a sister protocol to MQTT that allows for MQTT-like traffic over UDP. It was designed to be as close as possible to MQTT but has some differences in its header format, so the MQTT layer of
scapycan't be used to handle MQTT-SN packets.