ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

IEC104规约报文解析:APCI/ASDU结构、Wireshark抓包与故障排查

IEC104规约报文解析:APCI/ASDU结构、Wireshark抓包与故障排查 简介在电力远动通信系统中规约报文是设备间数据传输的载体工程师常需通过抓包定位异常。IEC104规约作为运行于TCP之上的应用层协议其报文由APCI和ASDU构成APCI负责会话控制与序号管理ASDU承载遥测、遥信等业务数据。掌握APDU边界识别、I帧序号计算、类型标识与传送原因的含义是解析报文的基础。借助Wireshark等工具可快速完成U帧握手确认、总召唤流程跟踪及数据完整性校验从而在远动通道调试中高效排查握手失败、序号跳变等典型故障。本文面向远动通信与电力自动化运维场景结合抓包实践讲解IEC104报文结构、常用字段及故障定位思路适合需要开展点表映射、规约调试与网络分析的工程师参考。1. IEC104规约报文分析看得懂十六进制对不上业务才是真门槛凌晨两点调度电话把值班工程师叫醒主站侧看着TCP连接是通的变电站侧就是不上数据。抓包出来几十条重复的STARTDT激活帧通道参数、IP地址、端口查过一遍最后发现是站端装置应用层没起来。这是IEC104规约报文分析里非常典型的一个坎104规约跑在TCP上控制信息在APCI里业务数据在ASDU里和串口时代的101规约完全不同。看懂IEC104报文关键不是逐字节翻译十六进制而是把U帧握手、I帧序号和ASDU里的类型标识、传送原因、信息对象地址对应到远动点表上。下面按这条线拆开讲覆盖APCI与ASDU结构、常用类型标识、用Wireshark从抓包到解析的流程以及现场常用的排障技巧适合刚接手远动通道调试、准备写点表映射脚本的工程师。2. IEC104规约报文先分层端口2404、APCI控制域和帧类型2.1 一条104报文由APCI和ASDU组成IEC104规约在IEC 60870-5-104标准里定义应用层直接跑在TCP之上默认端口2404。一个TCP连接可以双向传输报文报文的基本单位叫APDU应用规约数据单元结构分两段前6字节是APCI应用规约控制信息后面是ASDU应用服务数据单元。APCI包含启动字符0x68、APDU长度、4字节控制域ASDU承载遥测、遥信、遥控等具体业务。这里有个容易误解的地方APDU和TCP报文段不是一回事。APDU的边界由第2个字节的长度字段确定比如0x68 0x10表示后面还有16字节整条APDU共18字节。不管TCP层怎么分片、粘包解析器都靠这个长度字段把APDU一条条切出来而不是靠回车换行或固定超时。一条APDU最长253字节其中ASDU最多249字节比串口101规约的单帧容量大很多这也是104能批量上送几十个点的主要原因。平时说的“104报文分析”绝大多数场景是在抓包里把APDU边界划对再看控制域和ASDU。APDU长度对不上时Wireshark会显示“malformed packet”先查抓包是不是超过MTU后被拆开或者TCP流重组没打开。2.2 四字节控制域I帧、S帧、U帧的区别与报文值控制域的4字节是整个会话状态机的核心。前2比特标识帧类型I帧是信息帧低2位为00S帧是监视帧低2位为01U帧是控制帧低2位为11。I帧带双向序号S帧只带接收序号U帧不带序号。帧类型判定位携带序号典型作用常见报文示例I帧bit00bit10N(S)和N(R)携带ASDU业务数据68 10 08 00 08 00 ...S帧bit01bit10仅N(R)纯确认不携带ASDU68 04 01 00 02 00U帧bit01bit11无启动/停止数据传输、测试链路68 04 07 00 00 00I帧的发送序号N(S)和接收序号N(R)各占15位从0递增到32767后回绕。序号从字节里取出来时要注意位偏移N(S)是第1字节bit1到bit7拼接第2字节共15位N(R)是第3字节bit1到bit7拼接第4字节共15位。换算公式为N(S) ((b0 1) 0x7F) | (b1 7) N(R) ((b2 1) 0x7F) | (b3 7)其中b0到b3是控制域4字节。这个位运算很多解析脚本里都会出现写错会导致看到的序号跳变进而误判丢包。U帧没有序号它的4字节控制域只有第1字节有意义第2到第4字节为0。现场最常遇到的U帧报文是这几个STARTDT act主站请求数据传输为68 04 07 00 00 00STARTDT con从站确认为68 04 0B 00 00 00STOPDT act为68 04 13 00 00 00STOPDT con为68 04 23 00 00 00TESTFR act为68 04 43 00 00 00TESTFR con为68 04 83 00 00 00。记不住位定义没关系记这几个十六进制值就能应付绝大多数抓包场景。TCP连接建立后主站必须先发STARTDT act从站回STARTDT con此时才允许传I帧。如果抓包里只有TCP三次握手和不断重复的STARTDT act基本可以断定从站应用层没有正常启动或网关配置错误而不是链路问题。2.3 与101规约、61850通讯规约的边界很多刚接触的人会把104规约和101规约混在一起。101规约走串口或低速网络帧格式是FT1.2有起始字符、控制域、地址域、用户数据、校验和一帧最多255字节104规约是101规约在TCP/IP网络上的改造应用层的ASDU沿用了101的定义但链路层换成APCI加TCP。也就是说ASDU字段两边基本通用APCI和帧格式完全不通用。站内通信则更多遇到61850通讯规约。61850用于变电站站控层和间隔层之间的MMS、GOOSE、SV报文解决的是站内设备互操作104规约解决的是变电站与调度主站之间的远动信息传输两者在链路层面没有交集但调试时经常同时出现同一个测控装置既上送104到主站又在站内跑61850点表对不上时要从两端分别找原因。另外还要注意698规约和DL/T 645-1997是用电信息采集方向的内容面向电能表计费数据报文格式跟远动的104完全不同别拿104的解析思路往那上面套。3. ASDU字段拆解类型标识、传送原因和公共地址决定怎么解析3.1 ASDU头部字段逐个看ASDU从类型标识开始一个完整的ASDU由固定头和信息对象组成。固定头依次是类型标识1字节、可变结构限定词VSQ1字节、传送原因1字节、公共地址2字节。信息对象部分根据类型标识的不同而变化可能包含多个信息对象每个对象有信息对象地址IOA和对应的数据体。类型标识告诉解析器后面跟的是什么数据是单点遥信、双点遥信、短浮点遥测、还是遥控命令。这个字节不认对后面全是错的。可变结构限定词的bit7是连续标志低7位是信息对象个数如果连续标志为1表示这组信息对象的地址是连续的报文里只写第一个地址后面依次加1如果为0每个对象都带完整地址报文会明显变长。传送原因占1字节bit6是测试标志S/E位低6位是原因值。现场看到0x43、0x47这类值先转成二进制bit6为1表示这是测试链路时发的报文不是真实数据。公共地址占2字节小端存储用于区分不同厂站一个TCP连接上一般固定为一个值跨厂站共用通道时尤其要注意。3.2 现场最常用的类型标识与传送原因IEC104规约的类型标识沿用了101规约的定义真正天天用的就几个。以下是调试远动通道时最常遇到的类型类型标识十六进制名称信息对象内容10x01单点遥信 M_SP_NA-11字节bit0为分合状态30x03双点遥信 M_DP_NA-11字节bit0/bit1组合90x09带时标的单点遥信 M_SP_TB-1状态1字节加7字节时标130x0D短浮点遥测 M_ME_NC-14字节IEEE754浮点加1字节品质450x2D单点遥控 C_SC_NA-11字节命令含选择执行标志460x2E双点遥控 C_DC_NA-11字节命令1000x64总召唤 C_IC_NA-1信息对象地址一般为01030x67时钟同步 C_CS_NA-17字节CP56Time2a时标传送原因最常用的是这几个1表示周期上送2表示背景扫描3表示突发上送5表示请求6表示激活7表示激活确认8表示停止激活10表示激活终止20表示响应站召唤。排查“丢数据”问题时先看原因周期上送的数据丢了可能是扫描周期配置问题突发上送的丢了则要查事件缓存和确认机制。3.3 手工拆一条短浮点遥测报文拿一条实际报文来看完整拆解过程。假设抓包得到如下帧68 11 08 00 08 00 0D 01 03 01 00 00 00 00 00 00 C8 42 00第1字节0x68是启动字符第2字节0x11表示APDU长度17后面跟着4字节控制域和13字节ASDU。控制域08 00 08 00是I帧N(S)4N(R)4说明双方序号正常连续。ASDU部分逐字节看0x0D类型标识13短浮点遥测0x01VSQbit7为01个信息对象0x03传送原因突发上送0x01 0x00公共地址小端为10x00 0x00 0x00信息对象地址为00x00 0x00 0xC8 0x42IEEE754短浮点低字节在前实际值是0x42C800000x00品质描述字节正常值。0x42C80000按IEEE754转换得到100.0。这条报文表达的是1号厂站第0点遥测值100.0突变上送数据有效。如果点表里第0点是有功功率单位MW那这条报文就是“有功100MW变位上送”。3.4 信息对象地址与CP56Time2a时标的坑信息对象地址在104规约里是3字节小端范围最大到0xFFFFFF厂站点表通常按这个值映射。调试时最常见的坑是主站点表和厂站点表对不上主站看IOA256厂站侧却从1开始编号。抓包只能看到IOA原始值对点必须拿厂站点表来核对不能按报文里的数字猜含义。带时标的信息对象时标固定7字节格式是CP56Time2a前2字节是毫秒低字节在前后面依次是分、时、日、月、年各1字节。比如某条带时标遥信的时标字段为00 00 05 0D 19 02 0B表示毫秒0、分钟5、小时13、日25、月2、年11即2011年2月25日13时5分0秒。注意年份是偏移表示0对应2000年所以0x0B要按2011年来读。写解析脚本时年、月、日这几个字段都要加偏移和校验否则排序会乱。4. 用Wireshark分析104报文从U帧握手到总召唤数据上送4.1 抓包过滤与解码视图Wireshark从2.x版本起内置了IEC 60870-5-104解码器不需要额外装插件。抓包时建议在采集点用主机镜像端口或TAP避免在应用层设备上抓导致报文已经被改写。打开抓包文件后先过滤tshark -r capture.pcapng -Y tcp.port 2404 -c 20这条命令用tshark从抓包文件里筛出前20条与2404端口相关的报文。参数-r指定输入文件-Y是显示过滤器-c限制输出条数。在Wireshark图形界面里显示过滤器输入tcp.port 2404可以排除其他端口干扰如果想只看已被识别为104的帧可以输入iec60870_5_104但要注意只有解码器成功识别APDU时才会带上这个协议名TCP握手包不会出现。4.2 一次完整总召唤的报文序列新站接入调试时第一个要看的就是总召唤流程。正常顺序如下TCP三次握手建立连接主站发U帧STARTDT act从站回STARTDT con主站发I帧总召唤传送原因6激活从站回总召唤确认传送原因7激活确认从站批量上送全数据包括遥信、遥测全部上送完从站发总召唤结束传送原因10激活终止。对应抓包里的报文轮廓是方向报文含义主站 → 从站68 04 07 00 00 00STARTDT act从站 → 主站68 04 0B 00 00 00STARTDT con主站 → 从站68 0C 00 00 00 00 64 01 06 01 00 00 00 00总召唤原因6从站 → 主站68 0C 00 00 02 00 64 01 07 01 00 00 00 00总召唤确认原因7从站 → 主站68 11 02 00 02 00 0D 01 03 01 00 00 00 00 00 00 C8 42 00遥测上送值100.0从站 → 主站68 0C 04 00 02 00 64 01 0A 01 00 00 00 00总召唤结束原因10注意控制域里序号的连续性主站的总召唤N(S)0从站的确认N(S)0且N(R)1表示已收到主站第0帧后续数据帧N(S)逐步加1。如果中间某帧序号跳了说明有I帧丢失重传机制会触发但总召唤流程会变慢。4.3 在Wireshark里核对一条遥测I帧选中一条I帧在Packet Details面板展开“IEC 60870-5-104 APDU”能看到APCI和ASDU两个子树。APCI里显示帧类型、发送序号、接收序号ASDU里显示类型标识、可变结构限定词、传送原因、公共地址、信息对象地址和数值。以4.2中那条68 11开头的报文为例树形展开后应显示Type Identification13VSQ1个不连续对象Cause3Common Address1IOA0State100.0。这里建议把列显示调一下右键控制域里的“Send Sequence Number”选择“Apply as Column”把所有I帧序号按列排列方便快速扫一遍序号是否连续。总召唤后的数据量大时用这个方式排查漏帧比逐帧点开高效得多。4.4 TCP分片、乱序对104解码的影响104报文最长253字节远小于TCP的MSS通常1460字节正常不会因为长度产生分片。但抓包时如果开了巨型帧或者中间有TCP透明代理改了报文反而会出现一条APDU被拆到多个TCP段的情况。Wireshark默认会重组TCP流但如果抓包不完整重组失败就可能把后续报文全部标成malformed。遇到乱序或重传时不要直接在104解码视图里下结论。先切换到Follow TCP Stream看原始数据再对照长度字段手工切分APDU。重传的TCP段会带“TCP Retransmission”提示对应的104报文是重复的I帧这时要检查是网络丢包还是对端确认超时而不是数据本身出错。5. 104故障定位实践握不上、序号跳变和一段解析脚本5.1 握手失败先分清TCP和应用层主站收不到数据时第一抓包看TCP握手是否完成。如果SYN都发不出去问题在路由、防火墙或端口策略典型原因是2404端口未放通。TCP握手正常但看不到STARTDT act主站侧应用可能没启动。看到STARTDT act反复发、始终没有STARTDT con问题在从站侧应用层装置未运行、规约版本不匹配、或者从站收到act后认为配置未就绪不回应。此时再查从站的运行日志而不是继续抓主站。5.2 序号连续性检查序号跳变是丢包最直接的信号。用Wireshark把I帧N(S)排成列后逐行检查差值是否等于1。如果出现跳号接着看跳号前是否有TCP重传或乱序标记如果没有说明报文在中间设备上被丢弃需要检查交换机端口丢包统计和防火墙会话表老化时间。还有一种情况是序号回绕15位计数器到32767后归零这是正常现象不要当跳变处理。5.3 Python小脚本自动核对I帧序号和字段现场报文量大时手工核对不现实。把抓包导出的十六进制逐条喂给下面这个脚本它能自动输出I帧序号和关键字段import sys def parse_apdu(line: str): data bytes.fromhex(line.strip()) if len(data) 6 or data[0] ! 0x68: return None apdu_len data[1] body data[2:2 apdu_len] if len(body) 6: return None ctrl body[:4] # 低2位为00表示I帧 if (ctrl[0] 0x03) ! 0: return {frame: U或S帧} ns ((ctrl[0] 1) 0x7F) | (ctrl[1] 7) nr ((ctrl[2] 1) 0x7F) | (ctrl[3] 7) return { ns: ns, nr: nr, type_id: body[4], is_continuous: bool(body[5] 7), count: body[5] 0x7F, cause: body[6] 0x3F, common_addr: int.from_bytes(body[7:9], little), } for line in sys.stdin: line line.strip() if not line: continue p parse_apdu(line) if p and ns in p: print(fns{p[ns]:5d} nr{p[nr]:5d} ftype0x{p[type_id]:02x} cause{p[cause]:3d} faddr{p[common_addr]} count{p[count]})脚本先校验启动字符和长度字段然后只处理I帧U帧和S帧跳过。ns和nr按APCI的15位序号格式从字节里拼出来type_id是类型标识cause是传送原因。count是可变结构限定词里的对象个数。把抓包工具导出的十六进制文本重定向到脚本输入输出里如果ns不再连续递增就是丢包位置如果type_id里混进预想之外的类型再去抓包里定位具体那条帧。把跳变帧前后各20条报文再导出来比对发送间隔就能定位是网络丢包还是对端重传。本文还有配套的精品资源点击获取
返回列表