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
Constant Summary collapse
- INSPECT_MAX_WIDTH =
70
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 sum).
-
#calc_length ⇒ void
Recalculate all packet length fields.
-
#calc_sum ⇒ void
Recalculate all packet checksums.
-
#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.
152 153 154 |
# File 'lib/packetgen/packet.rb', line 152 def initialize @headers = [] end |
Instance Attribute Details
#headers ⇒ Array<Header::Base] (readonly)
Returns Array<Header::Base].
43 44 45 |
# File 'lib/packetgen/packet.rb', line 43 def headers @headers end |
Class Method Details
.capture(iface, options = {}) {|packet| ... } ⇒ Array<Packet>
Capture packets from iface
120 121 122 123 124 125 126 127 128 |
# File 'lib/packetgen/packet.rb', line 120 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
52 53 54 |
# File 'lib/packetgen/packet.rb', line 52 def self.gen(protocol, ={}) self.new.add protocol, end |
.parse(binary_str, first_header: nil) ⇒ Packet
Parse a binary string and generate a Packet from it.
# auto-detect first header
Packet.parse str
# force decoding a Ethernet header for first header
Packet.parse str, first_header: 'Eth'
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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/packetgen/packet.rb', line 65 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, binding| if hdr.send(binding.key) == binding.value first_header = hklass.to_s.gsub(/.*::/, '') break 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, 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 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.
135 136 137 |
# File 'lib/packetgen/packet.rb', line 135 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.
145 146 147 148 149 |
# File 'lib/packetgen/packet.rb', line 145 def self.write(filename, packets) pf = PcapNG::File.new pf.array_to_file packets pf.to_f filename end |
Instance Method Details
#==(other) ⇒ Boolean
274 275 276 |
# File 'lib/packetgen/packet.rb', line 274 def ==(other) to_s == other.to_s end |
#add(protocol, options = {}) ⇒ self
Add a protocol on packet stack
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/packetgen/packet.rb', line 161 def add(protocol, ={}) klass = check_protocol(protocol) header = klass.new() prev_header = @headers.last if prev_header binding = prev_header.class.known_headers[klass] if binding.nil? msg = "#{prev_header.class} knowns no layer association with #{protocol}. " msg << "Try #{prev_header.class}.bind_layer(PacketGen::Header::#{protocol}, " msg << "#{prev_header.class.to_s.gsub(/(.*)::/, '').downcase}_proto_field: " msg << "value_for_#{protocol.downcase})" raise ArgumentError, msg end prev_header[binding.key].read binding.value prev_header.body = header end header.packet = self @headers << header unless respond_to? protocol.downcase self.class.class_eval "def #{protocol.downcase}(arg=nil);" \ "header('#{protocol}', arg); end" end self end |
#body ⇒ StructFu
Get packet body
220 221 222 |
# File 'lib/packetgen/packet.rb', line 220 def body @headers.last.body end |
#body=(str) ⇒ void
This method returns an undefined value.
Set packet body
227 228 229 |
# File 'lib/packetgen/packet.rb', line 227 def body=(str) @headers.last.body = str end |
#calc ⇒ void
This method returns an undefined value.
Recalculate all calculatable fields (for now: length and sum)
213 214 215 216 |
# File 'lib/packetgen/packet.rb', line 213 def calc calc_length calc_sum end |
#calc_length ⇒ void
This method returns an undefined value.
Recalculate all packet length fields
205 206 207 208 209 |
# File 'lib/packetgen/packet.rb', line 205 def calc_length @headers.each do |header| header.calc_length if header.respond_to? :calc_length end end |
#calc_sum ⇒ void
This method returns an undefined value.
Recalculate all packet checksums
197 198 199 200 201 |
# File 'lib/packetgen/packet.rb', line 197 def calc_sum @headers.reverse.each do |header| header.calc_sum if header.respond_to? :calc_sum end end |
#inspect ⇒ String
260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/packetgen/packet.rb', line 260 def inspect str = dashed_line(self.class) @headers.each do |header| str << dashed_line(header.class, 2) header.to_h.each do |attr, value| next if attr == :body str << inspect_line(attr, value, 2) end end str << inspect_body end |
#is?(protocol) ⇒ Boolean
Check if a protocol header is embedded in packet
190 191 192 193 |
# File 'lib/packetgen/packet.rb', line 190 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.
241 242 243 |
# File 'lib/packetgen/packet.rb', line 241 def to_f(filename) File.new.array_to_file(filename: filename, array: [self]) end |
#to_s ⇒ String
Get binary string
233 234 235 |
# File 'lib/packetgen/packet.rb', line 233 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.
249 250 251 252 253 254 255 256 257 |
# File 'lib/packetgen/packet.rb', line 249 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.class.to_s.gsub(/.*::/, '') raise WireError, "don't known how to send a #{type} packet on wire" end end |