esp32_bluetooth_classic_sni.../libs/scapy/contrib/iec104.uts
Matheus Eduardo Garbelini 86890704fd initial commit
todo: add documentation & wireshark dissector
2021-08-31 19:51:03 +08:00

458 lines
16 KiB
Text
Executable file

% IEC 60870-5-104 test campaign
#
# execute test:
# > test/run_tests -t scapy/contrib/iec104.uts
#
+ iec104 infrastructure
= load the iec104 layer
load_contrib('scada.iec104')
= class attribute generator
assert(IEC104_IE_QOC.QU_FLAG_RESERVED_COMPATIBLE_4 == 4)
assert(IEC104_IE_QOC.QU_FLAG_RESERVED_COMPATIBLE_8 == 8)
assert(IEC104_IE_QOC.QU_FLAG_RESERVED_PREDEFINED_FUNCTION_9 == 9)
assert(IEC104_IE_QOC.QU_FLAG_RESERVED_PREDEFINED_FUNCTION_15 == 15)
= IEC60870_5_4_NormalizedFixPoint
test_data = [
(b'\x9c\x84', -0.963989, -31588),
(b'\x46\xf6', -0.075989, -2490),
(b'\xc9\xf6', -0.071991, -2359),
(b'\x40\xf5', -0.083984, -2752),
(b'\x89\x01', 0.011993, 393),
(b'\xd2\x0d', 0.107971, 3538),
(b'\xd7\x23', 0.279999, 9175),
(b'\x76\x3e', 0.487976, 15990),
(b'\x08\x6c', 0.843994, 27656),
(b'\xff\x7f', 0.999969, 32767)
]
nfp = IEC60870_5_4_NormalizedFixPoint('foo', 0)
for num_raw, num_fp, num_ss in test_data:
i_val = nfp.getfield(None, num_raw)[1]
assert(i_val == num_ss)
assert(round(nfp.i2h(None, i_val), 6) == round(num_fp, 6))
= Iec104SequenceNumber field
iec104_seq_num = IEC104SequenceNumber('rx_seq', 0)
test_data = {
1: b'\x02\x00',
2: b'\x04\x00',
14 : b'\x1c\x00',
16 : b'\x20\x00',
73 : b'\x92\x00',
127: b'\xfe\x00',
128: b'\x00\x01',
129: b'\x02\x01',
253: b'\xfa\x01',
254: b'\xfc\x01',
255: b'\xfe\x01',
5912: b'\x30\x2e',
31282: b'\x64\xf4',
32767: b'\xfe\xff'
}
for key in test_data:
assert(iec104_seq_num.getfield(None, test_data[key])[1] == key)
assert(iec104_seq_num.addfield(None, b'', key) == test_data[key])
+ raw layer dissection
= IEC104_U_Message
raw_u_msg = b'\x68\x04\x83\x00\x00\x00'
lyr = iec104_decode(b'\x68\x04\x83\x00\x00\x00')
assert(lyr.__class__ == IEC104_U_Message)
= IEC104_S_Message
raw_s_msg = b'\x68\x04\x01\x00\xa6\x17'
lyr = iec104_decode(raw_s_msg)
assert(lyr.__class__ == IEC104_S_Message)
= IEC104_I_Message_SeqIOA
raw_i_msg_seq_ioa = b'\x68\x1f\x2c\x00\x04\x00' # APCI
raw_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
lyr = iec104_decode(raw_i_msg_seq_ioa)
assert(lyr.__class__ == IEC104_I_Message_SeqIOA)
= IEC104_I_Message_SingleIOA
raw_i_msg_single_ioa = b'\x68\x0e\x00\x00\x00\x00\x64\x01\x06\x00\x0a\x00\x00\x00\x00\x14'
lyr = iec104_decode(raw_i_msg_single_ioa)
assert(lyr.__class__ == IEC104_I_Message_SingleIOA)
+ IEC104 S Message
= single IEC104 S Message
s_msg = b'\x68\x04\x01\x00\xa6\x17'
s_msg = IEC104_S_Message(s_msg)
assert(s_msg.rx_seq_num == 3027)
raw_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'
frm = Ether(raw_s_message)
s_msg = frm.getlayer(IEC104_S_Message)
assert(s_msg)
assert(s_msg.rx_seq_num == 7521)
frm = Ether(frm.do_build())
s_msg = frm.getlayer(IEC104_S_Message)
assert(s_msg)
assert(s_msg.rx_seq_num == 7521)
= double IEC104 S Message (test layer binding)
raw_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'
frm = Ether(raw_double_s_message)
s_msg = frm.getlayer(IEC104_S_Message)
assert(s_msg)
assert(s_msg.rx_seq_num == 7521)
s_msg = frm.getlayer(IEC104_S_Message, nb=2)
assert(s_msg)
assert(s_msg.rx_seq_num == 7649)
frm = Ether(frm.do_build())
s_msg = frm.getlayer(IEC104_S_Message)
assert(s_msg)
assert(s_msg.rx_seq_num == 7521)
s_msg = frm.getlayer(IEC104_S_Message, nb=2)
assert(s_msg)
assert(s_msg.rx_seq_num == 7649)
+ IEC104 U Message
= single IEC104 U Message
frm = Ether()/IP()/TCP()/IEC104_U_Message(startdt_act = 1, stopdt_con = 1, testfr_act=1)
frm = Ether(frm.do_build())
u_msg = frm.getlayer(IEC104_U_Message)
assert(u_msg)
assert(u_msg.startdt_act == 1)
assert(u_msg.startdt_con == 0)
assert(u_msg.stopdt_con == 1)
assert(u_msg.stopdt_act == 0)
assert(u_msg.testfr_act == 1)
assert(u_msg.testfr_con == 0)
u_msg_tst_act = b'\x68\x04\x43\x00\x00\x00'
u_msg = IEC104_U_Message(u_msg_tst_act)
assert(u_msg.testfr_act == 1)
u_msg_tst_con = b'\x68\x04\x83\x00\x00\x00'
u_msg = IEC104_U_Message(u_msg_tst_con)
assert(u_msg.testfr_con == 1)
u_msg_startdt_act = b'\x68\x04\x07\x00\x00\x00'
u_msg = IEC104_U_Message(u_msg_startdt_act)
assert(u_msg.startdt_act == 1)
u_msg_startdt_con = b'\x68\x04\x0b\x00\x00\x00'
u_msg = IEC104_U_Message(u_msg_startdt_con)
assert(u_msg.startdt_con == 1)
u_msg_stopdt_act = b'\x68\x04\x13\x00\x00\x00'
u_msg = IEC104_U_Message(u_msg_stopdt_act)
assert(u_msg.stopdt_act == 1)
u_msg_stopdt_con = b'\x68\x04\x23\x00\x00\x00'
u_msg = IEC104_U_Message(u_msg_stopdt_con)
assert(u_msg.stopdt_con == 1)
= double IEC104 U Message
frm = Ether()/IP()/TCP()/\
IEC104_U_Message(startdt_act = 1, stopdt_con = 1, testfr_act=1)/\
IEC104_U_Message(startdt_con = 1, stopdt_act = 1, testfr_con=1)
frm = Ether(frm.do_build())
u_msg = frm.getlayer(IEC104_U_Message)
assert(u_msg)
assert(u_msg.startdt_act == 1)
assert(u_msg.stopdt_con == 1)
assert(u_msg.testfr_act == 1)
u_msg = frm.getlayer(IEC104_U_Message, nb=2)
assert(u_msg)
assert(u_msg.startdt_con == 1)
assert(u_msg.stopdt_act == 1)
assert(u_msg.testfr_con == 1)
+ IEC104 I Message
= Sequence IOA, single IO - information object types dissection
for io_id in IEC104_IO_CLASSES:
io_class = IEC104_IO_CLASSES[io_id]
frm = Ether()/IP()/TCP(sport=IEC_104_IANA_PORT, dport=56780)/IEC104_I_Message_SeqIOA(io=io_class())
frm = Ether(frm.do_build())
io_layer = frm.getlayer(io_class)
assert(io_layer)
= Single IOA, single IO - information object types dissection
for io_id in IEC104_IO_WITH_IOA_CLASSES:
io_class = IEC104_IO_WITH_IOA_CLASSES[io_id]
frm = Ether()/IP()/TCP(sport=IEC_104_IANA_PORT, dport=56780)/IEC104_I_Message_SingleIOA(io=io_class())
frm = Ether(frm.do_build())
io_layer = frm.getlayer(io_class)
assert(io_layer)
= Sequence IOA, multiple IOs - information object types dissection
frm = 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)])
frm = Ether(frm.do_build())
i_msg_lyr = frm.getlayer(IEC104_I_Message_SeqIOA)
assert(i_msg_lyr)
assert(i_msg_lyr.information_object_address == 1234)
m_sp_ta_1_lyr = i_msg_lyr.io[0]
assert (m_sp_ta_1_lyr.minutes == 1)
assert (m_sp_ta_1_lyr.sec_milli == 2)
m_sp_ta_1_lyr = i_msg_lyr.io[1]
assert (m_sp_ta_1_lyr.minutes == 3)
assert (m_sp_ta_1_lyr.sec_milli == 4)
= Single IOA, multiple IOs - information object types dissection
frm = Ether()/IP()/TCP(sport=IEC_104_IANA_PORT, dport=56780)/\
IEC104_I_Message_SingleIOA(io=[IEC104_IO_C_RC_TA_1_IOA(information_object_address=1111, minutes = 1, sec_milli = 2),
IEC104_IO_C_RC_TA_1_IOA(information_object_address=2222,minutes = 3, sec_milli = 4)])
frm = Ether(frm.do_build())
i_msg_lyr = frm.getlayer(IEC104_I_Message_SingleIOA)
assert(i_msg_lyr)
m_sp_ta_1_lyr = i_msg_lyr.io[0]
assert (m_sp_ta_1_lyr.information_object_address==1111)
assert (m_sp_ta_1_lyr.minutes == 1)
assert (m_sp_ta_1_lyr.sec_milli == 2)
m_sp_ta_1_lyr = i_msg_lyr.io[1]
assert (m_sp_ta_1_lyr.information_object_address==2222)
assert (m_sp_ta_1_lyr.minutes == 3)
assert (m_sp_ta_1_lyr.sec_milli == 4)
= Sequence IOA, multiple APDUs
frm = 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)])/ \
IEC104_I_Message_SeqIOA(information_object_address=5432,
io=[IEC104_IO_C_RC_TA_1(minutes = 5, sec_milli = 6),
IEC104_IO_C_RC_TA_1(minutes = 7, sec_milli = 8)])
frm = Ether(frm.do_build())
i_msg_lyr = frm.getlayer(IEC104_I_Message_SeqIOA, nb=1)
assert(i_msg_lyr)
assert (i_msg_lyr.information_object_address == 1234)
assert(len(i_msg_lyr.io) == 2)
assert(i_msg_lyr.io[0].minutes == 1)
assert(i_msg_lyr.io[0].sec_milli == 2)
assert(i_msg_lyr.io[1].minutes == 3)
assert(i_msg_lyr.io[1].sec_milli == 4)
i_msg_lyr = frm.getlayer(IEC104_I_Message_SeqIOA, nb=2)
assert(i_msg_lyr)
assert (i_msg_lyr.information_object_address == 5432)
assert(len(i_msg_lyr.io) == 2)
assert(i_msg_lyr.io[0].minutes == 5)
assert(i_msg_lyr.io[0].sec_milli == 6)
assert(i_msg_lyr.io[1].minutes == 7)
assert(i_msg_lyr.io[1].sec_milli == 8)
= Single IOA, multiple APDUs
frm = Ether()/IP()/TCP(sport=IEC_104_IANA_PORT, dport=56780)/\
IEC104_I_Message_SingleIOA(io=[IEC104_IO_C_RC_TA_1_IOA(information_object_address=1111,
minutes = 1, sec_milli = 2),
IEC104_IO_C_RC_TA_1_IOA(information_object_address=2222,
minutes = 3, sec_milli = 4)])/ \
IEC104_I_Message_SingleIOA(io=[IEC104_IO_C_RC_TA_1_IOA(information_object_address=3333,
minutes = 5, sec_milli = 6),
IEC104_IO_C_RC_TA_1_IOA(information_object_address=4444,
minutes = 7, sec_milli = 8)])
frm = Ether(frm.do_build())
i_msg_lyr = frm.getlayer(IEC104_I_Message_SingleIOA, nb=1)
assert(i_msg_lyr)
assert(len(i_msg_lyr.io) == 2)
assert (i_msg_lyr.io[0].information_object_address == 1111)
assert(i_msg_lyr.io[0].minutes == 1)
assert(i_msg_lyr.io[0].sec_milli == 2)
assert (i_msg_lyr.io[1].information_object_address == 2222)
assert(i_msg_lyr.io[1].minutes == 3)
assert(i_msg_lyr.io[1].sec_milli == 4)
i_msg_lyr = frm.getlayer(IEC104_I_Message_SingleIOA, nb=2)
assert(i_msg_lyr)
assert(len(i_msg_lyr.io) == 2)
assert (i_msg_lyr.io[0].information_object_address == 3333)
assert(i_msg_lyr.io[0].minutes == 5)
assert(i_msg_lyr.io[0].sec_milli == 6)
assert (i_msg_lyr.io[1].information_object_address == 4444)
assert(i_msg_lyr.io[1].minutes == 7)
assert(i_msg_lyr.io[1].sec_milli == 8)
= Mixed Single and Sequence IOA, multiple APDU
frm = Ether()/IP()/TCP(sport=IEC_104_IANA_PORT, dport=56780)/\
IEC104_I_Message_SeqIOA(information_object_address=1111,
io=[IEC104_IO_C_RC_TA_1_IOA(minutes = 1, sec_milli = 2),
IEC104_IO_C_RC_TA_1_IOA(minutes = 3, sec_milli = 4)])/ \
IEC104_I_Message_SingleIOA(io=[IEC104_IO_C_RC_TA_1_IOA(information_object_address=3333,
minutes = 5, sec_milli = 6),
IEC104_IO_C_RC_TA_1_IOA(information_object_address=4444,
minutes = 7, sec_milli = 8)])/ \
IEC104_I_Message_SeqIOA(information_object_address=5555,
io=[IEC104_IO_C_RC_TA_1_IOA(minutes = 1, sec_milli = 9),
IEC104_IO_C_RC_TA_1_IOA(minutes = 3, sec_milli = 10)])/ \
IEC104_I_Message_SingleIOA(io=IEC104_IO_C_RP_NA_1_IOA(information_object_address=5555))
frm = Ether(frm.do_build())
i_msg_lyr = frm.getlayer(IEC104_I_Message_SeqIOA, nb=1)
assert(i_msg_lyr)
assert (i_msg_lyr.information_object_address == 1111)
i_msg_lyr = frm.getlayer(IEC104_I_Message_SeqIOA, nb=2)
assert(i_msg_lyr)
assert (i_msg_lyr.information_object_address == 5555)
i_msg_lyr = frm.getlayer(IEC104_I_Message_SingleIOA, nb=1)
assert(i_msg_lyr)
assert (i_msg_lyr.io[0].information_object_address == 3333)
+ mixed APDU types in one packet
= I/U/S Message sequence (mixed APDUs)
frm = Ether()/IP()/TCP(sport=IEC_104_IANA_PORT, dport=56780)/\
IEC104_I_Message_SeqIOA(information_object_address=1111,
rx_seq_num=1234,
tx_seq_num=6789,
io=[IEC104_IO_C_RC_TA_1_IOA(minutes = 1, sec_milli = 2),
IEC104_IO_C_RC_TA_1_IOA(minutes = 3, sec_milli = 4)])/\
IEC104_U_Message()/ \
IEC104_S_Message(rx_seq_num=666)
frm = Ether(frm.do_build())
i_msg = frm.getlayer(IEC104_I_Message_SeqIOA)
assert(i_msg)
u_msg = frm.getlayer(IEC104_U_Message)
assert(u_msg)
s_msg = frm.getlayer(IEC104_S_Message)
assert(s_msg)
+ information elements & objects
= ASDU allowed in given standard (examples)
layer = IEC104_IO_M_SP_NA_1()
assert(layer.defined_for_iec_101() is True)
assert(layer.defined_for_iec_104() is True)
layer = IEC104_IO_M_DP_TA_1()
assert(layer.defined_for_iec_101() is True)
assert(layer.defined_for_iec_104() is False)
layer = IEC104_IO_C_SC_TA_1()
assert(layer.defined_for_iec_101() is False)
assert(layer.defined_for_iec_104() is True)
= BCR - binary counter reading / IEC104_IO_M_IT_NA_1 - integrated totals
# (counter , sequence) test datas
values = [(1, 1), (1111, 17), (23456, 21), (31234, 30), (32767, 31)]
m_it_na = []
for value, sequence in values:
m_it_na.append(IEC104_IO_M_IT_NA_1(counter_value=value, sq=sequence))
frm = Ether()/IP()/TCP()/IEC104_I_Message_SeqIOA(io=m_it_na)
frm = Ether(frm.do_build())
i_msg = frm.getlayer(IEC104_I_Message_SeqIOA)
assert(i_msg)
for idx, value in enumerate(values):
value, sequence = value
assert(i_msg.io[idx].counter_value == value)
assert (i_msg.io[idx].sq == sequence)
= DIQ - double-point information with quality descriptor / IEC104_IO_M_DP_NA_1 - double-point information without time tag
frm = Ether() / IP() / TCP() / IEC104_I_Message_SeqIOA(io=IEC104_IO_M_DP_NA_1(dpi_value=IEC104_IE_DIQ.DPI_FLAG_STATE_UNDEFINED))
frm = Ether(frm.do_build())
i_msg = frm.getlayer(IEC104_I_Message_SeqIOA)
assert(i_msg)
assert(i_msg.io[0].dpi_value==IEC104_IE_DIQ.DPI_FLAG_STATE_UNDEFINED)
= VTI - value with transient state indication / IEC104_IO_M_ST_NA_1 - step position information
values = [0, 1, 2, 62, 63, -1, -2, -63, -64]
m_st_na_1 = []
for value in values:
m_st_na_1.append(IEC104_IO_M_ST_NA_1(value=value))
frm = Ether() / IP() / TCP() / IEC104_I_Message_SeqIOA(io=m_st_na_1)
frm = Ether(frm.do_build())
i_msg = frm.getlayer(IEC104_I_Message_SeqIOA)
assert (i_msg)
for idx, value in enumerate(values):
assert (i_msg.io[idx].value == value)
= IEC104_IO_C_RD_NA_1 - read command (zero byte field)
frm = Ether() / IP() / TCP() / IEC104_I_Message_SeqIOA(information_object_address=0x112233,
io=[
IEC104_IO_C_RD_NA_1(),
IEC104_IO_C_RD_NA_1()
])/ \
IEC104_I_Message_SeqIOA(information_object_address=0x445566,
io=[IEC104_IO_M_DP_NA_1(dpi_value=IEC104_IE_DIQ.DPI_FLAG_STATE_UNDEFINED)])/ \
IEC104_I_Message_SeqIOA(information_object_address=0x445567,
io=[IEC104_IO_C_RD_NA_1()])
frm = Ether(frm.do_build())
i_msg = frm.getlayer(IEC104_I_Message_SeqIOA)
assert (i_msg)
assert (i_msg.information_object_address == 0x112233)
assert (len(i_msg.io) == 2)
i_msg = frm.getlayer(IEC104_I_Message_SeqIOA, nb=2)
assert (i_msg)
assert (i_msg.information_object_address == 0x445566)