GoでEtherCATパケットを生成する
はじめに
この記事は CISTアドベントカレンダー2023の17日目です
EtherCATのペイロードを生成してgopacketで送信してみました。
EtherCATのアーキテクチャ等は解説しないので、もし興味がありましたらベッコフが提供しているドキュメントを見ることをお勧めします
EtherCATとは
EtherCATはベッコフオートメーションが開発したリアルタイム性のある産業イーサネット技術です。EtherCATプロトコルがIEC規格IEC61158で公開され、オートメーション技術、試験・計測技術およびその他の多数のアプリケーション分野に適したハードリアルタイムおよびソフトリアルタイム性能を提供します。
EtherCATを開発する際に最も留意したことは、短周期のサイクルタイム(≤ 100 µs)、精度の高い時刻同期(≤ 1 µs)を可能とする低ジッタおよび低ハードウェアコスト化です。
EtherCATは2003年4月に公表され、その年の11月にEtherCAT Technology Groupを設立しました。その後ETGは世界最大の産業用イーサネット・フィールドバス団体に成長しました。ETGはデバイスメーカとユーザを結びつけ、両者が技術作業部会でEtherCAT技術の進展に貢献できるように注力しています。
工場や製造現場にある機器を制御するときに使われている産業用ネットワークの1つです
サンプルコード
動かすためには以下が必要です
- goの開発環境(1.21以上)
- libpcap-dev(※)
- gopacket(パケットに関わるライブラリ)
- goecat(EtherCATのバイトデータを生成するライブラリ)
※ aptやbrewで提供されているパッケージ名です。それ以外の環境だと名前が異なる可能性があります
package main
import (
"encoding/hex"
"fmt"
"log"
"time"
"github.com/Aruminium/goecat/pkg/ethercat/command"
"github.com/Aruminium/goecat/pkg/ethercat/datagram"
"github.com/Aruminium/goecat/tools/packet"
"github.com/google/gopacket"
"github.com/google/gopacket/pcap"
)
var (
device string = "en7"
snapshot_len int32 = 1024
promiscuous bool = false
timeout time.Duration = 30 * time.Second
options gopacket.SerializeOptions = gopacket.SerializeOptions{
ComputeChecksums: true,
FixLengths: true,
}
handle *pcap.Handle
err error
)
func main() {
handle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
if err != nil {
log.Fatal(err)
}
defer handle.Close()
packet, err := packet.NewEtherCATPacket(device)
if err != nil {
log.Fatal(err)
}
ecatDatagram := datagram.Datagram{
Command: command.BRD,
Index: uint8(0x00),
Address: uint32(0x00000000),
LRCM: datagram.NewLrcm(false, false, 1),
IRQ: uint16(0x0000),
Data: []byte{0x00},
WKC: uint16(0x0000),
}
packet.Ecat.AppendDatagram(ecatDatagram)
data, err := packet.Send(handle, options)
if err != nil {
fmt.Printf("[-] Error while sending: %s\n", err.Error())
}
fmt.Println(hex.Dump(data))
}
LRCMは、Len+Reserved+Circulating+Moreの頭文字です
ドキュメントだと、Len, R, C, Mと表現されているのでわかりにくいです
実行結果
実行するとセグメントにパケットが流れるのでWiresharkでキャプチャしてあげます
最後に
今回はGoを用いてEtherCATパケットを生成してみました。
goecat
は私の初OSSとして公開したものになります
ちょっと面倒なbit処理やDatagramsのLength計算をやってくれます。
先のソースコードで言うとこちらです
lrcm := datagram.NewLrcm(0, 0, 1)
ecatDatagram := datagram.Datagram{
Command: command.BRD,
Index: uint8(0x00),
Address: uint32(0x00000000),
LRCM: lrcm,
IRQ: uint16(0x0000),
Data: []byte{0x00},
WKC: uint16(0x0000),
}
packet.Ecat.AppendDatagram(ecatDatagram)
data, err := packet.Send(handle, options)
Githubはgoecatです
Discussion