capp 1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5277c07b5623a004709e40ee59b46fd0f5a21617
4
+ data.tar.gz: 63df47ceb85aaa2d77ab4a100f8d7d1a241277fe
5
+ SHA512:
6
+ metadata.gz: d0bb5ba29e2ff727b16e2c5eaf2c49f3aa74bcb43e722df14455271a76f15938fbe5ce54d218316b81f250ddc3272fcd2ab1e233e4d0d298bf3a964c3611ff75
7
+ data.tar.gz: 2caceca5822d67d340ec641e17ca153f357dbc8794cea4977dcf01db4169b3b0a7b26aa8d744d8ccaffafc27845a83460ba018b3a8a148721622519ceb3aef46
Binary file
Binary file
@@ -0,0 +1,12 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'autotest/restart'
4
+
5
+ Autotest.add_hook :initialize do |at|
6
+ at.testlib = 'minitest/autorun'
7
+ end
8
+
9
+ Autotest.add_hook :run_command do |at|
10
+ system "rake compile"
11
+ end
12
+
File without changes
data/.hoerc ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ exclude: !ruby/regexp /TAGS|CVS|tmp|\.(swp|svn|DS_Store|cvsignore|git|chef|travis|bundle|so)/
@@ -0,0 +1,4 @@
1
+ === 1.0 / 2013-05-02
2
+
3
+ Birthday!
4
+
@@ -0,0 +1,24 @@
1
+ .autotest
2
+ .hoerc
3
+ History.rdoc
4
+ Manifest.txt
5
+ README.rdoc
6
+ Rakefile
7
+ ext/capp/capp.c
8
+ ext/capp/extconf.rb
9
+ ext/capp/structs.h
10
+ lib/capp.rb
11
+ lib/capp/packet.rb
12
+ lib/capp/test_case.rb
13
+ test/802.1X.pcap
14
+ test/arp.pcap
15
+ test/icmp4.pcap
16
+ test/icmp6.pcap
17
+ test/tcp4.pcap
18
+ test/tcp6.pcap
19
+ test/test_capp.rb
20
+ test/test_capp_packet.rb
21
+ test/test_capp_packet_tcp_header.rb
22
+ test/test_capp_root.rb
23
+ test/udp4.pcap
24
+ test/udp6.pcap
@@ -0,0 +1,84 @@
1
+ = capp
2
+
3
+ home :: https://github.com/drbrain/capp
4
+ rdoc :: http://docs.seattlerb.org/capp
5
+ bugs :: https://github.com/drbrain/capp/issues
6
+
7
+ == Description
8
+
9
+ Capp is a packet capture library that wraps libpcap. Capp provides a simple
10
+ API for capturing packets and automatically unpacks common packets (including
11
+ Ethernet, IP, TCP, UDP and ICMP). Capp also cooperates with other threads
12
+ better than other pcap wrapper libraries for ruby.
13
+
14
+ == Examples
15
+
16
+ Basic single-thread packet capturing:
17
+
18
+ require 'capp'
19
+
20
+ Capp.live.loop do |packet|
21
+ # ...
22
+ end
23
+
24
+ Basic multi-thread packet capturing:
25
+
26
+ require 'capp'
27
+ require 'thread'
28
+
29
+ q = Queue.new
30
+
31
+ Thread.new do
32
+ while packet = q.deq do
33
+ # ...
34
+ end
35
+ end
36
+
37
+ capp = Capp.live.loop do |packet|
38
+ q.enq packet
39
+ end
40
+
41
+ == Requirements
42
+
43
+ * libpcap, tested with 1.1.1 and 1.3.0
44
+
45
+ == Install
46
+
47
+ sudo gem install capp
48
+
49
+ == Developers
50
+
51
+ After checking out the source, run:
52
+
53
+ $ rake newb
54
+ $ rake newb
55
+
56
+ This task will install any missing dependencies, run the tests/specs,
57
+ and generate the RDoc. You need to run it twice as the first run installs the
58
+ dependencies needed to compile the C extension.
59
+
60
+ == License
61
+
62
+ (The MIT License)
63
+
64
+ Copyright (c) Eric Hodel
65
+
66
+ Permission is hereby granted, free of charge, to any person obtaining
67
+ a copy of this software and associated documentation files (the
68
+ 'Software'), to deal in the Software without restriction, including
69
+ without limitation the rights to use, copy, modify, merge, publish,
70
+ distribute, sublicense, and/or sell copies of the Software, and to
71
+ permit persons to whom the Software is furnished to do so, subject to
72
+ the following conditions:
73
+
74
+ The above copyright notice and this permission notice shall be
75
+ included in all copies or substantial portions of the Software.
76
+
77
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
78
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
79
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
80
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
81
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
82
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
83
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
84
+
@@ -0,0 +1,57 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ begin
6
+ require 'rake/extensiontask'
7
+ rescue LoadError => e
8
+ warn "\nmissing #{e.path} (for rake-compiler)" if e.respond_to? :path
9
+ warn "run: rake newb\n\n"
10
+ end
11
+
12
+ Hoe.plugin :git
13
+ Hoe.plugin :minitest
14
+ Hoe.plugin :travis
15
+
16
+ HOE = Hoe.spec 'capp' do
17
+ developer 'Eric Hodel', 'drbrain@segment7.net'
18
+
19
+ rdoc_locations << 'docs.seattlerb.org:/data/www/docs.seattlerb.org/capp/'
20
+
21
+ self.extra_rdoc_files << 'ext/capp/capp.c'
22
+ self.spec_extras[:extensions] = 'ext/capp/extconf.rb'
23
+
24
+ self.readme_file = 'README.rdoc'
25
+
26
+ self.extra_dev_deps << ['rake-compiler', '~> 0.8']
27
+ end
28
+
29
+ if Rake.const_defined? :ExtensionTask then
30
+ Rake::ExtensionTask.new 'capp', HOE.spec do |ext|
31
+ ext.lib_dir = 'lib/capp'
32
+ end
33
+
34
+ task test: :compile
35
+ end
36
+
37
+ namespace :travis do
38
+ task :install_libpcap do
39
+ sh 'sudo apt-get install libpcap-dev'
40
+ end
41
+
42
+ Rake::TestTask.new root_test: %w[compile] do |t|
43
+ t.libs << 'lib'
44
+ t.test_files = FileList['test/test_capp_root.rb']
45
+ end
46
+
47
+ task :run_root_test do
48
+ ruby = Gem.ruby
49
+ sh 'sudo', '-E', ruby, '-S', 'rake', '-t', 'travis:root_test'
50
+ end
51
+
52
+ task before: %w[install_libpcap]
53
+ end
54
+
55
+ task travis: %w[travis:run_root_test]
56
+
57
+ # vim: syntax=ruby
@@ -0,0 +1,1382 @@
1
+ #include <pcap/pcap.h>
2
+
3
+ #include <unistd.h>
4
+ #include <sys/socket.h>
5
+ #include <net/ethernet.h>
6
+ #include <net/if_arp.h>
7
+ #include <netinet/in.h>
8
+ #include <netinet/ip.h>
9
+ #include <netinet/ip6.h>
10
+ #include <netinet/ip_icmp.h>
11
+ #include <arpa/inet.h>
12
+
13
+ #include <ruby.h>
14
+ #include <ruby/io.h>
15
+
16
+ #include "extconf.h"
17
+ #include "structs.h"
18
+
19
+ #ifdef HAVE_NET_IF_DL_H
20
+ #include <net/if_dl.h>
21
+ #endif
22
+
23
+ /* Ethernet functions in the internet headers? WTF Linux? */
24
+ #ifdef HAVE_NETINET_ETHER_H
25
+ #include <netinet/ether.h>
26
+ #endif
27
+
28
+ #ifdef HAVE_RUBY_THREAD_H
29
+ #include <ruby/thread.h>
30
+ #else
31
+ void *rb_thread_call_with_gvl(void *(*func)(void *), void *data1);
32
+
33
+ void *rb_thread_call_without_gvl(void *(*func)(void *), void *data1,
34
+ rb_unblock_function_t *ubf, void *data2);
35
+ #endif
36
+
37
+ #ifndef ETHERTYPE_PAE
38
+ #define ETHERTYPE_PAE 0x888e
39
+ #endif
40
+
41
+ #ifndef ETHERTYPE_RSN_PREAUTH
42
+ #define ETHERTYPE_RSN_PREAUTH 0x88c7
43
+ #endif
44
+
45
+ #ifndef ARPHRD_FRELAY
46
+ #define ARPHRD_FRELAY 15
47
+ #endif
48
+
49
+ #ifndef ARPHRD_IEEE1394_EUI64
50
+ #define ARPHRD_IEEE1394_EUI64 27
51
+ #endif
52
+
53
+ #ifndef ARPOP_REVREQUEST
54
+ #define ARPOP_REVREQUEST 3
55
+ #endif
56
+
57
+ #ifndef ARPOP_REVREPLY
58
+ #define ARPOP_REVREPLY 4
59
+ #endif
60
+
61
+ #ifndef ARPOP_INVREQUEST
62
+ #define ARPOP_INVREQUEST 8
63
+ #endif
64
+
65
+ #ifndef ARPOP_INVREPLY
66
+ #define ARPOP_INVREPLY 9
67
+ #endif
68
+
69
+ #ifndef PCAP_NETMASK_UNKNOWN
70
+ #define PCAP_NETMASK_UNKNOWN 0xFFFFFFFF
71
+ #endif
72
+
73
+ #ifndef NUM2USHORT
74
+ #define NUM2USHORT (unsigned short)NUM2UINT
75
+ #endif
76
+
77
+ struct capp_loop_args {
78
+ pcap_t *handle;
79
+ int datalink;
80
+ const struct pcap_pkthdr *header;
81
+ const u_char *data;
82
+ };
83
+
84
+ #define GetCapp(obj, capp) Data_Get_Struct(obj, pcap_t, capp)
85
+
86
+ static ID id_arp;
87
+ static ID id_drop;
88
+ static ID id_ethernet;
89
+ static ID id_icmp;
90
+ static ID id_ifdrop;
91
+ static ID id_ipv4;
92
+ static ID id_ipv6;
93
+ static ID id_iv_datalink;
94
+ static ID id_iv_device;
95
+ static ID id_recv;
96
+ static ID id_type;
97
+ static ID id_tcp;
98
+ static ID id_udp;
99
+ static ID id_unknown_layer3;
100
+ static ID id_unpack_sockaddr_in;
101
+
102
+ static VALUE cCapp;
103
+ static VALUE cCappAddress;
104
+ static VALUE cCappDevice;
105
+ static VALUE cCappPacket;
106
+ static VALUE cCappPacketARPHeader;
107
+ static VALUE cCappPacketEthernetHeader;
108
+ static VALUE cCappPacketICMPHeader;
109
+ static VALUE cCappPacketIPv4Header;
110
+ static VALUE cCappPacketIPv6Header;
111
+ static VALUE cCappPacketTCPHeader;
112
+ static VALUE cCappPacketUDPHeader;
113
+ static VALUE cCappPacketUnknownLayer3Header;
114
+ static VALUE cSocket;
115
+
116
+ static VALUE eCappError;
117
+
118
+ /*
119
+ * call-seq:
120
+ * Capp.default_device_name -> string
121
+ *
122
+ * Returns the default device name
123
+ */
124
+ static VALUE
125
+ capp_s_default_device_name(VALUE klass)
126
+ {
127
+ char errbuf[PCAP_ERRBUF_SIZE];
128
+ char *device;
129
+
130
+ *errbuf = '\0';
131
+
132
+ device = pcap_lookupdev(errbuf);
133
+
134
+ if (device == NULL)
135
+ rb_raise(eCappError, "pcap_create: %s", errbuf);
136
+
137
+ if (*errbuf)
138
+ rb_warn("%s", errbuf);
139
+
140
+ return rb_usascii_str_new_cstr(device);
141
+ }
142
+
143
+ static VALUE
144
+ capp_sockaddr_to_address(struct sockaddr *addr)
145
+ {
146
+ VALUE address, sockaddr_string;
147
+ #ifdef HAVE_NET_IF_DL_H
148
+ struct ether_addr *ether;
149
+ struct sockaddr_dl *dl;
150
+ #endif
151
+
152
+ if (NULL == addr)
153
+ return Qnil;
154
+
155
+ switch (addr->sa_family) {
156
+ case AF_INET:
157
+ sockaddr_string = rb_str_new((char *)addr, sizeof(struct sockaddr_in));
158
+ address =
159
+ rb_funcall(cSocket, id_unpack_sockaddr_in, 1, sockaddr_string);
160
+ return rb_ary_entry(address, 1);
161
+ case AF_INET6:
162
+ sockaddr_string = rb_str_new((char *)addr, sizeof(struct sockaddr_in6));
163
+ address =
164
+ rb_funcall(cSocket, id_unpack_sockaddr_in, 1, sockaddr_string);
165
+ return rb_ary_entry(address, 1);
166
+ #ifdef HAVE_NET_IF_DL_H
167
+ case AF_LINK:
168
+ dl = (struct sockaddr_dl *)addr;
169
+ ether = (struct ether_addr *)LLADDR(dl);
170
+
171
+ return rb_usascii_str_new_cstr(ether_ntoa(ether));
172
+ #endif
173
+ default:
174
+ return rb_usascii_str_new_cstr("(unsupported address family)");
175
+ }
176
+ }
177
+
178
+ static VALUE
179
+ capp_addr_to_addresses(pcap_addr_t *addrs)
180
+ {
181
+ VALUE address, addresses, addr_args[4];
182
+ pcap_addr_t *addr;
183
+
184
+ addresses = rb_ary_new();
185
+
186
+ if (addrs) {
187
+ for (addr = addrs; addr; addr = addr->next) {
188
+ addr_args[0] = capp_sockaddr_to_address(addr->addr);
189
+ addr_args[1] = capp_sockaddr_to_address(addr->netmask);
190
+ addr_args[2] = capp_sockaddr_to_address(addr->broadaddr);
191
+ addr_args[3] = capp_sockaddr_to_address(addr->dstaddr);
192
+
193
+ address = rb_class_new_instance(4, addr_args, cCappAddress);
194
+
195
+ rb_ary_push(addresses, address);
196
+ }
197
+ }
198
+
199
+ return addresses;
200
+ }
201
+
202
+ /*
203
+ * call-seq:
204
+ * Capp.devices -> array
205
+ *
206
+ * Returns an Array containing the devices and their addresses:
207
+ *
208
+ * [#<struct Capp::Address
209
+ * address="lo0",
210
+ * netmask=nil,
211
+ * broadcast=
212
+ * [#<struct Capp::Address
213
+ * address="0:0:0:0:0:0",
214
+ * netmask=nil,
215
+ * broadcast=nil,
216
+ * destination=nil>,
217
+ * #<struct Capp::Address
218
+ * address="fe80::1%lo0",
219
+ * netmask="ffff:ffff:ffff:ffff::",
220
+ * broadcast=nil,
221
+ * destination=nil>,
222
+ * #<struct Capp::Address
223
+ * address="127.0.0.1",
224
+ * netmask="255.0.0.0",
225
+ * broadcast=nil,
226
+ * destination=nil>,
227
+ * #<struct Capp::Address
228
+ * address="::1",
229
+ * netmask="ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
230
+ * broadcast=nil,
231
+ * destination=nil>],
232
+ * destination=1>,
233
+ * # [...]
234
+ * ]
235
+ */
236
+ static VALUE
237
+ capp_s_devices(VALUE klass)
238
+ {
239
+ VALUE device, devices, dev_args[4];
240
+ char errbuf[PCAP_ERRBUF_SIZE];
241
+ pcap_if_t *iface, *ifaces;
242
+
243
+ *errbuf = '\0';
244
+
245
+ if (pcap_findalldevs(&ifaces, errbuf))
246
+ rb_raise(eCappError, "pcap_create: %s", errbuf);
247
+
248
+ if (*errbuf)
249
+ rb_warn("%s", errbuf);
250
+
251
+ devices = rb_ary_new();
252
+
253
+ for (iface = ifaces; iface; iface = iface->next) {
254
+ dev_args[0] = rb_usascii_str_new_cstr(iface->name);
255
+ if (iface->description) {
256
+ dev_args[1] = rb_usascii_str_new_cstr(iface->description);
257
+ } else {
258
+ dev_args[1] = Qnil;
259
+ }
260
+ dev_args[2] = capp_addr_to_addresses(iface->addresses);
261
+ dev_args[3] = UINT2NUM(iface->flags);
262
+
263
+ device = rb_class_new_instance(4, dev_args, cCappDevice);
264
+
265
+ rb_ary_push(devices, device);
266
+ }
267
+
268
+ pcap_freealldevs(ifaces);
269
+
270
+ return devices;
271
+ }
272
+
273
+ /*
274
+ * call-seq:
275
+ * Capp.live -> capp
276
+ * Capp.live device -> capp
277
+ * Capp.live device, capture_length, -> capp
278
+ * Capp.live device, capture_length, promiscuous -> capp
279
+ * Capp.live device, capture_length, promiscuous, timeout -> capp
280
+ *
281
+ * Creates a Capp instance that will capture packets from a network device.
282
+ *
283
+ * +device+ is the device to capture packets from. If the device is omitted
284
+ * the default device (::default_device_name) is used.
285
+ *
286
+ * +capture_length+ is the number of bytes to capture from each packet. If
287
+ * a length is omitted 65535 is used.
288
+ *
289
+ * +promiscuous+ places the device in promiscuous mode when true, allowing you
290
+ * to see packets not sent directly to or from the device. Promiscuous mode
291
+ * is enabled by default.
292
+ *
293
+ * The +timeout+ is the number of maximum number of milliseconds that will
294
+ * elapse between receiving a packet and yielding it to the block given to
295
+ * #loop. The default timeout is 10 milliseconds. See #timeout= for further
296
+ * discussion.
297
+ *
298
+ * After creating an instance use #loop to start capturing packets.
299
+ */
300
+ static VALUE
301
+ capp_s_open_live(int argc, VALUE *argv, VALUE klass)
302
+ {
303
+ VALUE obj, device, snaplen, promiscuous, timeout;
304
+ int promisc = 0;
305
+ char errbuf[PCAP_ERRBUF_SIZE];
306
+ pcap_t *handle;
307
+
308
+ rb_scan_args(argc, argv, "04", &device, &snaplen, &promiscuous, &timeout);
309
+
310
+ if (!RTEST(device)) device = capp_s_default_device_name(klass);
311
+ if (!RTEST(snaplen)) snaplen = INT2NUM(65535);
312
+ if (!RTEST(promiscuous)) promiscuous = Qtrue;
313
+ if (!RTEST(timeout)) timeout = INT2NUM(10);
314
+
315
+ if (RTEST(promiscuous))
316
+ promisc = 1;
317
+
318
+ *errbuf = '\0';
319
+
320
+ handle = pcap_open_live(StringValueCStr(device), NUM2INT(snaplen),
321
+ promisc, NUM2INT(timeout), errbuf);
322
+
323
+ if (NULL == handle)
324
+ rb_raise(eCappError, "pcap_create: %s", errbuf);
325
+
326
+ if (*errbuf)
327
+ rb_warn("%s", errbuf);
328
+
329
+ obj = Data_Wrap_Struct(klass, NULL, pcap_close, handle);
330
+
331
+ rb_ivar_set(obj, id_iv_device, device);
332
+
333
+ return obj;
334
+ }
335
+
336
+ /*
337
+ * call-seq:
338
+ * Capp.offline filename -> capp
339
+ * Capp.offline io -> capp
340
+ *
341
+ * Creates an Capp that instance that captures packets from a pcap savefile.
342
+ * A savefile may be loaded from an open +file+:
343
+ *
344
+ * open 'savefile' do |io|
345
+ * capp = Capp.offline io
346
+ * # ...
347
+ * end
348
+ *
349
+ * Or a +filename+:
350
+ *
351
+ * capp = Capp.offline 'savefile'
352
+ *
353
+ * After creating an instance use #loop to start capturing packets.
354
+ *
355
+ * NOTE: When you give Capp.offline a Ruby IO you should avoid buffered
356
+ * reads or writes to the IO due to limitations of libpcap. (Using a pipe and
357
+ * reading from one end and writing to the other is fine, of course.)
358
+ */
359
+ static VALUE
360
+ capp_s_open_offline(VALUE klass, VALUE file)
361
+ {
362
+ VALUE obj;
363
+ char errbuf[PCAP_ERRBUF_SIZE];
364
+ pcap_t *handle;
365
+
366
+ *errbuf = '\0';
367
+
368
+ if (TYPE(file) == T_FILE) {
369
+ FILE *c_file;
370
+ rb_io_t *fptr;
371
+ int fd;
372
+
373
+ GetOpenFile(file, fptr);
374
+
375
+ fd = dup(fptr->fd);
376
+
377
+ if (-1 == fd)
378
+ rb_sys_fail("dup");
379
+
380
+ c_file = fdopen(fd, "r");
381
+
382
+ if (NULL == c_file)
383
+ rb_sys_fail("fdopen");
384
+
385
+ handle = pcap_fopen_offline(c_file, errbuf);
386
+ } else {
387
+ handle = pcap_open_offline(StringValueCStr(file), errbuf);
388
+ }
389
+
390
+ if (NULL == handle) {
391
+ if (RFILE(file))
392
+ rb_raise(eCappError, "pcap_fopen_offline: %s", errbuf);
393
+
394
+ rb_raise(eCappError, "pcap_open_offline: %s", errbuf);
395
+ }
396
+
397
+ if (*errbuf)
398
+ rb_warn("%s", errbuf);
399
+
400
+ obj = Data_Wrap_Struct(klass, NULL, pcap_close, handle);
401
+
402
+ rb_ivar_set(obj, id_iv_device, Qnil);
403
+
404
+ return obj;
405
+ }
406
+
407
+ /*
408
+ * call-seq:
409
+ * Capp.pcap_lib_version -> libpcap version string
410
+ *
411
+ * Returns the libpcap version string:
412
+ *
413
+ * Capp.pcap_lib_version #=> "libpcap version 1.1.1"
414
+ *
415
+ */
416
+ static VALUE
417
+ capp_s_pcap_lib_version(VALUE klass)
418
+ {
419
+ return rb_usascii_str_new_cstr(pcap_lib_version());
420
+ }
421
+
422
+ /*
423
+ * call-seq:
424
+ * capp.datalinks #=> ["datalink name", ...]
425
+ *
426
+ * Returns the supported datalinks for this capture instance:
427
+ *
428
+ * p Capp.live.datalinks
429
+ * #=> ["EN10MB", "PPI", "IEEE802_11_RADIO", "IEEE802_11",
430
+ * "IEEE802_11_RADIO_AVS", "RAW"]
431
+ *
432
+ * These can be used to change the datalink used to capture packets by using
433
+ * #datalink=
434
+ */
435
+ static VALUE
436
+ capp_datalinks(VALUE self)
437
+ {
438
+ int *dlt_buf;
439
+ pcap_t *handle;
440
+ VALUE datalink_ary;
441
+ int i, datalink_count;
442
+
443
+ GetCapp(self, handle);
444
+
445
+ datalink_count = pcap_list_datalinks(handle, &dlt_buf);
446
+
447
+ if (datalink_count == -1)
448
+ rb_raise(eCappError, "%s", pcap_geterr(handle));
449
+
450
+ datalink_ary = rb_ary_new2(datalink_count);
451
+
452
+ for (i = 0; i < datalink_count; i++) {
453
+ const char *datalink_name_cstr = pcap_datalink_val_to_name(dlt_buf[i]);
454
+ VALUE datalink_name = rb_usascii_str_new_cstr(datalink_name_cstr);
455
+
456
+ rb_ary_push(datalink_ary, datalink_name);
457
+ }
458
+
459
+ pcap_free_datalinks(dlt_buf);
460
+
461
+ return datalink_ary;
462
+ }
463
+
464
+ /*
465
+ * call-seq:
466
+ * capp.datalink #=> "datalink name"
467
+ *
468
+ * Returns datalink used for capturing packets.
469
+ *
470
+ * Capp.live.datalink #=> ["EN10MB"]
471
+ */
472
+ static VALUE
473
+ capp_datalink(VALUE self)
474
+ {
475
+ const char *datalink_name;
476
+ int dlt;
477
+ pcap_t *handle;
478
+
479
+ GetCapp(self, handle);
480
+
481
+ dlt = pcap_datalink(handle);
482
+
483
+ datalink_name = pcap_datalink_val_to_name(dlt);
484
+ return rb_usascii_str_new_cstr(datalink_name);
485
+ }
486
+
487
+ static VALUE
488
+ capp_make_ether_str(const struct ether_addr *addr)
489
+ {
490
+ return rb_usascii_str_new_cstr(ether_ntoa(addr));
491
+ }
492
+
493
+ static void
494
+ capp_make_unknown_layer3_header(VALUE headers, off_t offset)
495
+ {
496
+ VALUE unknown_args[1];
497
+
498
+ unknown_args[0] = UINT2NUM(offset);
499
+
500
+ rb_hash_aset(headers, ID2SYM(id_unknown_layer3),
501
+ rb_class_new_instance(1, unknown_args, cCappPacketUnknownLayer3Header));
502
+ }
503
+
504
+ static void
505
+ capp_make_ethernet_header(VALUE headers, const struct ether_header *ether)
506
+ {
507
+ VALUE ether_args[3];
508
+
509
+ ether_args[0] =
510
+ capp_make_ether_str((struct ether_addr *)ether->ether_dhost);
511
+ ether_args[1] =
512
+ capp_make_ether_str((struct ether_addr *)ether->ether_shost);
513
+ ether_args[2] = UINT2NUM(ntohs(ether->ether_type));
514
+
515
+ rb_hash_aset(headers, ID2SYM(id_ethernet),
516
+ rb_class_new_instance(3, ether_args, cCappPacketEthernetHeader));
517
+ }
518
+
519
+ static void
520
+ capp_make_icmp_header(VALUE headers, const struct icmp *header)
521
+ {
522
+ VALUE icmp_args[3];
523
+
524
+ icmp_args[0] = UINT2NUM(header->icmp_type);
525
+ icmp_args[1] = UINT2NUM(header->icmp_code);
526
+ icmp_args[2] = UINT2NUM(ntohs(header->icmp_cksum));
527
+
528
+ rb_hash_aset(headers, ID2SYM(id_icmp),
529
+ rb_class_new_instance(3, icmp_args, cCappPacketICMPHeader));
530
+ }
531
+
532
+ static void
533
+ capp_make_tcp_header(VALUE headers, const struct tcphdr *header)
534
+ {
535
+ VALUE tcp_args[9];
536
+
537
+ tcp_args[0] = UINT2NUM(ntohs(header->th_sport));
538
+ tcp_args[1] = UINT2NUM(ntohs(header->th_dport));
539
+ tcp_args[2] = UINT2NUM(ntohl(header->th_seq));
540
+ tcp_args[3] = UINT2NUM(ntohl(header->th_ack));
541
+ tcp_args[4] = UINT2NUM(TH_OFF(header));
542
+ tcp_args[5] = UINT2NUM(header->th_flags);
543
+ tcp_args[6] = UINT2NUM(ntohs(header->th_win));
544
+ tcp_args[7] = UINT2NUM(ntohs(header->th_sum));
545
+ tcp_args[8] = UINT2NUM(ntohs(header->th_urp));
546
+
547
+ rb_hash_aset(headers, ID2SYM(id_tcp),
548
+ rb_class_new_instance(9, tcp_args, cCappPacketTCPHeader));
549
+ }
550
+
551
+ static void
552
+ capp_make_udp_header(VALUE headers, const struct udphdr *header)
553
+ {
554
+ VALUE udp_args[4];
555
+
556
+ udp_args[0] = UINT2NUM(ntohs(header->uh_sport));
557
+ udp_args[1] = UINT2NUM(ntohs(header->uh_dport));
558
+ udp_args[2] = UINT2NUM(ntohs(header->uh_ulen));
559
+ udp_args[3] = UINT2NUM(ntohs(header->uh_sum));
560
+
561
+ rb_hash_aset(headers, ID2SYM(id_udp),
562
+ rb_class_new_instance(4, udp_args, cCappPacketUDPHeader));
563
+ }
564
+
565
+ static void
566
+ capp_make_arp_header(VALUE headers, const struct arphdr *header)
567
+ {
568
+ VALUE arp_args[7];
569
+ u_char hln, pln;
570
+ u_short hrd, pro;
571
+ u_short sha_offset, spa_offset, tha_offset, tpa_offset;
572
+
573
+ hrd = ntohs(header->ar_hrd);
574
+ arp_args[0] = UINT2NUM(hrd);
575
+
576
+ pro = ntohs(header->ar_pro);
577
+ arp_args[1] = UINT2NUM(pro);
578
+ arp_args[2] = UINT2NUM(ntohs(header->ar_op));
579
+
580
+ hln = header->ar_hln;
581
+ pln = header->ar_pln;
582
+
583
+ sha_offset = sizeof(struct arphdr);
584
+ spa_offset = sizeof(struct arphdr) + hln;
585
+ tha_offset = sizeof(struct arphdr) + hln + pln;
586
+ tpa_offset = sizeof(struct arphdr) + hln + pln + hln;
587
+
588
+ switch (hrd) {
589
+ case ARPHRD_ETHER:
590
+ arp_args[3] =
591
+ capp_make_ether_str((struct ether_addr *)((char *)header + sha_offset));
592
+ arp_args[5] =
593
+ capp_make_ether_str((struct ether_addr *)((char *)header + tha_offset));
594
+ break;
595
+ default:
596
+ rb_raise(rb_eNotImpError, "unsupported ARP hardware type %d", hrd);
597
+ }
598
+
599
+ switch (pro) {
600
+ case ETHERTYPE_IP:
601
+ arp_args[4] =
602
+ rb_usascii_str_new_cstr(inet_ntoa(*(struct in_addr *)((char *)header + spa_offset)));
603
+ arp_args[6] =
604
+ rb_usascii_str_new_cstr(inet_ntoa(*(struct in_addr *)((char *)header + tpa_offset)));
605
+ break;
606
+ default:
607
+ rb_raise(rb_eNotImpError, "unsupported ARP protocol %x", pro);
608
+ }
609
+
610
+ rb_hash_aset(headers, ID2SYM(id_arp),
611
+ rb_class_new_instance(7, arp_args, cCappPacketARPHeader));
612
+ }
613
+
614
+ static void
615
+ capp_make_ipv4_header(VALUE headers, const struct ip *header)
616
+ {
617
+ const char * ip_payload;
618
+ VALUE ipv4_args[11];
619
+
620
+ ipv4_args[0] = UINT2NUM(header->ip_v);
621
+ ipv4_args[1] = UINT2NUM(header->ip_hl);
622
+ ipv4_args[2] = UINT2NUM(header->ip_tos);
623
+ ipv4_args[3] = UINT2NUM(ntohs(header->ip_len));
624
+ ipv4_args[4] = UINT2NUM(ntohs(header->ip_id));
625
+ ipv4_args[5] = UINT2NUM(ntohs(header->ip_off));
626
+ ipv4_args[6] = UINT2NUM(header->ip_ttl);
627
+ ipv4_args[7] = UINT2NUM(header->ip_p);
628
+ ipv4_args[8] = UINT2NUM(ntohs(header->ip_sum));
629
+ ipv4_args[9] = rb_usascii_str_new_cstr(inet_ntoa(header->ip_src));
630
+ ipv4_args[10] = rb_usascii_str_new_cstr(inet_ntoa(header->ip_dst));
631
+
632
+ ip_payload = (char *)header + header->ip_hl * 4;
633
+
634
+ switch (header->ip_p) {
635
+ case IPPROTO_ICMP:
636
+ capp_make_icmp_header(headers, (const struct icmp *)ip_payload);
637
+ break;
638
+ case IPPROTO_TCP:
639
+ capp_make_tcp_header(headers, (const struct tcphdr *)ip_payload);
640
+ break;
641
+ case IPPROTO_UDP:
642
+ capp_make_udp_header(headers, (const struct udphdr *)ip_payload);
643
+ break;
644
+ }
645
+
646
+ rb_hash_aset(headers, ID2SYM(id_ipv4),
647
+ rb_class_new_instance(11, ipv4_args, cCappPacketIPv4Header));
648
+ }
649
+
650
+ static VALUE
651
+ capp_make_ipv6_addr(struct in6_addr addr)
652
+ {
653
+ char buf[INET6_ADDRSTRLEN];
654
+ const char *ptr;
655
+
656
+ ptr = inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
657
+
658
+ if (!ptr)
659
+ rb_sys_fail("inet_ntop");
660
+
661
+ return rb_usascii_str_new_cstr(ptr);
662
+ }
663
+
664
+ static void
665
+ capp_make_ipv6_header(VALUE headers, const struct ip6_hdr *header)
666
+ {
667
+ const char * ip_payload;
668
+ VALUE ipv6_args[8];
669
+
670
+ ipv6_args[0] = UINT2NUM(6);
671
+ ipv6_args[1] = UINT2NUM((header->ip6_flow >> 20) & 0xff);
672
+ ipv6_args[2] = UINT2NUM(ntohl(header->ip6_flow & 0xfffff));
673
+ ipv6_args[3] = UINT2NUM(ntohs(header->ip6_plen));
674
+ ipv6_args[4] = UINT2NUM(header->ip6_nxt);
675
+ ipv6_args[5] = UINT2NUM(header->ip6_hlim);
676
+ ipv6_args[6] = capp_make_ipv6_addr(header->ip6_src);
677
+ ipv6_args[7] = capp_make_ipv6_addr(header->ip6_dst);
678
+
679
+ ip_payload = (char *)header + sizeof(struct ip6_hdr);
680
+
681
+ switch (header->ip6_nxt) {
682
+ case IPPROTO_ICMP:
683
+ case IPPROTO_ICMPV6:
684
+ capp_make_icmp_header(headers, (const struct icmp *)ip_payload);
685
+ break;
686
+ case IPPROTO_TCP:
687
+ capp_make_tcp_header(headers, (const struct tcphdr *)ip_payload);
688
+ break;
689
+ case IPPROTO_UDP:
690
+ capp_make_udp_header(headers, (const struct udphdr *)ip_payload);
691
+ break;
692
+ }
693
+
694
+ rb_hash_aset(headers, ID2SYM(id_ipv6),
695
+ rb_class_new_instance(8, ipv6_args, cCappPacketIPv6Header));
696
+ }
697
+
698
+ static void
699
+ capp_make_packet_ethernet(VALUE headers, const u_char *data)
700
+ {
701
+ VALUE ether_header;
702
+ uint16_t ethertype;
703
+ size_t ether_header_size = sizeof(struct ether_header);
704
+
705
+ capp_make_ethernet_header(headers, (const struct ether_header *)data);
706
+
707
+ ether_header = rb_hash_aref(headers, ID2SYM(id_ethernet));
708
+ ethertype = NUM2USHORT(rb_funcall(ether_header, id_type, 0));
709
+
710
+ switch (ethertype) {
711
+ case ETHERTYPE_ARP:
712
+ capp_make_arp_header(headers,
713
+ (const struct arphdr *)(data + ether_header_size));
714
+ break;
715
+ case ETHERTYPE_IP:
716
+ capp_make_ipv4_header(headers,
717
+ (const struct ip *)(data + ether_header_size));
718
+ break;
719
+ case ETHERTYPE_IPV6:
720
+ capp_make_ipv6_header(headers,
721
+ (const struct ip6_hdr *)(data + ether_header_size));
722
+ break;
723
+ default:
724
+ capp_make_unknown_layer3_header(headers, ether_header_size);
725
+ break;
726
+ }
727
+ }
728
+
729
+ static void
730
+ capp_make_packet_null(VALUE headers, const u_char *data)
731
+ {
732
+ uint32_t protocol_family;
733
+ size_t protocol_family_size = sizeof(protocol_family);
734
+
735
+ memcpy((char *)&protocol_family, (char *)data, protocol_family_size);
736
+
737
+ /*
738
+ * This isn't necessarily in our host byte order; if this is
739
+ * a DLT_LOOP capture, it's in network byte order, and if
740
+ * this is a DLT_NULL capture from a machine with the opposite
741
+ * byte-order, it's in the opposite byte order from ours.
742
+ *
743
+ * If the upper 16 bits aren't all zero, assume it's byte-swapped.
744
+ */
745
+ if ((protocol_family & 0xFFFF0000) != 0)
746
+ protocol_family = SWAPLONG(protocol_family);
747
+
748
+ switch (protocol_family) {
749
+ /* PF_INET */
750
+ case BSD_AFNUM_INET:
751
+ capp_make_ipv4_header(headers,
752
+ (const struct ip *)(data + protocol_family_size));
753
+ break;
754
+ /* PF_INET6 */
755
+ case BSD_AFNUM_INET6_BSD:
756
+ case BSD_AFNUM_INET6_DARWIN:
757
+ case BSD_AFNUM_INET6_FREEBSD:
758
+ capp_make_ipv6_header(headers,
759
+ (const struct ip6_hdr *)(data + protocol_family_size));
760
+ break;
761
+ default:
762
+ capp_make_unknown_layer3_header(headers, protocol_family_size);
763
+ break;
764
+ }
765
+ }
766
+
767
+ /*
768
+ * capp_make_packet parses out the packet structure (if it understands it) and
769
+ * calls Capp::Packet::new.
770
+ *
771
+ * Parsing starts at the datalink level and works its way through the packet
772
+ * to the payload. Each parsing function is passed the payload for the
773
+ * current packet and the collected headers. The function must insert new
774
+ * data from the packet payload into the headers and repeat, with its payload,
775
+ * if possible.
776
+ */
777
+
778
+ static VALUE
779
+ capp_make_packet(int datalink, const struct pcap_pkthdr *header,
780
+ const u_char *data)
781
+ {
782
+ VALUE headers = rb_hash_new();
783
+ VALUE packet_args[6];
784
+
785
+ switch (datalink) {
786
+ case DLT_NULL:
787
+ capp_make_packet_null(headers, data);
788
+ break;
789
+ case DLT_EN10MB:
790
+ capp_make_packet_ethernet(headers, data);
791
+ break;
792
+ }
793
+
794
+ packet_args[0] = rb_time_new(header->ts.tv_sec, header->ts.tv_usec);
795
+ packet_args[1] = UINT2NUM(header->len);
796
+ packet_args[2] = UINT2NUM(header->caplen);
797
+ packet_args[3] = rb_str_new((const char *)data, header->caplen);
798
+ packet_args[4] = UINT2NUM(datalink);
799
+ packet_args[5] = headers;
800
+
801
+ return rb_class_new_instance(6, packet_args, cCappPacket);
802
+ }
803
+
804
+ static void *
805
+ capp_loop_callback_with_gvl(void *ptr)
806
+ {
807
+ struct capp_loop_args *args = (struct capp_loop_args *)ptr;
808
+
809
+ rb_yield(capp_make_packet(args->datalink, args->header, args->data));
810
+
811
+ return NULL;
812
+ }
813
+
814
+ static void
815
+ capp_loop_callback(u_char *ptr, const struct pcap_pkthdr *header,
816
+ const u_char *data)
817
+ {
818
+ struct capp_loop_args *args = (struct capp_loop_args *)ptr;
819
+
820
+ args->header = header;
821
+ args->data = data;
822
+
823
+ rb_thread_call_with_gvl(capp_loop_callback_with_gvl, (void *)args);
824
+ }
825
+
826
+ static VALUE
827
+ capp_loop_end(VALUE self)
828
+ {
829
+ pcap_t *handle;
830
+
831
+ GetCapp(self, handle);
832
+
833
+ pcap_breakloop(handle);
834
+
835
+ return Qnil;
836
+ }
837
+
838
+ static void
839
+ capp_loop_interrupt(void *ptr)
840
+ {
841
+ pcap_t *handle = (pcap_t *)ptr;
842
+
843
+ pcap_breakloop(handle);
844
+ }
845
+
846
+ static void *
847
+ capp_loop_run_no_gvl(void *ptr)
848
+ {
849
+ struct capp_loop_args *args = (struct capp_loop_args *)ptr;
850
+ int res;
851
+
852
+ res = pcap_loop(args->handle, -1, capp_loop_callback, (u_char *)ptr);
853
+
854
+ return (void *)(intptr_t)res;
855
+ }
856
+
857
+ static VALUE
858
+ capp_loop_run(VALUE self)
859
+ {
860
+ struct capp_loop_args args;
861
+ int res;
862
+
863
+ GetCapp(self, args.handle);
864
+
865
+ args.datalink = pcap_datalink(args.handle);
866
+
867
+ rb_ivar_set(self, id_iv_datalink, INT2NUM(args.datalink));
868
+
869
+ res = (int)(intptr_t)rb_thread_call_without_gvl(capp_loop_run_no_gvl,
870
+ (void *)&args, capp_loop_interrupt, (void *)args.handle);
871
+
872
+ if (res == -1)
873
+ rb_raise(eCappError, "%s", pcap_geterr(args.handle));
874
+
875
+ return self;
876
+ }
877
+
878
+ /*
879
+ * call-seq:
880
+ * capp.loop { |packet| ... } -> self
881
+ * capp.loop -> enumerator
882
+ *
883
+ * Starts capturing packets. Each packet captured is yielded to the block.
884
+ * Packets are instances of Capp::Packet.
885
+ *
886
+ * If no block is given an enumerator is returned.
887
+ *
888
+ * You can stop capturing packets by returning from the block (or using break)
889
+ * or by calling #stop on the instance. Packet capture can be restarted
890
+ * later.
891
+ */
892
+ static VALUE
893
+ capp_loop(VALUE self)
894
+ {
895
+ RETURN_ENUMERATOR(self, 0, 0);
896
+
897
+ rb_ensure(capp_loop_run, self, capp_loop_end, self);
898
+
899
+ return self;
900
+ }
901
+
902
+ /*
903
+ * call-seq:
904
+ * capp.savefile_major_version -> integer
905
+ *
906
+ * When called on a capture instance created from a savefile, returns the
907
+ * major version of the savefile. When called on a live capture instance it
908
+ * returns a meaningless value.
909
+ */
910
+ static VALUE
911
+ capp_savefile_major_version(VALUE self)
912
+ {
913
+ pcap_t *handle;
914
+
915
+ GetCapp(self, handle);
916
+
917
+ return INT2NUM(pcap_major_version(handle));
918
+ }
919
+
920
+ /*
921
+ * call-seq:
922
+ * capp.savefile_minor_version -> integer
923
+ *
924
+ * When called on a capture instance created from a savefile, returns the
925
+ * minor version of the savefile. When called on a live capture instance it
926
+ * returns a meaningless value.
927
+ */
928
+ static VALUE
929
+ capp_savefile_minor_version(VALUE self)
930
+ {
931
+ pcap_t *handle;
932
+
933
+ GetCapp(self, handle);
934
+
935
+ return INT2NUM(pcap_minor_version(handle));
936
+ }
937
+
938
+ /*
939
+ * call-seq:
940
+ * capp.datalink = datalink_name
941
+ *
942
+ * Sets the link-layer header type to be used by the capture instance to the
943
+ * given +datalink_name+. You can see the supported datalink names by calling
944
+ * #datalinks on the capture instance.
945
+ *
946
+ * Note that most possible datalink types do not have full support in Capp.
947
+ * You may receive the raw packet without any further extraction of packet
948
+ * fields.
949
+ */
950
+ static VALUE
951
+ capp_set_datalink(VALUE self, VALUE datalink)
952
+ {
953
+ int dlt;
954
+ pcap_t *handle;
955
+ const char *datalink_name = StringValueCStr(datalink);
956
+
957
+ GetCapp(self, handle);
958
+
959
+ dlt = pcap_datalink_name_to_val(datalink_name);
960
+
961
+ if (-1 == dlt)
962
+ rb_raise(eCappError, "unrecognized datalink name %s", datalink_name);
963
+
964
+ if (pcap_set_datalink(handle, dlt))
965
+ rb_raise(eCappError, "%s", pcap_geterr(handle));
966
+
967
+ return datalink;
968
+ }
969
+
970
+ /*
971
+ * call-seq:
972
+ * capp.filter = filter -> self
973
+ *
974
+ * Sets the packet filter to the given +filter+ string. The format is the
975
+ * same format as for tcpdump. Read the pcap-filter(7) man page for
976
+ * documentation on the filter syntax.
977
+ */
978
+ static VALUE
979
+ capp_set_filter(VALUE self, VALUE filter)
980
+ {
981
+ VALUE device;
982
+ pcap_t *handle;
983
+ struct bpf_program program;
984
+ bpf_u_int32 network, netmask = PCAP_NETMASK_UNKNOWN;
985
+ char errbuf[PCAP_ERRBUF_SIZE];
986
+ int res;
987
+
988
+ device = rb_ivar_get(self, id_iv_device);
989
+
990
+ if (RTEST(device)) {
991
+ *errbuf = '\0';
992
+
993
+ res =
994
+ pcap_lookupnet(StringValueCStr(device), &network, &netmask, errbuf);
995
+
996
+ if (res == -1)
997
+ rb_raise(eCappError, "%s", errbuf);
998
+
999
+ if (*errbuf)
1000
+ rb_warn("%s", errbuf);
1001
+ }
1002
+
1003
+ GetCapp(self, handle);
1004
+
1005
+ res = pcap_compile(handle, &program, StringValueCStr(filter), 0, netmask);
1006
+
1007
+ if (res)
1008
+ rb_raise(eCappError, "%s", pcap_geterr(handle));
1009
+
1010
+ res = pcap_setfilter(handle, &program);
1011
+
1012
+ pcap_freecode(&program);
1013
+
1014
+ if (res)
1015
+ rb_raise(eCappError, "%s", pcap_geterr(handle));
1016
+
1017
+ return self;
1018
+ }
1019
+
1020
+ /*
1021
+ * call-seq:
1022
+ * capp.promiscuous = boolean
1023
+ *
1024
+ * Enables or disables promiscuous mode. When promiscuous mode is enabled
1025
+ * packets that were not sent directly to the device will be captured.
1026
+ */
1027
+ static VALUE
1028
+ capp_set_promisc(VALUE self, VALUE promiscuous)
1029
+ {
1030
+ pcap_t *handle;
1031
+ int promisc = RTEST(promiscuous);
1032
+
1033
+ GetCapp(self, handle);
1034
+
1035
+ if (pcap_set_promisc(handle, promisc))
1036
+ rb_raise(eCappError, "pcap already activated");
1037
+
1038
+ return promiscuous;
1039
+ }
1040
+
1041
+ /*
1042
+ * call-seq:
1043
+ * capp.snaplen = bytes
1044
+ *
1045
+ * Sets the number of +bytes+ captured from each packet.
1046
+ */
1047
+ static VALUE
1048
+ capp_set_snaplen(VALUE self, VALUE snaplen)
1049
+ {
1050
+ pcap_t *handle;
1051
+
1052
+ GetCapp(self, handle);
1053
+
1054
+ if (pcap_set_snaplen(handle, NUM2INT(snaplen)))
1055
+ rb_raise(eCappError, "pcap already activated");
1056
+
1057
+ return snaplen;
1058
+ }
1059
+
1060
+ /*
1061
+ * call-seq:
1062
+ * capp.timeout = milliseconds
1063
+ *
1064
+ * Sets the maximum amount of time in +milliseconds+ that will elapse between
1065
+ * receiving a packet and yielding it to #loop.
1066
+ *
1067
+ * Reducing the timeout will increase responsiveness as pcap_loop(3) must
1068
+ * "check in" more frequently while increasing the timeout will reduce
1069
+ * responsiveness.
1070
+ *
1071
+ * Setting the timeout too low may increase GVL contention when many packets
1072
+ * are arriving at once as #loop will be waking up frequently to service
1073
+ * captured packets.
1074
+ */
1075
+ static VALUE
1076
+ capp_set_timeout(VALUE self, VALUE milliseconds)
1077
+ {
1078
+ pcap_t *handle;
1079
+
1080
+ GetCapp(self, handle);
1081
+
1082
+ if (pcap_set_timeout(handle, NUM2INT(milliseconds)))
1083
+ rb_raise(eCappError, "pcap already activated");
1084
+
1085
+ return milliseconds;
1086
+ }
1087
+
1088
+ /*
1089
+ * call-seq:
1090
+ * capp.stats -> hash
1091
+ *
1092
+ * Retrieves packet capture statistics:
1093
+ *
1094
+ * p capp.stats #=> {:drop => 0, :ifdrop => 0, :recv => 123}
1095
+ */
1096
+ static VALUE
1097
+ capp_stats(VALUE self)
1098
+ {
1099
+ VALUE stats;
1100
+ pcap_t *handle;
1101
+ struct pcap_stat ps;
1102
+
1103
+ GetCapp(self, handle);
1104
+
1105
+ if (pcap_stats(handle, &ps))
1106
+ rb_raise(eCappError, "%s", pcap_geterr(handle));
1107
+
1108
+ stats = rb_hash_new();
1109
+
1110
+ rb_hash_aset(stats, ID2SYM(id_drop), UINT2NUM(ps.ps_drop));
1111
+ rb_hash_aset(stats, ID2SYM(id_ifdrop), UINT2NUM(ps.ps_ifdrop));
1112
+ rb_hash_aset(stats, ID2SYM(id_recv), UINT2NUM(ps.ps_recv));
1113
+
1114
+ return stats;
1115
+ }
1116
+
1117
+ /*
1118
+ * call-seq:
1119
+ * capp.stop -> capp
1120
+ *
1121
+ * Stops a running loop
1122
+ */
1123
+ static VALUE
1124
+ capp_stop(VALUE self)
1125
+ {
1126
+ pcap_t *handle;
1127
+
1128
+ GetCapp(self, handle);
1129
+
1130
+ pcap_breakloop(handle);
1131
+
1132
+ return self;
1133
+ }
1134
+
1135
+ void
1136
+ Init_capp(void) {
1137
+ id_arp = rb_intern("arp");
1138
+ id_drop = rb_intern("drop");
1139
+ id_ethernet = rb_intern("ethernet");
1140
+ id_icmp = rb_intern("icmp");
1141
+ id_ifdrop = rb_intern("ifdrop");
1142
+ id_ipv4 = rb_intern("ipv4");
1143
+ id_ipv6 = rb_intern("ipv6");
1144
+ id_iv_datalink = rb_intern("@datalink");
1145
+ id_iv_device = rb_intern("@device");
1146
+ id_recv = rb_intern("recv");
1147
+ id_tcp = rb_intern("tcp");
1148
+ id_type = rb_intern("type");
1149
+ id_udp = rb_intern("udp");
1150
+ id_unknown_layer3 = rb_intern("unknown_layer3");
1151
+ id_unpack_sockaddr_in = rb_intern("unpack_sockaddr_in");
1152
+
1153
+ cCapp = rb_define_class("Capp", rb_cObject);
1154
+
1155
+ cCappAddress = rb_const_get(cCapp, rb_intern("Address"));
1156
+ cCappDevice = rb_const_get(cCapp, rb_intern("Device"));
1157
+ cCappPacket = rb_const_get(cCapp, rb_intern("Packet"));
1158
+ eCappError = rb_const_get(cCapp, rb_intern("Error"));
1159
+
1160
+ cCappPacketARPHeader =
1161
+ rb_const_get(cCappPacket, rb_intern("ARPHeader"));
1162
+ cCappPacketEthernetHeader =
1163
+ rb_const_get(cCappPacket, rb_intern("EthernetHeader"));
1164
+ cCappPacketICMPHeader =
1165
+ rb_const_get(cCappPacket, rb_intern("ICMPHeader"));
1166
+ cCappPacketIPv4Header =
1167
+ rb_const_get(cCappPacket, rb_intern("IPv4Header"));
1168
+ cCappPacketIPv6Header =
1169
+ rb_const_get(cCappPacket, rb_intern("IPv6Header"));
1170
+ cCappPacketTCPHeader =
1171
+ rb_const_get(cCappPacket, rb_intern("TCPHeader"));
1172
+ cCappPacketUDPHeader =
1173
+ rb_const_get(cCappPacket, rb_intern("UDPHeader"));
1174
+ cCappPacketUnknownLayer3Header =
1175
+ rb_const_get(cCappPacket, rb_intern("UnknownLayer3Header"));
1176
+
1177
+ cSocket = rb_const_get(rb_cObject, rb_intern("Socket"));
1178
+
1179
+ rb_undef_alloc_func(cCapp);
1180
+
1181
+ rb_define_singleton_method(cCapp, "default_device_name", capp_s_default_device_name, 0);
1182
+ rb_define_singleton_method(cCapp, "devices", capp_s_devices, 0);
1183
+ rb_define_singleton_method(cCapp, "live", capp_s_open_live, -1);
1184
+ rb_define_singleton_method(cCapp, "offline", capp_s_open_offline, 1);
1185
+ rb_define_singleton_method(cCapp, "pcap_lib_version", capp_s_pcap_lib_version, 0);
1186
+
1187
+ rb_define_method(cCapp, "datalink", capp_datalink, 0);
1188
+ rb_define_method(cCapp, "datalink=", capp_set_datalink, 1);
1189
+ rb_define_method(cCapp, "datalinks", capp_datalinks, 0);
1190
+ rb_define_method(cCapp, "filter=", capp_set_filter, 1);
1191
+ rb_define_method(cCapp, "loop", capp_loop, 0);
1192
+ rb_define_method(cCapp, "promiscuous=", capp_set_promisc, 1);
1193
+ rb_define_method(cCapp, "savefile_major_version", capp_savefile_major_version, 0);
1194
+ rb_define_method(cCapp, "savefile_minor_version", capp_savefile_minor_version, 0);
1195
+ rb_define_method(cCapp, "snaplen=", capp_set_snaplen, 1);
1196
+ rb_define_method(cCapp, "stats", capp_stats, 0);
1197
+ rb_define_method(cCapp, "stop", capp_stop, 0);
1198
+ rb_define_method(cCapp, "timeout=", capp_set_timeout, 1);
1199
+
1200
+ /* Document-const: ARPHRD_ETHER
1201
+ *
1202
+ * Ethernet hardware
1203
+ */
1204
+ rb_define_const(cCapp, "ARPHRD_ETHER", INT2NUM(ARPHRD_ETHER));
1205
+
1206
+ /* Document-const: ARPHRD_FRELAY
1207
+ *
1208
+ * frame relay hardware
1209
+ */
1210
+ rb_define_const(cCapp, "ARPHRD_FRELAY", INT2NUM(ARPHRD_FRELAY));
1211
+
1212
+ /* Document-const: ARPHRD_IEEE1394
1213
+ *
1214
+ * IEEE1394 (FireWire™) hardware
1215
+ */
1216
+ rb_define_const(cCapp, "ARPHRD_IEEE1394", INT2NUM(ARPHRD_IEEE1394));
1217
+
1218
+ /* Document-const: ARPHRD_IEEE1394_EUI64
1219
+ *
1220
+ * IEEE1394 (FireWire™) hardware with EUI-64 addresses
1221
+ */
1222
+ rb_define_const(cCapp, "ARPHRD_IEEE1394_EUI64",
1223
+ INT2NUM(ARPHRD_IEEE1394_EUI64));
1224
+
1225
+ /* Document-const: ARPHRD_IEEE802
1226
+ *
1227
+ * token-ring hardware
1228
+ */
1229
+ rb_define_const(cCapp, "ARPHRD_IEEE802", INT2NUM(ARPHRD_IEEE802));
1230
+
1231
+ /* Document-const: ARPOP_INVREPLY
1232
+ *
1233
+ * ARP response identifying peer
1234
+ */
1235
+ rb_define_const(cCapp, "ARPOP_INVREPLY", INT2NUM(ARPOP_INVREPLY));
1236
+
1237
+ /* Document-const: ARPOP_INVREQUEST
1238
+ *
1239
+ * ARP request to identify peer
1240
+ */
1241
+ rb_define_const(cCapp, "ARPOP_INVREQUEST", INT2NUM(ARPOP_INVREQUEST));
1242
+
1243
+ /* Document-const: ARPOP_REPLY
1244
+ *
1245
+ * ARP response to resolve request
1246
+ */
1247
+ rb_define_const(cCapp, "ARPOP_REPLY", INT2NUM(ARPOP_REPLY));
1248
+
1249
+ /* Document-const: ARPOP_REQUEST
1250
+ *
1251
+ * ARP resolve address request
1252
+ */
1253
+ rb_define_const(cCapp, "ARPOP_REQUEST", INT2NUM(ARPOP_REQUEST));
1254
+
1255
+ /* Document-const: ARPOP_REVREPLY
1256
+ *
1257
+ * ARP response giving protocol address
1258
+ */
1259
+ rb_define_const(cCapp, "ARPOP_REVREPLY", INT2NUM(ARPOP_REVREPLY));
1260
+
1261
+ /* Document-const: ARPOP_REVREQUEST
1262
+ *
1263
+ * ARP request protocol address given hardware address
1264
+ */
1265
+ rb_define_const(cCapp, "ARPOP_REVREQUEST", INT2NUM(ARPOP_REVREQUEST));
1266
+
1267
+ /* Document-const: DLT_NULL
1268
+ *
1269
+ * BSD loopback encapsulation.
1270
+ */
1271
+ rb_define_const(cCapp, "DLT_NULL", INT2NUM(DLT_NULL));
1272
+
1273
+ /* Document-const: DLT_EN10MB
1274
+ *
1275
+ * Ethernet encapsulation.
1276
+ */
1277
+ rb_define_const(cCapp, "DLT_EN10MB", INT2NUM(DLT_EN10MB));
1278
+
1279
+ /* Document-const: ETHERTYPE_ARP
1280
+ *
1281
+ * Address Resolution Protocol
1282
+ */
1283
+ rb_define_const(cCapp, "ETHERTYPE_ARP", INT2NUM(ETHERTYPE_ARP));
1284
+
1285
+ /* Document-const: ETHERTYPE_IP
1286
+ *
1287
+ * IPv4
1288
+ */
1289
+ rb_define_const(cCapp, "ETHERTYPE_IP", INT2NUM(ETHERTYPE_IP));
1290
+
1291
+ /* Document-const: ETHERTYPE_IPV6
1292
+ *
1293
+ * IPv6
1294
+ */
1295
+ rb_define_const(cCapp, "ETHERTYPE_IPV6", INT2NUM(ETHERTYPE_IPV6));
1296
+
1297
+ /* Document-const: ETHERTYPE_LOOPBACK
1298
+ *
1299
+ * Used to test interfaces
1300
+ */
1301
+ rb_define_const(cCapp, "ETHERTYPE_LOOPBACK", INT2NUM(ETHERTYPE_LOOPBACK));
1302
+
1303
+ /* Document-const: ETHERTYPE_PUP
1304
+ *
1305
+ * PUP protocol
1306
+ */
1307
+ rb_define_const(cCapp, "ETHERTYPE_PUP", INT2NUM(ETHERTYPE_PUP));
1308
+
1309
+ /* Document-const: ETHERTYPE_PAE
1310
+ *
1311
+ * EAPOL PAE/802.1x
1312
+ */
1313
+ rb_define_const(cCapp, "ETHERTYPE_PAE", INT2NUM(ETHERTYPE_PAE));
1314
+
1315
+ /* Document-const: ETHERTYPE_REVARP
1316
+ *
1317
+ * Reverse Address Resolution Protocol
1318
+ */
1319
+ rb_define_const(cCapp, "ETHERTYPE_REVARP", INT2NUM(ETHERTYPE_REVARP));
1320
+
1321
+ /* Document-const: ETHERTYPE_RSN_PREAUTH
1322
+ *
1323
+ * 802.11i / RSN Pre-Authentication
1324
+ */
1325
+ rb_define_const(cCapp, "ETHERTYPE_RSN_PREAUTH",
1326
+ INT2NUM(ETHERTYPE_RSN_PREAUTH));
1327
+
1328
+ /* Document-const: ETHERTYPE_VLAN
1329
+ *
1330
+ * IEEE 802.1Q VLAN tagging
1331
+ */
1332
+ rb_define_const(cCapp, "ETHERTYPE_VLAN", INT2NUM(ETHERTYPE_VLAN));
1333
+
1334
+ /* Document-const: TCP_ACK
1335
+ *
1336
+ * TCP Acknowledged flag
1337
+ */
1338
+ rb_define_const(cCapp, "TCP_ACK", INT2NUM(TH_ACK));
1339
+
1340
+ /* Document-const: TCP_CWR
1341
+ *
1342
+ * TCP Congestion Window Reduced flag
1343
+ */
1344
+ rb_define_const(cCapp, "TCP_CWR", INT2NUM(TH_CWR));
1345
+
1346
+ /* Document-const: TCP_ECE
1347
+ *
1348
+ * TCP ECN echo flag
1349
+ */
1350
+ rb_define_const(cCapp, "TCP_ECE", INT2NUM(TH_ECE));
1351
+
1352
+ /* Document-const: TCP_FIN
1353
+ *
1354
+ * TCP Finish flag
1355
+ */
1356
+ rb_define_const(cCapp, "TCP_FIN", INT2NUM(TH_FIN));
1357
+
1358
+ /* Document-const: TCP_PUSH
1359
+ *
1360
+ * TCP Push flag
1361
+ */
1362
+ rb_define_const(cCapp, "TCP_PUSH", INT2NUM(TH_PUSH));
1363
+
1364
+ /* Document-const: TCP_RST
1365
+ *
1366
+ * TCP Reset flag
1367
+ */
1368
+ rb_define_const(cCapp, "TCP_RST", INT2NUM(TH_RST));
1369
+
1370
+ /* Document-const: TCP_SYN
1371
+ *
1372
+ * TCP Synchronize flag
1373
+ */
1374
+ rb_define_const(cCapp, "TCP_SYN", INT2NUM(TH_SYN));
1375
+
1376
+ /* Document-const: TCP_URG
1377
+ *
1378
+ * TCP Urgent flag
1379
+ */
1380
+ rb_define_const(cCapp, "TCP_URG", INT2NUM(TH_URG));
1381
+ }
1382
+