% Real-Time Publish-Subscribe Protocol (RTPS) dissection % % Copyright (C) 2021 Trend Micro Incorporated % Copyright (C) 2021 Alias Robotics S.L. % % This program is free software; you can redistribute it and/or modify it under % the terms of the GNU General Public License as published by the Free Software % Foundation; either version 2 of the License, or (at your option) any later % version. % % This program is distributed in the hope that it will be useful, but WITHOUT ANY % WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A % PARTICULAR PURPOSE. See the GNU General Public License for more details. % % You should have received a copy of the GNU General Public License along with % this program; if not, write to the Free Software Foundation, Inc., 51 Franklin % Street, Fifth Floor, Boston, MA 02110-1301, USA. % RTPS layer test campaign + Syntax check = Import the RTPS layer from scapy.contrib.rtps import * pkt = b"\x52\x54\x50\x53\x02\x01\x01\x10\x57\x63\x10\x01\xd6\xab\x40\x7f" \ b"\x5b\xd9\xbb\x1c\x0e\x01\x0c\x00\x88\x2a\x10\x01\x5d\x8c\x97\x40" \ b"\x78\xb6\x2d\xc2\x09\x01\x08\x00\xf4\x50\x81\x60\x51\xdd\x5c\x1c" \ b"\x15\x05\x10\x01\x00\x00\x10\x00\x00\x01\x00\xc7\x00\x01\x00\xc2" \ b"\x00\x00\x00\x00\x01\x00\x00\x00\x00\x03\x00\x00\x15\x00\x04\x00" \ b"\x02\x01\x00\x00\x16\x00\x04\x00\x01\x10\x00\x00\x02\x00\x08\x00" \ b"\x0a\x00\x00\x00\x00\x00\x00\x00\x50\x00\x10\x00\x57\x63\x10\x01" \ b"\xd6\xab\x40\x7f\x5b\xd9\xbb\x1c\x00\x00\x01\xc1\x58\x00\x04\x00" \ b"\x3f\x0c\x00\x00\x0f\x00\x04\x00\x00\x00\x00\x00\x31\x00\x18\x00" \ b"\x01\x00\x00\x00\xbd\xeb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \ b"\x00\x00\x00\x00\xac\x11\x00\x02\x48\x00\x18\x00\x01\x00\x00\x00" \ b"\xe9\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \ b"\xef\xff\x00\x01\x32\x00\x18\x00\x01\x00\x00\x00\xbd\xeb\x00\x00" \ b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x11\x00\x02" \ b"\x33\x00\x18\x00\x01\x00\x00\x00\xe8\x1c\x00\x00\x00\x00\x00\x00" \ b"\x00\x00\x00\x00\x00\x00\x00\x00\xef\xff\x00\x01\x07\x80\x38\x00" \ b"\x00\x00\x00\x00\x2c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \ b"\x00\x00\x00\x00\x1d\x00\x00\x00\x74\x65\x73\x74\x2e\x6c\x6f\x63" \ b"\x61\x6c\x2f\x30\x2e\x38\x2e\x30\x2f\x4c\x69\x6e\x75\x78\x2f\x4c" \ b"\x69\x6e\x75\x78\x00\x00\x00\x00\x19\x80\x04\x00\x00\x80\x06\x00" \ b"\x01\x00\x00\x00" + Test endianness = PID_BUILTIN_ENDPOINT_QOS endianness assert raw(PID_BUILTIN_ENDPOINT_QOS(parameterId=119, parameterLength=0, parameterData=b"")) == b'w\x00\x00\x00' + Test RTPS = RTPS default header values pkt2 = RTPS()/RTPSMessage(submessages=[ RTPSSubMessage_HEARTBEAT(), RTPSSubMessage_INFO_TS(), RTPSSubMessage_DATA(), ]) assert bytes(RTPS()) == b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = RTPS packet declaration pkt3 = RTPS( protocolVersion=ProtocolVersionPacket(major=2, minor=1), vendorId=VendorIdPacket(vendor_id=0x0110), guidPrefix=GUIDPrefixPacket( hostId=1466109953, appId=3601547391, instanceId=1540995868 ), magic=b"RTPS", ) / RTPSMessage( submessages=[ RTPSSubMessage_INFO_DST( submessageId=14, submessageFlags=1, octetsToNextHeader=12, guidPrefix=GUIDPrefixPacket( hostId=2284457985, appId=1569494848, instanceId=2025205186 ), ), RTPSSubMessage_INFO_TS( submessageId=9, submessageFlags=1, octetsToNextHeader=8, ts_seconds=1619087604, ts_fraction=475848017, ), RTPSSubMessage_DATA( submessageId=21, submessageFlags=5, octetsToNextHeader=272, extraFlags=0, octetsToInlineQoS=16, readerEntityIdKey=256, readerEntityIdKind=199, writerEntityIdKey=256, writerEntityIdKind=194, writerSeqNumHi=0, writerSeqNumLow=1, data=DataPacket( encapsulationKind=3, encapsulationOptions=0, parameterList=ParameterListPacket( parameterValues=[ PID_PROTOCOL_VERSION( parameterId=21, parameterLength=4, protocolVersion=ProtocolVersionPacket(major=2, minor=1), padding=b"\x00\x00", ), PID_VENDOR_ID( parameterId=22, parameterLength=4, vendorId=VendorIdPacket(vendor_id=0x0110), padding=b"\x00\x00", ), PID_PARTICIPANT_LEASE_DURATION( parameterId=2, parameterLength=8, parameterData=b"\n\x00\x00\x00\x00\x00\x00\x00", ), PID_PARTICIPANT_GUID( parameterId=80, parameterLength=16, guid=GUIDPacket( hostId=1466109953, appId=3601547391, instanceId=1540995868, entityId=449, ), ), PID_BUILTIN_ENDPOINT_SET( parameterId=88, parameterLength=4, parameterData=b"?\x0c\x00\x00", ), PID_DOMAIN_ID( parameterId=15, parameterLength=4, parameterData=b"\x00\x00\x00\x00", ), PID_DEFAULT_UNICAST_LOCATOR( parameterId=49, parameterLength=24, locator=LocatorPacket( locatorKind=1, port=60349, address="172.17.0.2" ), ), PID_DEFAULT_MULTICAST_LOCATOR( parameterId=72, parameterLength=24, locator=LocatorPacket( locatorKind=1, port=7401, address="239.255.0.1" ), ), PID_METATRAFFIC_UNICAST_LOCATOR( parameterId=50, parameterLength=24, locator=LocatorPacket( locatorKind=1, port=60349, address="172.17.0.2" ), ), PID_METATRAFFIC_MULTICAST_LOCATOR( parameterId=51, parameterLength=24, locator=LocatorPacket( locatorKind=1, port=7400, address="239.255.0.1" ), ), PID_UNKNOWN( parameterId=32775, parameterLength=56, parameterData=b"\x00\x00\x00\x00,\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00test.local/0.8.0/Linux/Linux\x00\x00\x00\x00", ), PID_UNKNOWN( parameterId=32793, parameterLength=4, parameterData=b"\x00\x80\x06\x00", ), ], sentinel=PID_SENTINEL(parameterId=1, parameterLength=0), ), ), ), ] ) = RTPS header dissect assert pkt3.build() == pkt + Test RTI RTPS = Test dissection d = b"\x52\x54\x50\x53\x02\x03\x01\x01\x01\x01\x30\xba\xa8\x7b\x1d\xce" \ b"\xb3\x29\x1e\x43\x09\x01\x08\x00\xd6\x64\xa8\x61\x16\x09\x34\x7c" \ b"\x15\x05\xdc\x02\x00\x00\x10\x00\x00\x00\x00\x00\x00\x01\x00\xc2" \ b"\x00\x00\x00\x00\x01\x00\x00\x00\x00\x03\x00\x00\x50\x00\x10\x00" \ b"\x01\x01\x30\xba\xa8\x7b\x1d\xce\xb3\x29\x1e\x43\x00\x00\x01\xc1" \ b"\x58\x00\x04\x00\x3f\x0c\x00\x00\x77\x00\x04\x00\x01\x00\x00\x00" \ b"\x15\x00\x04\x00\x02\x03\x00\x00\x16\x00\x04\x00\x01\x01\x00\x00" \ b"\x00\x80\x04\x00\x06\x00\x01\x00\x59\x00\x78\x01\x06\x00\x00\x00" \ b"\x16\x00\x00\x00\x64\x64\x73\x2e\x73\x79\x73\x5f\x69\x6e\x66\x6f" \ b"\x2e\x68\x6f\x73\x74\x6e\x61\x6d\x65\x00\x00\x00\x0d\x00\x00\x00" \ b"\x64\x66\x30\x62\x36\x64\x38\x33\x61\x62\x34\x36\x00\x00\x00\x00" \ b"\x18\x00\x00\x00\x64\x64\x73\x2e\x73\x79\x73\x5f\x69\x6e\x66\x6f" \ b"\x2e\x70\x72\x6f\x63\x65\x73\x73\x5f\x69\x64\x00\x05\x00\x00\x00" \ b"\x34\x38\x33\x30\x00\x00\x00\x00\x21\x00\x00\x00\x64\x64\x73\x2e" \ b"\x73\x79\x73\x5f\x69\x6e\x66\x6f\x2e\x65\x78\x65\x63\x75\x74\x61" \ b"\x62\x6c\x65\x5f\x66\x69\x6c\x65\x70\x61\x74\x68\x00\x00\x00\x00" \ b"\x42\x00\x00\x00\x2f\x75\x73\x72\x2f\x6c\x6f\x63\x61\x6c\x2f\x73" \ b"\x72\x63\x2f\x72\x74\x69\x2f\x72\x65\x73\x6f\x75\x72\x63\x65\x2f" \ b"\x61\x70\x70\x2f\x62\x69\x6e\x2f\x78\x36\x34\x4c\x69\x6e\x75\x78" \ b"\x32\x2e\x36\x67\x63\x63\x34\x2e\x34\x2e\x35\x2f\x72\x74\x69\x64" \ b"\x64\x73\x73\x70\x79\x00\x00\x00\x14\x00\x00\x00\x64\x64\x73\x2e" \ b"\x73\x79\x73\x5f\x69\x6e\x66\x6f\x2e\x74\x61\x72\x67\x65\x74\x00" \ b"\x14\x00\x00\x00\x78\x36\x34\x4c\x69\x6e\x75\x78\x32\x2e\x36\x67" \ b"\x63\x63\x34\x2e\x34\x2e\x35\x00\x20\x00\x00\x00\x64\x64\x73\x2e" \ b"\x73\x79\x73\x5f\x69\x6e\x66\x6f\x2e\x63\x72\x65\x61\x74\x69\x6f" \ b"\x6e\x5f\x74\x69\x6d\x65\x73\x74\x61\x6d\x70\x00\x14\x00\x00\x00" \ b"\x32\x30\x32\x31\x2d\x30\x36\x2d\x37\x20\x30\x34\x3a\x30\x39\x3a" \ b"\x30\x32\x5a\x00\x21\x00\x00\x00\x64\x64\x73\x2e\x73\x79\x73\x5f" \ b"\x69\x6e\x66\x6f\x2e\x65\x78\x65\x63\x75\x74\x69\x6f\x6e\x5f\x74" \ b"\x69\x6d\x65\x73\x74\x61\x6d\x70\x00\x00\x00\x00\x14\x00\x00\x00" \ b"\x32\x30\x32\x31\x2d\x31\x32\x2d\x31\x20\x30\x39\x3a\x31\x35\x3a" \ b"\x32\x39\x5a\x00\x31\x00\x18\x00\x01\x00\x00\x00\xf3\x1c\x00\x00" \ b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \ b"\x31\x00\x18\x00\x00\x00\x00\x01\xf3\x1c\x00\x00\x61\xab\xd9\x79" \ b"\xb5\x7c\x13\xa5\x29\x49\x2c\xa3\x00\x00\x00\x00\x32\x00\x18\x00" \ b"\x01\x00\x00\x00\xf2\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \ b"\x00\x00\x00\x00\x00\x00\x00\x00\x32\x00\x18\x00\x00\x00\x00\x01" \ b"\xf2\x1c\x00\x00\x61\xab\xd9\x79\xb5\x7c\x13\xa5\x29\x49\x2c\xa3" \ b"\x00\x00\x00\x00\x33\x00\x18\x00\x01\x00\x00\x00\xe8\x1c\x00\x00" \ b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xef\xff\x00\x01" \ b"\x02\x00\x08\x00\x06\x00\x00\x00\xff\xff\xff\x7f\x01\x80\x04\x00" \ b"\xff\xff\x00\x00\x62\x00\x28\x00\x22\x00\x00\x00\x52\x54\x49\x20" \ b"\x44\x61\x74\x61\x20\x44\x69\x73\x74\x72\x69\x62\x75\x74\x69\x6f" \ b"\x6e\x20\x53\x65\x72\x76\x69\x63\x65\x20\x53\x70\x79\x00\x00\x00" \ b"\x0f\x00\x04\x00\x00\x00\x00\x00\x0f\x80\x04\x00\x00\x00\x00\x00" \ b"\x10\x80\x14\x00\x02\x00\x00\x00\x01\x00\x00\x00\xe3\xff\x00\x00" \ b"\x00\x00\x00\x01\x00\x00\x01\x00\x16\x80\x08\x00\x10\x00\x00\x00" \ b"\x00\x00\x00\x00\x17\x80\x04\x00\x03\x00\x00\x00\x01\x00\x00\x00" p0 = RTPS(d) p1 = RTPS( protocolVersion=ProtocolVersionPacket(major=2, minor=3), vendorId=VendorIdPacket(vendor_id=0x0101), guidPrefix=GUIDPrefixPacket( hostId=16855226, appId=2826640846, instanceId=3005816387 ), magic=b"RTPS", ) / RTPSMessage( submessages=[ RTPSSubMessage_INFO_TS( submessageId=9, submessageFlags=1, octetsToNextHeader=8, ts_seconds=1638425814, ts_fraction=2083784982, ), RTPSSubMessage_DATA( submessageId=21, submessageFlags=5, octetsToNextHeader=732, extraFlags=0, octetsToInlineQoS=16, readerEntityIdKey=0, readerEntityIdKind=0, writerEntityIdKey=256, writerEntityIdKind=194, writerSeqNumHi=0, writerSeqNumLow=1, data=DataPacket( encapsulationKind=3, encapsulationOptions=0, parameterList=ParameterListPacket( parameterValues=[ PID_PARTICIPANT_GUID( parameterId=80, parameterLength=16, guid=GUIDPacket( hostId=16855226, appId=2826640846, instanceId=3005816387, entityId=449, ), ), PID_BUILTIN_ENDPOINT_SET( parameterId=88, parameterLength=4, parameterData=b"?\x0c\x00\x00", ), PID_BUILTIN_ENDPOINT_QOS( parameterId=119, parameterLength=4, parameterData=b"\x01\x00\x00\x00", ), PID_PROTOCOL_VERSION( parameterId=21, parameterLength=4, protocolVersion=ProtocolVersionPacket(major=2, minor=3), padding=b"\x00\x00", ), PID_VENDOR_ID( parameterId=22, parameterLength=4, vendorId=VendorIdPacket(vendor_id=0x0101), padding=b"\x00\x00", ), PID_PRODUCT_VERSION( parameterId=32768, parameterLength=4, productVersion=ProductVersionPacket( major=6, minor=0, release=1, revision=0 ), ), PID_PROPERTY_LIST( parameterId=89, parameterLength=376, parameterData=b"\x06\x00\x00\x00\x16\x00\x00\x00dds.sys_info.hostname\x00\x00\x00\r\x00\x00\x00df0b6d83ab46\x00\x00\x00\x00\x18\x00\x00\x00dds.sys_info.process_id\x00\x05\x00\x00\x004830\x00\x00\x00\x00!\x00\x00\x00dds.sys_info.executable_filepath\x00\x00\x00\x00B\x00\x00\x00/usr/local/src/rti/resource/app/bin/x64Linux2.6gcc4.4.5/rtiddsspy\x00\x00\x00\x14\x00\x00\x00dds.sys_info.target\x00\x14\x00\x00\x00x64Linux2.6gcc4.4.5\x00 \x00\x00\x00dds.sys_info.creation_timestamp\x00\x14\x00\x00\x002021-06-7 04:09:02Z\x00!\x00\x00\x00dds.sys_info.execution_timestamp\x00\x00\x00\x00\x14\x00\x00\x002021-12-1 09:15:29Z\x00", ), PID_DEFAULT_UNICAST_LOCATOR( parameterId=49, parameterLength=24, locator=LocatorPacket( locatorKind=1, port=7411, address="0.0.0.0" ), ), PID_DEFAULT_UNICAST_LOCATOR( parameterId=49, parameterLength=24, locator=LocatorPacket( locatorKind=16777216, port=7411, hostId=b"a\xab\xd9y\xb5|\x13\xa5)I,\xa3\x00\x00\x00\x00", ), ), PID_METATRAFFIC_UNICAST_LOCATOR( parameterId=50, parameterLength=24, locator=LocatorPacket( locatorKind=1, port=7410, address="0.0.0.0" ), ), PID_METATRAFFIC_UNICAST_LOCATOR( parameterId=50, parameterLength=24, locator=LocatorPacket( locatorKind=16777216, port=7410, hostId=b"a\xab\xd9y\xb5|\x13\xa5)I,\xa3\x00\x00\x00\x00", ), ), PID_METATRAFFIC_MULTICAST_LOCATOR( parameterId=51, parameterLength=24, locator=LocatorPacket( locatorKind=1, port=7400, address="239.255.0.1" ), ), PID_PARTICIPANT_LEASE_DURATION( parameterId=2, parameterLength=8, parameterData=b"\x06\x00\x00\x00\xff\xff\xff\x7f", ), PID_PLUGIN_PROMISCUITY_KIND( parameterId=32769, parameterLength=4, promiscuityKind=65535 ), PID_ENTITY_NAME( parameterId=98, parameterLength=40, parameterData=b'"\x00\x00\x00RTI Data Distribution Service Spy\x00\x00\x00', ), PID_DOMAIN_ID( parameterId=15, parameterLength=4, parameterData=b"\x00\x00\x00\x00", ), PID_RTI_DOMAIN_ID( parameterId=32783, parameterLength=4, domainId=0 ), PID_TRANSPORT_INFO_LIST( transportInfo=[ TransportInfoPacket(classID=1, messageSizeMax=65507), TransportInfoPacket( classID=16777216, messageSizeMax=65536 ), ], parameterId=32784, parameterLength=20, padding=b"\x02\x00\x00\x00", ), PID_REACHABILITY_LEASE_DURATION( parameterId=32790, parameterLength=8, lease_duration=LeaseDurationPacket( seconds=268435456, fraction=0 ), ), PID_VENDOR_BUILTIN_ENDPOINT_SET( parameterId=32791, parameterLength=4, flags=3 ), ], sentinel=PID_SENTINEL(parameterId=1, parameterLength=0), ), ), ), ] ) assert p0.build() == d assert p1.build() == d assert p1 == p0 + Test for pr #3914 = RTPS Heartbeat SequenceNumber_t packing and dissection d = b"\x52\x54\x50\x53\x02\x02\x01\x0f\x01\x0f\x45\xd2\xb3\xf5\x58\xb9" \ b"\x01\x00\x00\x00\x07\x01\x1c\x00\x00\x00\x03\xc7\x00\x00\x03\xc2" \ b"\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00" \ b"\x01\x00\x00\x00" p0 = RTPS(d) p1 = RTPS( protocolVersion=ProtocolVersionPacket(major=2, minor=2), vendorId=VendorIdPacket(vendor_id=0x010f), guidPrefix=GUIDPrefixPacket( hostId=0x010f45d2, appId=0xb3f558b9, instanceId=0x01000000 ), magic=b"RTPS", ) / RTPSMessage( submessages=[ RTPSSubMessage_HEARTBEAT( submessageId=0x07, submessageFlags=0x01, octetsToNextHeader=28, reader_id=b"\x00\x00\x03\xc7", writer_id=b"\x00\x00\x03\xc2", firstAvailableSeqNumHi=0, firstAvailableSeqNumLow=1, lastSeqNumHi=0, lastSeqNumLow=1, count=1 ) ] ) assert p0.build() == d assert p1.build() == d assert p0 == p1 + Test for pr #3915 = RTPS ACKNACK count packing and dissection d = b"\x52\x54\x50\x53\x02\x02\x01\x0f\x01\x0f\x45\xd2\xb3\xf5\x58\xb9" \ b"\x01\x00\x00\x00\x06\x03\x18\x00\x00\x00\x03\xc7\x00\x00\x03\xc2" \ b"\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00" p0 = RTPS(d) p1 = RTPS( protocolVersion=ProtocolVersionPacket(major=2, minor=2), vendorId=VendorIdPacket(vendor_id=0x010f), guidPrefix=GUIDPrefixPacket( hostId=0x010f45d2, appId=0xb3f558b9, instanceId=0x01000000 ), magic=b"RTPS", ) / RTPSMessage( submessages=[ RTPSSubMessage_ACKNACK( submessageId=6, submessageFlags=3, octetsToNextHeader=0x18, reader_id=b'\x00\x00\x03\xc7', writer_id=b'\x00\x00\x03\xc2', readerSNState=b'\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00', count=1 ) ] ) assert p0.build() == d assert p1.build() == d assert p0 == p1