• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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