All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.netflow.flows.cflow.NetFlowV1.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 scala.util.{Failure, Try}

/**
  * NetFlow Version 1
  *
  * *-------*---------------*------------------------------------------------------*
  * | 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             |
  * *-------*---------------*------------------------------------------------------*
  */
object NetFlowV1Packet {
  private val headerSize = 16
  private val flowSize = 48

  /**
    * Parse a Version 1 FlowPacket
    *
    * @param sender The sender's InetSocketAddress
    * @param buf Netty ByteBuf containing the UDP Packet
    */
  def apply(sender: InetSocketAddress, buf: ByteBuf): Try[NetFlowV1Packet] = Try[NetFlowV1Packet] {
    val version = buf.getUnsignedInteger(0, 2).toInt
    if (version != 1) 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 flows: List[NetFlowV1] = (0 to count - 1).toList.flatMap { i =>
      apply(sender, buf.slice(headerSize + (i * flowSize), flowSize), id, uptime, timestamp)
    }
    NetFlowV1Packet(id, sender, buf.readableBytes, uptime, timestamp, flows)
  }

  /**
    * Parse a Version 1 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
    */
  def apply(sender: InetSocketAddress,
            buf: ByteBuf,
            fpId: UUID,
            uptime: Long,
            timestamp: LocalDateTime): Option[NetFlowV1] =
    Try[NetFlowV1] {
      NetFlowV1(
        UUIDs.timeBased(),
        sender,
        buf.readableBytes(),
        uptime,
        timestamp,
        buf.getUnsignedInteger(32, 2).toInt, // srcPort
        buf.getUnsignedInteger(34, 2).toInt, // dstPort
        None,
        None, // srcAS and dstAS
        buf.getUnsignedInteger(16, 4), // pkts
        buf.getUnsignedInteger(20, 4), // bytes
        buf.getUnsignedByte(38).toInt, // proto
        buf.getUnsignedByte(39).toInt, // tos
        buf.getUnsignedByte(40).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
        fpId
      )
    }.toOption
}

case class NetFlowV1Packet(id: UUID,
                           sender: InetSocketAddress,
                           length: Int,
                           uptime: Long,
                           timestamp: LocalDateTime,
                           flows: List[NetFlowV1])
    extends FlowPacket {
  def version = "NetFlowV1 Packet"
  def count = flows.length
}

case class NetFlowV1(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,
                     packet: UUID)
    extends NetFlowData[NetFlowV1] {
  def version = "NetFlowV1"
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy