1. GOOSE报文为什么值得专门抓包分析
做继电保护或者变电站自动化调试的人,基本都绕不开IEC 61850这套标准。传统变电站里,大量开关量、模拟量和跳合闸命令是靠二次电缆硬接线来实现的,而现在越来越多的间隔层和过程层设备直接把数据放到以太网上,GOOSE就是其中最常用的一种通信机制。所谓GOOSE,全称是Generic Object Oriented Substation Event,翻译过来就是“面向通用对象的变电站事件”,它本质上就是一组二层多播以太网帧,携带ASN.1编码的应用数据,在局域网里以“心跳报文”的方式反复发送。
为什么要专门去抓GOOSE报文来分析?因为它在物理意义上“看不见、摸不着”。以前调试一条跳闸回路,用万用表量电压、摇绝缘就能判断问题,现在不行了,一个开关跳不开,可能出在光纤链路、交换机的VLAN配置、装置内部的GOOSE发布订阅配置、数据集映射、ASN.1编码错位等任何一个环节。你不抓包,就只能看到保护屏上的“接收异常”灯在闪,根本不知道是发送侧没发出来,还是接收侧没订阅对,又或者是报文在网络中途被交换机的过滤规则扔掉了。
抓包能解决的实际问题非常多。比如保护装置在报“GOOSE断链”,实际情况可能是发送端还在一秒一条地发心跳,只不过APPID被配置成了不同值,接收端匹配不上;又比如一套备自投逻辑在多个间隔之间做联锁闭锁,闭锁命令一直不发或发错值,抓包能直接看到数据集里每个成员的具体数值变化。再比如倒闸操作时开关拒动,可能是GOOSE报文里的Test测试位没有被清零,接收装置按策略直接忽略了测试报文,这种问题光看日志是看不出来的,非得看报文链路不可。
这篇文章适合谁看呢?我觉得有三类人最适合:第一类是在现场做继保调试和自动化调试的工程师,需要快速定位GOOSE通信故障;第二类是做IEC 61850一致性测试或者实验室仿真验证的研发和测试人员,需要深入理解报文结构;第三类是想系统学习Wireshark抓包技巧的学生和入门者,GOOSE报文结构规则,比起TCP/IP那一大堆状态机要清晰得多,非常适合作为ASN.1解码的入门练习材料。我下面写的所有内容都是围绕实际抓包和分析展开的,没有太多理论空转,每个步骤你都可以在自己电脑上复现。
2. 搭建一个能正确抓到GOOSE的抓包环境
2.1 网络拓扑应该怎么接
抓GOOSE这种二层报文,第一个问题不是用什么软件,而是网线插在哪里。GOOSE一般是过程层网络里的多播报文,目的MAC地址通常是01:0C:CD这一类地址段,它不会穿过三层路由,所以你不能随便找一台电脑往业务网上一挂就指望抓到它。正确的接法有三种。
第一种是交换机端口镜像,这也是现场最常用的方式。我把抓包电脑接到交换机的一个普通端口上,然后在交换机上配置SPAN/RSPAN镜像,把连接保护装置、智能终端的端口流量复制一份到抓包口。好处是抓包不影响原链路,对运行中的设备几乎零干扰。需要注意的是,镜像口的数据量可能很大,如果过程层网口跑满了,抓包电脑的网卡和磁盘可能顶不住,建议在抓包软件里直接加捕获过滤器,先从源头减少数据量。
第二种是用物理分光器或者网络TAP,这个一般在实验室或者对链路安全性要求特别高的场合用。TAP接在光纤链路上,一路分成两路,一路走原通信,一路走抓包设备,物理上更加透明,不会因为交换机CPU繁忙而丢镜像数据。缺点是设备贵,而且需要把链路先断开才能串进去,不适合在线操作。
第三种就是你直接拿一台笔记本电脑,插到过程层网络上的某个备用口。这个方法最省事,但如果这个网口上本身没有GOOSE流量经过,你抓半天也是空的。我试过在现场拿笔记本挂在保护装置所在的交换机组网里,结果那个口被划到了不同的VLAN,折腾了几十分钟才排查明白。所以用这个方法时,先确认一下管理VLAN划分,再看一下交换机的多播策略,别想当然。
2.2 Wireshark版本和抓包驱动要注意什么
Wireshark对IEC 61850的支持其实已经很成熟了,主流3.x版本都能直接识别GOOSE,并自动解码。不过这里有一个特别容易被忽视的点:Wireshark只是解析工具,真正跟网卡打交道的是底层的抓包驱动。
在Windows系统上,你必须先装好Npcap或WinPcap,否则Wireshark根本找不到网卡接口。Npcap和WinPcap二选一的话,我建议直接用最新版Npcap,它对802.1Q VLAN标签和高速抓包的支持更好。在Linux系统上,抓包依赖libpcap,Wireshark的发行版一般会自动带上,所以问题不大。
版本选择上,我个人的经验是不要太老,至少用3.4以上。老的版本在解析某些私有扩展字段和GOOSE数据集里的浮点数时会有问题,字段名称也可能跟新版不一样,你照着网上老教程写显示过滤器,可能一个包都过滤不出来。去官网下载稳定版就行,没必要追最新开发版,稳定版就足够应付现场调试。
另外,如果你的GOOSE报文中带有VLAN标签,并且某些交换机做了802.1p优先级分类,Wireshark解析时会把以太网类型显示成0x88B8,把VLAN标签正常展开。这些都是自动完成的,但前提是网卡驱动要支持VLAN剥离的设置。Npcap在安装时有个选项是“Support 802.1Q VLAN tagging”,默认是开着的,你要是之前精简安装过,建议重新装一下,否则抓到的帧可能少了VLAN信息,排障时少了一条关键线索。
2.3 抓包过滤器的配置方法
抓包过滤器是在“捕获”阶段生效的,它的作用是让不是GOOSE的流量根本不进内存,这样既节省硬盘空间,也能保证现场长时间抓包不丢帧。Wireshark里在Capture Options窗口的“Capture Filter”栏填上:```bash ether proto 0x88b8
这里0x88B8就是GOOSE的以太网类型,只抓这一个类型的帧就够了。如果GOOSE报文里都带了VLAN标签,你还可以在显示过滤器里加上VLAN条件,但捕获过滤器里写VLAN条件比较麻烦,现场我一般就只按EtherType过滤,数据量也很小。 显示过滤器是抓完之后再过滤用的,也就是说哪怕你全量捕获了,也能在后面筛选。常用的是这几条: - `goose`:只看所有GOOSE报文。 - `goose.appid == 0x1000`:只看APPID等于0x1000的GOOSE。 - `goose.stNum`:只看状态号变化的报文。 - `goose.test == 1`:过滤测试位为真的GOOSE报文,排查是否误发了测试报文。 写显示过滤器的时候,注意字段名在不同Wireshark版本里可能有小差异。比如状态号在大多数版本里是`goose.stNum`,顺序号是`goose.sqNum`,如果发现过滤不出来,你可以先只敲`goose`,然后在协议树里右键某个字段,选“Apply as Column”或“Prepare as Filter”,Wireshark会自动给出该版本的正确字段名。 ## 3. GOOSE报文的完整结构,从以太网头到ASN.1 ### 3.1 二层头的关键内容 GOOSE报文是标准的二层MAC帧,所以在Wireshark的Ethernet II部分就能看到最基础的信息。目的MAC地址固定是一个多播地址,范围从01:0C:CD 01:00:00到01:0C:CD 01:00:FF。为什么用这个特殊地址段?因为IEC 61850标准专门为GOOSE分配了这一段多播MAC,交换机需要识别这个地址段来转发多播帧。源MAC地址则是发送装置的物理地址,比如某个保护装置的网卡MAC。 在VLAN标签那一栏,你会看到三个比较重要的内容:VLAN ID、优先级和CFI。实际变电站里,过程层网络通常会用VLAN来做逻辑隔离,同一个交换机上不同业务的GOOSE流量往往划到不同的VLAN里,所以现场抓包时一定要看清VLAN ID。报文的优先级一般设成4或5,对应IEEE 802.1p里的“可控延时”级别,这是专门给GOOSE和SV这类需要确定性传输的报文用的。 然后就是以太网类型EtherType,GOOSE的固定值是0x88B8。如果这里显示的不是0x88B8,那就不是GOOSE。我曾经遇到有人把SV报文当成GOOSE抓,SV的EtherType是0x88BA,两者光看二层头很容易混淆,但作用完全不同。 ### 3.2 八字节GOOSE控制头 从EtherType后面开始,才是GOOSE这个协议自己的头。固定是八个字节,分成四个字段,每个两字节。 第一个是APPID,应用标识,用来识别不同的GOOSE控制块。它的值一般由工程整定,在一个变电站内应该保持唯一。Wireshark里看到的显示格式通常是十六进制,比如0x1001,你在保护装置的配置软件里查到的GOOSE控制块属性里也会看到对应的APPID,两者对上就说明这个报文来对了地方。 第二个是Length,长度字段。这个字段比较特殊,它算的不是整个帧的长度,而是从APPID字段之后开始的长度,换句话说,它包括了保留字段1、保留字段2和整个APDU的长度。有些新手不看标准,直接用帧总长度去比,发现对不上就开始怀疑抓包软件坏了,其实只是计算起点没搞对。你可以自己做一次简单验证:帧总长度减去以太网头和VLAN头之后,剩下的长度减掉4,应该跟这个Length字段的数值一致。 第三个和第四个分别是保留字段1、保留字段2。这两个字段在标准里是给扩展用的,正常情况下都是0x0000。如果看到非零值,要么是厂商自定义扩展,要么是配置有问题,不用太紧张,但值得留意。 ### 3.3 APDU和ASN.1 BER编码基础 八字节头部之后,是真正的应用层数据,叫APDU。这一块就不能用普通的文本方式去读了,因为它是ASN.1 BER编码的。我第一次接触GOOSE抓包时,看到一堆十六进制字节完全不知道从哪下手,后来学会ASN.1的基本规则才明白,它其实是一种非常规整的“打标签”格式。 ASN.1 BER编码的核心是TLV三元组:Tag、Length、Value。Tag用一个字节标识这个数据是什么类型,Length说明Value占多少个字节,Value则是真正的内容。看起来是不是有点像编程语言里的键值对?确实是这个思路。GOOSE把整个APDU看作一个APPLICATION级别的结构体,外层标记是0x61,意思是“应用类型、构造型、序号1”。 再往内,每一个字段也都有自己的上下文标签。比如gocbRef是第0号字段,用0x80开头;timeAllowedToLive是第1号字段,用0x81开头;datSet是第2号字段,用0x82开头。以此类推到第11号字段,也就是allData,用0xAB开头。记住这个规律后,你在任何一款十六进制编辑器里都能手工把GOOSE报文大卸八块,这个技巧在你需要分析Wireshark解析不出来的文件时特别有用。 ## 4. 用Wireshark逐字段解析GOOSE报文 ### 4.1 协议树怎么看 双击一条抓到的GOOSE报文,Wireshark会展示三层协议树。最上面是Frame,也就是整个帧的基本信息,包括抓包时间、帧长度等。中间是Ethernet II和VLAN,上面已经说过。最底下那一层,有的版本写的是“GOOSE”,有的版本写的是“IEC 61850 - GOOSE”,点开之后会看到完整的GOOSE头和应用数据。 一个典型的GOOSE协议树大概长这个样子:GOOSE APPID: 0x1000 (4096) Length: 122 Reserved 1: 0x0000 Reserved 2: 0x0000 APDU: 75 bytes goosePdu gocbRef: [PROTECTIED_PROCESS_BUS/LLN0$GO$GOOSE1] (35 bytes) timeAllowedToLive: 2000 ms datSet: [PROTECTIED_PROCESS_BUS/LLN0$dsGOOSE1] (49 bytes) goID: [PROTECTIED_PROCESS_BUS/LLN0$GO$GOOSE1] (35 bytes) t: 2025-01-01 08:00:00.123456 stNum: 1 sqNum: 0 test: False confRev: 1 ndsCom: False numDatSetEntries: 4 allData Data: 5 Data: 7 Data: 0 Data: 0
这一段其实是把ASN.1的十六进制都翻译成了可读形式,我们主要看的就是这些字段。每一个字段的意义,我在后面一节专门展开。 ### 4.2 那些关键字段的实际含义 先从`gocbRef`说起。它是GOOSE控制块的应用引用,格式一般是“LD/LN$GO$控制块名”。比如你在某保护装置的SCD文件里看到`PROTECTIED_PROCESS_BUS/LLN0$GO$GOOSE1`,报文的`gocbRef`字段里就应该一字不差地对上。如果对不上,接收侧会直接判定“订阅不匹配”,这个可以从抓包结果里第一时间看出来。 `timeAllowedToLive`是允许存活时间,单位是毫秒。它的意义在于接收侧用它来检测链路中断:如果在这个时间内没收到下一条GOOSE报文,就判定GOOSE链路断链。现场常见配置是2000毫秒或5000毫秒。抓包解码后直接看这个值,就知道断链告警的延时大概是多久。 `t`字段是报文生成时间,ASN.1解码后会以标准时间显示。我在实际排查中经常用它来判断发送装置的时间同步有没有问题。如果这个时间跟实际时钟差得很远,说明装置对时异常,会直接影响SOE和故障录波的对时,这个问题在抓包里一眼就能看出来。 `stNum`和`sqNum`这两个字段是报警和事故分析的重中之重。先记住一个原则:**stNum是状态变化次数,sqNum是本次状态下的重发序号**。正常运行状态下,装置稳定地以心跳周期重发报文,stNum维持不变,sqNum每发送一次加1,加到一个设定的最大值之后会回绕。一旦有开关变位或跳闸信号产生,stNum立即加1,sqNum回到0重新开始计数,同时重发频率会从正常的分泌周期瞬间变成短促重发序列,比如1毫秒、2毫秒、4毫秒、8毫秒等倍数递增,最后回到正常心跳周期。我抓过一次完整的开关变位过程,光看sqNum序列变化就能清楚还原现场当时发生了多少次重发、是否在规定时间内完成了快速重发。 `test`字段是测试位。如果这个值为True,代表当前GOOSE报文是在调试模式下发出的。接收侧通常会把测试位为真的报文当作无效数据处理,也就是说,如果现场的报文没抓到,但抓到后看到test=True,那接收装置的GOOSE通信状态灯可能依然是正常的,真正的问题在别处。生产投运前,这个位必须被置为False。我遇到过不止一次现场误动分析,最后发现就是有装置还停留在测试状态,把其他间隔的闭锁信号当正常信号处理了。 `confRev`是配置版本号,用来校验SCD配置一致性。如果发送和接收两侧的配置版本不一致,正确合规的接收装置通常会拒绝处理。抓包看到confRev异常时,应该去核对装置里的工程版本。 ### 4.3 数据集内容怎么读 GOOSE报文最核心的Payload其实不在头部,而在`allData`字段里。`numDatSetEntries`告诉你有几条数据,`allData`下面就会依次列出对应条数的数据项。这些数据项的格式按照SCD文件里数据集的顺序排列,可能是布尔量、整型、浮点型或者品质描述字。 比如一个典型的电流速断跳闸数据集,可能包含:一个布尔量表示跳闸命令,一个整型表示动作相别,一个浮点数表示故障电流值,一个品质字表示数据质量。Wireshark会自动按ASN.1标记解析出这些数据的类型和数值。看数据时不能只看数值本身,还要看品质位。品质字里的invalid和questionable位如果置上,说明数据是无效或可疑的,即使数值再大也不能作为判断依据。这个在现场特别容易踩坑。 ## 5. ASN.1手工解码技巧:从字节看真相 ### 5.1 BER长度字段的两种形式 Wireshark虽然能自动解码,但有时候你需要打开原始十六进制去核对,尤其是当Wireshark解析出来的字段顺序跟你预期的顺序不一样,或者某个字段明显错位的时候。这时候手工解码能力就是刚需。 BER编码里最常见的坑是Length字段的表示方式。短形式很好理解:如果Value长度小于128字节,Length就是一个单字节,直接写长度值。比如`0x0A`表示后面10个字节。长形式则是在首字节的最高位置1,低7位表示后面有几个长度字节。举例来说,`0x81 0x8D`表示后面一个字节是真正的长度值,即0x8D也就是141字节;`0x82 0x01 0xA0`表示后面的16位数值0x01A0就是长度。很多手动解锁时会犯的错误就是把0x81当成长度128,然后往后错读了一堆字段。你自己可以写一个简单的脚本来解码所有TLV结构,甚至可以递归展开整个APDU。 ### 5.2 手工拆APDU的具体步骤 我习惯的做法是先把帧复制成十六进制字符串,然后定位到APPID之后,找到APDU起始的那一个字节,通常就是0x61。然后按TLV结构一层层拨开。给你示范一下: 假设原始十六进制从APDU开始是:61 81 BA 80 1C 50 52 4F 54 45 43 54 49 45 44 5F 50 52 4F 43 45 53 53 5F 42 55 53 2F 4C 4C 4E 30 24 47 4F 24 47 4F 4F 53 45 31 81 02 07 D0 82 31 ...
第一步,`61`是外层标记,`81 BA`表示长度是0xBA,184字节,整个APDU是184字节。 第二步,往内第一个字段是`80 1C`,Tag是0x80,Length是0x1C,28字节,那么后面28个字节就是gocbRef的字符串内容。你把那28个字节按ASCII读出,也就是`PROTECTIED_PROCESS_BUS/LLN0$GO$GOOSE1`。 第三步,接着是`81 02 07 D0`。Tag是0x81,也就是timeAllowedToLive,Length是2,值是0x07D0,转成十进制就是2000。 第四步,下一段`82 31`,Tag是0x82,也就是datSet,Length是0x31,49字节,再按ASCII读出来就是数据集引用路径。 按这种办法,你可以一路把整个APDU的字段拆完。看上去繁琐,但每拆一次,你对GOOSE编码的理解就会加深一层。后面看到Wireshark显示的内容,你就能在心里反向验算一遍。 ### 5.3 数据集本身的编码规则 allData里的每一条数据也遵循TLV。常见的标记有:0x82表示布尔量,0x83表示位串,0x84表示有符号整数,0x85表示无符号整数,0x86表示浮点数。数据类型的标记不会跟头部字段混淆,因为它们在allData这个构造类型里面,有明确的嵌套上下文。 比如你看到一条`82 01 01`,Tag是0x82,Length是1,Value是0x01,那就是一个布尔量且值为True。看到`84 02 00 2C`,Tag是0x84,Length是2,值是0x002C,那就是一个整型数44。看到`85 02 01 F4`,那就是无符号整数500。浮点数稍微麻烦一点,它可能是IEEE 754标准的四字节浮点,也可能是IEC 61850特有的32位浮点编码,具体要看工程实现。Wireshark一般能识别出来,但手工拆解时要多留个心眼,别拿着两个字节就去套整数。 ### 5.4 手工解码最常见的两个错 第一个错是长形式长度读错。上一条命令类似0x81 0x8D,很多人把0x81当成长度本身,导致接下来所有字段全部移位。记住一点:0x81到0x84这个区间的值在这里不是长度,而是“接下来几个字节是长度”的长形式标记。 第二个错是把应用标签和上下文标签搞混。APDU的外层0x61是所有GOOSE报文都一样的,它不是某个字段的标记。真正区分字段的是0x80往后的上下文标记。如果你以为0x61之后就是gocbRef,那解码结果就会完全错乱。我在帮一个同事排查他就是一直把0x61当成gocbRef的头部,套了十几次都对不上,用小脚本拆开之后发现其实就是外层外壳。 ## 6. 实例分析:一次典型的GOOSE事件抓包解码 ### 6.1 案例基本情况 为了更直观地说明怎么看,我用一个模拟环境来演示。这里不涉及真实厂站,就用软件搭建了一套最简单的GOOSE发送和接收链路,模拟一个间隔的测控装置往智能终端发跳闸命令。这个GOOSE报文的目的MAC是01:0C:CD 01:00:01,VLAN ID是1,EtherType是0x88B8,APPID是0x1000,数据集里包含四条数据:一个布尔跳闸命令、一个整数相别、一个浮点电流值、一个品质字。 抓包过程很简单,我在发送端和接收端中间加了一台普通交换机,用镜像端口把所有GOOSE流量镜像到了抓包电脑,然后在Wireshark里输入`ether proto 0x88b8`作为捕获过滤器,抓了大概两分钟,一共抓到两百多条报文。 ### 6.2 从正常心跳到变位的关键时刻 一开始的报文全是正常心跳,协议树里stNum一直是7,sqNum从100逐渐跳到110左右,数据集里的布尔跳闸命令是False,相别是0,电流值是0.00A。这样的状态持续了大约一分半钟。接着我模拟了一次A相接地故障,发送装置发出跳闸命令。 变位后的第一条报文完全不一样:stNum从7直接跳到8,sqNum归零,timeAllowedToLive恢复为2000毫秒,布尔跳闸命令变成True,相别字段变成1,电流值变成了4268.35A。更关键的是随后的重发序列。我按照抓包的时间戳排序,看到在第一个变位报文后,后续几条报文间隔大约是1毫秒、2毫秒、4毫秒、8毫秒,这种呈倍数递增的序列正是GOOSE快速重发机制的典型特征。通过这个重发序列可以看出,智能终端在极短时间内收到了多条同样内容的GOOSE报文,冗余机制生效,不会因为偶然丢包而误判成链路中断。 ### 6.3 用命令行的方式回放和分析 图形界面很好用,但在处理大量报文时我更喜欢回到命令行,用tshark做批处理。用下面这条命令把GOOSE关键字段导成CSV: ```bash tshark -r goose_demo.pcapng -Y goose -T fields -e frame.time -e goose.appid -e goose.stNum -e goose.sqNum -e goose.test -e frame.len这样导出来就是一张几千行的表格,你可以在Excel或者脚本里快速统计sqNum的跳变规律,找出所有stNum变化的时间点。对于现场事故分析,这种表格可以作为书面报告的原始证据附在后面,比截图清晰得多。
6.4 导出报告时要注意什么
现场分析报告里,我一般会把抓包文件重命名成带时间戳和描述的名称,比如“20250101_A相跳闸_过程层A网_保护装置至智能终端.pcapng”,然后只把跟事故时间段相关的几十条报文截取到新文件里,用Wireshark的File > Export Specified Packets功能就行。导出时勾上“Displayed”选项,只导显示过滤器筛出来的报文,文件小、内容干净,别人打开也不会一上来看到一堆无关流量。
7. 常见问题与排查技巧实录
7.1 一直抓不到GOOSE报文怎么办
我遇到的最常见情况是,抓包电脑明明接在交换机上了,Wireshark也正常显示其他流量,但就是看不到一道GOOSE。优先检查三件事:
第一,确认EtherType没错。有人把SV报文当成GOOSE抓,类型是0x88BA,当然看不到。第二,确认VLAN没钻进去。如果交换机把GOOSE划在VLAN 101里,你的抓包口在VLAN 100,同样是收不到。可以用vlan显示过滤器先看看抓到的流量里有哪些VLAN。第三,确认交换机没过滤多播。部分交换机默认会把未知多播地址直接丢弃,需要在端口配置里打开多播转发或放行01:0C:CD 01:00:00/16这个地址段。
物理层问题也不能忽视。光纤收发器或者光模块的光功率衰减过大,表现为抓包软件长时间只有极少量报文,中间可能伴有大量CRC校验错误帧。我在Wireshark的统计菜单里看过Bad Checksums计数,如果非常频繁,先查物理链路,别急着改配置。
7.2 Wireshark明明抓到了,但没解析成GOOSE
这种情况多半是EtherType识别被跳过。你先看那个报文的Ethernet II层的类型字段是不是0x88B8,如果是,但协议树里没有GOOSE那层,可以右键该报文,选择“Decode As”,手动指定为“IEC 61850 GOOSE”或“GOOSE”。也可能是你抓到的是带VLAN的帧,而底层的抓包驱动把VLAN剥离了,导致识别顺序有问题。重装Npcap时勾上支持802.1Q那个选项就行。
还有一种情况是Wireshark版本太旧,没有内置GOOSE解析器。解决办法就是升级到3.4以上。如果因为某些原因必须用旧版本,也可以尝试加载独立解析插件,但那样比较折腾,我一般建议直接用新版本,省下时间做正事。
7.3 变位报文为什么没有触发stNum变化
现场排查“装置明明应该发跳闸报文,但接收侧没有动作”时,抓包经常看到一种现象:报文一直在发,numDatSetEntries也对,数据集里的布尔量也变成True了,但stNum纹丝不动,sqNum还在按心跳节奏慢慢加。这说明发送装置并没有把这次数据变化当作一次新的“状态变化”,很可能是因为数据集里布尔量的品质位有问题,或者发送侧控制块的配置里把该数据集设成了周期型而不是变化型。抓包看到这种情况时,重点可以转到装置的SCD和数据集配置上。
7.4 时间戳乱跳或者显示成1970年
GOOSE报文里的t字段是ASN.1的UtcTime,编码方式不是简单字符串,而是一个固定的二进制时间结构。Wireshark新版本能正确显示,但如果显示成很离谱的年份,多半是装置里对时没有完成,或者抓包文件同时存在多个IED的时间基准不一致。此时先检查装置对时状态,再检查网络中是否有PTP/SNTP对时报文。不要一上来就怀疑Wireshark解码有问题,它解码不出人可读时间的前提条件是字节结构规范,如果发送装置自己乱发,解析出来当然也是乱的。
7.5 快速排查速查表
| 现象 | 可能原因 | 首选排查动作 |
|---|---|---|
| 抓不到GOOSE | 镜像口配置错误、VLAN不匹配、多播被丢弃 | 检查交换机端口配置与多播过滤策略 |
| 抓到了但无GOOSE解析 | 旧版Wireshark或EtherType未识别 | 升级版本或“Decode As”指定GOOSE |
| stNum不变但数据已变 | 数据集配置为周期型或品质位异常 | 核对SCD中数据集属性和品质字 |
| test=True却仍然被接收 | 接收侧未判断测试位 | 查看接收装置GOOSE订阅设置 |
| 报文长度校验错误 | 物理链路劣化或VLAN剥离 | 检查光功率、CRC统计、重装Npcap |
| t字段显示异常 | 装置对时异常或编码不规范 | 检查对时状态与告警记录 |
8. 一点实战心得与后续扩展
最后分享几个我自己的经验。第一个是要学会“带着问题抓包”,不要漫无目的地抓一堆回来再分析。抓之前先想清楚你要验证什么,是要确认发送侧发了报文,还是确认接收侧收到并处理了报文,对应的抓包位置和过滤条件其实是不一样的。
第二个经验是抓包的电脑不要用无线网卡,直接用有线网卡,而且最好用能支持千兆的独立网卡,不要用某些主板自带的节能型网卡,它在低流量时会自动降低功耗,导致接收延时变大,甚至丢包。现场调试时我还遇到过USB转网卡在长时间抓包后掉线的问题,可靠性很差,有条件还是用内置网卡。
第三个经验是重放工具的使用。在测试接收装置对GOOSE处理是否正确时,我经常用Scapy构造一个仿真GOOSE报文直接发给接收装置,验证它在极端场景下的行为,比如发送一个超长APDU、一个乱序的数据集、一个测试位置真的报文。这样做比反复改装置配置效率高得多。不过重放有风险,务必在隔离的测试环境中进行,不能直接对运行中的设备发这类报文。
GOOSE相关的知识往后延伸还有很多可以玩的东西,比如跟SV报文联合分析、用MMS跟GOOSE做关联对比、在Wireshark里加载SCD文件实现自动映射字段名称等等。这些内容以后有机会我再逐一展开。当下最重要的,是你先把这个抓包链路搭好,把几份报文从头到尾至少手工解码一遍,之后再看任何GOOSE相关问题都会顺手得多。