Class: PacketGen::Header::TFTP

Inherits:
Base
  • Object
show all
Defined in:
lib/packetgen/header/tftp.rb

Overview

A TFTP (Trivial File Transfer Protocol, RFC 1350) header consists of:

  • an #opcode (BinStruct::Int16Enum),

  • and a body. Its content depends on opcode.

Specialized subclasses exists to handle Read Request, Write Request, DATA, ACK and ERROR packets.

TFTP parsing

When parsing, only first packet (read or write request) should be decoded as TFTP packet, as others uses custom UDP ports.

So, to decode subsequent TFTP packets, a method #decode! is provided for this purpose. This method takes a single array argument. This array should contain all subsequent TFTP packets (others packet types may also be included in this array: they won’t be modified). #decode! will modify array in-place by replacing UDP packets by TFTP ones (if decoded as TFTP packets):

# packets is an array of packets: TFTP::RRQ, UDP (should be TFTP::DATA), UDP (not a TFTP packet) and UDP (TFTP::ACK)
packets.map { |pkt| pkt.headers.last.class.to_s }.join(',')  # => TFTP::RRQ,UDP,UDP,UDP
# Here, decoding TFTP packets
packets[0].tftp.decode!(packets[1..-1])
packets.map { |pkt| pkt.headers.last.class.to_s }.join(',')  # => TFTP::RRQ,TFTP::DATA,UDP,TFTP::ACK

Examples:

Create a TFTP header

# standalone
tftp = PacketGen::Header::TFTP.new
# in a packet
pkt = PacketGen.gen('IP').add('UDP').add('TFTP')
# access to TFTP header
pkt.tftp.class   # => PacketGen::Header::TFTP

TFTP attributes

tftp = PacketGen::Header::TFTP.new
tftp.opcode = 'RRQ'
tftp.opcode = 1
tftp.body = 'this is a body'

Author:

  • Sylvain Daubert

  • LemonTree55

Since:

  • 2.3.0

Direct Known Subclasses

ACK, DATA, ERROR, RRQ

Defined Under Namespace

Classes: ACK, DATA, ERROR, RRQ, WRQ

Constant Summary collapse

OPCODES =

Known opcodes

Since:

  • 2.3.0

{
  'RRQ' => 1,
  'WRQ' => 2,
  'DATA' => 3,
  'ACK' => 4,
  'Error' => 5
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Base

bind, calculate_and_set_length, #header_id, inherited, #ip_header, #ll_header

Methods included from PacketGen::Headerable

included, #method_name, #packet, #packet=, #parse?, #protocol_name, #to_s

Constructor Details

#initialize(options = {}) ⇒ TFTP

Returns a new instance of TFTP.

Since:

  • 2.3.0


72
73
74
75
76
77
78
79
80
# File 'lib/packetgen/header/tftp.rb', line 72

def initialize(options={})
  type = protocol_name.sub(/^.*::/, '')
  opcode = OPCODES[type]
  if (self.class != TFTP) && !opcode.nil?
    super({ opcode: opcode }.merge(options))
  else
    super
  end
end

Instance Attribute Details

#bodyString, Headerable

TFTP body, if opcode is unknown

Returns:


70
# File 'lib/packetgen/header/tftp.rb', line 70

define_attr :body, BinStruct::String

#opcodeInteger

16-bit operation code

Returns:

  • (Integer)

65
# File 'lib/packetgen/header/tftp.rb', line 65

define_attr :opcode, BinStruct::Int16Enum, enum: OPCODES

Instance Method Details

#added_to_packet(packet) ⇒ void

This method returns an undefined value.

Callback called when a TFTP header is added to a packet Here, add #tftp method as a shortcut to existing #tftp(rrq|wrq|data|ack|error).

Parameters:

Since:

  • 2.3.0


135
136
137
138
139
# File 'lib/packetgen/header/tftp.rb', line 135

def added_to_packet(packet)
  return if packet.respond_to?(:tftp)

  packet.instance_eval("def tftp(arg=nil); header(#{self.class}, arg); end") # def tftp(arg=nil); header(TFTP, arg); end
end

#decode!(ary) ⇒ void

This method returns an undefined value.

Decode subsequent TFTP packets to this one. Packets are modified in place in ary.

Parameters:

Since:

  • 2.3.0


105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/packetgen/header/tftp.rb', line 105

def decode!(ary)
  client_tid = packet.udp.sport
  server_tid = nil
  ary.each do |pkt|
    next unless pkt.is?('UDP')

    if server_tid.nil?
      next unless pkt.udp.dport == client_tid

      server_tid = pkt.udp.sport
    else
      tids = [server_tid, client_tid]
      ports = [pkt.udp.sport, pkt.udp.dport]
      next unless (tids - ports).empty?
    end
    decode_tftp_packet(pkt)
  end
end

#human_opcodeString

Get human readable opcode

Returns:

  • (String)

Since:

  • 2.3.0


126
127
128
# File 'lib/packetgen/header/tftp.rb', line 126

def human_opcode
  self[:opcode].to_human
end

#old_readObject

Since:

  • 2.3.0


83
# File 'lib/packetgen/header/tftp.rb', line 83

alias old_read read

#read(str) ⇒ TFTP

Populate object from binary string

Parameters:

  • str (String)

Returns:

Since:

  • 2.3.0


88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/packetgen/header/tftp.rb', line 88

def read(str)
  if self.instance_of? TFTP
    super
    if OPCODES.value?(opcode)
      TFTP.const_get(human_opcode).new.read(str)
    else
      self
    end
  else
    old_read(str)
  end
end