111 lines
3.0 KiB
Ruby
111 lines
3.0 KiB
Ruby
|
|
module PacketFu
|
|
|
|
# The Write class facilitates writing to libpcap files, which is the native file format
|
|
# for packet capture utilities such as tcpdump, Wireshark, and PacketFu::PcapFile.
|
|
#
|
|
# == Example
|
|
#
|
|
# cap = PacketFu::Capture.new(:start => true)
|
|
# sleep 10
|
|
# cap.save
|
|
# pkt_array = cap.array
|
|
# PacketFu::Write.a2f(:file => 'pcaps/my_capture.pcap', :array => pkt_array)
|
|
#
|
|
# === array_to_file() Arguments
|
|
#
|
|
# :filename | :file | :out
|
|
# The file to write to. If it exists, it will be overwritten. By default, no file will be written.
|
|
#
|
|
# :array | arr
|
|
# The array to read packet data from. Note, these should be strings, and not packet objects!
|
|
#
|
|
# :ts | :timestamp
|
|
# The starting timestamp. By default, it is the result of Time.now.to_i
|
|
#
|
|
# :ts_inc | :timestamp_increment
|
|
# The timestamp increment, in seconds. (Sorry, no usecs yet)
|
|
#
|
|
# == See Also
|
|
#
|
|
# Read, Capture
|
|
class Write
|
|
|
|
# Writes an array of binary data to a libpcap file.
|
|
def self.array_to_file(args={})
|
|
filename = args[:filename] || args[:file] || args[:out] || :nowrite
|
|
arr = args[:arr] || args[:array] || []
|
|
ts = args[:ts] || args[:timestamp] || Time.now.to_i
|
|
ts_inc = args[:ts_inc] || args[:timestamp_increment] || 1
|
|
|
|
if arr.class != Array
|
|
raise ArgumentError, "This needs to be an array."
|
|
end
|
|
|
|
formatted_packets = []
|
|
arr.each do |pkt|
|
|
this_pkt = PcapPacket.new
|
|
this_pkt.data = pkt[0,0xffff]
|
|
this_pkt.orig_len = pkt.size # orig_len isn't calc'ed already.
|
|
this_pkt.ts_sec = ts += decimal_to_usecs(ts_inc)[0]
|
|
formatted_packets << this_pkt.to_s
|
|
end
|
|
filedata = PcapFile.new
|
|
filedata.read(PcapFile.new.to_s + formatted_packets.join) # Like a cat playing the bass.
|
|
|
|
if filename != :nowrite
|
|
out = File.new(filename.to_s, 'w')
|
|
out.print filedata
|
|
out.close
|
|
# Return [filename, file size, # of packets, initial timestamp, timestamp increment]
|
|
ret = [filename,filedata.to_s.size,arr.size,ts,ts_inc]
|
|
else
|
|
ret = [nil,filedata.to_s.size,arr.size,ts,ts_inc]
|
|
end
|
|
|
|
end
|
|
def self.append(args={})
|
|
file = args[:file] || args[:out] || :nowrite
|
|
pkt = args[:packet] || args[:pkt] || nil
|
|
ts = args[:ts] || args[:timestamp] || Time.now.to_i
|
|
if (file == :nowrite)
|
|
return false
|
|
end
|
|
if (!file.kind_of?(File))
|
|
file = File.new(file, "a")
|
|
end
|
|
|
|
pc_pkt = PcapPacket.new
|
|
pc_pkt.data = pkt.to_s[0,0xffff]
|
|
pc_pkt.orig_len = pkt.size
|
|
pc_pkt.ts_sec = decimal_to_usecs(ts)[0]
|
|
file.print(pc_pkt.to_s)
|
|
|
|
return pc_pkt.to_s.size
|
|
end
|
|
|
|
|
|
# A synonym for array_to_file()
|
|
def self.a2f(args={})
|
|
self.array_to_file(args)
|
|
end
|
|
|
|
# TODO: Wire this in later to enable incrementing by microseconds.
|
|
def self.decimal_to_usecs(decimal)
|
|
secs = decimal.to_i
|
|
usecs = decimal.to_f.to_s.split('.')[1]
|
|
[secs,usecs]
|
|
end
|
|
|
|
# IRB tab-completion hack.
|
|
def truth
|
|
"Stranger than fiction" ; true
|
|
end
|
|
#:stopdoc:
|
|
alias_method :array_to_file, :truth
|
|
alias_method :a2f, :truth
|
|
#:startdoc:
|
|
|
|
end
|
|
end
|