こんにちは、イガラシです。
Acroquestでは社内勉強会がいくつかありますが、
その中の一つに、具体的に実践した内容を発表する会があります。
その会で先日、プロジェクトで取り組んだ「Packetbeatのカスタマイズ」を発表したのですが、
マニアックな内容にも関わらず、思いのほか好評だったので、ブログ記事として書きたいと思います。
Packetbeatのカスタマイズ、といっても公式に書いてある新しいプロトコルに対応する、というものではありません。
あるカプセル化されたパケットの中身を解析するため、Packetbeatが対応していないカプセル化プロトコルに対応しよう。
という少し(かなり)ニッチな対応を行いました。
今回対応したカプセル化プロトコルは、「NVGRE」になります。
パケットの解析処理
Packetbeatがキャプチャしたパケットを解析する処理は、gopacketによって行われています。
NVGREがGREの拡張だったので、gopacketが対応していたGREパケットの解析処理を修正して、NVGREパケットを解析できるようにしました。
NVGREの解析処理
gopacket/layers/gre.go
func (g *GRE) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { g.ChecksumPresent = data[0]&0x80 != 0 g.RoutingPresent = data[0]&0x40 != 0 g.KeyPresent = data[0]&0x20 != 0 g.SeqPresent = data[0]&0x10 != 0 : : // ↓ここから修正したコード baseOffset = 4 if g.ChecksumPresent { g.Checksum = binary.BigEndian.Uint16(data[baseOffset:baseOffset+2]) g.Offset = binary.BigEndian.Uint16(data[baseOffset+2:baseOffset+4]) baseOffset += 4 } if g.KeyPresent { g.Key = binary.BigEndian.Uint32(data[baseOffset:baseOffset+4]) baseOffset += 4 } : : }
元のソースでは、フラグによるオプションフィールドの有無に関わらず、フィールドの値を取得していました。
NVGREだと特定のフィールドしか設定されないため、フラグが有効な場合にフィールドの値を取得するように修正しました。
1.2.定数の定義
gopacket/layers/enums.go
const ( EthernetTypeLLC EthernetType = 0 EthernetTypeIPv4 EthernetType = 0x0800 : EthernetTypeEthernetCTP EthernetType = 0x9000 EthernetTypeTrasparentEtherBridge EthernetType = 0x6558 // 追加した定数 )
NVGREで定義されている、ProtocolTypeの値(0x6558)を定数として追加します。
gopacket/layers/enums.go
func init() { : EthernetTypeMetadata[EthernetTypeLLC] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeLLC), Name: "LLC", LayerType: LayerTypeLLC} EthernetTypeMetadata[EthernetTypeIPv4] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4), Name: "IPv4", LayerType: LayerTypeIPv4} : EthernetTypeMetadata[EthernetTypeEAPOL] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeEAPOL), Name: "EAPOL", LayerType: LayerTypeEAPOL} // ↓追加した定義↓ EthernetTypeMetadata[EthernetTypeTrasparentEtherBridge] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeEthernet), Name: "TransparentEthernetBridge", LayerType: LayerTypeEthernet}
ProtocolType別に、「Payload部分をどのプロトコルとして解釈するか?」という定義を追加します。
Packetbeatがパケットを解析するときに、この定義を使ってパケットの中身を解析していきます。
ここまでで、パケット解析ライブラリgopacketの拡張は完了です。
PacketbeatでNVGREに対応する
Packetbeatが、gopacketを使ってパケット解析を行う処理は、「decoder/decoder.go」に記述されています。
その中で、プロトコルスタックを順に解析する処理は、OnPacket()で行われています。
packetbeat/decoder/decoder.go
func (d *Decoder) OnPacket(data []byte, ci *gopacket.CaptureInfo) { for len(data) > 0 { err := current.DecodeFromBytes(data, d) if err != nil { logp.Info("packet decode failed with: %v", err) break } nextType := current.NextLayerType() data = current.LayerPayload() processed, err = d.process(&packet, currentType) if err != nil { logp.Info("Error processing packet: %v", err) break } if processed { break } // choose next decoding layer next, ok := d.decoders[nextType] if !ok { break } // jump to next layer current = next currentType = nextType } }
OnPacketは、decodersで指定されたプロトコルの解析を行うようになっているので、decodersを初期化しているメソッドでGREを解析対象に含めるようにします。
packetbeat/decoder/decoder.go
func New( f *flows.Flows, datalink layers.LinkType, icmp4 icmp.ICMPv4Processor, icmp6 icmp.ICMPv6Processor, tcp tcp.Processor, udp udp.Processor, ) (*Decoder, error) { : : defaultLayerTypes := []gopacket.DecodingLayer{ &d.sll, // LinuxSLL &d.eth, // Ethernet &d.lo, // loopback on OS X &d.stD1Q, // VLAN &d.stIP4, &d.stIP6, // IP &d.icmp4, &d.icmp6, // ICMP &d.tcp, &d.udp, // TCP/UDP } d.AddLayers(defaultLayerTypes) d.AddLayer(&d.gre) // 追加した行
「d.gre」は、Decoderのフィールド定義に追加しておきます。
ここまでの対応で、Packetbeatでカプセル化パケットNVGREを解析できるようになりました。
当初は、どうやってNVGREに対応すればよいか分からず、Packetbeat/gopacketのソースコードを読んでいました。
対応できてからは、以外と簡単に対応できるようになっているな、と思えるようになりました。
Packetbeatは便利ですし、このように改造もできるので、
是非みなさんも使ってみてください^^
Acroquest Technologyでは、キャリア採用を行っています。
- ビッグデータ(Hadoop/Spark、NoSQL)、データ分析(Elasticsearch、Python関連)、Web開発(SpringCloud/SpringBoot、AngularJS)といった最新のOSSを利用する開発プロジェクトに関わりたい。
- マイクロサービス、DevOpsなどの技術を使ったり、データ分析、機械学習などのスキルを活かしたい。
- 社会貢献性の高いプロジェクトや、顧客の価値を創造するようなプロジェクトで、提案からリリースまで携わりたい。
- 書籍・雑誌等の執筆や、対外的な勉強会の開催・参加を通した技術の発信、社内勉強会での技術情報共有により、エンジニアとして成長したい。
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
Elasticsearchを仕事で使いこみたいデータ分析エンジニア募集中! - Acroquest Technology株式会社のエンジニア中途・インターンシップ・契約・委託の求人 - Wantedlywww.wantedly.com