IEC 61850模型与MMS报文解析实战:从协议基础到报文抓取分析

1次阅读
没有评论

共计 2640 个字符,预计需要花费 7 分钟才能阅读完成。

image.webp

背景痛点:从寄存器到信息模型

传统变电站协议如 Modbus 采用简单的寄存器地址映射机制,就像用 Excel 表格记录数据——每个点表对应固定的寄存器地址。而 IEC 61850 带来的变革相当于从纸质档案升级到数据库系统:

IEC 61850 模型与 MMS 报文解析实战:从协议基础到报文抓取分析

  • 数据对象化:将断路器、变压器等设备抽象为 LogicalDevice/LogicalNode,例如 XCBR1 代表 1 号断路器
  • 自描述特性 :通过 SCL 文件(Substation Configuration Language) 明确定义数据属性,比如 Modbus 需要查点表才能知道 40001 地址的含义,而 61850 的 MMS 报文直接携带 IED1/XCBR1.Pos.stVal 这样的语义化路径
  • 服务抽象:ACSI 服务如 GetDirectory、GetVariableValue 被映射到 MMS 的 Read/Write 服务原语,就像把具体操作(打开文件)转化为通用 API 调用

协议栈解剖:从应用到以太网帧

用分层视角看 61850 通信,就像快递包裹的层层包装:

@startuml
skinparam monochrome true

frame 应用层 {[ACSI 服务]
  (GetVariableValue)
}

frame 表示层 {[MMS 协议]
  (ReadRequest)
}

frame 传输层 {[TCP 102 端口]
}

frame 网络层 {[IP 协议]
}

frame 数据链路层 {[Ethernet II]
}

[ACSI 服务] --> [MMS 协议] : 映射
[MMS 协议] --> [TCP 102 端口] : 承载
[TCP 102 端口] --> [IP 协议]
[IP 协议] --> [Ethernet II]
@enduml

关键点在于 MMS 如何封装 ACSI 服务:当客户端请求读取IED1/MMXU1.PhV.phsA.cVal.mag.f(A 相电压幅值)时:

  1. ACSI 层生成 GetVariableValue 服务请求
  2. MMS 层转换为 ReadRequest PDU,包含 ObjectName 和 VariableSpecification
  3. 通过 BER 编码规则转换为 ASN.1 二进制流
  4. TCP 层拆分为多个 Segment 传输

抓包实战:Wireshark 技巧与 Python 解码

抓包过滤器配置

针对不同报文类型的 BPF 语法:

# 抓取 MMS 报文(TCP 102 端口)tcp port 102

# 抓取 GOOSE 报文(目的 MAC 01-0C-CD-01 开头)ether dst 01:0c:cd:01:00:00/ff:ff:ff:ff:00:00

# 抓取 SV 报文(APPID 范围 4000-7FFF)ether[16:2] >= 0x4000 and ether[16:2] <= 0x7fff

Python 解析 MMS 响应示例

安装依赖库:

pip install asn1tools scapy

解析 GetVariableAccessAttributes 响应的关键代码:

import asn1tools
from scapy.all import rdpcap

# 加载 61850 标准 ASN.1 定义
mms_asn = asn1tools.compile_files('61850-8-1.asn', 'ber')

# 从抓包文件提取 MMS PDU
pcap = rdpcap('mms_traffic.pcap')
mms_pdu = bytes(pcap[0][TCP].payload)

# 解码 MMS PDU
decoded = mms_asn.decode('MMSpdu', mms_pdu)

# 提取变量属性
if 'confirmed-ResponsePDU' in decoded:
    var_attrs = decoded['confirmed-ResponsePDU']['response']['getVariableAccessAttributes']
    print(f"变量名: {var_attrs['name']}")
    print(f"数据类型: {var_attrs['typeDescription']['structure']['components'][0]['type']}")
    print(f"是否可读: {'mmsDeletable'in var_attrs['accessControl']}")

代码执行后会输出类似结果:

变量名: IED1/MMXU1.PhV.phsA
数据类型: AnalogueValue
是否可读: True

避坑指南:工程实践中的血泪经验

CID 文件版本冲突

常见报错 Association model mismatch 往往因为:

  • IED 设备升级后未导出新 CID
  • SCL 文件中的 LN 实例数与设备实际不符
  • DataSet 成员顺序与设备内部不一致

解决方案

  1. 使用 IED 配置工具重新导出 CID
  2. 比对 SCL 文件中 Communication 段与设备实际通信配置
  3. 使用报文比对工具验证 DataSet 成员顺序

TCP 窗口优化

当传输大量报告 (Report) 或日志时,默认 TCP 窗口可能成为瓶颈:

  • 在 Linux 客户端调整窗口大小:
    # 查看当前值
    sysctl net.ipv4.tcp_rmem
    
    # 临时设置为 2MB
    echo 2097152 > /proc/sys/net/core/rmem_max
  • 在 Windows 注册表修改 HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters 下的 TcpWindowSize

扩展思考:设备指纹识别

通过分析 MMS 交互特征可识别 IED 设备类型:

  1. 服务支持矩阵:某些厂商设备不支持 Write 服务
  2. 响应时延特征:老型号设备处理 GetDirectory 响应通常 >50ms
  3. 对象命名风格:如西门子设备常用大写 LN 前缀(CBSW1),ABB 设备带厂商标识(ABB_ROCK
  4. TCP 参数特征:初始窗口大小、MSS 值等

实现思路示例:

def fingerprint_ied(mms_pdu):
    vendor = 'Unknown'
    if b'SIEMENS' in mms_pdu:
        vendor = 'Siemens SIPROTEC'
    elif len(mms_pdu) > 200 and b'ABB' in mms_pdu[100:150]:
        vendor = 'ABB REF615'
    return vendor

结语

理解 61850 通信就像学一门外语——需要同时掌握语法(SCL 模型)和发音规则(MMS 编码)。建议从实际报文中逆向学习:先用 Wireshark 捕获正常通信流量,再尝试修改 CID 文件观察报文变化,最后动手实现简单的客户端程序。当你能准确预测每个字节的含义时,就真正掌握了智能变电站的通信脉搏。

正文完
 0
评论(没有评论)