1% IEC 60870-5-104 test campaign 2 3# 4# execute test: 5# > test/run_tests -t test/contrib/iec104.uts 6# 7 8+ iec104 infrastructure 9 10= load the iec104 layer 11 12load_contrib('scada.iec104') 13 14= class attribute generator 15 16assert IEC104_IE_QOC.QU_FLAG_RESERVED_COMPATIBLE_4 == 4 17assert IEC104_IE_QOC.QU_FLAG_RESERVED_COMPATIBLE_8 == 8 18assert IEC104_IE_QOC.QU_FLAG_RESERVED_PREDEFINED_FUNCTION_9 == 9 19assert IEC104_IE_QOC.QU_FLAG_RESERVED_PREDEFINED_FUNCTION_15 == 15 20 21= IEC60870_5_4_NormalizedFixPoint 22 23test_data = [ 24 (b'\x9c\x84', -0.963989, -31588), 25 (b'\x46\xf6', -0.075989, -2490), 26 (b'\xc9\xf6', -0.071991, -2359), 27 (b'\x40\xf5', -0.083984, -2752), 28 (b'\x89\x01', 0.011993, 393), 29 (b'\xd2\x0d', 0.107971, 3538), 30 (b'\xd7\x23', 0.279999, 9175), 31 (b'\x76\x3e', 0.487976, 15990), 32 (b'\x08\x6c', 0.843994, 27656), 33 (b'\xff\x7f', 0.999969, 32767) 34] 35 36nfp = IEC60870_5_4_NormalizedFixPoint('foo', 0) 37 38for num_raw, num_fp, num_ss in test_data: 39 i_val = nfp.getfield(None, num_raw)[1] 40 assert i_val == num_ss 41 assert round(nfp.i2h(None, i_val), 6) == round(num_fp, 6) 42 43 44= Iec104SequenceNumber field 45 46iec104_seq_num = IEC104SequenceNumber('rx_seq', 0) 47 48test_data = { 49 1: b'\x02\x00', 50 2: b'\x04\x00', 51 14 : b'\x1c\x00', 52 16 : b'\x20\x00', 53 73 : b'\x92\x00', 54 127: b'\xfe\x00', 55 128: b'\x00\x01', 56 129: b'\x02\x01', 57 253: b'\xfa\x01', 58 254: b'\xfc\x01', 59 255: b'\xfe\x01', 60 5912: b'\x30\x2e', 61 31282: b'\x64\xf4', 62 32767: b'\xfe\xff' 63} 64 65for key in test_data: 66 assert iec104_seq_num.getfield(None, test_data[key])[1] == key 67 assert iec104_seq_num.addfield(None, b'', key) == test_data[key] 68 69+ raw layer dissection 70 71= IEC104_U_Message 72 73raw_u_msg = b'\x68\x04\x83\x00\x00\x00' 74 75lyr = iec104_decode(b'\x68\x04\x83\x00\x00\x00') 76assert lyr.__class__ == IEC104_U_Message 77 78= IEC104_S_Message 79 80raw_s_msg = b'\x68\x04\x01\x00\xa6\x17' 81 82lyr = iec104_decode(raw_s_msg) 83assert lyr.__class__ == IEC104_S_Message 84 85= IEC104_I_Message_SeqIOA 86 87raw_i_msg_seq_ioa = b'\x68\x1f\x2c\x00\x04\x00' # APCI 88raw_i_msg_seq_ioa += b'\x01\x92\x14\x00\x23\x00\x12\x54\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' # ASDU 89 90lyr = iec104_decode(raw_i_msg_seq_ioa) 91assert lyr.__class__ == IEC104_I_Message_SeqIOA 92 93= IEC104_I_Message_SingleIOA 94 95raw_i_msg_single_ioa = b'\x68\x0e\x00\x00\x00\x00\x64\x01\x06\x00\x0a\x00\x00\x00\x00\x14' 96 97lyr = iec104_decode(raw_i_msg_single_ioa) 98assert lyr.__class__ == IEC104_I_Message_SingleIOA 99 100+ IEC104 S Message 101 102= single IEC104 S Message 103 104s_msg = b'\x68\x04\x01\x00\xa6\x17' 105 106s_msg = IEC104_S_Message(s_msg) 107 108assert s_msg.rx_seq_num == 3027 109 110raw_s_message = b'\x00\x14\xab\x00\x3c\x13\x00\x1b\x8d\xf1\xdc\x12\x08\x00\x45\x10\x00\x3a\x8d\xdb\x40\x00\x3d\x06\x54\x46\x1a\x52\x01\xde\xc1\x28\x15\x5c\xaa\x56\x09\x64\x16\x67\x6c\xd7\x53\x07\x28\x98\x80\x18\x79\x5e\x9b\x14\x00\x00\x01\x01\x08\x0a\x9e\x08\xaa\x23\x73\xe8\x6c\xc3\x68\x04\x01\x00\xc2\x3a' 111 112frm = Ether(raw_s_message) 113 114s_msg = frm.getlayer(IEC104_S_Message) 115assert s_msg 116assert s_msg.rx_seq_num == 7521 117 118frm = Ether(frm.do_build()) 119 120s_msg = frm.getlayer(IEC104_S_Message) 121assert s_msg 122assert s_msg.rx_seq_num == 7521 123 124= double IEC104 S Message (test layer binding) 125 126raw_double_s_message = b'\x00\x14\xab\x00\x3c\x13\x00\x1b\x8d\xf1\xdc\x12\x08\x00\x45\x10\x00\x40\x8d\xdb\x40\x00\x3d\x06\x54\x46\x0c\x35\x1b\x33\xc1\x28\x15\x44\xaa\x56\x09\x64\x16\x67\x6c\xd7\x53\x07\x28\x98\x80\x18\x79\x5e\x9b\x14\x00\x00\x01\x01\x08\x0a\x9e\x08\xaa\x23\x73\xe8\x6c\xc3\x68\x04\x01\x00\xc2\x3a\x68\x04\x01\x00\xc2\x3b' 127 128frm = Ether(raw_double_s_message) 129 130s_msg = frm.getlayer(IEC104_S_Message) 131assert s_msg 132assert s_msg.rx_seq_num == 7521 133 134s_msg = frm.getlayer(IEC104_S_Message, nb=2) 135assert s_msg 136assert s_msg.rx_seq_num == 7649 137 138frm = Ether(frm.do_build()) 139 140s_msg = frm.getlayer(IEC104_S_Message) 141assert s_msg 142assert s_msg.rx_seq_num == 7521 143 144s_msg = frm.getlayer(IEC104_S_Message, nb=2) 145assert s_msg 146assert s_msg.rx_seq_num == 7649 147 148+ IEC104 U Message 149 150= single IEC104 U Message 151 152frm = Ether()/IP()/TCP()/IEC104_U_Message(startdt_act = 1, stopdt_con = 1, testfr_act=1) 153frm = Ether(frm.do_build()) 154u_msg = frm.getlayer(IEC104_U_Message) 155assert u_msg 156assert u_msg.startdt_act == 1 157assert u_msg.startdt_con == 0 158assert u_msg.stopdt_con == 1 159assert u_msg.stopdt_act == 0 160assert u_msg.testfr_act == 1 161assert u_msg.testfr_con == 0 162 163u_msg_tst_act = b'\x68\x04\x43\x00\x00\x00' 164u_msg = IEC104_U_Message(u_msg_tst_act) 165assert u_msg.testfr_act == 1 166 167u_msg_tst_con = b'\x68\x04\x83\x00\x00\x00' 168u_msg = IEC104_U_Message(u_msg_tst_con) 169assert u_msg.testfr_con == 1 170 171u_msg_startdt_act = b'\x68\x04\x07\x00\x00\x00' 172u_msg = IEC104_U_Message(u_msg_startdt_act) 173assert u_msg.startdt_act == 1 174 175u_msg_startdt_con = b'\x68\x04\x0b\x00\x00\x00' 176u_msg = IEC104_U_Message(u_msg_startdt_con) 177assert u_msg.startdt_con == 1 178 179u_msg_stopdt_act = b'\x68\x04\x13\x00\x00\x00' 180u_msg = IEC104_U_Message(u_msg_stopdt_act) 181assert u_msg.stopdt_act == 1 182 183u_msg_stopdt_con = b'\x68\x04\x23\x00\x00\x00' 184u_msg = IEC104_U_Message(u_msg_stopdt_con) 185assert u_msg.stopdt_con == 1 186 187= double IEC104 U Message 188 189frm = Ether()/IP()/TCP()/\ 190 IEC104_U_Message(startdt_act = 1, stopdt_con = 1, testfr_act=1)/\ 191 IEC104_U_Message(startdt_con = 1, stopdt_act = 1, testfr_con=1) 192 193frm = Ether(frm.do_build()) 194u_msg = frm.getlayer(IEC104_U_Message) 195assert u_msg 196assert u_msg.startdt_act == 1 197assert u_msg.stopdt_con == 1 198assert u_msg.testfr_act == 1 199 200u_msg = frm.getlayer(IEC104_U_Message, nb=2) 201assert u_msg 202assert u_msg.startdt_con == 1 203assert u_msg.stopdt_act == 1 204assert u_msg.testfr_con == 1 205 206+ IEC104 I Message 207 208= Sequence IOA, single IO - information object types dissection 209 210for io_id in IEC104_IO_CLASSES: 211 io_class = IEC104_IO_CLASSES[io_id] 212 frm = Ether()/IP()/TCP(sport=IEC_104_IANA_PORT, dport=56780)/IEC104_I_Message_SeqIOA(io=io_class()) 213 frm = Ether(frm.do_build()) 214 io_layer = frm.getlayer(io_class) 215 assert io_layer 216 217= Single IOA, single IO - information object types dissection 218 219for io_id in IEC104_IO_WITH_IOA_CLASSES: 220 io_class = IEC104_IO_WITH_IOA_CLASSES[io_id] 221 frm = Ether()/IP()/TCP(sport=IEC_104_IANA_PORT, dport=56780)/IEC104_I_Message_SingleIOA(io=io_class()) 222 frm = Ether(frm.do_build()) 223 io_layer = frm.getlayer(io_class) 224 assert io_layer 225 226= Sequence IOA, multiple IOs - information object types dissection 227 228frm = Ether()/IP()/TCP(sport=IEC_104_IANA_PORT, dport=56780)/IEC104_I_Message_SeqIOA(information_object_address=1234, io=[IEC104_IO_C_RC_TA_1(minutes = 1, sec_milli = 2),IEC104_IO_C_RC_TA_1(minutes = 3, sec_milli = 4)]) 229frm = Ether(frm.do_build()) 230 231i_msg_lyr = frm.getlayer(IEC104_I_Message_SeqIOA) 232assert i_msg_lyr 233 234assert i_msg_lyr.information_object_address == 1234 235 236m_sp_ta_1_lyr = i_msg_lyr.io[0] 237assert (m_sp_ta_1_lyr.minutes == 1) 238assert (m_sp_ta_1_lyr.sec_milli == 2) 239 240m_sp_ta_1_lyr = i_msg_lyr.io[1] 241assert (m_sp_ta_1_lyr.minutes == 3) 242assert (m_sp_ta_1_lyr.sec_milli == 4) 243 244= Single IOA, multiple IOs - information object types dissection 245 246frm = Ether()/IP()/TCP(sport=IEC_104_IANA_PORT, dport=56780)/\ 247 IEC104_I_Message_SingleIOA(io=[IEC104_IO_C_RC_TA_1_IOA(information_object_address=1111, minutes = 1, sec_milli = 2), 248 IEC104_IO_C_RC_TA_1_IOA(information_object_address=2222,minutes = 3, sec_milli = 4)]) 249frm = Ether(frm.do_build()) 250 251i_msg_lyr = frm.getlayer(IEC104_I_Message_SingleIOA) 252assert i_msg_lyr 253 254m_sp_ta_1_lyr = i_msg_lyr.io[0] 255assert (m_sp_ta_1_lyr.information_object_address==1111) 256assert (m_sp_ta_1_lyr.minutes == 1) 257assert (m_sp_ta_1_lyr.sec_milli == 2) 258 259 260m_sp_ta_1_lyr = i_msg_lyr.io[1] 261assert (m_sp_ta_1_lyr.information_object_address==2222) 262assert (m_sp_ta_1_lyr.minutes == 3) 263assert (m_sp_ta_1_lyr.sec_milli == 4) 264 265= Sequence IOA, multiple APDUs 266 267frm = Ether()/IP()/TCP(sport=IEC_104_IANA_PORT, dport=56780)/\ 268 IEC104_I_Message_SeqIOA(information_object_address=1234, 269 io=[IEC104_IO_C_RC_TA_1(minutes = 1, sec_milli = 2), 270 IEC104_IO_C_RC_TA_1(minutes = 3, sec_milli = 4)])/ \ 271 IEC104_I_Message_SeqIOA(information_object_address=5432, 272 io=[IEC104_IO_C_RC_TA_1(minutes = 5, sec_milli = 6), 273 IEC104_IO_C_RC_TA_1(minutes = 7, sec_milli = 8)]) 274 275frm = Ether(frm.do_build()) 276i_msg_lyr = frm.getlayer(IEC104_I_Message_SeqIOA, nb=1) 277assert i_msg_lyr 278assert (i_msg_lyr.information_object_address == 1234) 279assert len(i_msg_lyr.io) == 2 280assert i_msg_lyr.io[0].minutes == 1 281assert i_msg_lyr.io[0].sec_milli == 2 282assert i_msg_lyr.io[1].minutes == 3 283assert i_msg_lyr.io[1].sec_milli == 4 284 285i_msg_lyr = frm.getlayer(IEC104_I_Message_SeqIOA, nb=2) 286assert i_msg_lyr 287assert (i_msg_lyr.information_object_address == 5432) 288assert len(i_msg_lyr.io) == 2 289assert i_msg_lyr.io[0].minutes == 5 290assert i_msg_lyr.io[0].sec_milli == 6 291assert i_msg_lyr.io[1].minutes == 7 292assert i_msg_lyr.io[1].sec_milli == 8 293 294= Single IOA, multiple APDUs 295 296frm = Ether()/IP()/TCP(sport=IEC_104_IANA_PORT, dport=56780)/\ 297 IEC104_I_Message_SingleIOA(io=[IEC104_IO_C_RC_TA_1_IOA(information_object_address=1111, 298 minutes = 1, sec_milli = 2), 299 IEC104_IO_C_RC_TA_1_IOA(information_object_address=2222, 300 minutes = 3, sec_milli = 4)])/ \ 301 IEC104_I_Message_SingleIOA(io=[IEC104_IO_C_RC_TA_1_IOA(information_object_address=3333, 302 minutes = 5, sec_milli = 6), 303 IEC104_IO_C_RC_TA_1_IOA(information_object_address=4444, 304 minutes = 7, sec_milli = 8)]) 305 306frm = Ether(frm.do_build()) 307i_msg_lyr = frm.getlayer(IEC104_I_Message_SingleIOA, nb=1) 308assert i_msg_lyr 309assert len(i_msg_lyr.io) == 2 310assert (i_msg_lyr.io[0].information_object_address == 1111) 311assert i_msg_lyr.io[0].minutes == 1 312assert i_msg_lyr.io[0].sec_milli == 2 313assert (i_msg_lyr.io[1].information_object_address == 2222) 314assert i_msg_lyr.io[1].minutes == 3 315assert i_msg_lyr.io[1].sec_milli == 4 316 317i_msg_lyr = frm.getlayer(IEC104_I_Message_SingleIOA, nb=2) 318assert i_msg_lyr 319assert len(i_msg_lyr.io) == 2 320assert (i_msg_lyr.io[0].information_object_address == 3333) 321assert i_msg_lyr.io[0].minutes == 5 322assert i_msg_lyr.io[0].sec_milli == 6 323assert (i_msg_lyr.io[1].information_object_address == 4444) 324assert i_msg_lyr.io[1].minutes == 7 325assert i_msg_lyr.io[1].sec_milli == 8 326 327= Mixed Single and Sequence IOA, multiple APDU 328 329frm = Ether()/IP()/TCP(sport=IEC_104_IANA_PORT, dport=56780)/\ 330 IEC104_I_Message_SeqIOA(information_object_address=1111, 331 io=[IEC104_IO_C_RC_TA_1_IOA(minutes = 1, sec_milli = 2), 332 IEC104_IO_C_RC_TA_1_IOA(minutes = 3, sec_milli = 4)])/ \ 333 IEC104_I_Message_SingleIOA(io=[IEC104_IO_C_RC_TA_1_IOA(information_object_address=3333, 334 minutes = 5, sec_milli = 6), 335 IEC104_IO_C_RC_TA_1_IOA(information_object_address=4444, 336 minutes = 7, sec_milli = 8)])/ \ 337 IEC104_I_Message_SeqIOA(information_object_address=5555, 338 io=[IEC104_IO_C_RC_TA_1_IOA(minutes = 1, sec_milli = 9), 339 IEC104_IO_C_RC_TA_1_IOA(minutes = 3, sec_milli = 10)])/ \ 340 IEC104_I_Message_SingleIOA(io=IEC104_IO_C_RP_NA_1_IOA(information_object_address=5555)) 341 342frm = Ether(frm.do_build()) 343 344i_msg_lyr = frm.getlayer(IEC104_I_Message_SeqIOA, nb=1) 345assert i_msg_lyr 346assert (i_msg_lyr.information_object_address == 1111) 347 348i_msg_lyr = frm.getlayer(IEC104_I_Message_SeqIOA, nb=2) 349assert i_msg_lyr 350assert (i_msg_lyr.information_object_address == 5555) 351 352i_msg_lyr = frm.getlayer(IEC104_I_Message_SingleIOA, nb=1) 353assert i_msg_lyr 354assert (i_msg_lyr.io[0].information_object_address == 3333) 355 356+ mixed APDU types in one packet 357 358= I/U/S Message sequence (mixed APDUs) 359 360frm = Ether()/IP()/TCP(sport=IEC_104_IANA_PORT, dport=56780)/\ 361 IEC104_I_Message_SeqIOA(information_object_address=1111, 362 rx_seq_num=1234, 363 tx_seq_num=6789, 364 io=[IEC104_IO_C_RC_TA_1_IOA(minutes = 1, sec_milli = 2), 365 IEC104_IO_C_RC_TA_1_IOA(minutes = 3, sec_milli = 4)])/\ 366 IEC104_U_Message()/ \ 367 IEC104_S_Message(rx_seq_num=666) 368 369frm = Ether(frm.do_build()) 370i_msg = frm.getlayer(IEC104_I_Message_SeqIOA) 371assert i_msg 372u_msg = frm.getlayer(IEC104_U_Message) 373assert u_msg 374s_msg = frm.getlayer(IEC104_S_Message) 375assert s_msg 376 377+ information elements & objects 378 379= ASDU allowed in given standard (examples) 380 381layer = IEC104_IO_M_SP_NA_1() 382assert layer.defined_for_iec_101() is True 383assert layer.defined_for_iec_104() is True 384 385layer = IEC104_IO_M_DP_TA_1() 386assert layer.defined_for_iec_101() is True 387assert layer.defined_for_iec_104() is False 388 389layer = IEC104_IO_C_SC_TA_1() 390assert layer.defined_for_iec_101() is False 391assert layer.defined_for_iec_104() is True 392 393 394= BCR - binary counter reading / IEC104_IO_M_IT_NA_1 - integrated totals 395 396# (counter , sequence) test data 397values = [(1, 1), (1111, 17), (23456, 21), (31234, 30), (32767, 31)] 398m_it_na = [] 399for value, sequence in values: 400 m_it_na.append(IEC104_IO_M_IT_NA_1(counter_value=value, sq=sequence)) 401 402frm = Ether()/IP()/TCP()/IEC104_I_Message_SeqIOA(io=m_it_na) 403frm = Ether(frm.do_build()) 404i_msg = frm.getlayer(IEC104_I_Message_SeqIOA) 405assert i_msg 406 407for idx, value in enumerate(values): 408 value, sequence = value 409 assert i_msg.io[idx].counter_value == value 410 assert (i_msg.io[idx].sq == sequence) 411 412= DIQ - double-point information with quality descriptor / IEC104_IO_M_DP_NA_1 - double-point information without time tag 413 414frm = Ether() / IP() / TCP() / IEC104_I_Message_SeqIOA(io=IEC104_IO_M_DP_NA_1(dpi_value=IEC104_IE_DIQ.DPI_FLAG_STATE_UNDEFINED)) 415frm = Ether(frm.do_build()) 416 417i_msg = frm.getlayer(IEC104_I_Message_SeqIOA) 418assert i_msg 419assert i_msg.io[0].dpi_value==IEC104_IE_DIQ.DPI_FLAG_STATE_UNDEFINED 420 421= VTI - value with transient state indication / IEC104_IO_M_ST_NA_1 - step position information 422 423values = [0, 1, 2, 62, 63, -1, -2, -63, -64] 424m_st_na_1 = [] 425for value in values: 426 m_st_na_1.append(IEC104_IO_M_ST_NA_1(value=value)) 427 428frm = Ether() / IP() / TCP() / IEC104_I_Message_SeqIOA(io=m_st_na_1) 429frm = Ether(frm.do_build()) 430 431i_msg = frm.getlayer(IEC104_I_Message_SeqIOA) 432assert (i_msg) 433 434for idx, value in enumerate(values): 435 assert (i_msg.io[idx].value == value) 436 437= IEC104_IO_C_RD_NA_1 - read command (zero byte field) 438 439frm = Ether() / IP() / TCP() / IEC104_I_Message_SeqIOA(information_object_address=0x112233, 440 io=[ 441 IEC104_IO_C_RD_NA_1(), 442 IEC104_IO_C_RD_NA_1() 443 ])/ \ 444 IEC104_I_Message_SeqIOA(information_object_address=0x445566, 445 io=[IEC104_IO_M_DP_NA_1(dpi_value=IEC104_IE_DIQ.DPI_FLAG_STATE_UNDEFINED)])/ \ 446 IEC104_I_Message_SeqIOA(information_object_address=0x445567, 447 io=[IEC104_IO_C_RD_NA_1()]) 448 449frm = Ether(frm.do_build()) 450 451i_msg = frm.getlayer(IEC104_I_Message_SeqIOA) 452assert (i_msg) 453assert (i_msg.information_object_address == 0x112233) 454assert (len(i_msg.io) == 2) 455 456i_msg = frm.getlayer(IEC104_I_Message_SeqIOA, nb=2) 457assert (i_msg) 458assert (i_msg.information_object_address == 0x445566) 459