ICMP network packet: Nim parsing library

KS implementation details

License: CC0-1.0

References

This page hosts a formal specification of ICMP network packet using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Nim source code to parse ICMP network packet

icmp_packet.nim

import kaitai_struct_nim_runtime
import options

type
  IcmpPacket* = ref object of KaitaiStruct
    `icmpType`*: IcmpPacket_IcmpTypeEnum
    `destinationUnreachable`*: IcmpPacket_DestinationUnreachableMsg
    `timeExceeded`*: IcmpPacket_TimeExceededMsg
    `echo`*: IcmpPacket_EchoMsg
    `parent`*: KaitaiStruct
  IcmpPacket_IcmpTypeEnum* = enum
    echo_reply = 0
    destination_unreachable = 3
    source_quench = 4
    redirect = 5
    echo = 8
    time_exceeded = 11
  IcmpPacket_DestinationUnreachableMsg* = ref object of KaitaiStruct
    `code`*: IcmpPacket_DestinationUnreachableMsg_DestinationUnreachableCode
    `checksum`*: uint16
    `parent`*: IcmpPacket
  IcmpPacket_DestinationUnreachableMsg_DestinationUnreachableCode* = enum
    net_unreachable = 0
    host_unreachable = 1
    protocol_unreachable = 2
    port_unreachable = 3
    fragmentation_needed_and_df_set = 4
    source_route_failed = 5
    dst_net_unkown = 6
    sdt_host_unkown = 7
    src_isolated = 8
    net_prohibited_by_admin = 9
    host_prohibited_by_admin = 10
    net_unreachable_for_tos = 11
    host_unreachable_for_tos = 12
    communication_prohibited_by_admin = 13
    host_precedence_violation = 14
    precedence_cuttoff_in_effect = 15
  IcmpPacket_TimeExceededMsg* = ref object of KaitaiStruct
    `code`*: IcmpPacket_TimeExceededMsg_TimeExceededCode
    `checksum`*: uint16
    `parent`*: IcmpPacket
  IcmpPacket_TimeExceededMsg_TimeExceededCode* = enum
    time_to_live_exceeded_in_transit = 0
    fragment_reassembly_time_exceeded = 1
  IcmpPacket_EchoMsg* = ref object of KaitaiStruct
    `code`*: seq[byte]
    `checksum`*: uint16
    `identifier`*: uint16
    `seqNum`*: uint16
    `data`*: seq[byte]
    `parent`*: IcmpPacket

proc read*(_: typedesc[IcmpPacket], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): IcmpPacket
proc read*(_: typedesc[IcmpPacket_DestinationUnreachableMsg], io: KaitaiStream, root: KaitaiStruct, parent: IcmpPacket): IcmpPacket_DestinationUnreachableMsg
proc read*(_: typedesc[IcmpPacket_TimeExceededMsg], io: KaitaiStream, root: KaitaiStruct, parent: IcmpPacket): IcmpPacket_TimeExceededMsg
proc read*(_: typedesc[IcmpPacket_EchoMsg], io: KaitaiStream, root: KaitaiStruct, parent: IcmpPacket): IcmpPacket_EchoMsg


proc read*(_: typedesc[IcmpPacket], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): IcmpPacket =
  template this: untyped = result
  this = new(IcmpPacket)
  let root = if root == nil: cast[IcmpPacket](this) else: cast[IcmpPacket](root)
  this.io = io
  this.root = root
  this.parent = parent

  let icmpTypeExpr = IcmpPacket_IcmpTypeEnum(this.io.readU1())
  this.icmpType = icmpTypeExpr
  if this.icmpType == icmp_packet.destination_unreachable:
    let destinationUnreachableExpr = IcmpPacket_DestinationUnreachableMsg.read(this.io, this.root, this)
    this.destinationUnreachable = destinationUnreachableExpr
  if this.icmpType == icmp_packet.time_exceeded:
    let timeExceededExpr = IcmpPacket_TimeExceededMsg.read(this.io, this.root, this)
    this.timeExceeded = timeExceededExpr
  if  ((this.icmpType == icmp_packet.echo) or (this.icmpType == icmp_packet.echo_reply)) :
    let echoExpr = IcmpPacket_EchoMsg.read(this.io, this.root, this)
    this.echo = echoExpr

proc fromFile*(_: typedesc[IcmpPacket], filename: string): IcmpPacket =
  IcmpPacket.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[IcmpPacket_DestinationUnreachableMsg], io: KaitaiStream, root: KaitaiStruct, parent: IcmpPacket): IcmpPacket_DestinationUnreachableMsg =
  template this: untyped = result
  this = new(IcmpPacket_DestinationUnreachableMsg)
  let root = if root == nil: cast[IcmpPacket](this) else: cast[IcmpPacket](root)
  this.io = io
  this.root = root
  this.parent = parent

  let codeExpr = IcmpPacket_DestinationUnreachableMsg_DestinationUnreachableCode(this.io.readU1())
  this.code = codeExpr
  let checksumExpr = this.io.readU2be()
  this.checksum = checksumExpr

proc fromFile*(_: typedesc[IcmpPacket_DestinationUnreachableMsg], filename: string): IcmpPacket_DestinationUnreachableMsg =
  IcmpPacket_DestinationUnreachableMsg.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[IcmpPacket_TimeExceededMsg], io: KaitaiStream, root: KaitaiStruct, parent: IcmpPacket): IcmpPacket_TimeExceededMsg =
  template this: untyped = result
  this = new(IcmpPacket_TimeExceededMsg)
  let root = if root == nil: cast[IcmpPacket](this) else: cast[IcmpPacket](root)
  this.io = io
  this.root = root
  this.parent = parent

  let codeExpr = IcmpPacket_TimeExceededMsg_TimeExceededCode(this.io.readU1())
  this.code = codeExpr
  let checksumExpr = this.io.readU2be()
  this.checksum = checksumExpr

proc fromFile*(_: typedesc[IcmpPacket_TimeExceededMsg], filename: string): IcmpPacket_TimeExceededMsg =
  IcmpPacket_TimeExceededMsg.read(newKaitaiFileStream(filename), nil, nil)

proc read*(_: typedesc[IcmpPacket_EchoMsg], io: KaitaiStream, root: KaitaiStruct, parent: IcmpPacket): IcmpPacket_EchoMsg =
  template this: untyped = result
  this = new(IcmpPacket_EchoMsg)
  let root = if root == nil: cast[IcmpPacket](this) else: cast[IcmpPacket](root)
  this.io = io
  this.root = root
  this.parent = parent

  let codeExpr = this.io.readBytes(int(1))
  this.code = codeExpr
  let checksumExpr = this.io.readU2be()
  this.checksum = checksumExpr
  let identifierExpr = this.io.readU2be()
  this.identifier = identifierExpr
  let seqNumExpr = this.io.readU2be()
  this.seqNum = seqNumExpr
  let dataExpr = this.io.readBytesFull()
  this.data = dataExpr

proc fromFile*(_: typedesc[IcmpPacket_EchoMsg], filename: string): IcmpPacket_EchoMsg =
  IcmpPacket_EchoMsg.read(newKaitaiFileStream(filename), nil, nil)