ruby-pcap 0.7.8

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,54 @@
1
+ <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
2
+ <html> <head>
3
+ <title>Ruby/Pcap Library</title>
4
+ </head>
5
+
6
+ <body bgcolor="ffffff">
7
+ <h1>Ruby/Pcap��ĥ�饤�֥��</h1>
8
+
9
+ LBL �� libpcap (Packet Capture library) �ؤ� ruby ���󥿥ե������Ǥ���
10
+
11
+ <h2>�⥸�塼��</h2>
12
+ <ul>
13
+ <li><a href="Pcap.html"><code>Pcap</code></a>
14
+ </ul>
15
+
16
+ <h2>���饹</h2>
17
+
18
+ �ʲ��Υ��饹������ <code>Pcap</code> �⥸�塼��β����������Ƥ��ޤ���
19
+ �������äƻ��Ѥ���Ȥ��� <code>Pcap</code> �⥸�塼���
20
+ <code>include</code> ���뤫���⤷���� <code>Pcap::Capture</code> �Τ�
21
+ ���˻��Ȥ��Ƥ���������
22
+
23
+ <ul>
24
+ <li><a href="Capture.html"><code>Capture</code></a>
25
+ <li><a href="Pcaplet.html"><code>Pcaplet</code></a>
26
+ <li><a href="Packet.html"><code>Packet</code></a>
27
+ <ul>
28
+ <li><a href="IPPacket.html"><code>IPPacket</code></a>
29
+ <ul>
30
+ <li><a href="TCPPacket.html"><code>TCPPacket</code></a>
31
+ <li><a href="UDPPacket.html"><code>UDPPacket</code></a>
32
+ <li><a href="ICMPPacket.html"><code>ICMPPacket</code></a>
33
+ </ul>
34
+ </ul>
35
+ <li><a href="IPAddress.html"><code>IPAddress</code></a>
36
+ <li><a href="Dumper.html"><code>Dumper</code></a>
37
+ <li><a href="Filter.html"><code>Filter</code></a>
38
+ </ul>
39
+
40
+ <h2>�㳰</h2>
41
+
42
+ <ul>
43
+ <li><a href="PcapError.html"><code>PcapError</code></a>
44
+ <ul>
45
+ <li><a href="TruncatedPacket.html"><code>TruncatedPacket</code></a>
46
+ </ul>
47
+ </ul>
48
+
49
+ <hr>
50
+ <P ALIGN="RIGHT">
51
+ <A HREF="mailto:fukusima@goto.info.waseda.ac.jp">
52
+ fukusima@goto.info.waseda.ac.jp</A><BR>
53
+ </P>
54
+ </body> </html>
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'pcaplet'
4
+ httpdump = Pcaplet.new('-s 1500')
5
+
6
+ HTTP_REQUEST = Pcap::Filter.new('tcp and dst port 80', httpdump.capture)
7
+ HTTP_RESPONSE = Pcap::Filter.new('tcp and src port 80', httpdump.capture)
8
+
9
+ httpdump.add_filter(HTTP_REQUEST | HTTP_RESPONSE)
10
+ httpdump.each_packet {|pkt|
11
+ data = pkt.tcp_data
12
+ case pkt
13
+ when HTTP_REQUEST
14
+ if data and data =~ /^GET\s+(\S+)/
15
+ path = $1
16
+ host = pkt.dst.to_s
17
+ host << ":#{pkt.dst_port}" if pkt.dport != 80
18
+ s = "#{pkt.src}:#{pkt.sport} > GET http://#{host}#{path}"
19
+ end
20
+ when HTTP_RESPONSE
21
+ if data and data =~ /^(HTTP\/.*)$/
22
+ status = $1
23
+ s = "#{pkt.dst}:#{pkt.dport} < #{status}"
24
+ end
25
+ end
26
+ puts s if s
27
+ }
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'pcap'
4
+
5
+ if 3 != ARGV.size
6
+ STDERR.puts "Usage: #{$0} in.pcap out.pcap delta"
7
+ exit(2)
8
+ end
9
+
10
+ in_filename, out_filename, delta = ARGV
11
+
12
+ inp = outc = outp = nil
13
+ begin
14
+ inp = Pcap::Capture.open_offline(in_filename)
15
+ outc = Pcap::Capture.open_dead(inp.datalink, inp.snaplen)
16
+ outp = Pcap::Dumper.open(outc, out_filename)
17
+ inp.loop(-1) do |pkt|
18
+ pkt.time_i += delta.to_i
19
+ outp.dump(pkt)
20
+ end
21
+ rescue Exception => e
22
+ STDERR.puts e.message,e.backtrace
23
+ ensure
24
+ inp.close if inp
25
+ outp.close if outp
26
+ outc.close if outc
27
+ end
28
+
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'pcaplet'
4
+ include Pcap
5
+
6
+ class Time
7
+ # tcpdump style format
8
+ def to_s
9
+ sprintf "%0.2d:%0.2d:%0.2d.%0.6d", hour, min, sec, tv_usec
10
+ end
11
+ end
12
+
13
+ pcaplet = Pcaplet.new
14
+ pcaplet.each_packet { |pkt|
15
+ print "#{pkt.time} #{pkt}"
16
+ if pkt.tcp?
17
+ print " (#{pkt.tcp_data_len})"
18
+ print " ack #{pkt.tcp_ack}" if pkt.tcp_ack?
19
+ print " win #{pkt.tcp_win}"
20
+ end
21
+ if pkt.ip?
22
+ print " (DF)" if pkt.ip_df?
23
+ end
24
+ print "\n"
25
+ }
26
+ pcaplet.close
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'pcap'
4
+
5
+ dev = Pcap.lookupdev
6
+ cap = Pcap::Capture.open_live(dev)
7
+ cap.setfilter("ip")
8
+ cap.loop do |pkt|
9
+ print pkt, "\n"
10
+ end
11
+ cap.close
@@ -0,0 +1,938 @@
1
+ /*
2
+ * Pcap.c
3
+ *
4
+ * $Id: Pcap.c,v 1.10 2000/08/13 05:56:31 fukusima Exp $
5
+ *
6
+ * Copyright (C) 1998-2000 Masaki Fukushima
7
+ */
8
+
9
+ #include "ruby_pcap.h"
10
+ #include "rubysig.h"
11
+ #include <sys/time.h>
12
+ #include <sys/types.h>
13
+ #include <unistd.h>
14
+
15
+ #define DEFAULT_DATALINK DLT_EN10MB
16
+ #define DEFAULT_SNAPLEN 68
17
+ #define DEFAULT_PROMISC 1
18
+ #define DEFAULT_TO_MS 1000
19
+
20
+ #ifdef PCAP_DONT_TRAP
21
+ #define MAYBE_TRAP_BEG do {} while (0)
22
+ #define MAYBE_TRAP_END do {} while (0)
23
+ #else
24
+ #define MAYBE_TRAP_BEG TRAP_BEG
25
+ #define MAYBE_TRAP_END TRAP_END
26
+ #endif
27
+
28
+ static char pcap_errbuf[PCAP_ERRBUF_SIZE];
29
+
30
+ VALUE mPcap, rbpcap_convert = Qnil;
31
+ VALUE ePcapError;
32
+ VALUE eTruncatedPacket;
33
+ VALUE cFilter;
34
+ static VALUE cCapture;
35
+ static VALUE cPcapStat;
36
+ static VALUE cDumper;
37
+
38
+ struct filter_object {
39
+ char *expr;
40
+ struct bpf_program program;
41
+ int datalink;
42
+ int snaplen;
43
+ VALUE param;
44
+ VALUE optimize;
45
+ VALUE netmask;
46
+ };
47
+
48
+ #define GetFilter(obj, filter) \
49
+ Data_Get_Struct(obj, struct filter_object, filter)
50
+
51
+
52
+ static VALUE
53
+ pcap_s_lookupdev(self)
54
+ VALUE self;
55
+ {
56
+ char *dev;
57
+
58
+ dev = pcap_lookupdev(pcap_errbuf);
59
+ if (dev == NULL) {
60
+ rb_raise(ePcapError, "%s", pcap_errbuf);
61
+ }
62
+ return rb_str_new2(dev);
63
+ }
64
+
65
+ static VALUE
66
+ pcap_s_findalldevs(self)
67
+ VALUE self;
68
+ {
69
+ pcap_if_t *alldevsp;
70
+ VALUE return_ary;
71
+ char pcap_errbuf[PCAP_ERRBUF_SIZE];
72
+
73
+ return_ary = rb_ary_new();
74
+
75
+ pcap_findalldevs(&alldevsp, pcap_errbuf);
76
+
77
+ if (alldevsp == NULL) // List is empty, probably an error
78
+ rb_raise(ePcapError, "%s", pcap_errbuf);
79
+
80
+ for (; alldevsp->next != NULL; alldevsp = alldevsp->next)
81
+ rb_ary_push(return_ary, rb_str_new2(alldevsp->name));
82
+
83
+ pcap_freealldevs(alldevsp);
84
+
85
+ return return_ary;
86
+ }
87
+
88
+ static VALUE
89
+ pcap_s_lookupnet(self, dev)
90
+ VALUE self;
91
+ VALUE dev;
92
+ {
93
+ bpf_u_int32 net, mask, m;
94
+ struct in_addr addr;
95
+
96
+ Check_Type(dev, T_STRING);
97
+ if (pcap_lookupnet(StringValuePtr(dev), &net, &mask, pcap_errbuf) == -1) {
98
+ rb_raise(ePcapError, "%s", pcap_errbuf);
99
+ }
100
+
101
+ addr.s_addr = net;
102
+ m = ntohl(mask);
103
+ return rb_ary_new3(2, new_ipaddr(&addr), UINT32_2_NUM(m));
104
+ }
105
+
106
+ static VALUE
107
+ pcap_s_convert(self)
108
+ VALUE self;
109
+ {
110
+ return rbpcap_convert;
111
+ }
112
+
113
+ static VALUE
114
+ pcap_s_convert_set(self, val)
115
+ VALUE self;
116
+ {
117
+ rbpcap_convert = val;
118
+ return Qnil;
119
+ }
120
+
121
+ /*
122
+ * Capture object
123
+ */
124
+
125
+ struct capture_object {
126
+ pcap_t *pcap;
127
+ bpf_u_int32 netmask;
128
+ int dl_type; /* data-link type (DLT_*) */
129
+ };
130
+
131
+ static void
132
+ closed_capture()
133
+ {
134
+ rb_raise(rb_eRuntimeError, "device is already closed");
135
+ }
136
+
137
+ #define GetCapture(obj, cap) {\
138
+ Data_Get_Struct(obj, struct capture_object, cap);\
139
+ if (cap->pcap == NULL) closed_capture();\
140
+ }
141
+
142
+ /* called from GC */
143
+ static void
144
+ free_capture(cap)
145
+ struct capture_object *cap;
146
+ {
147
+ DEBUG_PRINT("free_capture");
148
+ if (cap->pcap != NULL) {
149
+ DEBUG_PRINT("closing capture");
150
+ rb_thread_fd_close(pcap_fileno(cap->pcap));
151
+ pcap_close(cap->pcap);
152
+ cap->pcap = NULL;
153
+ }
154
+ free(cap);
155
+ }
156
+
157
+ static VALUE
158
+ capture_open_live(argc, argv, class)
159
+ int argc;
160
+ VALUE *argv;
161
+ VALUE class;
162
+ {
163
+ VALUE v_device, v_snaplen, v_promisc, v_to_ms;
164
+ char *device;
165
+ int snaplen, promisc, to_ms;
166
+ int rs;
167
+ VALUE self;
168
+ struct capture_object *cap;
169
+ pcap_t *pcap;
170
+ bpf_u_int32 net, netmask;
171
+
172
+ DEBUG_PRINT("capture_open_live");
173
+
174
+ /* scan arg */
175
+ rs = rb_scan_args(argc, argv, "13", &v_device, &v_snaplen,
176
+ &v_promisc, &v_to_ms);
177
+
178
+ /* device */
179
+ Check_SafeStr(v_device);
180
+ device = RSTRING_PTR(v_device);
181
+ /* snaplen */
182
+ if (rs >= 2) {
183
+ Check_Type(v_snaplen, T_FIXNUM);
184
+ snaplen = FIX2INT(v_snaplen);
185
+ } else {
186
+ snaplen = DEFAULT_SNAPLEN;
187
+ }
188
+ if (snaplen < 0)
189
+ rb_raise(rb_eArgError, "invalid snaplen");
190
+ /* promisc */
191
+ if (rs >= 3) {
192
+ promisc = RTEST(v_promisc);
193
+ } else {
194
+ promisc = DEFAULT_PROMISC;
195
+ }
196
+ /* to_ms */
197
+ if (rs >= 4) {
198
+ Check_Type(v_to_ms, T_FIXNUM);
199
+ to_ms = FIX2INT(v_to_ms);
200
+ } else
201
+ to_ms = DEFAULT_TO_MS;
202
+
203
+ /* open */
204
+ pcap = pcap_open_live(device, snaplen, promisc, to_ms, pcap_errbuf);
205
+ if (pcap == NULL) {
206
+ rb_raise(ePcapError, "%s", pcap_errbuf);
207
+ }
208
+ if (pcap_lookupnet(device, &net, &netmask, pcap_errbuf) == -1) {
209
+ netmask = 0;
210
+ rb_warning("cannot lookup net: %s\n", pcap_errbuf);
211
+ }
212
+
213
+ /* setup instance */
214
+ self = Data_Make_Struct(class, struct capture_object,
215
+ 0, free_capture, cap);
216
+ cap->pcap = pcap;
217
+ cap->netmask = netmask;
218
+ cap->dl_type = pcap_datalink(pcap);
219
+
220
+ return self;
221
+ }
222
+
223
+ static VALUE
224
+ capture_open_offline(class, fname)
225
+ VALUE class;
226
+ VALUE fname;
227
+ {
228
+ VALUE self;
229
+ struct capture_object *cap;
230
+ pcap_t *pcap;
231
+
232
+ DEBUG_PRINT("capture_open_offline");
233
+
234
+ /* open offline */
235
+ Check_SafeStr(fname);
236
+ pcap = pcap_open_offline(RSTRING_PTR(fname), pcap_errbuf);
237
+ if (pcap == NULL) {
238
+ rb_raise(ePcapError, "%s", pcap_errbuf);
239
+ }
240
+
241
+ /* setup instance */
242
+ self = Data_Make_Struct(class, struct capture_object,
243
+ 0, free_capture, cap);
244
+ cap->pcap = pcap;
245
+ cap->netmask = 0;
246
+ cap->dl_type = pcap_datalink(pcap);
247
+
248
+ return self;
249
+ }
250
+
251
+ static VALUE
252
+ capture_open_dead(argc, argv, class)
253
+ int argc;
254
+ VALUE *argv;
255
+ VALUE class;
256
+ {
257
+ VALUE self;
258
+ struct capture_object *cap;
259
+ pcap_t *pcap;
260
+ VALUE v_linktype, v_snaplen;
261
+ int linktype, snaplen;
262
+ int rs;
263
+
264
+ DEBUG_PRINT("capture_open_dead");
265
+
266
+ /* scan arg */
267
+ rs = rb_scan_args(argc, argv, "02", &v_linktype, &v_snaplen);
268
+ if (rs >= 1) {
269
+ Check_Type(v_linktype, T_FIXNUM);
270
+ linktype = FIX2INT(v_linktype);
271
+ } else {
272
+ linktype = DEFAULT_DATALINK;
273
+ }
274
+ if (rs == 2) {
275
+ Check_Type(v_snaplen, T_FIXNUM);
276
+ snaplen = FIX2INT(v_snaplen);
277
+ } else {
278
+ snaplen = DEFAULT_SNAPLEN;
279
+ }
280
+
281
+ pcap = pcap_open_dead(linktype, snaplen);
282
+
283
+ if (pcap == NULL) {
284
+ rb_raise(ePcapError, "Error calling pcap_open_dead");
285
+ }
286
+
287
+ /* setup instance */
288
+ self = Data_Make_Struct(class, struct capture_object,
289
+ 0, free_capture, cap);
290
+ cap->pcap = pcap;
291
+ cap->netmask = 0;
292
+ cap->dl_type = pcap_datalink(pcap);
293
+
294
+ return self;
295
+ }
296
+
297
+ static VALUE
298
+ capture_close(self)
299
+ VALUE self;
300
+ {
301
+ struct capture_object *cap;
302
+
303
+ DEBUG_PRINT("capture_close");
304
+ GetCapture(self, cap);
305
+
306
+ rb_thread_fd_close(pcap_fileno(cap->pcap));
307
+ pcap_close(cap->pcap);
308
+ cap->pcap = NULL;
309
+ return Qnil;
310
+ }
311
+
312
+ static void
313
+ handler(cap, pkthdr, data)
314
+ struct capture_object *cap;
315
+ const struct pcap_pkthdr *pkthdr;
316
+ const u_char *data;
317
+ {
318
+ rb_yield(new_packet(data, pkthdr, cap->dl_type));
319
+ }
320
+
321
+ static VALUE
322
+ capture_dispatch(argc, argv, self)
323
+ int argc;
324
+ VALUE *argv;
325
+ VALUE self;
326
+ {
327
+ VALUE v_cnt;
328
+ int cnt;
329
+ struct capture_object *cap;
330
+ int ret;
331
+
332
+ DEBUG_PRINT("capture_dispatch");
333
+ GetCapture(self, cap);
334
+
335
+ /* scan arg */
336
+ if (rb_scan_args(argc, argv, "01", &v_cnt) >= 1) {
337
+ FIXNUM_P(v_cnt);
338
+ cnt = FIX2INT(v_cnt);
339
+ } else {
340
+ cnt = -1;
341
+ }
342
+
343
+ MAYBE_TRAP_BEG;
344
+ ret = pcap_dispatch(cap->pcap, cnt, handler, (u_char *)cap);
345
+ MAYBE_TRAP_END;
346
+ if (ret == -1) {
347
+ rb_raise(ePcapError, "dispatch: %s", pcap_geterr(cap->pcap));
348
+ }
349
+
350
+ return INT2FIX(ret);
351
+ }
352
+
353
+ static VALUE
354
+ capture_fh(argc, argv, self)
355
+ int argc;
356
+ VALUE *argv;
357
+ VALUE self;
358
+ {
359
+ VALUE v_cnt;
360
+ int cnt;
361
+ struct capture_object *cap;
362
+ int ret;
363
+
364
+ DEBUG_PRINT("capture_fh");
365
+ GetCapture(self, cap);
366
+
367
+ return rb_funcall(rb_path2class("IO"), rb_intern("new"), 1, INT2FIX(pcap_fileno(cap->pcap)));
368
+ }
369
+
370
+ static VALUE
371
+ capture_loop(argc, argv, self)
372
+ int argc;
373
+ VALUE *argv;
374
+ VALUE self;
375
+ {
376
+ VALUE v_cnt;
377
+ int cnt;
378
+ struct capture_object *cap;
379
+ int ret;
380
+
381
+ DEBUG_PRINT("capture_loop");
382
+ GetCapture(self, cap);
383
+
384
+ /* scan arg */
385
+ if (rb_scan_args(argc, argv, "01", &v_cnt) >= 1) {
386
+ FIXNUM_P(v_cnt);
387
+ cnt = FIX2INT(v_cnt);
388
+ } else {
389
+ cnt = -1;
390
+ }
391
+
392
+ if (pcap_file(cap->pcap) != NULL) {
393
+ MAYBE_TRAP_BEG;
394
+ ret = pcap_loop(cap->pcap, cnt, handler, (u_char *)cap);
395
+ MAYBE_TRAP_END;
396
+ }
397
+ else {
398
+ int fd = pcap_fileno(cap->pcap);
399
+ fd_set rset;
400
+ struct timeval tm;
401
+
402
+ FD_ZERO(&rset);
403
+ tm.tv_sec = 0;
404
+ tm.tv_usec = 0;
405
+ for (;;) {
406
+ do {
407
+ FD_SET(fd, &rset);
408
+ if (select(fd+1, &rset, NULL, NULL, &tm) == 0) {
409
+ rb_thread_wait_fd(fd);
410
+ }
411
+ MAYBE_TRAP_BEG;
412
+ ret = pcap_dispatch(cap->pcap, 1, handler, (u_char *)cap);
413
+ MAYBE_TRAP_END;
414
+ } while (ret == 0);
415
+
416
+ if (ret <= 0)
417
+ break;
418
+ if (cnt > 0) {
419
+ cnt -= ret;
420
+ if (cnt <= 0)
421
+ break;
422
+ }
423
+ }
424
+ }
425
+
426
+ return INT2FIX(ret);
427
+ }
428
+
429
+ static VALUE
430
+ capture_setfilter(argc, argv, self)
431
+ int argc;
432
+ VALUE *argv;
433
+ VALUE self;
434
+ {
435
+ struct capture_object *cap;
436
+ VALUE vfilter, optimize;
437
+ char *filter;
438
+ int opt;
439
+ struct bpf_program program;
440
+
441
+ DEBUG_PRINT("capture_setfilter");
442
+ GetCapture(self, cap);
443
+
444
+ /* scan arg */
445
+ if (rb_scan_args(argc, argv, "11", &vfilter, &optimize) == 1) {
446
+ optimize = Qtrue;
447
+ }
448
+
449
+ /* check arg */
450
+ if (IsKindOf(vfilter, cFilter)) {
451
+ struct filter_object *f;
452
+ GetFilter(vfilter, f);
453
+ filter = f->expr;
454
+ } else {
455
+ Check_Type(vfilter, T_STRING);
456
+ filter = RSTRING_PTR(vfilter);
457
+ }
458
+ opt = RTEST(optimize);
459
+
460
+ /* operation */
461
+ if (pcap_compile(cap->pcap, &program, filter,
462
+ opt, cap->netmask) < 0)
463
+ rb_raise(ePcapError, "setfilter: %s", pcap_geterr(cap->pcap));
464
+ if (pcap_setfilter(cap->pcap, &program) < 0)
465
+ rb_raise(ePcapError, "setfilter: %s", pcap_geterr(cap->pcap));
466
+
467
+ return Qnil;
468
+ }
469
+
470
+ static VALUE
471
+ capture_datalink(self)
472
+ VALUE self;
473
+ {
474
+ struct capture_object *cap;
475
+
476
+ DEBUG_PRINT("capture_datalink");
477
+ GetCapture(self, cap);
478
+
479
+ return INT2NUM(pcap_datalink(cap->pcap));
480
+ }
481
+
482
+ static VALUE
483
+ capture_snapshot(self)
484
+ VALUE self;
485
+ {
486
+ struct capture_object *cap;
487
+
488
+ DEBUG_PRINT("capture_snapshot");
489
+ GetCapture(self, cap);
490
+
491
+ return INT2NUM(pcap_snapshot(cap->pcap));
492
+ }
493
+
494
+ static VALUE
495
+ capture_stats(self)
496
+ VALUE self;
497
+ {
498
+ struct capture_object *cap;
499
+ struct pcap_stat stat;
500
+ VALUE v_stat;
501
+
502
+ DEBUG_PRINT("capture_stats");
503
+ GetCapture(self, cap);
504
+
505
+ if (pcap_stats(cap->pcap, &stat) == -1)
506
+ return Qnil;
507
+
508
+ v_stat = rb_funcall(cPcapStat, rb_intern("new"), 3,
509
+ UINT2NUM(stat.ps_recv),
510
+ UINT2NUM(stat.ps_drop),
511
+ UINT2NUM(stat.ps_ifdrop));
512
+
513
+ return v_stat;
514
+ }
515
+
516
+ static VALUE
517
+ capture_inject(self, v_buf)
518
+ VALUE self;
519
+ VALUE v_buf;
520
+ {
521
+ struct capture_object *cap;
522
+ const void *buf;
523
+ size_t bufsiz;
524
+ int r;
525
+
526
+ DEBUG_PRINT("capture_inject");
527
+ GetCapture(self, cap);
528
+
529
+ Check_Type(v_buf, T_STRING);
530
+ buf = (void *)RSTRING_PTR(v_buf);
531
+ bufsiz = RSTRING_LEN(v_buf);
532
+
533
+ r = pcap_inject(cap->pcap, buf, bufsiz);
534
+ if (0 > r) {
535
+ rb_raise(ePcapError, "pcap_inject failure: %s", pcap_geterr(cap->pcap));
536
+ }
537
+ if (bufsiz != r) {
538
+ rb_raise(ePcapError, "pcap_inject expected to write %d but actually wrote %d", bufsiz, r);
539
+ }
540
+ return Qnil;
541
+ }
542
+
543
+ /*
544
+ * Dumper object
545
+ */
546
+
547
+ struct dumper_object {
548
+ pcap_dumper_t *pcap_dumper;
549
+ int dl_type;
550
+ bpf_u_int32 snaplen;
551
+ };
552
+
553
+ static void
554
+ closed_dumper()
555
+ {
556
+ rb_raise(rb_eRuntimeError, "dumper is already closed");
557
+ }
558
+
559
+ #define GetDumper(obj, dumper) {\
560
+ Data_Get_Struct(obj, struct dumper_object, dumper);\
561
+ if (dumper->pcap_dumper == NULL) closed_dumper();\
562
+ }
563
+
564
+ /* called from GC */
565
+ static void
566
+ free_dumper(dumper)
567
+ struct dumper_object *dumper;
568
+ {
569
+ DEBUG_PRINT("free_dumper");
570
+ if (dumper->pcap_dumper != NULL) {
571
+ DEBUG_PRINT("closing dumper");
572
+ pcap_dump_close(dumper->pcap_dumper);
573
+ dumper->pcap_dumper = NULL;
574
+ }
575
+ free(dumper);
576
+ }
577
+
578
+ static VALUE
579
+ dumper_open(class, v_cap, v_fname)
580
+ VALUE class;
581
+ VALUE v_cap;
582
+ VALUE v_fname;
583
+ {
584
+ struct dumper_object *dumper;
585
+ struct capture_object *cap;
586
+ pcap_dumper_t *pcap_dumper;
587
+ VALUE self;
588
+
589
+ DEBUG_PRINT("dumper_open");
590
+
591
+ CheckClass(v_cap, cCapture);
592
+ GetCapture(v_cap, cap);
593
+ Check_SafeStr(v_fname);
594
+
595
+ pcap_dumper = pcap_dump_open(cap->pcap, RSTRING_PTR(v_fname));
596
+ if (pcap_dumper == NULL) {
597
+ rb_raise(ePcapError, "dumper_open: %s", pcap_geterr(cap->pcap));
598
+ }
599
+
600
+ self = Data_Make_Struct(class, struct dumper_object, 0,
601
+ free_dumper, dumper);
602
+ dumper->pcap_dumper = pcap_dumper;
603
+ dumper->dl_type = cap->dl_type;
604
+ dumper->snaplen = pcap_snapshot(cap->pcap);
605
+
606
+ return self;
607
+ }
608
+
609
+ static VALUE
610
+ dumper_close(self)
611
+ VALUE self;
612
+ {
613
+ struct dumper_object *dumper;
614
+
615
+ DEBUG_PRINT("dumper_close");
616
+ GetDumper(self, dumper);
617
+
618
+ pcap_dump_close(dumper->pcap_dumper);
619
+ dumper->pcap_dumper = NULL;
620
+ return Qnil;
621
+ }
622
+
623
+ static VALUE
624
+ dumper_dump(self, v_pkt)
625
+ VALUE self;
626
+ VALUE v_pkt;
627
+ {
628
+ struct dumper_object *dumper;
629
+ struct packet_object *pkt;
630
+
631
+ DEBUG_PRINT("dumper_dump");
632
+ GetDumper(self, dumper);
633
+
634
+ CheckClass(v_pkt, cPacket);
635
+ GetPacket(v_pkt, pkt);
636
+ if (pkt->hdr.dl_type != dumper->dl_type)
637
+ rb_raise(rb_eArgError, "Cannot dump this packet: data-link type mismatch");
638
+ if (pkt->hdr.pkthdr.caplen > dumper->snaplen)
639
+ rb_raise(rb_eArgError, "Cannot dump this packet: too large caplen");
640
+
641
+ pcap_dump((u_char *)dumper->pcap_dumper, &pkt->hdr.pkthdr, pkt->data);
642
+ return Qnil;
643
+ }
644
+
645
+ static VALUE
646
+ dumper_dump_raw(self, v_buf)
647
+ VALUE self;
648
+ VALUE v_buf;
649
+ {
650
+ struct dumper_object *dumper;
651
+ const u_char *buf;
652
+ struct pcap_pkthdr pkt_hdr;
653
+
654
+ DEBUG_PRINT("dumper_dump_raw");
655
+ GetDumper(self, dumper);
656
+
657
+ Check_Type(v_buf, T_STRING);
658
+ buf = (void *)RSTRING_PTR(v_buf);
659
+
660
+ gettimeofday(&(pkt_hdr.ts), NULL);
661
+ pkt_hdr.caplen = dumper->snaplen;
662
+ pkt_hdr.len = RSTRING_LEN(v_buf);
663
+
664
+ pcap_dump((u_char *)dumper->pcap_dumper, &pkt_hdr, buf);
665
+ return Qnil;
666
+ }
667
+
668
+ /*
669
+ * Filter object
670
+ */
671
+
672
+ /* called from GC */
673
+ static void
674
+ mark_filter(filter)
675
+ struct filter_object *filter;
676
+ {
677
+ rb_gc_mark(filter->param);
678
+ rb_gc_mark(filter->optimize);
679
+ rb_gc_mark(filter->netmask);
680
+ }
681
+
682
+ static void
683
+ free_filter(filter)
684
+ struct filter_object *filter;
685
+ {
686
+ free(filter->expr);
687
+ free(filter);
688
+ /*
689
+ * This cause memory leak because filter->program hold some memory.
690
+ * We overlook it because libpcap does not implement pcap_freecode().
691
+ */
692
+ }
693
+
694
+ static VALUE
695
+ filter_new(argc, argv, class)
696
+ int argc;
697
+ VALUE *argv;
698
+ VALUE class;
699
+ {
700
+ VALUE self, v_expr, v_optimize, v_capture, v_netmask;
701
+ struct filter_object *filter;
702
+ struct capture_object *capture;
703
+ pcap_t *pcap;
704
+ char *expr;
705
+ int n, optimize, snaplen, linktype;
706
+ bpf_u_int32 netmask;
707
+
708
+ n = rb_scan_args(argc, argv, "13", &v_expr, &v_capture,
709
+ &v_optimize, &v_netmask);
710
+ /* filter expression */
711
+ Check_Type(v_expr, T_STRING);
712
+ expr = StringValuePtr(v_expr);
713
+ /* capture object */
714
+ if (IsKindOf(v_capture, cCapture)) {
715
+ CheckClass(v_capture, cCapture);
716
+ GetCapture(v_capture, capture);
717
+ pcap = capture->pcap;
718
+ } else if (NIL_P(v_capture)) {
719
+ /* assume most common case */
720
+ snaplen = DEFAULT_SNAPLEN;
721
+ linktype = DEFAULT_DATALINK;
722
+ pcap = 0;
723
+ } else {
724
+ snaplen = NUM2INT(rb_funcall(v_capture, rb_intern("[]"), 1, INT2FIX(0)));
725
+ linktype = NUM2INT(rb_funcall(v_capture, rb_intern("[]"), 1, INT2FIX(1)));
726
+ pcap = 0;
727
+ }
728
+ /* optimize flag */
729
+ optimize = 1;
730
+ if (n >= 3) {
731
+ optimize = RTEST(v_optimize);
732
+ }
733
+ /* netmask */
734
+ netmask = 0;
735
+ if (n >= 4) {
736
+ bpf_u_int32 mask = NUM2UINT(v_netmask);
737
+ netmask = htonl(mask);
738
+ }
739
+
740
+ filter = (struct filter_object *)xmalloc(sizeof(struct filter_object));
741
+ if (pcap) {
742
+ if (pcap_compile(pcap, &filter->program, expr, optimize, netmask) < 0)
743
+ rb_raise(ePcapError, "%s", pcap_geterr(pcap));
744
+ filter->datalink = pcap_datalink(pcap);
745
+ filter->snaplen = pcap_snapshot(pcap);
746
+ } else {
747
+ #ifdef HAVE_PCAP_COMPILE_NOPCAP
748
+ if (pcap_compile_nopcap(snaplen, linktype, &filter->program, expr, optimize, netmask) < 0)
749
+ /* libpcap-0.5 provides no error report for pcap_compile_nopcap */
750
+ rb_raise(ePcapError, "pcap_compile_nopcap error");
751
+ filter->datalink = linktype;
752
+ filter->snaplen = snaplen;
753
+ #else
754
+ rb_raise(rb_eArgError, "pcap_compile_nopcap needs libpcap-0.5 or later");
755
+ #endif
756
+ }
757
+ self = Data_Wrap_Struct(class, mark_filter, free_filter, filter);
758
+ filter->expr = strdup(expr);
759
+ filter->param = v_capture;
760
+ filter->optimize = optimize ? Qtrue : Qfalse;
761
+ filter->netmask = INT2NUM(ntohl(netmask));
762
+
763
+ return self;
764
+ }
765
+
766
+ VALUE
767
+ filter_match(self, v_pkt)
768
+ VALUE self, v_pkt;
769
+ {
770
+ struct filter_object *filter;
771
+ struct packet_object *pkt;
772
+ struct pcap_pkthdr *h;
773
+
774
+ GetFilter(self, filter);
775
+ CheckClass(v_pkt, cPacket);
776
+ GetPacket(v_pkt, pkt);
777
+ h = &pkt->hdr.pkthdr;
778
+
779
+ if (filter->datalink != pkt->hdr.dl_type)
780
+ rb_raise(rb_eRuntimeError, "Incompatible datalink type");
781
+ if (filter->snaplen < h->caplen)
782
+ rb_raise(rb_eRuntimeError, "Incompatible snaplen");
783
+
784
+ if (bpf_filter(filter->program.bf_insns, pkt->data, h->len, h->caplen))
785
+ return Qtrue;
786
+ else
787
+ return Qfalse;
788
+ }
789
+
790
+ static VALUE
791
+ filter_source(self)
792
+ VALUE self;
793
+ {
794
+ struct filter_object *filter;
795
+
796
+ GetFilter(self, filter);
797
+ return rb_str_new2(filter->expr);
798
+ }
799
+
800
+ static VALUE
801
+ new_filter(expr, param, optimize, netmask)
802
+ char *expr;
803
+ VALUE param, optimize, netmask;
804
+ {
805
+ return rb_funcall(cFilter,
806
+ rb_intern("new"), 4,
807
+ rb_str_new2(expr), param, optimize, netmask);
808
+ }
809
+
810
+ static VALUE
811
+ filter_or(self, other)
812
+ VALUE self, other;
813
+ {
814
+ struct filter_object *filter, *filter2;
815
+ char *expr;
816
+
817
+ CheckClass(other, cFilter);
818
+ GetFilter(self, filter);
819
+ GetFilter(other, filter2);
820
+
821
+ expr = ALLOCA_N(char, strlen(filter->expr) + strlen(filter2->expr) + 16);
822
+ sprintf(expr, "( %s ) or ( %s )", filter->expr, filter2->expr);
823
+ return new_filter(expr, filter->param, filter->optimize, filter->netmask);
824
+ }
825
+
826
+ static VALUE
827
+ filter_and(self, other)
828
+ VALUE self, other;
829
+ {
830
+ struct filter_object *filter, *filter2;
831
+ char *expr;
832
+
833
+ CheckClass(other, cFilter);
834
+ GetFilter(self, filter);
835
+ GetFilter(other, filter2);
836
+
837
+ expr = ALLOCA_N(char, strlen(filter->expr) + strlen(filter2->expr) + 16);
838
+ sprintf(expr, "( %s ) and ( %s )", filter->expr, filter2->expr);
839
+ return new_filter(expr, filter->param, filter->optimize, filter->netmask);
840
+ }
841
+
842
+ static VALUE
843
+ filter_not(self)
844
+ VALUE self;
845
+ {
846
+ struct filter_object *filter;
847
+ char *expr;
848
+
849
+ GetFilter(self, filter);
850
+ expr = ALLOCA_N(char, strlen(filter->expr) + 16);
851
+ sprintf(expr, "not ( %s )", filter->expr);
852
+ return new_filter(expr, filter->param, filter->optimize, filter->netmask);
853
+ }
854
+
855
+ /*
856
+ * Class definition
857
+ */
858
+
859
+ void
860
+ Init_pcap(void)
861
+ {
862
+ DEBUG_PRINT("Init_pcap");
863
+
864
+ /* define module Pcap */
865
+ mPcap = rb_define_module("Pcap");
866
+ rb_define_module_function(mPcap, "lookupdev", pcap_s_lookupdev, 0);
867
+ rb_define_module_function(mPcap, "findalldevs", pcap_s_findalldevs, 0);
868
+ rb_define_module_function(mPcap, "lookupnet", pcap_s_lookupnet, 1);
869
+ rb_global_variable(&rbpcap_convert);
870
+ rb_define_singleton_method(mPcap, "convert?", pcap_s_convert, 0);
871
+ rb_define_singleton_method(mPcap, "convert=", pcap_s_convert_set, 1);
872
+ rb_define_const(mPcap, "DLT_NULL", INT2NUM(DLT_NULL));
873
+ rb_define_const(mPcap, "DLT_EN10MB", INT2NUM(DLT_EN10MB));
874
+ rb_define_const(mPcap, "DLT_EN3MB", INT2NUM(DLT_EN3MB));
875
+ rb_define_const(mPcap, "DLT_AX25", INT2NUM(DLT_AX25));
876
+ rb_define_const(mPcap, "DLT_PRONET", INT2NUM(DLT_PRONET));
877
+ rb_define_const(mPcap, "DLT_CHAOS", INT2NUM(DLT_CHAOS));
878
+ rb_define_const(mPcap, "DLT_IEEE802", INT2NUM(DLT_IEEE802));
879
+ rb_define_const(mPcap, "DLT_ARCNET", INT2NUM(DLT_ARCNET));
880
+ rb_define_const(mPcap, "DLT_SLIP", INT2NUM(DLT_SLIP));
881
+ rb_define_const(mPcap, "DLT_PPP", INT2NUM(DLT_PPP));
882
+ rb_define_const(mPcap, "DLT_FDDI", INT2NUM(DLT_FDDI));
883
+ rb_define_const(mPcap, "DLT_ATM_RFC1483", INT2NUM(DLT_ATM_RFC1483));
884
+ #ifdef DLT_RAW
885
+ rb_define_const(mPcap, "DLT_RAW", INT2NUM(DLT_RAW));
886
+ rb_define_const(mPcap, "DLT_SLIP_BSDOS", INT2NUM(DLT_SLIP_BSDOS));
887
+ rb_define_const(mPcap, "DLT_PPP_BSDOS", INT2NUM(DLT_PPP_BSDOS));
888
+ #endif
889
+
890
+ /* define class Capture */
891
+ cCapture = rb_define_class_under(mPcap, "Capture", rb_cObject);
892
+ rb_include_module(cCapture, rb_mEnumerable);
893
+ rb_define_singleton_method(cCapture, "open_live", capture_open_live, -1);
894
+ rb_define_singleton_method(cCapture, "open_offline", capture_open_offline, 1);
895
+ rb_define_singleton_method(cCapture, "open_dead", capture_open_dead, -1);
896
+ rb_define_method(cCapture, "close", capture_close, 0);
897
+ rb_define_method(cCapture, "dispatch", capture_dispatch, -1);
898
+ rb_define_method(cCapture, "loop", capture_loop, -1);
899
+ rb_define_method(cCapture, "each_packet", capture_loop, -1);
900
+ rb_define_method(cCapture, "each", capture_loop, -1);
901
+ rb_define_method(cCapture, "fh", capture_fh, -1);
902
+ rb_define_method(cCapture, "setfilter", capture_setfilter, -1);
903
+ rb_define_method(cCapture, "datalink", capture_datalink, 0);
904
+ rb_define_method(cCapture, "snapshot", capture_snapshot, 0);
905
+ rb_define_method(cCapture, "snaplen", capture_snapshot, 0);
906
+ rb_define_method(cCapture, "stats", capture_stats, 0);
907
+ rb_define_method(cCapture, "inject", capture_inject, 1);
908
+
909
+ /* define class Dumper */
910
+ cDumper = rb_define_class_under(mPcap, "Dumper", rb_cObject);
911
+ rb_define_singleton_method(cDumper, "open", dumper_open, 2);
912
+ rb_define_method(cDumper, "close", dumper_close, 0);
913
+ rb_define_method(cDumper, "dump", dumper_dump, 1);
914
+ rb_define_method(cDumper, "dump_raw", dumper_dump_raw, 1);
915
+
916
+ /* define class Filter */
917
+ cFilter = rb_define_class_under(mPcap, "Filter", rb_cObject);
918
+ rb_define_singleton_method(cFilter, "new", filter_new, -1);
919
+ rb_define_singleton_method(cFilter, "compile", filter_new, -1);
920
+ rb_define_method(cFilter, "=~", filter_match, 1);
921
+ rb_define_method(cFilter, "===", filter_match, 1);
922
+ rb_define_method(cFilter, "source", filter_source, 0);
923
+ rb_define_method(cFilter, "|", filter_or, 1);
924
+ rb_define_method(cFilter, "&", filter_and, 1);
925
+ rb_define_method(cFilter, "~@", filter_not, 0);
926
+ /*rb_define_method(cFilter, "&", filter_and, 1);*/
927
+
928
+ /* define class PcapStat */
929
+ cPcapStat = rb_struct_define(NULL, "recv", "drop", "ifdrop", NULL);
930
+ rb_define_const(mPcap, "Stat", cPcapStat);
931
+
932
+ /* define exception classes */
933
+ ePcapError = rb_define_class_under(mPcap, "PcapError", rb_eStandardError);
934
+ eTruncatedPacket = rb_define_class_under(mPcap, "TruncatedPacket", ePcapError);
935
+
936
+ Init_packet();
937
+ rb_f_require(Qnil, rb_str_new2("pcap_misc"));
938
+ }