# coding: utf8 % ProfinetIO layer test campaign + Syntax check = Import the ProfinetIO layer from scapy.contrib.pnio import * from scapy.config import conf import re old_conf_dissector = conf.debug_dissector conf.debug_dissector=True + Check DCE/RPC layer = ProfinetIO default values raw(ProfinetIO()) == b'\x00\x00' = ProfinetIO overloads Ethertype p = Ether() / ProfinetIO() p.type == 0x8892 = ProfinetIO overloads UDP dport p = UDP() / ProfinetIO() p.dport == 0x8892 = Ether guesses ProfinetIO as payload class p = Ether(hex_bytes('ffffffffffff00000000000088920102')) isinstance(p.payload, ProfinetIO) and p.frameID == 0x0102 = UDP guesses ProfinetIO as payload class p = UDP(hex_bytes('12348892000a00000102')) isinstance(p.payload, ProfinetIO) and p.frameID == 0x0102 + PNIO RTC PDU tests = ProfinetIO PNIORealTime_IOxS parsing of a single status p = PNIORealTime_IOxS(b'\x80') assert p.dataState == 1 assert p.instance == 0 assert p.reserved == 0 assert p.extension == 0 p = PNIORealTime_IOxS(b'\xe1') assert p.dataState == 1 assert p.instance == 3 assert p.reserved == 0 assert p.extension == 1 True = ProfinetIO PNIORealTime_IOxS building of a single status p = PNIORealTime_IOxS(dataState = 'good', instance='subslot', extension=0) assert raw(p) == b'\x80' p = PNIORealTime_IOxS(dataState = 'bad', instance='device', extension=1) assert raw(p) == b'\x41' True = ProfinetIO PNIORealTime_IOxS parsing with multiple statuses TestPacket = type( 'TestPacket', (Packet,), { 'name': 'TestPacket', 'fields_desc': [ PacketListField('data', [], next_cls_cb= PNIORealTime_IOxS.is_extension_set) ], } ) p = TestPacket(b'\x81\xe1\x01\x80') assert len(p.data) == 4 assert p.data[0].dataState == 1 assert p.data[0].instance == 0 assert p.data[0].reserved == 0 assert p.data[0].extension == 1 assert p.data[1].dataState == 1 assert p.data[1].instance == 3 assert p.data[1].reserved == 0 assert p.data[1].extension == 1 assert p.data[2].dataState == 0 assert p.data[2].instance == 0 assert p.data[2].reserved == 0 assert p.data[2].extension == 1 assert p.data[3].dataState == 1 assert p.data[3].instance == 0 assert p.data[3].reserved == 0 assert p.data[3].extension == 0 = ProfinetIO RTC PDU parsing without configuration p = Ether(b'\x00\x02\x04\x06\x08\x0a\x01\x03\x05\x07\x09\x0B\x88\x92\x80\x00\x01\x02\x03\x04\xf0\x00\x35\x00') assert p[Ether].dst == '00:02:04:06:08:0a' assert p[Ether].src == '01:03:05:07:09:0b' assert p[Ether].type == 0x8892 assert p[ProfinetIO].frameID == 0x8000 assert isinstance(p[ProfinetIO].payload, PNIORealTimeCyclicPDU) assert len(p[PNIORealTimeCyclicPDU].data) == 1 assert isinstance(p[PNIORealTimeCyclicPDU].data[0], PNIORealTimeCyclicDefaultRawData) assert p[PNIORealTimeCyclicDefaultRawData].data == b'\x01\x02\x03\x04' assert p[PNIORealTimeCyclicPDU].padding == b'' assert p[PNIORealTimeCyclicPDU].cycleCounter == 0xf000 assert p[PNIORealTimeCyclicPDU].dataStatus == 0x35 assert p[PNIORealTimeCyclicPDU].transferStatus == 0 True = ProfinetIO RTC PDU building p = Ether(src='01:03:05:07:09:0b', dst='00:02:04:06:08:0a')/ProfinetIO(frameID = 'PTCP-RTSyncPDU')/PNIORealTimeCyclicPDU( data=[ PNIORealTimeCyclicPDU.build_fixed_len_raw_type(10)(data = b'\x80'*10) ], padding = b'\x00'*8, cycleCounter = 900, dataStatus = 0x35, transferStatus = 0 ) assert( raw(p) == \ b'\x00\x02\x04\x06\x08\x0a' \ b'\x01\x03\x05\x07\x09\x0b' \ b'\x88\x92' \ b'\x00\x80' \ b'\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80' \ b'\x00\x00\x00\x00\x00\x00\x00\x00' \ b'\x03\x84' \ b'\x35' \ b'\x00' ) = ProfinetIO RTC PDU parsing with config scapy.config.conf.contribs['PNIO_RTC'][('01:03:05:07:09:0b', '00:02:04:06:08:0a', 0x8010)] = [ PNIORealTimeCyclicPDU.build_fixed_len_raw_type(5), PNIORealTimeCyclicPDU.build_fixed_len_raw_type(3), PNIORealTimeCyclicPDU.build_fixed_len_raw_type(2) ] p = Ether( b'\x00\x02\x04\x06\x08\x0a' \ b'\x01\x03\x05\x07\x09\x0B' \ b'\x88\x92' \ b'\x80\x10' \ b'\x01\x02\x03\x04\x05' \ b'\x01\x02\x03' \ b'\x01\x02' \ b'\x00\x00' \ b'\xf0\x00' \ b'\x35' \ b'\x00' ) assert p[Ether].dst == '00:02:04:06:08:0a' assert p[Ether].src == '01:03:05:07:09:0b' assert p[Ether].type == 0x8892 assert p[ProfinetIO].frameID == 0x8010 assert isinstance(p[ProfinetIO].payload, PNIORealTimeCyclicPDU) assert len(p[PNIORealTimeCyclicPDU].data) == 3 assert isinstance(p[PNIORealTimeCyclicPDU].data[0], scapy.config.conf.raw_layer) assert p[PNIORealTimeCyclicPDU].data[0].data == b'\x01\x02\x03\x04\x05' assert isinstance(p[PNIORealTimeCyclicPDU].data[1], scapy.config.conf.raw_layer) assert p[PNIORealTimeCyclicPDU].data[1].data == b'\x01\x02\x03' assert isinstance(p[PNIORealTimeCyclicPDU].data[2], scapy.config.conf.raw_layer) assert p[PNIORealTimeCyclicPDU].data[2].data == b'\x01\x02' assert p[PNIORealTimeCyclicPDU].padding == b'\x00' * 2 assert p[PNIORealTimeCyclicPDU].cycleCounter == 0xf000 assert p[PNIORealTimeCyclicPDU].dataStatus == 0x35 assert p[PNIORealTimeCyclicPDU].transferStatus == 0 p = Ether(b'\x00\x02\x04\x06\x08\x0a\x01\x03\x05\x07\x09\x0B\x88\x92\x80\x00\x01\x02\x03\x04\xf0\x00\x35\x00') assert p[Ether].dst == '00:02:04:06:08:0a' assert p[Ether].src == '01:03:05:07:09:0b' assert p[Ether].type == 0x8892 assert p[ProfinetIO].frameID == 0x8000 assert isinstance(p[ProfinetIO].payload, PNIORealTimeCyclicPDU) assert len(p[PNIORealTimeCyclicPDU].data) == 1 assert isinstance(p[PNIORealTimeCyclicPDU].data[0], PNIORealTimeCyclicDefaultRawData) assert p[PNIORealTimeCyclicDefaultRawData].data == b'\x01\x02\x03\x04' assert p[PNIORealTimeCyclicPDU].padding == b'' assert p[PNIORealTimeCyclicPDU].cycleCounter == 0xf000 assert p[PNIORealTimeCyclicPDU].dataStatus == 0x35 assert p[PNIORealTimeCyclicPDU].transferStatus == 0 True = PROFIsafe parsing (query with F_CRC_SEED=0) p = PROFIsafe.build_PROFIsafe_class(PROFIsafeControl, 2)(b'\x80\x80\x40\x01\x02\x03') assert p.data == b'\x80\x80' assert p.control == 0x40 assert p.crc == 0x010203 True = PROFIsafe parsing (query with F_CRC_SEED=1) p = PROFIsafe.build_PROFIsafe_class(PROFIsafeControlCRCSeed, 2)(b'\x80\x80\x40\x01\x02\x03\x04') assert p.data == b'\x80\x80' assert p.control == 0x40 assert p.crc == 0x01020304 True = PROFIsafe parsing (response with F_CRC_SEED=0) p = PROFIsafe.build_PROFIsafe_class(PROFIsafeStatus, 1)(b'\x80\x40\x01\x02\x03') assert p.data == b'\x80' assert p.status == 0x40 assert p.crc == 0x010203 True = PROFIsafe parsing (response with F_CRC_SEED=1) p = PROFIsafe.build_PROFIsafe_class(PROFIsafeStatusCRCSeed, 1)(b'\x80\x40\x01\x02\x03\x04') assert p.data == b'\x80' assert p.status == 0x40 assert p.crc == 0x01020304 True = PROFIsafe building (query with F_CRC_SEED=0) p = PROFIsafe.build_PROFIsafe_class(PROFIsafeControl, 2)(data = b'\x81\x80', control=0x40, crc=0x040506) assert raw(p) == b'\x81\x80\x40\x04\x05\x06' = PROFIsafe building (query with F_CRC_SEED=1) p = PROFIsafe.build_PROFIsafe_class(PROFIsafeControlCRCSeed, 2)(data = b'\x81\x80', control=0x02, crc=0x04050607) assert raw(p) == b'\x81\x80\x02\x04\x05\x06\x07' = PROFIsafe building (response with F_CRC_SEED=0) p = PROFIsafe.build_PROFIsafe_class(PROFIsafeStatus, 3)(data = b'\x01\x81\x00', status=0x01, crc=0x040506) assert raw(p) == b'\x01\x81\x00\x01\x04\x05\x06' = PROFIsafe building (response with F_CRC_SEED=1) p = PROFIsafe.build_PROFIsafe_class(PROFIsafeStatusCRCSeed, 3)(data = b'\x01\x81\x80', status=0x01, crc=0x04050607) assert raw(p) == b'\x01\x81\x80\x01\x04\x05\x06\x07' conf.debug_dissector = old_conf_dissector