Class: PacketGen::Header::TFTP

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

Overview

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

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

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   # => PacketGen::Header::TFTP

TFTP attributes

tftp.opcode = 'RRQ'
tftp.opcode = 1
tftp.body.read 'this is a body'

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

Author:

  • Sylvain Daubert

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

Methods inherited from Types::Fields

#[], #[]=, #bits_on, define_bit_fields_on, define_field, define_field_after, define_field_before, #fields, fields, inherited, #inspect, #offset_of, #optional?, #optional_fields, #present?, remove_bit_fields_on, remove_field, #sz, #to_h, #to_s, update_field

Constructor Details

#initialize(options = {}) ⇒ TFTP

Returns a new instance of TFTP.

Since:

  • 2.3.0



68
69
70
71
72
73
74
75
76
# File 'lib/packetgen/header/tftp.rb', line 68

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

Returns:

  • (String)


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

define_field :body, Types::String

#opcodeInteger

16-bit operation code

Returns:

  • (Integer)


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

define_field :opcode, Types::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



131
132
133
134
135
# File 'lib/packetgen/header/tftp.rb', line 131

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



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/packetgen/header/tftp.rb', line 101

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



122
123
124
# File 'lib/packetgen/header/tftp.rb', line 122

def human_opcode
  self[:opcode].to_human
end

#old_readObject

Since:

  • 2.3.0



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

alias old_read read

#read(str) ⇒ TFTP

Populate object from binary string

Parameters:

  • str (String)

Returns:

Since:

  • 2.3.0



84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/packetgen/header/tftp.rb', line 84

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