Class: PacketGen::Packet
- Inherits:
-
Object
- Object
- PacketGen::Packet
- Defined in:
- lib/packetgen/packet.rb
Overview
An object of type Packet handles a network packet. This packet may contain multiple protocol headers, starting from MAC layer or from Network (OSI) layer.
Creating a packet is fairly simple:
Packet.gen 'IP', src: '192.168.1.1', dst: '192.168.1.2'
Create a packet
Packets may be hand-made or parsed from a binary string:
Packet.gen('IP', src: '192.168.1.1', dst: '192.168.1.2').add('UDP', sport: 45000, dport: 23)
Packet.parse(binary_string)
Access packet information
pkt = Packet.gen('IP').add('UDP')
# read information
pkt.udp.sport
pkt.ip.ttl
# set information
pkt.udp.dport = 2323
pkt.ip.ttl = 1
pkt.ip(ttl: 1, id: 1234)
Save a packet to a file
pkt.write('file.pcapng')
Get packets
Packets may be captured from wire:
Packet.capture do |packet|
do_some_stuffs
end
packets = Packet.capture(iface: 'eth0', max: 5) # get 5 packets from eth0
Packets may also be read from a file:
packets = Packet.read(file.pcapng)
Save packets to a file
Packet.write 'file.pcapng', packets
Instance Attribute Summary collapse
-
#headers ⇒ Array<Header::Base]
readonly
Array<Header::Base].
Class Method Summary collapse
-
.capture(options = {}) {|packet| ... } ⇒ Array<Packet>
Capture packets.
-
.gen(protocol, options = {}) ⇒ Packet
Create a new Packet.
-
.parse(binary_str, first_header: nil) ⇒ Packet
Parse a binary string and generate a Packet from it.
-
.read(filename) ⇒ Array<Packet>
Read packets from
filename. -
.write(filename, packets) ⇒ void
Write packets to
filename.
Instance Method Summary collapse
- #==(other) ⇒ Boolean
-
#add(protocol, options = {}) ⇒ self
Add a protocol on packet stack.
-
#body ⇒ Types
Get packet body.
-
#body=(str) ⇒ void
Set packet body.
-
#calc ⇒ void
Recalculate all calculatable fields (for now: length and checksum).
-
#calc_checksum ⇒ void
Recalculate all packet checksums.
-
#calc_length ⇒ void
Recalculate all packet length fields.
-
#decapsulate(*headers) ⇒ self
Remove headers from
self. -
#encapsulate(other) ⇒ self
Encapulate another packet in
self. -
#initialize ⇒ Packet
constructor
A new instance of Packet.
- #inspect ⇒ String
-
#is?(protocol) ⇒ Boolean
Check if a protocol header is embedded in packet.
-
#parse(binary_str, first_header: nil) ⇒ Packet
Parse a binary string and populate Packet from it.
-
#to_f(filename) ⇒ Array
(also: #write)
Write a PCapNG file to disk.
-
#to_s ⇒ String
Get binary string.
-
#to_w(iface = nil) ⇒ void
send packet on wire.
Constructor Details
#initialize ⇒ Packet
Returns a new instance of Packet.
128 129 130 |
# File 'lib/packetgen/packet.rb', line 128 def initialize @headers = [] end |
Instance Attribute Details
#headers ⇒ Array<Header::Base] (readonly)
Returns Array<Header::Base].
50 51 52 |
# File 'lib/packetgen/packet.rb', line 50 def headers @headers end |
Class Method Details
.capture(options = {}) {|packet| ... } ⇒ Array<Packet>
Capture packets
84 85 86 87 88 89 90 91 92 |
# File 'lib/packetgen/packet.rb', line 84 def self.capture(={}) capture = Capture.new() if block_given? capture.start { |packet| yield packet } else capture.start end capture.packets end |
.gen(protocol, options = {}) ⇒ Packet
Create a new Packet
56 57 58 |
# File 'lib/packetgen/packet.rb', line 56 def self.gen(protocol, ={}) self.new.add protocol, end |
.parse(binary_str, first_header: nil) ⇒ Packet
69 70 71 |
# File 'lib/packetgen/packet.rb', line 69 def self.parse(binary_str, first_header: nil) new.parse binary_str, first_header: first_header end |
.read(filename) ⇒ Array<Packet>
Read packets from filename.
For more control, see PacketGen::PcapNG::File or PCAPRUB::Pcap.
101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/packetgen/packet.rb', line 101 def self.read(filename) begin PcapNG::File.new.read_packets filename rescue => e raise ArgumentError, e unless File.extname(filename.downcase) == '.pcap' packets = [] PCAPRUB::Pcap.open_offline(filename).each_packet do |packet| next unless packet = PacketGen.parse(packet.to_s) packets << packet end packets end end |
.write(filename, packets) ⇒ void
This method returns an undefined value.
Write packets to filename
For more options, see PacketGen::PcapNG::File.
121 122 123 124 125 |
# File 'lib/packetgen/packet.rb', line 121 def self.write(filename, packets) pf = PcapNG::File.new pf.array_to_file packets pf.to_f filename end |
Instance Method Details
#==(other) ⇒ Boolean
281 282 283 |
# File 'lib/packetgen/packet.rb', line 281 def ==(other) to_s == other.to_s end |
#add(protocol, options = {}) ⇒ self
Add a protocol on packet stack
137 138 139 140 141 142 143 |
# File 'lib/packetgen/packet.rb', line 137 def add(protocol, ={}) klass = check_protocol(protocol) header = klass.new() add_header header self end |
#body ⇒ Types
Get packet body
178 179 180 |
# File 'lib/packetgen/packet.rb', line 178 def body @headers.last.body if @headers.last.respond_to? :body end |
#body=(str) ⇒ void
This method returns an undefined value.
Set packet body
185 186 187 |
# File 'lib/packetgen/packet.rb', line 185 def body=(str) @headers.last.body = str end |
#calc ⇒ void
This method returns an undefined value.
Recalculate all calculatable fields (for now: length and checksum)
171 172 173 174 |
# File 'lib/packetgen/packet.rb', line 171 def calc calc_length calc_checksum end |
#calc_checksum ⇒ void
This method returns an undefined value.
Recalculate all packet checksums
155 156 157 158 159 |
# File 'lib/packetgen/packet.rb', line 155 def calc_checksum @headers.reverse.each do |header| header.calc_checksum if header.respond_to? :calc_checksum end end |
#calc_length ⇒ void
This method returns an undefined value.
Recalculate all packet length fields
163 164 165 166 167 |
# File 'lib/packetgen/packet.rb', line 163 def calc_length @headers.each do |header| header.calc_length if header.respond_to? :calc_length end end |
#decapsulate(*headers) ⇒ self
Remove headers from self
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/packetgen/packet.rb', line 231 def decapsulate(*headers) headers.each do |header| idx = @headers.index(header) raise FormatError, 'header not in packet!' if idx.nil? prev_header = idx > 0 ? @headers[idx - 1] : nil next_header = (idx+1) < @headers.size ? @headers[idx + 1] : nil @headers.delete_at(idx) if prev_header and next_header add_header(next_header, previous_header: prev_header) end end rescue ArgumentError => ex raise FormatError, ex. end |
#encapsulate(other) ⇒ self
Encapulate another packet in self
221 222 223 |
# File 'lib/packetgen/packet.rb', line 221 def encapsulate(other) other.headers.each { |h| add_header h } end |
#inspect ⇒ String
271 272 273 274 275 276 277 |
# File 'lib/packetgen/packet.rb', line 271 def inspect str = Inspect.dashed_line(self.class) @headers.each do |header| str << header.inspect end str << Inspect.inspect_body(body) end |
#is?(protocol) ⇒ Boolean
Check if a protocol header is embedded in packet
148 149 150 151 |
# File 'lib/packetgen/packet.rb', line 148 def is?(protocol) klass = check_protocol protocol @headers.any? { |h| h.is_a? klass } end |
#parse(binary_str, first_header: nil) ⇒ Packet
Parse a binary string and populate Packet from it.
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/packetgen/packet.rb', line 252 def parse(binary_str, first_header: nil) @headers.clear if first_header.nil? # No decoding forced for first header. Have to guess it! first_header = guess_first_header(binary_str) if first_header.nil? raise ParseError, 'cannot identify first header in string' end end add first_header @headers[-1, 1] = @headers.last.read(binary_str) # Decode upper headers recursively decode_bottom_up self end |
#to_f(filename) ⇒ Array Also known as: write
Write a PCapNG file to disk.
199 200 201 |
# File 'lib/packetgen/packet.rb', line 199 def to_f(filename) File.new.array_to_file(filename: filename, array: [self]) end |
#to_s ⇒ String
Get binary string
191 192 193 |
# File 'lib/packetgen/packet.rb', line 191 def to_s @headers.first.to_s end |
#to_w(iface = nil) ⇒ void
This method returns an undefined value.
send packet on wire. Use first header #to_w method.
207 208 209 210 211 212 213 214 215 |
# File 'lib/packetgen/packet.rb', line 207 def to_w(iface=nil) iface ||= PacketGen.default_iface if @headers.first.respond_to? :to_w @headers.first.to_w(iface) else type = @headers.first.protocol_name raise WireError, "don't known how to send a #{type} packet on wire" end end |