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('eth0') do |packet|
do_some_stuffs
end
packets = Packet.capture('eth0', max: 5) # get 5 packets
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(iface, options = {}) {|packet| ... } ⇒ Array<Packet>
Capture packets from
iface. -
.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 ⇒ StructFu
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.
-
#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.
160 161 162 |
# File 'lib/packetgen/packet.rb', line 160 def initialize @headers = [] end |
Instance Attribute Details
#headers ⇒ Array<Header::Base] (readonly)
Returns Array<Header::Base].
48 49 50 |
# File 'lib/packetgen/packet.rb', line 48 def headers @headers end |
Class Method Details
.capture(iface, options = {}) {|packet| ... } ⇒ Array<Packet>
Capture packets from iface
128 129 130 131 132 133 134 135 136 |
# File 'lib/packetgen/packet.rb', line 128 def self.capture(iface, ={}) capture = Capture.new(iface, ) if block_given? capture.start { |packet| yield packet } else capture.start end capture.packets end |
.gen(protocol, options = {}) ⇒ Packet
Create a new Packet
54 55 56 |
# File 'lib/packetgen/packet.rb', line 54 def self.gen(protocol, ={}) self.new.add protocol, end |
.parse(binary_str, first_header: nil) ⇒ Packet
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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/packetgen/packet.rb', line 67 def self.parse(binary_str, first_header: nil) pkt = new if first_header.nil? # No decoding forced for first header. Have to guess it! Header.all.each do |hklass| hdr = hklass.new hdr.read binary_str # First header is found when: # * for one known header, # * it exists a known binding with a upper header hklass.known_headers.each do |nh, bindings| bindings.each do |binding| if hdr.send(binding.key) == binding.value first_header = hklass.to_s.gsub(/.*::/, '') break end break unless first_header.nil? end end break unless first_header.nil? end if first_header.nil? raise ParseError, 'cannot identify first header in string' end end pkt.add(first_header) pkt.headers.last.read binary_str # Decode upper headers recursively decode_packet_bottom_up = true while decode_packet_bottom_up do last_known_hdr = pkt.headers.last last_known_hdr.class.known_headers.each do |nh, bindings| bindings.each do |binding| if last_known_hdr.send(binding.key) == binding.value str = last_known_hdr.body pkt.add nh.to_s.gsub(/.*::/, '') pkt.headers.last.read str break end end break unless last_known_hdr == pkt.headers.last end decode_packet_bottom_up = (pkt.headers.last != last_known_hdr) end pkt end |
.read(filename) ⇒ Array<Packet>
Read packets from filename.
For more control, see PacketGen::PcapNG::File.
143 144 145 |
# File 'lib/packetgen/packet.rb', line 143 def self.read(filename) PcapNG::File.new.read_packets filename end |
.write(filename, packets) ⇒ void
This method returns an undefined value.
Write packets to filename
For more options, see PacketGen::PcapNG::File.
153 154 155 156 157 |
# File 'lib/packetgen/packet.rb', line 153 def self.write(filename, packets) pf = PcapNG::File.new pf.array_to_file packets pf.to_f filename end |
Instance Method Details
#==(other) ⇒ Boolean
288 289 290 |
# File 'lib/packetgen/packet.rb', line 288 def ==(other) to_s == other.to_s end |
#add(protocol, options = {}) ⇒ self
Add a protocol on packet stack
169 170 171 172 173 174 175 |
# File 'lib/packetgen/packet.rb', line 169 def add(protocol, ={}) klass = check_protocol(protocol) header = klass.new() add_header header self end |
#body ⇒ StructFu
Get packet body
210 211 212 |
# File 'lib/packetgen/packet.rb', line 210 def body @headers.last.body end |
#body=(str) ⇒ void
This method returns an undefined value.
Set packet body
217 218 219 |
# File 'lib/packetgen/packet.rb', line 217 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)
203 204 205 206 |
# File 'lib/packetgen/packet.rb', line 203 def calc calc_length calc_checksum end |
#calc_checksum ⇒ void
This method returns an undefined value.
Recalculate all packet checksums
187 188 189 190 191 |
# File 'lib/packetgen/packet.rb', line 187 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
195 196 197 198 199 |
# File 'lib/packetgen/packet.rb', line 195 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
263 264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/packetgen/packet.rb', line 263 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) add_header(next_header, prev_header) if prev_header and next_header end rescue ArgumentError => ex raise FormatError, ex. end |
#encapsulate(other) ⇒ self
Encapulate another packet in self
253 254 255 |
# File 'lib/packetgen/packet.rb', line 253 def encapsulate(other) other.headers.each { |h| add_header h } end |
#inspect ⇒ String
278 279 280 281 282 283 284 |
# File 'lib/packetgen/packet.rb', line 278 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
180 181 182 183 |
# File 'lib/packetgen/packet.rb', line 180 def is?(protocol) klass = check_protocol protocol @headers.any? { |h| h.is_a? klass } end |
#to_f(filename) ⇒ Array Also known as: write
Write a PCapNG file to disk.
231 232 233 |
# File 'lib/packetgen/packet.rb', line 231 def to_f(filename) File.new.array_to_file(filename: filename, array: [self]) end |
#to_s ⇒ String
Get binary string
223 224 225 |
# File 'lib/packetgen/packet.rb', line 223 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.
239 240 241 242 243 244 245 246 247 |
# File 'lib/packetgen/packet.rb', line 239 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 |