metasploit-framework/lib/scruby/packet.rb

218 lines
4.9 KiB
Ruby
Executable File

#!/usr/bin/env ruby
# Copyright (C) 2007 Sylvain SARMEJEANNE
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2.
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
module Scruby
class Packet
attr_accessor :layers_list
# Constructor
def initialize(arg1, arg2)
# List of layers
@layers_list = []
# There are two cases for the arguments:
# 1) arg1 is a string to dissect and arg2 the wanted dissector
# 2) arg1 and arg2 are layers to bind together.
# First case
if arg1.is_a?(String) and arg2.is_a?(String)
# Getting the dissector from its string
dis = Scruby.get_dissector(arg2)
return if not dis
# These variables are used in the loop below.
remain = arg1
begin
# Creating a new layer and adding it to the current packet
new_layer = dis.new(remain)
@layers_list.push(new_layer)
# Preparing the remaining string for the next loop
remain = new_layer.tobedecoded
# If the upper layer was guessed by the new layer
if not new_layer.guesses[0].nil?
# In this version, only the first guess is considered.
dis = new_layer.guesses[0]
# Else, it is considered as raw data.
else
dis = Raw
end
end until remain.length == 0
# Second case
else
@layers_list = [arg1, arg2].flatten
end
end
def /(upper)
return Packet./(self, upper)
end
# Add a layer/packet/some raw data on top of a layer/packet/some raw data
def Packet./(lower, upper)
# Transforms a string into a Raw layer. This allows
# "IP()/"GET HTTP 1.0\r\n\r\n".
lower = Raw.new(:load=>lower) if lower.is_a?(String)
upper = Raw.new(:load=>upper) if upper.is_a?(String)
# Packet/Layer
if lower.instance_of?(Packet) and not upper.instance_of?(Packet)
return Packet.new(lower.layers_list, upper)
# Packet/Packet
elsif lower.instance_of?(Packet) and upper.instance_of?(Packet)
return Packet.new(lower.layers_list, upper.layers_list)
# Layer/Packet
elsif not lower.instance_of?(Packet) and upper.instance_of?(Packet)
return Packet.new(lower, upper.layers_list)
# Layer/Layer
elsif not lower.instance_of?(Packet) and not upper.instance_of?(Packet)
return Packet.new(lower, upper)
end
end
# Converts an object to a string
def to_s
out = ''
@layers_list.each do |layer|
out += layer.to_s
end
return out
end
# Displays the packet with more details than tostring
def show
out = ''
@layers_list.each do |layer|
out += layer.show + "\n"
end
return out
end
# Returns the string ready to be sent on the wire
def to_net
out = ''
payload = ''
underlayer = nil
@layers_list.each do |layer|
# Only some protocols need to be aware of upper layers
if Scruby.aware_proto.include?(layer.protocol)
payload = self.get_payload(layer)
end
layer.pre_send(underlayer, payload)
out += layer.to_net()
underlayer = layer
payload = ''
end
return out
end
# Returns the payload of a layer
def get_payload(layer_arg = self)
payload = ''
concat = false
@layers_list.each do |layer|
if layer == layer_arg
concat = true
elsif concat == true
payload += layer.to_net()
end
end
return payload
end
# Return the first layer of this type with its payload
def get_layer(wanted_layer)
mylayer = nil
# Get the index of the first occurance of this layer
@layers_list.each do |layer|
if layer.class == wanted_layer
mylayer = layer
end
end
# No occurance was found
return if mylayer.nil?
# Getting the index of the wanted layer
index = @layers_list.index(mylayer)
# Returning a packet contains all layers, beginning at the wanted layer
return Packet.new(@layers_list[index..-1], nil)
end
# Return the first layer of this type with its payload
# Differs from get_layer() in that it returns the layer not the packet object
def layer(wanted_layer)
ret = get_layer(wanted_layer)
ret.layers_list[0]
end
# Checks wether the packet has a given layer
def has_layer(wanted_layer)
return (not self.get_layer(wanted_layer).nil?)
end
# Returns the last layer of the packet
def last_layer
return @layers_list[-1]
end
# Decode the raw data with the given dissector
def decode_payload_as(dissector)
last = self.last_layer
# Applying this function doesn't make sense if Raw isn't the last layer
return if last.class.to_s.split('::')[1] != 'Raw'
# Building a new packet from the Raw payload with the given dissector
p = Packet.new(last.load, dissector.to_s.split('::')[1])
# Removing the Raw layer from the original packet
@layers_list.pop
# Binding the new packet over the original packet
@layers_list.concat(p.layers_list)
end
end
end