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

io.netflow.flows.cflow.Template.scala Maven / Gradle / Ivy

The newest version!
package io.netflow
package flows.cflow

import java.net.InetSocketAddress
import java.time.LocalDateTime
import java.util.UUID

import io.netflow.lib._
import io.netflow.util.UUIDs
import io.netty.buffer._

import scala.util.{Failure, Try}

abstract class TemplateMeta[T <: Template](implicit m: Manifest[T]) {
  def apply(sender: InetSocketAddress, buf: ByteBuf, fpId: UUID, flowsetId: Int, timestamp: LocalDateTime): Try[T] =
    Try[T] {
      val templateId = buf.getUnsignedShort(0)
      if (!(templateId < 0 || templateId > 255)) // 0-255 reserved for flowset ID
        return Failure(new IllegalTemplateIdException(templateId))

      var map = Map[String, Int]("flowsetId" -> flowsetId)
      var idx, dataFlowSetOffset = 0
      flowsetId match {
        case 0 | 2 =>
          val fieldCount = buf.getUnsignedShort(2)
          var offset = 4
          while (idx < fieldCount) {
            val typeName = buf.getUnsignedShort(offset)
            val typeLen = buf.getUnsignedShort(offset + 2)
            if (typeName < 93 && typeName > 0) {
              map ++= Map("offset_" + typeName -> dataFlowSetOffset, "length_" + typeName -> typeLen)
            }
            dataFlowSetOffset += typeLen
            offset += 4
            idx += 1
          }
        case 1 | 3 =>
          val scopeLen = buf.getUnsignedInteger(2, 2).toInt
          val optionLen = buf.getUnsignedInteger(4, 2).toInt
          var offset = 6
          var curLen = 0
          while (curLen < scopeLen + optionLen) {
            val typeName = buf.getUnsignedShort(offset)
            val scopeBool = if (curLen < scopeLen) 1 else 0
            map ++= Map("scope_" + typeName -> scopeBool)
            val typeLen = buf.getUnsignedShort(offset + 2)
            if (typeName < 93 && typeName > 0) {
              map ++= Map("offset_" + typeName -> dataFlowSetOffset, "length_" + typeName -> typeLen)
            }
            dataFlowSetOffset += typeLen
            offset += 4
            curLen += 4
          }
      }
      map ++= Map("length" -> dataFlowSetOffset)
      this(sender, templateId, fpId, timestamp, map)
    }

  def apply(sender: InetSocketAddress, id: Int, fpId: UUID, timestamp: LocalDateTime, map: Map[String, Int]): T
}

trait Template extends Flow[Template] {
  def versionNumber: Int
  def number: Int
  def map: Map[String, Int]

  lazy val version = "NetFlowV" + versionNumber + { if (isOptionTemplate) "Option" else "" } + "Template " + number
  lazy val arrayMap: Array[String] = map.flatMap(b => Seq(b._1, b._2.toString)).toArray
  def objectMap = map.map(b => (b._1, b._2.toString))

  lazy val length: Int = map.get("length") match {
    case Some(len: Int) => len
    case _              => -1
  }

  lazy val flowsetId: Int = map.get("flowsetId") match {
    case Some(flowsetId: Int) => flowsetId
    case _                    => -1
  }

  lazy val isOptionTemplate = flowsetId == 1 || flowsetId == 3

  def typeOffset(typeName: TemplateFields.Value): Int = map.get("offset_" + typeName.id) match {
    case Some(offset: Int) => offset
    case _                 => -1
  }

  def typeLen(typeName: TemplateFields.Value): Int = map.get("length_" + typeName.id) match {
    case Some(len: Int) => len
    case _              => 0
  }

  def key() = (sender, id)
  def hasField(typeName: TemplateFields.Value): Boolean = map.contains("offset_" + typeName.id)

  import io.netflow.flows.cflow.TemplateFields._
  lazy val hasSrcAS = hasField(SRC_AS)
  lazy val hasDstAS = hasField(DST_AS)
  lazy val hasDirection = hasField(DIRECTION)

  lazy val fields = map.keys.filter(_.startsWith("offset_")).map(b => TemplateFields(b.replace("offset_", "").toInt))

  private val excludeFields = List(
    SRC_AS,
    DST_AS,
    PROT,
    SRC_TOS,
    L4_SRC_PORT,
    L4_DST_PORT,
    IPV4_SRC_ADDR,
    IPV4_DST_ADDR,
    IPV4_NEXT_HOP,
    IPV6_SRC_ADDR,
    IPV6_DST_ADDR,
    IPV6_NEXT_HOP,
    DIRECTION,
    InPKTS,
    OutPKTS,
    InBYTES,
    OutBYTES,
    FIRST_SWITCHED,
    LAST_SWITCHED,
    TCP_FLAGS // SNMP_INPUT, SNMP_OUTPUT, SRC_MASK, DST_MASK
  )

  lazy val extraFields = map.keys
    .filter(_.startsWith("offset_"))
    .flatMap(b => Tryo(TemplateFields(b.replace("offset_", "").toInt)))
    .filterNot(excludeFields.contains)

  def getExtraFields(buf: ByteBuf): Map[String, Long] =
    extraFields.foldRight(Map[String, Long]()) { (field, map) =>
      buf.getUnsignedInteger(this, field) match {
        case Some(v) => map ++ Map(field.toString -> v)
        case _       => map
      }
    }
}

case class NetFlowV9Template(number: Int,
                             sender: InetSocketAddress,
                             packet: UUID,
                             last: LocalDateTime,
                             map: Map[String, Int])
    extends Template {
  val versionNumber = 9
  lazy val id = UUIDs.timeBased()
}

object NetFlowV9Template extends TemplateMeta[NetFlowV9Template] {
  def apply(sender: InetSocketAddress, id: Int, packet: UUID, timestamp: LocalDateTime, map: Map[String, Int]) =
    NetFlowV9Template(id, sender, packet, timestamp, map)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy