1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
|
# -*- coding: binary -*-
module PacketFu
# ICMPHeader is a complete ICMP struct, used in ICMPPacket. ICMP is
# typically used for network administration and connectivity testing.
#
# For more on ICMP packets, see
# http://www.networksorcery.com/enp/protocol/icmp.htm
#
# ==== Header Definition
#
# Int8 :icmp_type # Type
# Int8 :icmp_code # Code
# Int16 :icmp_sum Default: calculated # Checksum
# String :body
class ICMPHeader < Struct.new(:icmp_type, :icmp_code, :icmp_sum, :body)
include StructFu
def initialize(args={})
super(
Int8.new(args[:icmp_type]),
Int8.new(args[:icmp_code]),
Int16.new(args[:icmp_sum] || icmp_calc_sum),
StructFu::String.new.read(args[:body])
)
end
# Returns the object in string form.
def to_s
self.to_a.map {|x| x.to_s}.join
end
# Reads a string to populate the object.
def read(str)
force_binary(str)
return self if str.nil?
self[:icmp_type].read(str[0,1])
self[:icmp_code].read(str[1,1])
self[:icmp_sum].read(str[2,2])
self[:body].read(str[4,str.size])
self
end
# Setter for the type.
def icmp_type=(i); typecast i; end
# Getter for the type.
def icmp_type; self[:icmp_type].to_i; end
# Setter for the code.
def icmp_code=(i); typecast i; end
# Getter for the code.
def icmp_code; self[:icmp_code].to_i; end
# Setter for the checksum. Note, this is calculated automatically with
# icmp_calc_sum.
def icmp_sum=(i); typecast i; end
# Getter for the checksum.
def icmp_sum; self[:icmp_sum].to_i; end
# Calculates and sets the checksum for the object.
def icmp_calc_sum
checksum = (icmp_type.to_i << 8) + icmp_code.to_i
chk_body = (body.to_s.size % 2 == 0 ? body.to_s : body.to_s + "\x00")
if 1.respond_to? :ord
chk_body.split("").each_slice(2).map { |x| (x[0].ord << 8) + x[1].ord }.each { |y| checksum += y }
else
chk_body.split("").each_slice(2).map { |x| (x[0] << 8) + x[1] }.each { |y| checksum += y }
end
checksum = checksum % 0xffff
checksum = 0xffff - checksum
checksum == 0 ? 0xffff : checksum
end
# Recalculates the calculatable fields for ICMP.
def icmp_recalc(arg = :all)
case arg.to_sym
when :icmp_sum
self.icmp_sum=icmp_calc_sum
when :all
self.icmp_sum=icmp_calc_sum
else
raise ArgumentError, "No such field `#{arg}'"
end
end
# Readability aliases
def icmp_sum_readable
"0x%04x" % icmp_sum
end
end
end
|