はじめに
Go言語でNetFlowのパケットを受信して処理するためのパッケージ
の使い方を説明します。
サンプルプログラム
GiHUBのリポジトリにcmd/nf-dumpというサンプルプログラムがあります。
そのままです。
/*
Command nf-dump decodes NetFlow packets from UDP datagrams.
Usage:
nf-dump [flags]
Flags:
-addr string Listen address (default ":2055")
*/
package main
import (
"bytes"
"flag"
"log"
"net"
"github.com/tehmaze/netflow"
"github.com/tehmaze/netflow/ipfix"
"github.com/tehmaze/netflow/netflow1"
"github.com/tehmaze/netflow/netflow5"
"github.com/tehmaze/netflow/netflow6"
"github.com/tehmaze/netflow/netflow7"
"github.com/tehmaze/netflow/netflow9"
"github.com/tehmaze/netflow/session"
)
// Safe default
var readSize = 2 << 16
func main() {
listen := flag.String("addr", ":2055", "Listen address")
flag.Parse()
var addr *net.UDPAddr
var err error
if addr, err = net.ResolveUDPAddr("udp", *listen); err != nil {
log.Fatal(err)
}
var server *net.UDPConn
if server, err = net.ListenUDP("udp", addr); err != nil {
log.Fatal(err)
}
if err = server.SetReadBuffer(readSize); err != nil {
log.Fatal(err)
}
decoders := make(map[string]*netflow.Decoder)
for {
buf := make([]byte, 8192)
var remote *net.UDPAddr
var octets int
if octets, remote, err = server.ReadFromUDP(buf); err != nil {
log.Printf("error reading from %s: %v\n", remote, err)
continue
}
log.Printf("received %d bytes from %s\n", octets, remote)
d, found := decoders[remote.String()]
if !found {
s := session.New()
d = netflow.NewDecoder(s)
decoders[remote.String()] = d
}
m, err := d.Read(bytes.NewBuffer(buf[:octets]))
if err != nil {
log.Println("decoder error:", err)
continue
}
switch p := m.(type) {
case *netflow1.Packet:
netflow1.Dump(p)
case *netflow5.Packet:
netflow5.Dump(p)
case *netflow6.Packet:
netflow6.Dump(p)
case *netflow7.Packet:
netflow7.Dump(p)
case *netflow9.Packet:
netflow9.Dump(p)
case *ipfix.Message:
ipfix.Dump(p)
}
}
}
このプログラムのポイントは、
UDPのポートをオープンして受信状態にする
listen := flag.String("addr", ":2055", "Listen address")
flag.Parse()
var addr *net.UDPAddr
var err error
if addr, err = net.ResolveUDPAddr("udp", *listen); err != nil {
log.Fatal(err)
}
var server *net.UDPConn
if server, err = net.ListenUDP("udp", addr); err != nil {
log.Fatal(err)
}
2055番ポートです。
送信元毎にデコーダーを作成する
d, found := decoders[remote.String()]
if !found {
s := session.New()
d = netflow.NewDecoder(s)
decoders[remote.String()] = d
}
NetFlowパケットをデコードする
m, err := d.Read(bytes.NewBuffer(buf[:octets]))
if err != nil {
log.Println("decoder error:", err)
continue
}
NetFlowのバージョン毎にダンプする
switch p := m.(type) {
case *netflow1.Packet:
netflow1.Dump(p)
case *netflow5.Packet:
netflow5.Dump(p)
case *netflow6.Packet:
netflow6.Dump(p)
case *netflow7.Packet:
netflow7.Dump(p)
case *netflow9.Packet:
netflow9.Dump(p)
case *ipfix.Message:
ipfix.Dump(p)
}
よく使われるのは、v5,v9,ipfix(v10)です。
実行結果
実行結果
$go run main.go
2024/09/27 17:48:57 received 172 bytes from 10.30.1.12:3285
NetFlow version 9 packet
2024/09/27 17:49:05 received 472 bytes from 192.168.1.32:36573
IPFIX message
2024/09/27 17:49:05 received 472 bytes from 192.168.1.32:36573
IPFIX message
2024/09/27 17:49:05 received 472 bytes from 192.168.1.32:36573
IPFIX message
2024/09/27 17:49:05 received 96 bytes from 192.168.1.32:36573
IPFIX message
2024/09/27 17:49:05 received 352 bytes from 192.168.1.32:36573
IPFIX message
2024/09/27 17:49:07 received 172 bytes from 10.30.1.12:3285
NetFlow version 9 packet
2024/09/27 17:49:07 received 60 bytes from 10.30.1.12:3285
NetFlow version 9 packet
2024/09/27 17:49:22 received 172 bytes from 10.30.1.12:3285
NetFlow version 9 packet
2024/09/27 17:49:22 received 60 bytes from 10.30.1.12:3285
NetFlow version 9 packet
2024/09/27 17:49:27 received 400 bytes from 10.30.1.12:3285
NetFlow version 9 packet
2024/09/27 17:49:37 received 60 bytes from 10.30.1.12:3285
NetFlow version 9 packet
2024/09/27 17:49:43 received 1236 bytes from 10.30.1.12:3285
NetFlow version 9 packet
2024/09/27 17:49:48 received 400 bytes from 10.30.1.12:3285
NetFlow version 9 packet
data set template 258, length: 76
1 records:
record 0:
octetDeltaCount: 3534
postOctetDeltaCount: 3534
packetDeltaCount: 6
postPacketDeltaCount: 6
flowStartSysUpTime: 1857598410
flowEndSysUpTime: 1857658690
ingressInterface: 1416
egressInterface: 514
icmpTypeCodeIPv4: 0
protocolIdentifier: 0
ipClassOfService: 1
postIpClassOfService: 17
applicationId: [0 0 0 20 0 0 48 68 0]
66: [0 0 0 0]
65: [0 0]
forwardingStatus: 0
flowEndReason: 12
sourceIPv6Address: 540:20a:1e01:a0a:1e01:900::
data set template 258, length: 76
1 records:
record 0:
octetDeltaCount: 222
postOctetDeltaCount: 222
packetDeltaCount: 3
postPacketDeltaCount: 3
flowStartSysUpTime: 1857477520
flowEndSysUpTime: 1857477520
ingressInterface: 161
egressInterface: 61598
icmpTypeCodeIPv4: 0
protocolIdentifier: 0
ipClassOfService: 1
postIpClassOfService: 17
applicationId: [0 0 0 20 0 0 48 68 0]
66: [0 0 0 0]
65: [0 0]
forwardingStatus: 0
flowEndReason: 14
sourceIPv6Address: 4c3:a:1e01:ac0:a801:fa00::
data set template 258, length: 76
1 records:
record 0:
octetDeltaCount: 219
postOctetDeltaCount: 219
packetDeltaCount: 3
postPacketDeltaCount: 3
flowStartSysUpTime: 1857477520
flowEndSysUpTime: 1857477520
ingressInterface: 61598
egressInterface: 161
icmpTypeCodeIPv4: 1
protocolIdentifier: 0
ipClassOfService: 0
postIpClassOfService: 17
applicationId: [0 0 0 20 0 0 48 68 0]
66: [0 0 0 0]
65: [0 0]
forwardingStatus: 0
flowEndReason: 14
sourceIPv6Address: 4c3:c0:a801:fa0a:1e01:a00::
data set template 258, length: 76
1 records:
record 0:
octetDeltaCount: 296
postOctetDeltaCount: 296
packetDeltaCount: 1
postPacketDeltaCount: 1
flowStartSysUpTime: 1857579750
flowEndSysUpTime: 1857654850
ingressInterface: 53
egressInterface: 4004
icmpTypeCodeIPv4: 1
protocolIdentifier: 0
ipClassOfService: 0
postIpClassOfService: 17
applicationId: [0 0 0 20 0 0 48 68 0]
66: [0 0 0 0]
65: [0 0]
forwardingStatus: 0
flowEndReason: 12
sourceIPv6Address: 540:20a:1e01:fe0a:1e01:a00::
data set template 258, length: 76
1 records:
record 0:
octetDeltaCount: 63
postOctetDeltaCount: 63
packetDeltaCount: 1
postPacketDeltaCount: 1
flowStartSysUpTime: 1857579750
flowEndSysUpTime: 1857654850
ingressInterface: 4004
egressInterface: 53
icmpTypeCodeIPv4: 0
protocolIdentifier: 0
ipClassOfService: 1
postIpClassOfService: 17
applicationId: [0 0 0 20 0 0 48 68 0]
66: [0 0 0 0]
65: [0 0]
forwardingStatus: 0
flowEndReason: 12
sourceIPv6Address: 540:20a:1e01:a0a:1e01:fe00::
余談
このパッケージもTWSNMP FC/FKで使用しています。