ffi-pcap 0.2.0 → 0.2.1
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 +2 -1
- data/.pkg_ignore +25 -0
- data/.rspec +1 -0
- data/.specopts +1 -0
- data/.yardopts +1 -0
- data/{ChangeLog.rdoc → ChangeLog.md} +15 -5
- data/LICENSE.txt +1 -4
- data/README.md +92 -0
- data/Rakefile +30 -20
- data/examples/em_selectable_pcap.rb +38 -0
- data/examples/em_timer.rb +26 -0
- data/examples/ipfw_divert.rb +28 -8
- data/examples/print_bytes.rb +5 -1
- data/examples/replay.rb +11 -0
- data/examples/selectable_pcap.rb +29 -0
- data/ffi-pcap.gemspec +60 -0
- data/gemspec.yml +23 -0
- data/lib/ffi/pcap.rb +7 -13
- data/lib/ffi/pcap/addr.rb +16 -15
- data/lib/ffi/pcap/bpf_instruction.rb +25 -0
- data/lib/ffi/pcap/bpf_program.rb +85 -0
- data/lib/ffi/pcap/bsd.rb +9 -98
- data/lib/ffi/pcap/bsd/af.rb +18 -0
- data/lib/ffi/pcap/bsd/in6_addr.rb +16 -0
- data/lib/ffi/pcap/bsd/in_addr.rb +18 -0
- data/lib/ffi/pcap/bsd/sock_addr.rb +19 -0
- data/lib/ffi/pcap/bsd/sock_addr_dl.rb +24 -0
- data/lib/ffi/pcap/bsd/sock_addr_family.rb +19 -0
- data/lib/ffi/pcap/bsd/sock_addr_in.rb +21 -0
- data/lib/ffi/pcap/bsd/sock_addr_in6.rb +20 -0
- data/lib/ffi/pcap/bsd/typedefs.rb +7 -0
- data/lib/ffi/pcap/capture_wrapper.rb +296 -256
- data/lib/ffi/pcap/common_wrapper.rb +152 -127
- data/lib/ffi/pcap/copy_handler.rb +32 -32
- data/lib/ffi/pcap/crt.rb +7 -10
- data/lib/ffi/pcap/data_link.rb +178 -153
- data/lib/ffi/pcap/dead.rb +42 -29
- data/lib/ffi/pcap/dumper.rb +39 -41
- data/lib/ffi/pcap/error_buffer.rb +21 -36
- data/lib/ffi/pcap/exceptions.rb +21 -15
- data/lib/ffi/pcap/file_header.rb +24 -18
- data/lib/ffi/pcap/in_addr.rb +4 -4
- data/lib/ffi/pcap/interface.rb +22 -20
- data/lib/ffi/pcap/live.rb +296 -252
- data/lib/ffi/pcap/offline.rb +50 -43
- data/lib/ffi/pcap/packet.rb +186 -143
- data/lib/ffi/pcap/packet_header.rb +20 -18
- data/lib/ffi/pcap/pcap.rb +269 -212
- data/lib/ffi/pcap/stat.rb +19 -49
- data/lib/ffi/pcap/stat_ex.rb +42 -0
- data/lib/ffi/pcap/time_val.rb +52 -38
- data/lib/ffi/pcap/typedefs.rb +16 -20
- data/spec/data_link_spec.rb +39 -35
- data/spec/dead_spec.rb +0 -4
- data/spec/error_buffer_spec.rb +7 -9
- data/spec/file_header_spec.rb +17 -14
- data/spec/live_spec.rb +12 -5
- data/spec/offline_spec.rb +10 -11
- data/spec/packet_behaviors.rb +20 -6
- data/spec/packet_injection_spec.rb +9 -8
- data/spec/packet_spec.rb +22 -26
- data/spec/pcap_spec.rb +52 -40
- data/spec/spec_helper.rb +16 -5
- data/spec/wrapper_behaviors.rb +0 -3
- data/tasks/doc.rake +69 -0
- data/tasks/gem.rake +200 -0
- data/tasks/git.rake +40 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +286 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- metadata +142 -92
- data/README.rdoc +0 -30
- data/VERSION +0 -1
- data/lib/ffi/pcap/bpf.rb +0 -106
- data/lib/ffi/pcap/version.rb +0 -6
- data/tasks/rcov.rb +0 -6
- data/tasks/rdoc.rb +0 -17
- data/tasks/spec.rb +0 -9
- data/tasks/yard.rb +0 -21
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'ffi/pcap/bsd/typedefs'
|
2
|
+
require 'ffi/pcap/bsd/sock_addr_family'
|
3
|
+
|
4
|
+
module FFI
|
5
|
+
module PCap
|
6
|
+
#
|
7
|
+
# sockaddr inet, always good to have around
|
8
|
+
#
|
9
|
+
class SockAddrIn < SockAddrFamily
|
10
|
+
|
11
|
+
dsl_layout do
|
12
|
+
field :len, :uint8, :desc => 'length of structure (16)'
|
13
|
+
field :family, :sa_family_t, :desc => 'address family (AF_INET)'
|
14
|
+
field :port, :in_port_t, :desc => '16-bit TCP or UDP port number'
|
15
|
+
field :addr, :in_addr_t, :desc => '32-bit IPv4 address'
|
16
|
+
array :_sa_zero, [:uint8,8], :desc => 'unused'
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'ffi/pcap/bsd/typedefs'
|
2
|
+
|
3
|
+
module FFI
|
4
|
+
module PCap
|
5
|
+
#
|
6
|
+
# IPv6 socket address
|
7
|
+
#
|
8
|
+
class SockAddrIn6 < SockAddrFamily
|
9
|
+
|
10
|
+
dsl_layout do
|
11
|
+
field :len, :uint8, :desc => 'length of structure(24)'
|
12
|
+
field :family, :sa_family_t, :desc => 'address family (AF_INET6)'
|
13
|
+
field :port, :in_port_t, :desc => 'transport layer port'
|
14
|
+
field :flowinfo, :uint32, :desc => 'priority & flow label'
|
15
|
+
struct :addr, ::FFI::PCap::In6Addr, :desc => 'IPv6 address'
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -2,288 +2,328 @@ require 'ffi/pcap/common_wrapper'
|
|
2
2
|
require 'ffi/pcap/copy_handler'
|
3
3
|
|
4
4
|
module FFI
|
5
|
-
module PCap
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
5
|
+
module PCap
|
6
|
+
#
|
7
|
+
# A superclass for both offline and live interfaces, but not dead
|
8
|
+
# interfaces. This class provides all the features necessary for
|
9
|
+
# receiving packets through libpcap.
|
10
|
+
#
|
11
|
+
# The loop and dispatch methods default to using a {CopyHandler} object
|
12
|
+
# when preparing values to the callback block. This is done to safely
|
13
|
+
# provide references to packets outside of the callback blocks.
|
14
|
+
# See CopyHandler for more information.
|
15
|
+
#
|
16
|
+
# Note that for performance reasons, you may not need or want to incur
|
17
|
+
# the extra overhead of creating a copy for every Packet. You can supply
|
18
|
+
# a `nil` value for the loop handler which will simply pass volatile
|
19
|
+
# references to packets directly to your block. You can also write
|
20
|
+
# custom handlers which implement the `receive_pcap` method and
|
21
|
+
# implement custom defined behaviors.
|
22
|
+
#
|
23
|
+
class CaptureWrapper < CommonWrapper
|
24
|
+
|
25
|
+
include Enumerable
|
26
|
+
|
27
|
+
# Default packet count (-1: infinite loop)
|
28
|
+
DEFAULT_COUNT = -1
|
29
|
+
|
30
|
+
attr_accessor :handler
|
31
|
+
|
32
|
+
#
|
33
|
+
# Adds an extra parameter :handler for specifying a capture handler
|
34
|
+
# when using loop or dispatch. The handler defaults to {CopyHandler},
|
35
|
+
# which always yields a copy of each packet to a block.
|
36
|
+
#
|
37
|
+
# Setting :handler to `nil` will pass packets directly to a block
|
38
|
+
# without copying them, which may be desirable if the packets are
|
39
|
+
# only ever processed within the block, and code does not need to
|
40
|
+
# retain a reference to them elsewhere.
|
41
|
+
#
|
42
|
+
def initialize(pcap, opts={}, &block)
|
43
|
+
@handler = opts.fetch(handler,CopyHandler)
|
44
|
+
|
45
|
+
trap('INT') do
|
46
|
+
stop()
|
47
|
+
close()
|
48
|
+
|
49
|
+
raise(SignalException,'INT',caller)
|
50
|
+
end
|
51
|
+
|
52
|
+
trap('TERM') do
|
53
|
+
stop()
|
54
|
+
close()
|
55
|
+
|
56
|
+
raise(SignalException,'TERM',caller)
|
57
|
+
end
|
58
|
+
|
59
|
+
super(pcap, opts, &block)
|
39
60
|
end
|
40
61
|
|
41
|
-
|
42
|
-
|
62
|
+
#
|
63
|
+
# Processes packets from a live capture or savefile until cnt packets
|
64
|
+
# are processed, the end of the savefile is reached (when reading
|
65
|
+
# from a savefile), `pcap_breakloop()` is called, or an error occurs.
|
66
|
+
#
|
67
|
+
# It does not return when live read timeouts occur. A value of -1 or
|
68
|
+
# 0 for cnt is equivalent to infinity, so that packets are processed
|
69
|
+
# until another ending condition occurs.
|
70
|
+
#
|
71
|
+
# (In older versions of libpcap, the behavior when cnt was 0 was
|
72
|
+
# undefined; different platforms and devices behaved differently, so
|
73
|
+
# code that must work with older versions of libpcap should use -1,
|
74
|
+
# nor 0, as the value of cnt.)
|
75
|
+
#
|
76
|
+
# @param [Hash] opts
|
77
|
+
# Receive options.
|
78
|
+
#
|
79
|
+
# @option [optional, Integer] :count
|
80
|
+
# Limit to :count number of packets. Default is infinite.
|
81
|
+
#
|
82
|
+
# @yield [self, pkt]
|
83
|
+
#
|
84
|
+
# @yieldparam [CaptureWrapper] self
|
85
|
+
# A reference to self is passed to the block.
|
86
|
+
#
|
87
|
+
# @yieldparam [Packet] pkt
|
88
|
+
# A packet object is yielded which references the header and bytes.
|
89
|
+
#
|
90
|
+
#
|
91
|
+
# @return [Integer, nil]
|
92
|
+
# Returns 0 if cnt is exhausted, or `nil` if the loop terminated due
|
93
|
+
# to a call to `pcap_breakloop()` before any packets were processed.
|
94
|
+
# It does not return when live read timeouts occur; instead,
|
95
|
+
# it attempts to read more packets.
|
96
|
+
#
|
97
|
+
# @raise [ReadError]
|
98
|
+
# An exception is raised if an error occurs or if libpcap returns
|
99
|
+
# an unexpected value.
|
100
|
+
#
|
101
|
+
def loop(opts={}, &block)
|
102
|
+
cnt = (opts[:count] || DEFAULT_COUNT)
|
103
|
+
h = opts[:handler]
|
43
104
|
|
44
|
-
|
45
|
-
end
|
105
|
+
ret = PCap.pcap_loop(_pcap, cnt, _wrap_callback(h, block), nil)
|
46
106
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
raise(NoMethodError,
|
54
|
-
"The handler #{h.class} has no receive_pcap method")
|
55
|
-
end
|
56
|
-
return lambda do |usr,phdr,body|
|
57
|
-
yld = h.receive_pcap(self, Packet.new(phdr,body))
|
58
|
-
blk.call(*yld) if blk and yld
|
59
|
-
end
|
60
|
-
elsif blk.kind_of?(Proc) or blk.kind_of?(Method)
|
61
|
-
return lambda do |usr,phdr,body|
|
62
|
-
blk.call(pcap, Packet.new(phdr,body))
|
63
|
-
end
|
107
|
+
if ret == -1
|
108
|
+
raise(ReadError,"pcap_loop(): #{geterr}",caller)
|
109
|
+
elsif ret -2
|
110
|
+
return nil
|
111
|
+
elsif ret > -1
|
112
|
+
return ret
|
64
113
|
else
|
65
|
-
raise(
|
114
|
+
raise(ReadError,"unexpected return from pcap_loop(): #{ret}",caller)
|
66
115
|
end
|
67
116
|
end
|
68
|
-
public
|
69
117
|
|
118
|
+
alias each loop
|
70
119
|
|
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
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
120
|
+
#
|
121
|
+
# Processes packets from a live capture or savefile until cnt packets
|
122
|
+
# are processed, the end of the current bufferful of packets is
|
123
|
+
# reached when doing a live capture, the end of the savefile is
|
124
|
+
# reached (when reading from a savefile), `pcap_breakloop()` is called,
|
125
|
+
# or an error occurs.
|
126
|
+
#
|
127
|
+
# Thus, when doing a live capture, cnt is the maximum number of
|
128
|
+
# packets to process before returning, but is not a minimum number;
|
129
|
+
# when reading a live capture, only one bufferful of packets is read
|
130
|
+
# at a time, so fewer than cnt packets may be processed. A value of
|
131
|
+
# -1 or 0 for cnt causes all the packets received in one buffer to be
|
132
|
+
# processed when reading a live capture, and causes all the packets
|
133
|
+
# in the file to be processed when reading a savefile.
|
134
|
+
#
|
135
|
+
# Note: In older versions of libpcap, the behavior when cnt was 0 was
|
136
|
+
# undefined; different platforms and devices behaved differently, so
|
137
|
+
# code that must work with older versions of libpcap should use -1,
|
138
|
+
# nor 0, as the value of cnt.
|
139
|
+
#
|
140
|
+
# @yield [self, pkt]
|
141
|
+
#
|
142
|
+
# @yieldparam [CaptureWrapper] self
|
143
|
+
# A reference to self is passed to the block.
|
144
|
+
#
|
145
|
+
# @yieldparam [Packet] pkt
|
146
|
+
# A packet object is yielded which references the header and bytes.
|
147
|
+
#
|
148
|
+
# @return [Integer, nil]
|
149
|
+
# Returns the number of packets processed on success; this can be 0
|
150
|
+
# if no packets were read from a live capture or if no more packets
|
151
|
+
# are available in a savefile. It returns `nil` if the loop
|
152
|
+
# terminated due to a call to {CommonWrapper#stop} before any
|
153
|
+
# packets were processed.
|
154
|
+
#
|
155
|
+
# @raise [ReadError]
|
156
|
+
# An exception is raised if an error occurs or if libpcap returns
|
157
|
+
# an unexpected value.
|
158
|
+
#
|
159
|
+
def dispatch(opts={}, &block)
|
160
|
+
cnt = (opts[:count] || DEFAULT_COUNT) # default to infinite loop
|
161
|
+
h = opts[:handler]
|
162
|
+
|
163
|
+
ret = PCap.pcap_dispatch(_pcap, cnt, _wrap_callback(h, block),nil)
|
164
|
+
|
165
|
+
if ret == -1
|
166
|
+
raise(ReadError,"pcap_dispatch(): #{geterr}",caller)
|
167
|
+
elsif ret -2
|
168
|
+
return nil
|
169
|
+
elsif ret > -1
|
170
|
+
return ret
|
171
|
+
else
|
172
|
+
raise(ReadError,"unexpected return from pcap_dispatch() -> #{ret}",caller)
|
173
|
+
end
|
122
174
|
end
|
123
|
-
end
|
124
175
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
# processed when reading a savefile.
|
141
|
-
#
|
142
|
-
# Note: In older versions of libpcap, the behavior when cnt was 0 was
|
143
|
-
# undefined; different platforms and devices behaved differently, so
|
144
|
-
# code that must work with older versions of libpcap should use -1, nor
|
145
|
-
# 0, as the value of cnt.
|
146
|
-
#
|
147
|
-
# @yield [self, pkt]
|
148
|
-
#
|
149
|
-
# @yieldparam [CaptureWrapper] self
|
150
|
-
# A reference to self is passed to the block.
|
151
|
-
#
|
152
|
-
# @yieldparam [Packet] pkt
|
153
|
-
# A packet object is yielded which references the header and bytes.
|
154
|
-
#
|
155
|
-
# @return [Integer, nil]
|
156
|
-
# Returns the number of packets processed on success; this can be 0 if
|
157
|
-
# no packets were read from a live capture or if no more packets are
|
158
|
-
# available in a savefile. It returns nil if the loop terminated due
|
159
|
-
# to a call to CommonWrapper.stop() before any packets were processed.
|
160
|
-
#
|
161
|
-
# @raise [ReadError]
|
162
|
-
# An exception is raised if an error occurs or if libpcap returns
|
163
|
-
# an unexpected value.
|
164
|
-
#
|
165
|
-
def dispatch(opts={}, &block)
|
166
|
-
cnt = opts[:count] || -1 # default to infinite loop
|
167
|
-
h = opts[:handler]
|
168
|
-
|
169
|
-
ret = FFI::PCap.pcap_loop(_pcap, cnt, _wrap_callback(h, block),nil)
|
170
|
-
if ret == -1
|
171
|
-
raise(ReadError, "pcap_dispatch(): #{geterr()}")
|
172
|
-
elsif ret -2
|
173
|
-
return nil
|
174
|
-
elsif ret > -1
|
175
|
-
return ret
|
176
|
-
else
|
177
|
-
raise(ReadError, "unexpected return from pcap_dispatch() -> #{ret}")
|
176
|
+
#
|
177
|
+
# This method uses the older `pcap_next()` function which has been
|
178
|
+
# deprecated in favor of `pcap_next_ex()`. It is included only for
|
179
|
+
# backward compatability purposes.
|
180
|
+
#
|
181
|
+
# Important Note. According to libpcap documentation:
|
182
|
+
#
|
183
|
+
# Unfortunately, there is no way to determine whether an error
|
184
|
+
# occured or not when using pcap_next().
|
185
|
+
#
|
186
|
+
def old_next
|
187
|
+
header = PacketHeader.new
|
188
|
+
bytes = PCap.pcap_next(_pcap, header)
|
189
|
+
|
190
|
+
return Packet.new(header, bytes) unless bytes.null?
|
178
191
|
end
|
179
|
-
end
|
180
192
|
|
193
|
+
#
|
194
|
+
# Reads the next packet from a pcap device and returns a
|
195
|
+
# success/failure indication.
|
196
|
+
#
|
197
|
+
# @return [Packet, nil]
|
198
|
+
# A packet is returned on success or a `nil` if the timeout expired
|
199
|
+
# or all packets in a dump file have been exhausted when reading
|
200
|
+
# from a savefile.
|
201
|
+
#
|
202
|
+
# @raise [ReadError]
|
203
|
+
# This exception is raised if there was an error calling
|
204
|
+
# `pcap_next_ex()`.
|
205
|
+
#
|
206
|
+
# @raise [TimeoutError]
|
207
|
+
# This exception is raised if the timeout expires
|
208
|
+
#
|
209
|
+
def next
|
210
|
+
hdr_p = MemoryPointer.new(:pointer)
|
211
|
+
buf_p = MemoryPointer.new(:pointer)
|
181
212
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
bytes = FFI::PCap.pcap_next(_pcap, header)
|
194
|
-
if bytes.null?
|
195
|
-
return nil # or raise an exception?
|
196
|
-
else
|
197
|
-
return Packet.new(header, bytes)
|
213
|
+
case PCap.pcap_next_ex(_pcap, hdr_p, buf_p)
|
214
|
+
when -1 # error
|
215
|
+
raise(ReadError,"pcap_next_ex(): #{geterr}",caller)
|
216
|
+
when 0 # live capture read timeout expired
|
217
|
+
return nil
|
218
|
+
when -2 # savefile packets exhausted
|
219
|
+
return nil
|
220
|
+
when 1
|
221
|
+
hdr = PacketHeader.new(hdr_p.get_pointer(0))
|
222
|
+
return Packet.new(hdr, buf_p.get_pointer(0))
|
223
|
+
end
|
198
224
|
end
|
199
|
-
end
|
200
225
|
|
226
|
+
alias next_extra next
|
227
|
+
alias next_ex next
|
201
228
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
#
|
214
|
-
# @raise [TimeoutError]
|
215
|
-
# This exception is raised if the timeout expires
|
216
|
-
#
|
217
|
-
def next
|
218
|
-
hdr_p = MemoryPointer.new(:pointer)
|
219
|
-
buf_p = MemoryPointer.new(:pointer)
|
220
|
-
|
221
|
-
case FFI::PCap.pcap_next_ex(_pcap, hdr_p, buf_p)
|
222
|
-
when -1 # error
|
223
|
-
raise(ReadError, "pcap_next_ex(): #{geterr()}")
|
224
|
-
when 0 # live capture read timeout expired
|
225
|
-
return nil
|
226
|
-
when -2 # savefile packets exhausted
|
227
|
-
return nil
|
228
|
-
when 1
|
229
|
-
hdr = PacketHeader.new( hdr_p.get_pointer(0) )
|
230
|
-
return Packet.new(hdr, buf_p.get_pointer(0))
|
229
|
+
#
|
230
|
+
# Sets a flag that will force {#dispatch} or {#loop} to return rather
|
231
|
+
# than looping; they will return the number of packets that have been
|
232
|
+
# processed so far, or `nil` if no packets have been processed so far.
|
233
|
+
#
|
234
|
+
# breakloop does not guarantee that no further packets will be
|
235
|
+
# processed by {#dispatch} or {#loop} after it is called. At most
|
236
|
+
# one more packet may be processed.
|
237
|
+
#
|
238
|
+
def breakloop
|
239
|
+
PCap.pcap_breakloop(_pcap)
|
231
240
|
end
|
232
|
-
end
|
233
241
|
|
234
|
-
|
235
|
-
alias next_ex next
|
242
|
+
alias stop breakloop
|
236
243
|
|
244
|
+
#
|
245
|
+
# Used to specify a pcap filter for the pcap interface. This method
|
246
|
+
# compiles a filter expression and applies it on the wrapped pcap
|
247
|
+
# interface.
|
248
|
+
#
|
249
|
+
# @param [String] expression
|
250
|
+
# A pcap filter expression. See pcap-filter(7) manpage for syntax.
|
251
|
+
#
|
252
|
+
# @param [Hash] opts
|
253
|
+
# Compile options. See compile()
|
254
|
+
#
|
255
|
+
# @raise [LibError]
|
256
|
+
# On failure, an exception is raised with the relevant error
|
257
|
+
# message from libpcap.
|
258
|
+
#
|
259
|
+
def set_filter(expression, opts={})
|
260
|
+
code = compile(expression, opts)
|
261
|
+
ret = PCap.pcap_setfilter(_pcap, code)
|
237
262
|
|
238
|
-
|
239
|
-
|
240
|
-
# processed so far, or nil if no packets have been processed so far.
|
241
|
-
#
|
242
|
-
# breakloop does not guarantee that no further packets will be
|
243
|
-
# processed by dispatch() or loop() after it is called. At most
|
244
|
-
# one more packet may be processed.
|
245
|
-
#
|
246
|
-
def breakloop
|
247
|
-
FFI::PCap.pcap_breakloop(_pcap)
|
248
|
-
end
|
263
|
+
# done with this, we can free it
|
264
|
+
code.free!
|
249
265
|
|
250
|
-
|
266
|
+
if ret < 0
|
267
|
+
raise(LibError, "pcap_setfilter(): #{geterr}",caller)
|
268
|
+
end
|
251
269
|
|
270
|
+
return expression
|
271
|
+
end
|
252
272
|
|
253
|
-
|
254
|
-
|
255
|
-
# interface.
|
256
|
-
#
|
257
|
-
# @param [String] expression
|
258
|
-
# A pcap filter expression. See pcap-filter(7) manpage for syntax.
|
259
|
-
#
|
260
|
-
# @param [Hash] opts
|
261
|
-
# Compile options. See compile()
|
262
|
-
#
|
263
|
-
# @raise [LibError]
|
264
|
-
# On failure, an exception is raised with the relevant error message
|
265
|
-
# from libpcap.
|
266
|
-
#
|
267
|
-
def set_filter(expression, opts={})
|
268
|
-
code = compile(expression, opts)
|
269
|
-
ret = FFI::PCap.pcap_setfilter(_pcap, code)
|
270
|
-
code.free! # done with this, we can free it
|
271
|
-
raise(LibError, "pcap_setfilter(): #{geterr()}") if ret < 0
|
272
|
-
return expression
|
273
|
-
end
|
273
|
+
alias setfilter set_filter
|
274
|
+
alias filter= set_filter
|
274
275
|
|
275
|
-
|
276
|
-
|
276
|
+
def fileno
|
277
|
+
PCap.pcap_fileno(_pcap)
|
278
|
+
end
|
277
279
|
|
278
|
-
|
280
|
+
def selectable_fd
|
281
|
+
if PCap.respond_to?(:pcap_get_selectable_fd)
|
282
|
+
PCap.pcap_get_selectable_fd(pcap)
|
283
|
+
else
|
284
|
+
raise(NotImplementedError, "selectable pcap IO is not available for your platform")
|
285
|
+
end
|
286
|
+
end
|
279
287
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
attach_function :pcap_next, [:pcap_t, PacketHeader], :pointer
|
284
|
-
attach_function :pcap_next_ex, [:pcap_t, :pointer, :pointer], :int
|
285
|
-
attach_function :pcap_breakloop, [:pcap_t], :void
|
286
|
-
attach_function :pcap_setfilter, [:pcap_t, BPFProgram], :int
|
288
|
+
def selectable_io
|
289
|
+
::IO.new(self.selectable_fd, 'r')
|
290
|
+
end
|
287
291
|
|
288
|
-
|
292
|
+
def _wrap_callback(h, block)
|
293
|
+
h ||= @handler
|
294
|
+
|
295
|
+
if h
|
296
|
+
h = h.new() if h.kind_of?(Class)
|
297
|
+
|
298
|
+
unless h.respond_to?(:receive_pcap)
|
299
|
+
raise(NoMethodError, "The handler #{h.class} has no receive_pcap method",caller)
|
300
|
+
end
|
301
|
+
|
302
|
+
return lambda { |usr,phdr,body|
|
303
|
+
yld = h.receive_pcap(self, Packet.new(phdr,body))
|
304
|
+
|
305
|
+
block.call(*yld) if (block && yld)
|
306
|
+
}
|
307
|
+
elsif (block.kind_of?(Proc) || block.kind_of?(Method))
|
308
|
+
return lambda { |usr,phdr,body|
|
309
|
+
block.call(pcap,Packet.new(phdr,body))
|
310
|
+
}
|
311
|
+
else
|
312
|
+
raise(ArgumentError,"Neither a handler nor block were provided",caller)
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
private :_wrap_callback
|
317
|
+
|
318
|
+
end
|
319
|
+
|
320
|
+
callback :pcap_handler, [:pointer, PacketHeader, :pointer], :void
|
321
|
+
attach_function :pcap_loop, [:pcap_t, :int, :pcap_handler, :pointer], :int
|
322
|
+
attach_function :pcap_dispatch, [:pcap_t, :int, :pcap_handler, :pointer], :int
|
323
|
+
attach_function :pcap_next, [:pcap_t, PacketHeader], :pointer
|
324
|
+
attach_function :pcap_next_ex, [:pcap_t, :pointer, :pointer], :int
|
325
|
+
attach_function :pcap_breakloop, [:pcap_t], :void
|
326
|
+
attach_function :pcap_setfilter, [:pcap_t, BPFProgram], :int
|
327
|
+
attach_function :pcap_fileno, [:pcap_t], :int
|
328
|
+
end
|
289
329
|
end
|