capp 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+