io.netflow.flows.cflow.NetFlowV6.scala Maven / Gradle / Ivy
The newest version!
package io.netflow.flows.cflow
import java.net.{InetAddress, InetSocketAddress}
import java.time.{Duration, Instant, LocalDateTime, ZoneId}
import java.util.UUID
import io.netflow.lib._
import io.netflow.util.UUIDs
import io.netty.buffer._
import akka.actor.ActorSystem
import scala.util.{Failure, Try}
/**
* NetFlow Version 6
*
* *-------*---------------*------------------------------------------------------*
* | Bytes | Contents | Description |
* *-------*---------------*------------------------------------------------------*
* | 0-1 | version | The version of NetFlow records exported 005 |
* *-------*---------------*------------------------------------------------------*
* | 2-3 | count | Number of flows exported in this packet (1-30) |
* *-------*---------------*------------------------------------------------------*
* | 4-7 | SysUptime | Current time in milli since the export device booted |
* *-------*---------------*------------------------------------------------------*
* | 8-11 | unix_secs | Current count of seconds since 0000 UTC 1970 |
* *-------*---------------*------------------------------------------------------*
* | 12-15 | unix_nsecs | Residual nanoseconds since 0000 UTC 1970 |
* *-------*---------------*------------------------------------------------------*
* | 16-19 | flow_sequence | Sequence counter of total flows seen |
* *-------*---------------*------------------------------------------------------*
* | 20 | engine_type | Type of flow-switching engine |
* *-------*---------------*------------------------------------------------------*
* | 21 | engine_id | Slot number of the flow-switching engine |
* *-------*---------------*------------------------------------------------------*
* | 22-23 | sampling_int | First two bits hold the sampling mode |
* | | | remaining 14 bits hold value of sampling interval |
* *-------*---------------*------------------------------------------------------*
*/
object NetFlowV6Packet {
private val headerSize = 24
private val flowSize = 52
/**
* Parse a Version 6 FlowPacket
*
* @param sender The sender's InetSocketAddress
* @param buf Netty ByteBuf containing the UDP Packet
*/
def apply(sender: InetSocketAddress, buf: ByteBuf)(implicit system: ActorSystem): Try[NetFlowV6Packet] =
Try[NetFlowV6Packet] {
val version = buf.getUnsignedInteger(0, 2).toInt
if (version != 6) return Failure(new InvalidFlowVersionException(version))
val count = buf.getUnsignedInteger(2, 2).toInt
if (count <= 0 || buf.readableBytes < headerSize + count * flowSize)
return Failure(new CorruptFlowPacketException)
val uptime = buf.getUnsignedInteger(4, 4)
val epochTimestamp = buf.getUnsignedInteger(8, 4) * 1000
val timestamp = LocalDateTime.ofInstant(Instant.ofEpochMilli(epochTimestamp), ZoneId.systemDefault())
val id = UUIDs.startOf(epochTimestamp)
val flowSequence = buf.getUnsignedInteger(16, 4)
val engineType = buf.getUnsignedInteger(20, 1).toInt
val engineId = buf.getUnsignedInteger(21, 1).toInt
// the first 2 bits are the sampling mode, the remaining 14 the interval
val sampling = buf.getUnsignedInteger(22, 2).toInt
val samplingInterval = sampling & 0x3FFF
val samplingMode = sampling >> 14
val flows: List[NetFlowV6] = (0 to count - 1).toList.flatMap { i =>
apply(sender, buf.slice(headerSize + (i * flowSize), flowSize), id, uptime, timestamp, samplingInterval)
}
NetFlowV6Packet(id,
sender,
buf.readableBytes,
uptime,
timestamp,
flows,
flowSequence,
engineType,
engineId,
samplingInterval,
samplingMode)
}
/**
* Parse a Version 6 Flow
*
* @param sender The sender's InetSocketAddress
* @param buf Netty ByteBuf Slice containing the UDP Packet
* @param fpId FlowPacket-UUID this Flow arrived on
* @param uptime Millis since UNIX Epoch when the exporting device/sender booted
* @param timestamp LocalDateTime when this flow was exported
* @param samplingInterval Interval samples are sent
*/
def apply(sender: InetSocketAddress,
buf: ByteBuf,
fpId: UUID,
uptime: Long,
timestamp: LocalDateTime,
samplingInterval: Int)(implicit system: ActorSystem): Option[NetFlowV6] =
Try[NetFlowV6] {
val sampling = NodeConfig.values.netflow.calculateSamples
val pkts = buf.getUnsignedInteger(16, 4)
val bytes = buf.getUnsignedInteger(20, 4)
NetFlowV6(
UUIDs.timeBased(),
sender,
buf.readableBytes(),
uptime,
timestamp,
buf.getUnsignedInteger(32, 2).toInt, // srcPort
buf.getUnsignedInteger(34, 2).toInt, // dstPort
Option(buf.getUnsignedInteger(40, 2).toInt).filter(_ != -1), // srcAS
Option(buf.getUnsignedInteger(42, 2).toInt).filter(_ != -1), // dstAS
if (sampling) pkts * samplingInterval else pkts, // pkts
if (sampling) bytes * samplingInterval else bytes, // bytes
buf.getUnsignedByte(38).toInt, // proto
buf.getUnsignedByte(39).toInt, // tos
buf.getUnsignedByte(37).toInt, // tcpflags
Some(buf.getUnsignedInteger(24, 4))
.filter(_ != 0)
.map(x => timestamp.minus(Duration.ofMillis(uptime - x))), // start
Some(buf.getUnsignedInteger(28, 4))
.filter(_ != 0)
.map(x => timestamp.minus(Duration.ofMillis(uptime - x))), // stop
buf.getInetAddress(0, 4), // srcAddress
buf.getInetAddress(4, 4), // dstAddress
Option(buf.getInetAddress(8, 4)).filter(_.getHostAddress != "0.0.0.0"), // nextHop
buf.getUnsignedInteger(12, 2).toInt, // snmpInput
buf.getUnsignedInteger(14, 2).toInt, // snmpOutput
buf.getUnsignedByte(44).toInt, // srcMask
buf.getUnsignedByte(45).toInt, // dstMask
fpId
)
}.toOption
}
case class NetFlowV6Packet(id: UUID,
sender: InetSocketAddress,
length: Int,
uptime: Long,
timestamp: LocalDateTime,
flows: List[NetFlowV6],
flowSequence: Long,
engineType: Int,
engineId: Int,
samplingInterval: Int,
samplingMode: Int)
extends FlowPacket {
def version = "NetFlowV6 Packet"
def count = flows.length
}
case class NetFlowV6(id: UUID,
sender: InetSocketAddress,
length: Int,
uptime: Long,
timestamp: LocalDateTime,
srcPort: Int,
dstPort: Int,
srcAS: Option[Int],
dstAS: Option[Int],
pkts: Long,
bytes: Long,
proto: Int,
tos: Int,
tcpflags: Int,
start: Option[LocalDateTime],
stop: Option[LocalDateTime],
srcAddress: InetAddress,
dstAddress: InetAddress,
nextHop: Option[InetAddress],
snmpInput: Int,
snmpOutput: Int,
srcMask: Int,
dstMask: Int,
packet: UUID)
extends NetFlowData[NetFlowV6] {
def version = "NetFlowV6"
}