Closed martinkirsche closed 4 years ago
Hi,
Forwarder Addresses and ID are defined in clients.conf as Clients. It's not a specification. it's my own restriction for security. (Forwarders should be defined by clients.conf.)
your Encapsulation format is not correct.
[0x04, 0xFE, 0x00, 0x01, 0x16, 0x04, 0x04, 0x01, 0x00, 0x3c, 0x47]
Client ID in the CONNECT is missing and Packet lengthes are not correct.
[0x05, 0xFE, 0x00, 0x01, 0x16, 0x08, 0x04, 0x01, 0x00, 0x3c, 0x47, 0x43, 0x44]
clientID "CD"
sock.sendto(bytearray([0x05, 0xFE, 0x00, 0x01, 0x16, 0x08, 0x04, 0x01, 0x01, 0x3c, 0x47, 0x43, 0x44]), ("127.0.0.1", 10000))
sock.sendto(bytearray([0x05, 0xFE, 0x00, 0x02, 0x16, 0x08, 0x04, 0x01, 0x01, 0x3c, 0x47, 0x43, 0x45]), ("127.0.0.1", 10000))
Result of the correct message is
20200320 153357.170 ENCAPSULATED <--- Forwarder01 05 FE 00 01 16 08 04 01 01 3C 47 43 44
20200320 153357.170 CONNECT <--- CD 08 04 01 01 3C 47 43 44
20200320 153357.171 CONNECT ===> CD 10 0E 00 04 4D 51 54 54 04 00 3C 47 00 02 43 44
20200320 153357.441 CONNACK <=== CD 20 02 01 00
20200320 153357.441 CONNACK ---> CD 03 05 00
20200320 153357.441 ENCAPSULATED ---> Forwarder01 FE 00 01 16 03 05 00
20200320 153409.798 ENCAPSULATED <--- Forwarder01 05 FE 00 02 16 08 04 01 01 3C 47 43 45
20200320 153409.798 CONNECT <--- CE 08 04 01 01 3C 47 43 45
20200320 153409.798 CONNECT ===> CE 10 0E 00 04 4D 51 54 54 04 00 3C 47 00 02 43 45
20200320 153409.955 CONNACK <=== CE 20 02 00 00
20200320 153409.955 CONNACK ---> CE 03 05 00
20200320 153409.955 ENCAPSULATED ---> Forwarder01 FE 00 02 16 03 05 00
Hi, you are right the length field of the message was wrong. But the length field of the forwarding is fine.
However, in your modified example you also changed the client ID at the second connect call. In that case the bug is not triggered. So I restructured my example to get a better overview of what is actually happening.
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("127.0.0.1", 22002))
def connect(wireless_node_id):
return bytearray([
# Forwarder Encapsulation
0x04, # Length(0)
0xFE, # MsgType(1)
0x00, # Ctrl(2)
wireless_node_id, # Wireless Node Id (3)
# Message
0x07, # Length(0)
0x04, # MsgType(1)
0x04, # Flags(2)
0x01, # ProtocolId(3)
0x00, # Duration(4)
0x3c, # Duration(5)
0x47, # ClientId(6)
])
def ping(wireless_node_id):
return bytearray([
# Forwarder Encapsulation
0x04, # Length(0)
0xFE, # MsgType(1)
0x00, # Ctrl(2)
wireless_node_id, # Wireless Node Id (3)
# Message
0x02, # Length(0)
0x16, # MsgType(1)
])
sock.sendto(connect(1), ("127.0.0.1", 10000))
print(sock.recvfrom(6))
sock.sendto(ping(1), ("127.0.0.1", 10000))
print(sock.recvfrom(5))
# Reconnecting using a different Wireless Node Id. But the gateway will send the answer to the old Wireless Node Id.
sock.sendto(connect(2), ("127.0.0.1", 10000))
print(sock.recvfrom(6))
# The next message will trigger the error.
#Error: MQTTSNGWClientRecvTask Client(127.0.0.1:22002) is not connecting. message has been discarded.
sock.sendto(ping(2), ("127.0.0.1", 10000))
# This message was just added to check if the old Wireless Node Id will still work.
sock.sendto(ping(1), ("127.0.0.1", 10000))
print(sock.recvfrom(5))
The bug will still get triggered, even if the length field has the right value.
Wireless Id and Client Id pare is a key to identify the client to ensure security. So, the Gateway can not change the wireless Id of a forwarded client. According to the spec, Wireless Node Id: identifies the wireless node which has sent or should receive the encapsulated MQTT-SN message. The mapping between this Id and the address of the wireless node is implemented by the for- warder, if needed.
I think the identity of a wireless node is most likely bound to some kind of hardware device. But that is not necessarily true for the the client, which can run on any device. This is probably why they use two different IDs, one for the wireless node and one for the client. Handling them as a pair to identify the client is not mentioned within the MQTT-SN spec.
It should be possible to let the client use a different wireless node to communicate as long as the client does a reconnect.
My forwarder uses the client MAC address as the Wireless Node Id for the encapsulated MQTT-SN messages. It can happen that the MAC address changes (random MAC or different hardware). However the MQTT-SN ClientId won't change.
It looks like the gateway won't notice such a change and will keep using the old Wireless Node Id even if the MQTT-SN client already reconnected using its new Wireless Node Id.
I can't find anything in the MQTT-SN Protocol Specification that forces the ClientId and Wireless Node Id to be the same or only change together.
The following script will trigger the issue:
And the MQTTSNGateway's log output: