caper 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +9 -0
- data/History.rdoc +31 -0
- data/LICENSE.ffi-pcap +23 -0
- data/README.rdoc +55 -0
- data/Rakefile +26 -0
- data/VERSION +1 -0
- data/examples/ipfw_divert.rb +45 -0
- data/examples/print_bytes.rb +17 -0
- data/examples/test_loop.rb +48 -0
- data/lib/caper.rb +40 -0
- data/lib/caper/addr.rb +19 -0
- data/lib/caper/bpf.rb +104 -0
- data/lib/caper/bsd.rb +96 -0
- data/lib/caper/capture_wrapper.rb +287 -0
- data/lib/caper/common_wrapper.rb +173 -0
- data/lib/caper/copy_handler.rb +36 -0
- data/lib/caper/crt.rb +13 -0
- data/lib/caper/data_link.rb +171 -0
- data/lib/caper/dead.rb +35 -0
- data/lib/caper/dumper.rb +53 -0
- data/lib/caper/error_buffer.rb +42 -0
- data/lib/caper/exceptions.rb +19 -0
- data/lib/caper/file_header.rb +24 -0
- data/lib/caper/in_addr.rb +7 -0
- data/lib/caper/interface.rb +27 -0
- data/lib/caper/live.rb +301 -0
- data/lib/caper/offline.rb +51 -0
- data/lib/caper/packet.rb +163 -0
- data/lib/caper/packet_header.rb +23 -0
- data/lib/caper/pcap.rb +250 -0
- data/lib/caper/stat.rb +56 -0
- data/lib/caper/time_val.rb +46 -0
- data/lib/caper/typedefs.rb +25 -0
- data/lib/caper/version.rb +4 -0
- data/spec/data_link_spec.rb +65 -0
- data/spec/dead_spec.rb +34 -0
- data/spec/dumps/http.pcap +0 -0
- data/spec/dumps/simple_tcp.pcap +0 -0
- data/spec/error_buffer_spec.rb +17 -0
- data/spec/file_header_spec.rb +28 -0
- data/spec/live_spec.rb +87 -0
- data/spec/offline_spec.rb +61 -0
- data/spec/packet_behaviors.rb +68 -0
- data/spec/packet_injection_spec.rb +38 -0
- data/spec/packet_spec.rb +111 -0
- data/spec/pcap_spec.rb +149 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/wrapper_behaviors.rb +110 -0
- data/tasks/rcov.rb +6 -0
- data/tasks/rdoc.rb +17 -0
- data/tasks/spec.rb +9 -0
- data/tasks/yard.rb +16 -0
- metadata +140 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'caper/capture_wrapper'
|
2
|
+
|
3
|
+
module Caper
|
4
|
+
# A wrapper class for pcap devices opened with open_offline()
|
5
|
+
#
|
6
|
+
class Offline < CaptureWrapper
|
7
|
+
attr_accessor :path
|
8
|
+
|
9
|
+
# Creates a pcap interface for reading saved capture files.
|
10
|
+
#
|
11
|
+
# @param [String] path
|
12
|
+
# The path to the file to open.
|
13
|
+
#
|
14
|
+
# @param [Hash] opts
|
15
|
+
# Options are ignored and passed to the super-class except for those
|
16
|
+
# below.
|
17
|
+
#
|
18
|
+
# @option opts [ignored] :path
|
19
|
+
# The :path option will be overridden with the value of the path
|
20
|
+
# argument. If specified in opts, its value will be ignored.
|
21
|
+
#
|
22
|
+
# @return [Offline]
|
23
|
+
# A Caper::Offline wrapper.
|
24
|
+
#
|
25
|
+
# @raise [LibError]
|
26
|
+
# On failure, an exception is raised with the relevant error
|
27
|
+
# message from libpcap.
|
28
|
+
#
|
29
|
+
def initialize(path, opts={}, &block)
|
30
|
+
@path = path
|
31
|
+
@errbuf = ErrorBuffer.create()
|
32
|
+
@pcap = Caper.pcap_open_offline(File.expand_path(@path), @errbuf)
|
33
|
+
raise(LibError, "pcap_open_offline(): #{@errbuf.to_s}") if @pcap.null?
|
34
|
+
super(@pcap, opts, &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def swapped?
|
38
|
+
Caper.pcap_is_swapped(_pcap) == 1 ? true : false
|
39
|
+
end
|
40
|
+
|
41
|
+
def file_version
|
42
|
+
"#{Caper.pcap_major_version(_pcap)}.#{Caper.pcap_minor_version(_pcap)}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
attach_function :pcap_open_offline, [:string, :pointer], :pcap_t
|
47
|
+
attach_function :pcap_is_swapped, [:pcap_t], :int
|
48
|
+
attach_function :pcap_major_version, [:pcap_t], :int
|
49
|
+
attach_function :pcap_minor_version, [:pcap_t], :int
|
50
|
+
|
51
|
+
end
|
data/lib/caper/packet.rb
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
|
2
|
+
module Caper
|
3
|
+
class Packet
|
4
|
+
attr_reader :body_ptr, :header
|
5
|
+
|
6
|
+
# Creates a Packet from a Ruby string object.
|
7
|
+
#
|
8
|
+
# see new() for more information about the arguments.
|
9
|
+
def self.from_string(body, opts={})
|
10
|
+
new(nil, body, opts)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Allocates a Packet using new memory. Used primarily for pcap_loop
|
14
|
+
# and pcap_dispatch to retain packets after new ones have been received
|
15
|
+
# or a pcap device is closed.
|
16
|
+
def self.allocate(phdr, buf)
|
17
|
+
new(phdr, buf).copy()
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param [PacketHeader, nil] hdr
|
21
|
+
# The pcap pkthdr struct for this packet or nil. hdr may only be
|
22
|
+
# nil if a string is supplied for the body. A header will be
|
23
|
+
# created automatically and set_body called with opts.
|
24
|
+
#
|
25
|
+
# @param [FFI::Pointer, String] body
|
26
|
+
# A string or pointer for the body of the packet. A String may
|
27
|
+
# only be specified if hdr is set to nil.
|
28
|
+
#
|
29
|
+
# @param [optional, Hash] opts
|
30
|
+
# Specifies additional options at creation time. Only those
|
31
|
+
# below are applicable for all initiatialization styles.
|
32
|
+
# All other options are sent to set_body(), but only if the header
|
33
|
+
# is nil and body is a String. See set_body() for more info.
|
34
|
+
#
|
35
|
+
# @option opts [optional, Time] :time, :timestamp
|
36
|
+
# Sets the timestamp in the header.
|
37
|
+
#
|
38
|
+
# @raise [ArgumentError, TypeError]
|
39
|
+
# An exception is raised if any of the parameter rules described
|
40
|
+
# are not followed.
|
41
|
+
#
|
42
|
+
def initialize(hdr, body, opts={})
|
43
|
+
o = opts.dup
|
44
|
+
ts = o.delete(:time) || o.delete(:timestamp)
|
45
|
+
case hdr
|
46
|
+
when PacketHeader
|
47
|
+
raise(ArgumentError, "NULL header pointer") if hdr.to_ptr.null?
|
48
|
+
@header = hdr
|
49
|
+
when ::FFI::Pointer
|
50
|
+
raise(ArgumentError, "NULL header pointer") if hdr.null?
|
51
|
+
@header = PacketHeader.new(hdr)
|
52
|
+
when nil
|
53
|
+
if body.is_a? String
|
54
|
+
set_body(body, o)
|
55
|
+
else
|
56
|
+
raise(TypeError, "invalid body with nil header: #{body.class}")
|
57
|
+
end
|
58
|
+
else
|
59
|
+
raise(TypeError, "invalid header: #{hdr.class}")
|
60
|
+
end
|
61
|
+
|
62
|
+
@header.ts.time = ts if ts
|
63
|
+
|
64
|
+
unless @body_ptr
|
65
|
+
if body.is_a?(FFI::Pointer) and not body.null?
|
66
|
+
@body_ptr = body
|
67
|
+
else
|
68
|
+
raise(TypeError, "invalid body for header: #{body.class}")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Sets the body from a string. A pointer is automatically derived from
|
74
|
+
#
|
75
|
+
# @param [String] data
|
76
|
+
# The body to set
|
77
|
+
#
|
78
|
+
# @param [Hash] opts
|
79
|
+
# Body length options.
|
80
|
+
#
|
81
|
+
# @option opts [optional, Integer] :caplen, :captured
|
82
|
+
# The captured length (or snaplen) for this packet.
|
83
|
+
# Length of data portion present. Defaults to body.size(). If
|
84
|
+
# caplen is larger than the body, then it is overridden with body.size.
|
85
|
+
#
|
86
|
+
# @option opts [optional, Integer] :len, :length
|
87
|
+
# The total length of the packet (off wire). Defaults to caplen. If
|
88
|
+
# If :length is less than the :caplen, it is overridden as :caplen.
|
89
|
+
#
|
90
|
+
#
|
91
|
+
# @return [String]
|
92
|
+
# Returns the data as supplied per attr_writer convention.
|
93
|
+
#
|
94
|
+
def set_body(data, opts={})
|
95
|
+
cl = opts[:caplen] || opts[:captured] || data.size
|
96
|
+
l = opts[:length] || opts[:len] || cl
|
97
|
+
clen = (cl < data.size) ? cl : data.size
|
98
|
+
len = (l < clen) ? clen : l
|
99
|
+
|
100
|
+
@header ||= PacketHeader.new
|
101
|
+
@header.caplen = len || @header.caplen
|
102
|
+
@header.len = len || @header.caplen
|
103
|
+
@body_ptr = FFI::MemoryPointer.from_string(data)
|
104
|
+
return self
|
105
|
+
end
|
106
|
+
|
107
|
+
alias body= set_body
|
108
|
+
|
109
|
+
# @return [String]
|
110
|
+
# A String representation of the packet data.
|
111
|
+
# The reference to the string is not kept by the object and changes
|
112
|
+
# won't affect the data in this packet.
|
113
|
+
def body
|
114
|
+
@body_ptr.read_string(@header.caplen)
|
115
|
+
end
|
116
|
+
|
117
|
+
# @return [Time]
|
118
|
+
# Returns the pcap timestamp as a Time object
|
119
|
+
def time
|
120
|
+
@header.ts.time
|
121
|
+
end
|
122
|
+
|
123
|
+
alias timestamp time
|
124
|
+
|
125
|
+
# Sets the pcap timestamp.
|
126
|
+
def time=(t)
|
127
|
+
@header.ts.time=(t)
|
128
|
+
end
|
129
|
+
|
130
|
+
def caplen
|
131
|
+
@header.caplen
|
132
|
+
end
|
133
|
+
|
134
|
+
alias captured caplen
|
135
|
+
|
136
|
+
def len
|
137
|
+
@header.len
|
138
|
+
end
|
139
|
+
|
140
|
+
alias length len
|
141
|
+
|
142
|
+
# An optimized copy which allocates new memory for a PacketHeader and
|
143
|
+
# body.
|
144
|
+
#
|
145
|
+
# DANGEROUS: This method uses direct FFI bindings for the copy and
|
146
|
+
# may crash Ruby if the packet header or body is incorrect.
|
147
|
+
#
|
148
|
+
# @raise [StandardError]
|
149
|
+
# An exception is raised if the header or body is a NULL pointer.
|
150
|
+
#
|
151
|
+
def copy
|
152
|
+
raise(StandardError, "header is a NULL pointer") if @header.to_ptr.null?
|
153
|
+
raise(StandardError, "body is a NULL pointer") if body_ptr.null?
|
154
|
+
cpy_hdr = PacketHeader.new
|
155
|
+
cpy_buf = FFI::MemoryPointer.new(@header.caplen)
|
156
|
+
CRT.memcpy(cpy_hdr, @header, PacketHeader.size)
|
157
|
+
CRT.memcpy(cpy_buf, @body_ptr, @header.caplen)
|
158
|
+
self.class.new( cpy_hdr, cpy_buf )
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Caper
|
2
|
+
|
3
|
+
# Generic per-packet information, as supplied by libpcap. This structure
|
4
|
+
# is used to track only the libpcap header and just contains the timestamp
|
5
|
+
# and length information used by libpcap.
|
6
|
+
#
|
7
|
+
# See pcap_pkthdr struct in pcap.h
|
8
|
+
class PacketHeader < FFI::Struct
|
9
|
+
include FFI::DRY::StructHelper
|
10
|
+
|
11
|
+
dsl_layout do
|
12
|
+
struct :ts, ::Caper::TimeVal, :desc => 'time stamp'
|
13
|
+
field :caplen, :bpf_uint32, :desc => 'length of portion present'
|
14
|
+
field :len, :bpf_uint32, :desc => 'length of packet (off wire)'
|
15
|
+
end
|
16
|
+
|
17
|
+
alias timestamp ts
|
18
|
+
alias captured caplen
|
19
|
+
alias length len
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/lib/caper/pcap.rb
ADDED
@@ -0,0 +1,250 @@
|
|
1
|
+
require 'enumerator'
|
2
|
+
|
3
|
+
module Caper
|
4
|
+
DEFAULT_SNAPLEN = 65535 # Default snapshot length for packets
|
5
|
+
|
6
|
+
attach_function :pcap_lookupdev, [:pointer], :string
|
7
|
+
|
8
|
+
# Find the default device on which to capture.
|
9
|
+
#
|
10
|
+
# @return [String]
|
11
|
+
# Name of default device
|
12
|
+
#
|
13
|
+
# @raise [LibError]
|
14
|
+
# On failure, an exception is raised with the relevant error
|
15
|
+
# message from libpcap.
|
16
|
+
#
|
17
|
+
def Caper.lookupdev
|
18
|
+
e = ErrorBuffer.create()
|
19
|
+
unless name = Caper.pcap_lookupdev(e)
|
20
|
+
raise(LibError, "pcap_lookupdev(): #{e.to_s}")
|
21
|
+
end
|
22
|
+
return name
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
attach_function :pcap_lookupnet, [:string, :pointer, :pointer, :pointer], :int
|
27
|
+
|
28
|
+
# Determine the IPv4 network number and mask relevant with a network
|
29
|
+
# device.
|
30
|
+
#
|
31
|
+
# @param [String] device
|
32
|
+
# The name of the device to look up.
|
33
|
+
#
|
34
|
+
# @yield [netp, maskp]
|
35
|
+
#
|
36
|
+
# @yieldparam [FFI::MemoryPointer] netp
|
37
|
+
# A pointer to the network return value.
|
38
|
+
#
|
39
|
+
# @yieldparam [FFI::MemoryPointer] maskp
|
40
|
+
# A pointer to the netmask return value.
|
41
|
+
#
|
42
|
+
# @return [nil, String]
|
43
|
+
# The IPv4 network number and mask presented as "n.n.n.n/m.m.m.m".
|
44
|
+
# nil is returned when a block is specified.
|
45
|
+
#
|
46
|
+
# @raise [LibError]
|
47
|
+
# On failure, an exception is raised with the relevant error message
|
48
|
+
# from libpcap.
|
49
|
+
#
|
50
|
+
def Caper.lookupnet(device)
|
51
|
+
netp = FFI::MemoryPointer.new(find_type(:bpf_uint32))
|
52
|
+
maskp = FFI::MemoryPointer.new(find_type(:bpf_uint32))
|
53
|
+
errbuf = ErrorBuffer.create()
|
54
|
+
unless Caper.pcap_lookupnet(device, netp, maskp, errbuf) == 0
|
55
|
+
raise(LibError, "pcap_lookupnet(): #{errbuf.to_s}")
|
56
|
+
end
|
57
|
+
if block_given?
|
58
|
+
yield(netp, maskp)
|
59
|
+
else
|
60
|
+
return( netp.get_array_of_uchar(0,4).join('.') << "/" <<
|
61
|
+
maskp.get_array_of_uchar(0,4).join('.') )
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
# Opens a new Live device for capturing from the network. See Live.new()
|
67
|
+
# for arguments.
|
68
|
+
#
|
69
|
+
# If passed a block, the block is passed to Live.new() and the Live
|
70
|
+
# object is closed after completion of the block
|
71
|
+
def Caper.open_live(opts={},&block)
|
72
|
+
ret = Live.new(opts, &block)
|
73
|
+
return block_given? ? ret.close : ret
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
# Opens a new Dead pcap interface for compiling filters or opening
|
78
|
+
# a capture for output. See Dead.new() for arguments.
|
79
|
+
def Caper.open_dead(opts={}, &block)
|
80
|
+
ret = Dead.new(opts, &block)
|
81
|
+
return block_given? ? ret.close : ret
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
# Opens a saved capture file for reading. See Offline.new for arguments.
|
86
|
+
def Caper.open_offline(path, opts={}, &block)
|
87
|
+
ret = Offline.new(path, opts={}, &block)
|
88
|
+
return block_given? ? ret.close : ret
|
89
|
+
end
|
90
|
+
|
91
|
+
# Same as open_offline
|
92
|
+
def Caper.open_file(path, opts={}, &block)
|
93
|
+
open_offline(path, opts, &block)
|
94
|
+
end
|
95
|
+
|
96
|
+
attach_function :pcap_findalldevs, [:pointer, :pointer], :int
|
97
|
+
attach_function :pcap_freealldevs, [Interface], :void
|
98
|
+
|
99
|
+
# List all capture devices and yield them each to a block
|
100
|
+
#
|
101
|
+
# @yield [dev]
|
102
|
+
#
|
103
|
+
# @yieldparam [Interface] dev
|
104
|
+
# An Interface structure for each device.
|
105
|
+
#
|
106
|
+
# @return [nil]
|
107
|
+
#
|
108
|
+
# @raise [LibError]
|
109
|
+
# On failure, an exception is raised with the relevant error
|
110
|
+
# message from libpcap.
|
111
|
+
#
|
112
|
+
def Caper.each_device
|
113
|
+
devices = ::FFI::MemoryPointer.new(:pointer)
|
114
|
+
errbuf = ErrorBuffer.create()
|
115
|
+
|
116
|
+
Caper.pcap_findalldevs(devices, errbuf)
|
117
|
+
node = devices.get_pointer(0)
|
118
|
+
|
119
|
+
if node.null?
|
120
|
+
raise(LibError, "pcap_findalldevs(): #{errbuf.to_s}")
|
121
|
+
end
|
122
|
+
|
123
|
+
device = Interface.new(node)
|
124
|
+
|
125
|
+
while device
|
126
|
+
yield(device)
|
127
|
+
device = device.next
|
128
|
+
end
|
129
|
+
|
130
|
+
Caper.pcap_freealldevs(node)
|
131
|
+
return nil
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
# Returns an array of device name and network/netmask pairs for
|
136
|
+
# each interface found on the system.
|
137
|
+
#
|
138
|
+
# If an interface does not have an address assigned, its network/netmask
|
139
|
+
# value is returned as a nil value.
|
140
|
+
def Caper.dump_devices
|
141
|
+
Caper.enum_for(:each_device).map do |dev|
|
142
|
+
net = begin; Caper.lookupnet(dev.name); rescue LibError; end
|
143
|
+
[dev.name, net]
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
# Returns an array of device names for each interface found on the system.
|
149
|
+
def Caper.device_names
|
150
|
+
Caper.enum_for(:each_device).map {|dev| dev.name }
|
151
|
+
end
|
152
|
+
|
153
|
+
attach_function :pcap_lib_version, [], :string
|
154
|
+
|
155
|
+
|
156
|
+
# Get the version information for libpcap.
|
157
|
+
#
|
158
|
+
# @return [String]
|
159
|
+
# Information about the version of the libpcap library being used;
|
160
|
+
# note that it contains more information than just a version number.
|
161
|
+
#
|
162
|
+
def Caper.lib_version
|
163
|
+
Caper.pcap_lib_version
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
# Extract just the version number from the lib_version string.
|
168
|
+
#
|
169
|
+
# @return [String]
|
170
|
+
# Version number.
|
171
|
+
#
|
172
|
+
def Caper.lib_version_number
|
173
|
+
if lib_version() =~ /libpcap version (\d+\.\d+.\d+)/
|
174
|
+
return $1
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
# Unix Only:
|
180
|
+
begin
|
181
|
+
|
182
|
+
attach_function :pcap_get_selectable_fd, [:pcap_t], :int
|
183
|
+
|
184
|
+
|
185
|
+
# Drops privileges back to the uid of the SUDO_USER environment
|
186
|
+
# variable.
|
187
|
+
#
|
188
|
+
# Only available on Unix.
|
189
|
+
#
|
190
|
+
# This is useful for the paranoid when sudo is used to run a
|
191
|
+
# ruby pcap program as root.
|
192
|
+
#
|
193
|
+
# This method can generally be called right after a call to
|
194
|
+
# open_live() has returned a pcap handle or another privileged
|
195
|
+
# call has completed. Note, however, that once privileges are
|
196
|
+
# dropped, pcap functions that a require higher privilege will
|
197
|
+
# no longer work.
|
198
|
+
#
|
199
|
+
# @raise [StandardError]
|
200
|
+
# An error is raised if privileges cannot be dropped for
|
201
|
+
# some reason. This may be because the SUDO_USER environment
|
202
|
+
# variable is not set, because we already have a lower
|
203
|
+
# privilige and the SUDO_USER id is not the current uid,
|
204
|
+
# or because the SUDO_USER environment variable is not
|
205
|
+
# a valid user.
|
206
|
+
#
|
207
|
+
def Caper.drop_sudo_privs
|
208
|
+
if ENV["SUDO_USER"] and pwent=Etc.getpwnam(ENV["SUDO_USER"])
|
209
|
+
Process::Sys.setgid(pwent.gid)
|
210
|
+
Process::Sys.setegid(pwent.gid)
|
211
|
+
Process::Sys.setuid(pwent.uid)
|
212
|
+
Process::Sys.seteuid(pwent.uid)
|
213
|
+
return true if (
|
214
|
+
Process::Sys.getuid == pwent.uid and
|
215
|
+
Process::Sys.geteuid == pwent.uid and
|
216
|
+
Process::Sys.getgid == pwent.gid and
|
217
|
+
Process::Sys.getegid == pwent.gid )
|
218
|
+
end
|
219
|
+
raise(StandardError, "Unable to drop privileges")
|
220
|
+
end
|
221
|
+
|
222
|
+
rescue FFI::NotFoundError
|
223
|
+
$pcap_not_unix=true
|
224
|
+
end
|
225
|
+
|
226
|
+
# Win32 only:
|
227
|
+
begin
|
228
|
+
attach_function :pcap_setbuff, [:pcap_t, :int], :int
|
229
|
+
attach_function :pcap_setmode, [:pcap_t, :pcap_w32_modes_enum], :int
|
230
|
+
attach_function :pcap_setmintocopy, [:pcap_t, :int], :int
|
231
|
+
rescue FFI::NotFoundError
|
232
|
+
$pcap_not_win32=true
|
233
|
+
end if $pcap_not_unix
|
234
|
+
|
235
|
+
# MSDOS only???:
|
236
|
+
begin
|
237
|
+
attach_function :pcap_stats_ex, [:pcap_t, StatEx], :int
|
238
|
+
attach_function :pcap_set_wait, [:pcap_t, :pointer, :int], :void
|
239
|
+
attach_function :pcap_mac_packets, [], :ulong
|
240
|
+
rescue FFI::NotFoundError
|
241
|
+
end if $pcap_not_win32
|
242
|
+
|
243
|
+
|
244
|
+
#### XXX not sure if we even want FILE io stuff yet (or ever).
|
245
|
+
|
246
|
+
#attach_function :pcap_fopen_offline, [:FILE, :pointer], :pcap_t
|
247
|
+
#attach_function :pcap_file, [:pcap_t], :FILE
|
248
|
+
#attach_function :pcap_dump_fopen, [:pcap_t, :FILE], :pcap_dumper_t
|
249
|
+
#attach_function :pcap_fileno, [:pcap_t], :int
|
250
|
+
end
|