class Capp::Packet

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.

Constants

ARPHeader

ARP header. See RFC 826

EthernetHeader

802.3 Ethernet header

ICMPHeader

ICMP header. See RFC 792

IPv4Header

IPv4 header. See RFC 791

IPv6Header

IPv6 header. See RFC 2460

TCPHeader

TCP header. See RFC 793

UDPHeader

UDP header. See RFC 768

UnknownLayer3Header

Fake header for an unknown layer 3 protocol. See also #unknown_layer3_header

Attributes

arp_header[R]

The ARP header if this is an ARP packet.

capture_length[R]

Length of packet that was captured

captured[R]

Captured portion of the entire packet including datalink layer.

ethernet_header[R]

The Ethernet header if this is an Ethernet packet.

icmp_header[R]

ICMP header if this is an ICMP (v4) packet.

ipv4_header[R]

IPv4 header if this is an IPv4 packet.

ipv6_header[R]

IPv6 header if this is an IPv6 packet.

length[R]

Total length of packet including the portion not captured.

protocols[R]

Array of protocol names in this packet. This list is ordered from lowest to highest level.

tcp_header[R]

TCP header if this is a TCP packet.

timestamp[R]

Packet capture timestamp

udp_header[R]

UDP header if this is a UDP packet.

unknown_layer3_header[R]

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.

Public Class Methods

new(timestamp, length, capture_length, captured, datalink, headers) click to toggle source

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

Public Instance Methods

destination(resolver = nil) click to toggle source

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
dump() click to toggle source

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
hexdump(offset = 0) click to toggle source

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
ipv4?() click to toggle source

Is this an IPv4 packet?

# File lib/capp/packet.rb, line 375
def ipv4?
  @ipv4_header
end
ipv6?() click to toggle source

Is this an IPv6 packet?

# File lib/capp/packet.rb, line 382
def ipv6?
  @ipv6_header
end
payload() click to toggle source

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
payload_offset() click to toggle source

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
source(resolver = nil) click to toggle source

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
tcp?() click to toggle source

Is this a TCP packet?

# File lib/capp/packet.rb, line 389
def tcp?
  @tcp_header
end
udp?() click to toggle source

Is this a UDP packet?

# File lib/capp/packet.rb, line 396
def udp?
  @udp_header
end