Capp::Packet provides convenient extraction of data from packets.
Packet objects are automatically created when a packet is read from the opened interface. Unfortunately Capp does not understand every type of packet. If Capp doesn't understand your packet the layer 3 payload can be retrieved from unknown_layer3_header.
If Capp doesn't understand your packets you can extract the data by editing capp.c and submitting a patch. See README for the source code location.
To look up IP source and destination names Resolv (from the ruby standard library, require 'resolv') to avoid blocking on name lookups in a cross-platform manner.
ARP header. See RFC 826
802.3 Ethernet header
ICMP header. See RFC 792
IPv4 header. See RFC 791
IPv6 header. See RFC 2460
TCP header. See RFC 793
UDP header. See RFC 768
Fake header for an unknown layer 3 protocol. See also #unknown_layer3_header
The ARP header if this is an ARP packet.
Length of packet that was captured
Captured portion of the entire packet including datalink layer.
The Ethernet header if this is an Ethernet packet.
ICMP header if this is an ICMP (v4) packet.
IPv4 header if this is an IPv4 packet.
IPv6 header if this is an IPv6 packet.
Total length of packet including the portion not captured.
Array of protocol names in this packet. This list is ordered from lowest to highest level.
TCP header if this is a TCP packet.
Packet capture timestamp
UDP header if this is a UDP packet.
Fake header for unknown layer 3 protocols. The datalink type will indicate the layer 3 protocol. For an Ethernet packet see the #ethernet_header for the type, etc. This method only provides the payload offset of the packet content.
Creates a new packet. Ordinarily this is performed from Capp#loop. The
timestamp
is the packet capture timestamp, length
is the total length of the packet, capture_length
is the
number of captured bytes from the packet. The datalink
is the
type of link the packet was captured on. headers
is a Hash of
parsed headers.
# File lib/capp/packet.rb, line 216 def initialize timestamp, length, capture_length, captured, datalink, headers @capture_length = capture_length @captured = captured @datalink = datalink @length = length @protocols = headers.keys @timestamp = timestamp @arp_header = headers[:arp] @ethernet_header = headers[:ethernet] @icmp_header = headers[:icmp] @ipv4_header = headers[:ipv4] @ipv6_header = headers[:ipv6] @tcp_header = headers[:tcp] @udp_header = headers[:udp] @unknown_layer3_header = headers[:unknown_layer3] end
Returns the destination of the packet regardless of protocol
If a Resolv-compatible resolver
is given the name will be
looked up.
# File lib/capp/packet.rb, line 239 def destination resolver = nil destination = if ipv4? then @ipv4_header elsif ipv6? then @ipv6_header else raise NotImplementedError end.destination destination = resolve destination, resolver if tcp? then destination << ".#{@tcp_header.destination_port}" elsif udp? then destination << ".#{@udp_header.destination_port}" end destination end
Returns the captured bytes with non-printing characters replaced by “.”
# File lib/capp/packet.rb, line 263 def dump @captured.tr "\0000-\0037\1177-\3377", "." end
Dumps the captured packet from offset
with offsets,
hexadecimal output for the bytes and the ASCII content with non-printing
characters replaced by “.”
# File lib/capp/packet.rb, line 272 def hexdump offset = 0 data = @captured[offset, @capture_length] data.scan(/.{,16}/).map.with_index do |chunk, index| next nil if chunk.empty? hex = chunk.unpack('C*').map { |byte| '%02x' % byte } dump = chunk.tr "\0000-\0037\1177-\3377", "." length = hex.length hex.fill ' ', length, 16 - length if length < 16 "\t0x%04x: %s%s %s%s %s%s %s%s %s%s %s%s %s%s %s%s %s" % [ index * 16, *hex, dump ] end.join "\n" end
Is this an IPv4 packet?
# File lib/capp/packet.rb, line 375 def ipv4? @ipv4_header end
Is this an IPv6 packet?
# File lib/capp/packet.rb, line 382 def ipv6? @ipv6_header end
The payload of the packet.
For example, for a UDP packet captured from an Ethernet interface this is payload after the Ethernet, IP and UDP headers
# File lib/capp/packet.rb, line 295 def payload @captured[payload_offset, @capture_length] end
The offset into the captured data where the payload starts.
Note that this method does not work properly for IPv6 packets with options set, but I have yet to encounter such an example in the wild.
# File lib/capp/packet.rb, line 305 def payload_offset offset = case @datalink when Capp::DLT_NULL then 4 when Capp::DLT_EN10MB then 14 end case when ipv4? then offset += @ipv4_header.ihl * 4 when ipv6? then offset += 40 else raise NotImplementedError end case when tcp? then offset += @tcp_header.offset * 4 when udp? then offset += 8 else raise NotImplementedError end offset end
Returns the source of the packet regardless of protocol.
If a Resolv-compatible resolver
is given the name will be
looked up.
# File lib/capp/packet.rb, line 351 def source resolver = nil source = if ipv4? then @ipv4_header elsif ipv6? then @ipv6_header else raise NotImplementedError end.source.dup source = resolve source, resolver if tcp? then source << ".#{@tcp_header.source_port}" elsif udp? then source << ".#{@udp_header.source_port}" end source end
Is this a TCP packet?
# File lib/capp/packet.rb, line 389 def tcp? @tcp_header end
Is this a UDP packet?
# File lib/capp/packet.rb, line 396 def udp? @udp_header end