Class: Caper::Live

Inherits:
CaptureWrapper show all
Defined in:
lib/caper/live.rb

Overview

Creates a pcap interface for capturing from the network.

Returns:

  • (Live)

    A Caper::Live wrapper.

Raises:

  • (LibError)

    On failure, an exception is raised with the relevant error message from libpcap.

  • (ArgumentError)

    May raise an exception if a :device cannot be autodetected using Caper.lookupdev() for any reason. This should never happen on most platforms.

Constant Summary collapse

DEFAULT_TO_MS =

Default timeout for pcap_open_live()

1000
@@have_setdirection =
Caper.respond_to?(:pcap_setdirection)
@@have_inject =
Caper.respond_to?(:pcap_inject)
@@have_sendpacket =
Caper.respond_to?(:pcap_sendpacket)

Instance Attribute Summary collapse

Attributes inherited from CaptureWrapper

#handler

Attributes inherited from CommonWrapper

#pcap

Instance Method Summary collapse

Methods inherited from CaptureWrapper

#breakloop, #dispatch, #loop, #next, #old_next, #set_filter

Methods inherited from CommonWrapper

#close, #closed?, #compile, #datalink, #geterr, #open_dump, #ready?, #snaplen, #supported_datalinks, #to_ptr

Constructor Details

#initialize(opts = nil) {|_self| ... } ⇒ Live

Returns a new instance of Live.

Yields:

  • (_self)

Yield Parameters:

  • _self (Caper::Live)

    the object that the method was called on

Raises:



55
56
57
58
59
60
61
62
63
64
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
# File 'lib/caper/live.rb', line 55

def initialize(opts=nil)
  opts ||= {}
  @device = opts[:device] || opts[:dev] || Caper.lookupdev()
  unless @device
    raise(ArgumentError, "Couldn't detect a device. One must be specified.")
  end

  @snaplen   = opts[:snaplen] || DEFAULT_SNAPLEN
  @promisc   = opts[:promisc] ? 1 : 0
  @timeout   = opts[:timeout] || DEFAULT_TO_MS
  @direction = (opts[:direction] || opts[:dir])

  @errbuf = ErrorBuffer.create()
  @pcap = Caper.pcap_open_live(@device, @snaplen, @promisc, @timeout, @errbuf)
  raise(LibError, "pcap_open_live(): #{@errbuf.to_s}") if @pcap.null?

  # call super to get all our ducks in a row
  super(@pcap, opts)

  set_direction(@direction) if @direction

  # Cache network and netmask from pcap_lookupdev.
  # These pointers may be used internally (and should get autoreleased)
  @netp, @maskp = nil
  begin
    Caper.lookupnet(@device) do |netp, maskp|
      @netp = netp
      @maskp = maskp
    end
  rescue LibError
    warn "Warning: #{$!}"
  end

  yield self if block_given?
end

Instance Attribute Details

#deviceObject (readonly)

Returns the value of attribute device.



53
54
55
# File 'lib/caper/live.rb', line 53

def device
  @device
end

#directionObject (readonly)

Returns the value of attribute direction.



53
54
55
# File 'lib/caper/live.rb', line 53

def direction
  @direction
end

#promiscObject (readonly)

Returns the value of attribute promisc.



53
54
55
# File 'lib/caper/live.rb', line 53

def promisc
  @promisc
end

#timeoutObject (readonly)

Returns the value of attribute timeout.



53
54
55
# File 'lib/caper/live.rb', line 53

def timeout
  @timeout
end

Instance Method Details

#inject(pkt) ⇒ Integer

Transmit a packet using pcap_inject()

(not available on all platforms)

Parameters:

  • obj (Packet, String)

    The packet to send. This can be a Packet or String object.

Returns:

  • (Integer)

    The number of bytes sent.

Raises:

  • (ArgumentError)

    An exception is raised if the pkt object type is incorrect or if it is a Packet and the body pointer is null.

  • (LibError)

    On failure, an exception is raised with the relevant libpcap error message.

  • (NotImplementedError)

    If the pcap_inject() function is not available from your libpcap library pcap_sendpacket will be tried, if both are missing, this exception will be raised.



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/caper/live.rb', line 220

def inject(pkt)
  if @@have_inject
    if pkt.kind_of? Packet
      len = pkt.caplen
      bufp = pkt.body_ptr
      raise(ArgumentError, "packet data null pointer") if bufp.null?
    elsif pkt.kind_of? String
      len = pkt.size
      bufp = FFI::MemoryPointer.from_string(pkt)
    else
      raise(ArgumentError, "Don't know how to inject #{pkt.class}")
    end

    if (sent=Caper.pcap_inject(_pcap, bufp, len)) < 0
      raise(LibError, "pcap_inject(): #{geterr()}")
    end
    return sent
  else 
    # fake it with sendpacket on windows
    if sendpacket(pkt)
      return (Packet === pkt)? pkt.caplen : pkt.size
    end
  end
end

#netmaskObject

Returns the dotted notation string for the IPv4 netmask for the device used by this pcap interface.



100
101
102
103
# File 'lib/caper/live.rb', line 100

def netmask
  return nil unless @maskp
  @netmask ||= @maskp.get_array_of_uchar(0,4).join('.')
end

#netmask_n32Object

Returns the 32-bit numeric representation of the IPv4 network address for this device.



114
115
116
117
# File 'lib/caper/live.rb', line 114

def netmask_n32
  return nil unless @maskp
  ::FFI::DRY::NetEndian.ntohl(@maskp.get_uint32(0))
end

#networkObject

Returns the dotted notation string for the IPv4 network address for the device used by this pcap interface.



93
94
95
96
# File 'lib/caper/live.rb', line 93

def network
  return nil unless @netp
  @network ||= @netp.get_array_of_uchar(0,4).join('.')
end

#network_n32Object

Returns the 32-bit numeric representation of the IPv4 network address for this device.



107
108
109
110
# File 'lib/caper/live.rb', line 107

def network_n32
  return nil unless @netp
  ::FFI::DRY::NetEndian.ntohl(@netp.get_uint32(0))
end

#non_blockingBoolean Also known as: non_blocking?

get the state of non-blocking mode on a capture device

Returns:

  • (Boolean)

    non-blocking mode

Raises:

  • (LibError)

    On failure, an exception is raised with the relevant error message from libpcap.



168
169
170
171
172
173
174
# File 'lib/caper/live.rb', line 168

def non_blocking
  if (mode=Caper.pcap_getnonblock(_pcap, @errbuf)) == -1
    raise(LibError, "pcap_getnonblock(): #{@errbuf.to_s}", caller)
  else
    return mode == 1
  end
end

#sendpacket(pkt) ⇒ True Also known as: send_packet

Transmit a packet using pcap_sendpacket()

(not available on all platforms)

Parameters:

  • obj (Packet, String)

    The packet to send. This can be a Packet or String object.

Returns:

  • (True)

    True is returned on success. Otherwise an exception is raised.

Raises:

  • (ArgumentError)

    An exception is raised if the pkt object type is incorrect or if it is a Packet and the body pointer is null.

  • (LibError)

    On failure, an exception is raised with the relevant libpcap error message.

  • (NotImplementedError)

    If the pcap_sendpacket() function is not available from your libpcap library this exception will be raised.



269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/caper/live.rb', line 269

def sendpacket(pkt)
  unless @@have_sendpacket
    raise(NotImplementedError, 
          "packet injectors are not avaiable from your pcap library") 
  end

  if pkt.kind_of? Packet
    len = pkt.caplen
    bufp = pkt.body_ptr
    raise(ArgumentError, "packet data null pointer") if bufp.null?
  elsif pkt.kind_of? String
    len = pkt.size
    bufp = FFI::MemoryPointer.from_string(pkt)
  else
    raise(ArgumentError, "Don't know how to send #{pkt.class}")
  end

  if Caper.pcap_sendpacket(_pcap, bufp, len) != 0
    raise(LibError, "pcap_sendpacket(): #{geterr()}")
  end
  return true
end

#set_direction(dir) ⇒ Object Also known as: direction=

Sets the direction for which packets will be captured.

(Not supported on all platforms)



124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/caper/live.rb', line 124

def set_direction(dir)
  unless @@have_setdirection
    raise(NotImplementedError, 
          "pcap_setdirection() is not avaiable from your pcap library") 
  end

  dirs = Caper.enum_type(:pcap_direction_t)
  if Caper.pcap_setdirection(_pcap, dirs[:"pcap_d_#{dir}"]) == 0
    return true
  else
    raise(LibError, "pcap_setdirection(): #{geterr()}", caller)
  end
end

#set_non_blocking(mode) ⇒ Object Also known as: non_blocking=

set the state of non-blocking mode on a capture device

Parameters:

  • mode (Boolean)

Raises:

  • (LibError)

    On failure, an exception is raised with the relevant error message from libpcap.



148
149
150
151
152
153
154
155
# File 'lib/caper/live.rb', line 148

def set_non_blocking(mode)
  mode =  mode ? 1 : 0
  if Caper.pcap_setnonblock(_pcap, mode, @errbuf) == 0
    return mode == 1
  else
    raise(LibError, "pcap_setnonblock(): #{@errbuf.to_s}", caller)
  end
end

#statsStats

Get capture statistics

Returns:

  • (Stats)

Raises:

  • (LibError)

    On failure, an exception is raised with the relevant error message from libpcap.



186
187
188
189
190
191
192
# File 'lib/caper/live.rb', line 186

def stats
  stats = Stat.new
  unless Caper.pcap_stats(_pcap, stats) == 0
    raise(LibError, "pcap_stats(): #{geterr()}")
  end
  return stats
end