ruby-pcap 0.7.8

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