blackfoundry-pcap 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,145 @@
1
+ 2000-08-13 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
2
+
3
+ * version 0.6 released.
4
+
5
+ * packet.c (packet_match): Packet#=~ added.
6
+
7
+ * Pcap.c (capture_setfilter): Filter object can be used in
8
+ Capture#setfilter.
9
+
10
+ * lib/pcaplet.rb: invoke gzip when reading /\.gz$/ file.
11
+ Pcaplet.new accept options.
12
+
13
+ * Pcap.c: implement Filter logical operation.
14
+ (filter_source): Filter#source added.
15
+
16
+ 2000-08-09 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
17
+
18
+ * Pcap.c (filter_new): use pcap_compile_nopcap() if available.
19
+
20
+ 1999-11-08 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
21
+
22
+ * version 0.5 released.
23
+
24
+ * Pcap.c: Call Check_SafeStr() before I/O operation.
25
+
26
+ * lib/pcaplet.rb: Use getopts instead of parseparg.
27
+
28
+ 1999-11-05 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
29
+
30
+ * Filter document added.
31
+
32
+ 1999-11-04 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
33
+
34
+ * Pcap.c (filter_match): datalink and caplen check.
35
+
36
+ 1999-10-30 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
37
+
38
+ * Pcap.c (Init_pcap): added Pcap.{lookupdev,lookupnet}.
39
+
40
+ 1999-10-29 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
41
+
42
+ * Pcap.c: use RTEST instead of Qtrue/Qfalse test.
43
+
44
+ 1999-08-27 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
45
+
46
+ * ip_packet.c (ipaddr_s_new): changed to use gethostbyname().
47
+
48
+ * icmp_packet.c: icmp_type_info lacks type 31-36 hole.
49
+
50
+ 1999-08-26 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
51
+
52
+ * version 0.4 released.
53
+
54
+ * ICMPPacket document added.
55
+
56
+ 1999-08-25 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
57
+
58
+ * udp_packet.c: UdpPacket renamed to UDPPacket.
59
+
60
+ * tcp_packet.c: TcpPacket renamed to TCPPacket.
61
+
62
+ * ip_packet.c: IpPacket renamed to IPPacket.
63
+
64
+ 1999-08-24 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
65
+
66
+ * icmp_packet.c: ICMP support.
67
+
68
+ 1999-08-18 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
69
+
70
+ * Pcap.c (Init_pcap): PcapStat is now defined as Pcap::Stat.
71
+
72
+ 1999-08-17 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
73
+
74
+ * ip_packet.c (setup_ip_packet): check ip_v == 4
75
+
76
+ 1999-08-14 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
77
+
78
+ * ip_packet.c (setup_ip_packet): ntohs must be used for ip_len.
79
+
80
+ * packet.c (Init_packet): Packet#udp? added.
81
+
82
+ 1999-07-23 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
83
+
84
+ * extconf.rb: --with-pcap-prefix is changed to --with-pcap-dir
85
+
86
+ 1999-07-14 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
87
+
88
+ * ip_packet.c (Init_ip_packet): IP address is now represented by
89
+ new class IPAddress implemented in C. IpAddress is obsolete but
90
+ remains for backward compatibility.
91
+
92
+ 1999-07-11 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
93
+
94
+ * Pcap.c (Init_pcap): Capture includes Enumerable.
95
+
96
+ 1999-07-02 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
97
+
98
+ * version 0.3.1 released.
99
+
100
+ * Pcap.c: Filter class is added.
101
+
102
+ * tcp_packet.c (tcpp_data): data length bug is fixed.
103
+
104
+ 1999-06-27 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
105
+
106
+ * Pcap.c (capture_loop): improved to be thread-friendly.
107
+
108
+ 1999-05-24 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
109
+
110
+ * version 0.3 released.
111
+
112
+ * extconf.rb: --with-pcap-prefix option added.
113
+
114
+ * changed to based on ruby-1.3.x.
115
+
116
+ 1999-04-20 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
117
+
118
+ * version 0.2 released.
119
+
120
+ 1999-04-18 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
121
+
122
+ * UdpPacket documentation added.
123
+
124
+ 1999-02-08 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
125
+
126
+ * udp_packet.c: UDP supprot added.
127
+
128
+ 1998-12-07 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
129
+
130
+ * version 0.1.1 released.
131
+
132
+ * Document about exception classes added.
133
+
134
+ * Pcap.c (CheckClass): CheckClass added.
135
+ (dumper_dump): check data-link type and caplen.
136
+
137
+ 1998-12-06 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
138
+
139
+ * packet.c: Packet#datalink added.
140
+
141
+ * English document added.
142
+
143
+ 1998-12-01 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
144
+
145
+ * version 0.1 released.
data/README ADDED
@@ -0,0 +1,48 @@
1
+ * Introduction
2
+
3
+ ruby-pcap is a ruby extension to LBL libpcap (Packet Capture library).
4
+ This library also includes classes to access TCP/IP header.
5
+
6
+ * Installation
7
+
8
+ Requirements:
9
+
10
+ - ruby-1.4.x
11
+ - libpcap (http://www.tcpdump.org/)
12
+
13
+ Compile:
14
+
15
+ If ruby supports dynamic link of extension module on your OS,
16
+ following commands will install ruby-pcap.
17
+
18
+ ruby extconf.rb [options]
19
+ make
20
+ make install
21
+
22
+ You can specify options when you run 'ruby extconf.rb':
23
+
24
+ `--with-pcap-dir=PREFIX'
25
+ Directory where libpcap is installed. Default is '/usr/local'.
26
+
27
+ If dynamic link isn't available, you can link ruby-pcap statically
28
+ with ruby. Extract ruby-pcap under the directory 'ext' in ruby source
29
+ tree, then build ruby.
30
+
31
+ * Usage
32
+
33
+ See the documentation under the directory 'doc'.
34
+ Directory 'examples' contains some simple scripts.
35
+
36
+ * Author
37
+
38
+ Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
39
+
40
+ ruby-pcap is copyrighted free software by Masaki Fukushima.
41
+
42
+ You can redistribute it and/or modify it under the terms of
43
+ the GPL (GNU GENERAL PUBLIC LICENSE). See COPYING file about GPL.
44
+
45
+ THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
46
+ WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
47
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. See the GPL for
48
+ more details.
@@ -0,0 +1,50 @@
1
+ * $B35MW(B
2
+
3
+ ruby-pcap $B$O(B Ruby $B$+$i(B LBL $B$N(B libpcap (Packet Capture library) $B$X%"%/(B
4
+ $B%;%9$9$k$?$a$N3HD%%i%$%V%i%j$G$9!#(BTCP/IP$B$N%X%C%@$N>pJs$K%"%/%;%9$9$k$?(B
5
+ $B$a$N%/%i%9$b4^$s$G$$$^$9!#(B
6
+
7
+ * $B%$%s%9%H!<%k(B
8
+
9
+ $BI,MW$J$b$N(B:
10
+
11
+ - ruby-1.4.x
12
+ - libpcap (http://www.tcpdump.org/)
13
+
14
+ $B%3%s%Q%$%k(B:
15
+
16
+ ruby $B$,3HD%%i%$%V%i%j$N%@%$%J%_%C%/%j%s%/$r%5%]!<%H$7$F$$$k>l9g$O!"(B
17
+ $B0J2<$N<j=g$G%$%s%9%H!<%k$G$-$^$9!#(B
18
+
19
+ ruby extconf.rb [options]
20
+ make
21
+ make install
22
+
23
+ 'ruby extconf.rb'$B$r<B9T$9$k;~$K$O0J2<$N%*%W%7%g%s$r;XDj$G$-$^$9!#(B
24
+
25
+ `--with-pcap-dir=PREFIX'
26
+ libpcap$B$,%$%s%9%H!<%k$5$l$F$$$k%G%#%l%/%H%j$r;XDj$7$^$9!#(B
27
+ $B%G%U%)%k%H$O(B'/usr/local'$B$G$9!#(B
28
+
29
+ $B%@%$%J%_%C%/%j%s%/$,;H$($J$$>l9g$O(B ruby $B$K@EE*$K%j%s%/$7$F2<$5$$!#(B
30
+ $B$=$N>l9g$O(B ruby $B%=!<%9Cf$N(B 'ext' $B%G%#%l%/%H%j$N2<$G(B ruby-pcap $B$rE83+$7(B
31
+ $B$F$+$i(B ruby $B$r%S%k%I$7$F2<$5$$!#(B
32
+
33
+ * $B;H$$J}(B
34
+
35
+ doc $B$*$h$S(B doc-ja $B%G%#%l%/%H%j0J2<$K$"$k%U%!%$%k$r8+$F2<$5$$!#(B
36
+ examples $B%G%#%l%/%H%j$K4JC1$J%5%s%W%k%9%/%j%W%H$,$"$j$^$9!#(B
37
+
38
+ * $B:n<T(B
39
+
40
+ $BJ!Eh@55!(B <fukusima@goto.info.waseda.ac.jp>
41
+
42
+ ruby-pcap$B$OJ!Eh@55!$,Cx:n8"$rJ];}$9$k(B free software $B$G$9!#(B
43
+
44
+ ruby-pcap$B$O(BGPL(GNU GENERAL PUBLIC LICENSE)$B$K=>$C$F:FG[I[$^$?$O(B
45
+ $BJQ99$9$k$3$H$,$G$-$^$9!#(BGPL$B$K$D$$$F$O(BCOPYING$B%U%!%$%k$r;2>H$7$F(B
46
+ $B$/$@$5$$!#(B
47
+
48
+ ruby-pcap$B$OL5J]>Z$G$9!#:n<T$O(Bruby-pcap$B$N%P%0$J$I$+$iH/@8$9$k(B
49
+ $B$$$+$J$kB;32$KBP$7$F$b@UG$$r;}$A$^$;$s!#>\:Y$K$D$$$F$O(B GPL $B$r(B
50
+ $B;2>H$7$F$/$@$5$$!#(B
@@ -0,0 +1,23 @@
1
+ require 'rake'
2
+
3
+ task :default => [:make]
4
+
5
+ task :make do
6
+ puts `ruby extconf.rb`
7
+ puts `make`
8
+ end
9
+
10
+ require 'jeweler'
11
+ Jeweler::Tasks.new do |s|
12
+ s.version = '0.1'
13
+ s.name = 'blackfoundry-pcap'
14
+ s.summary = 'extensions to ruby-pcap'
15
+ s.email = 'david@blackfoundry.com'
16
+ s.description =<<-eod
17
+ Some extensions to the pcap library.
18
+ eod
19
+ s.executables = []
20
+ s.authors = ['David Turnbull']
21
+ s.files = ['Rakefile', 'lib'] + Dir['ext/**'] + Dir['lib/**']
22
+ end
23
+
@@ -0,0 +1,798 @@
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
+ static char pcap_errbuf[PCAP_ERRBUF_SIZE];
20
+
21
+ VALUE mPcap, rbpcap_convert = Qnil;
22
+ VALUE ePcapError;
23
+ VALUE eTruncatedPacket;
24
+ VALUE cFilter;
25
+ static VALUE cCapture;
26
+ static VALUE cPcapStat;
27
+ static VALUE cDumper;
28
+
29
+ struct filter_object {
30
+ char *expr;
31
+ struct bpf_program program;
32
+ int datalink;
33
+ int snaplen;
34
+ VALUE param;
35
+ VALUE optimize;
36
+ VALUE netmask;
37
+ };
38
+
39
+ #define GetFilter(obj, filter) \
40
+ Data_Get_Struct(obj, struct filter_object, filter)
41
+
42
+
43
+ static VALUE
44
+ pcap_s_lookupdev(self)
45
+ VALUE self;
46
+ {
47
+ char *dev;
48
+
49
+ dev = pcap_lookupdev(pcap_errbuf);
50
+ if (dev == NULL) {
51
+ rb_raise(ePcapError, "%s", pcap_errbuf);
52
+ }
53
+ return rb_str_new2(dev);
54
+ }
55
+
56
+ static VALUE
57
+ pcap_s_lookupnet(self, dev)
58
+ VALUE self;
59
+ VALUE dev;
60
+ {
61
+ bpf_u_int32 net, mask, m;
62
+ struct in_addr addr;
63
+
64
+ Check_Type(dev, T_STRING);
65
+ if (pcap_lookupnet(STR2CSTR(dev), &net, &mask, pcap_errbuf) == -1) {
66
+ rb_raise(ePcapError, "%s", pcap_errbuf);
67
+ }
68
+
69
+ addr.s_addr = net;
70
+ m = ntohl(mask);
71
+ return rb_ary_new3(2, new_ipaddr(&addr), UINT32_2_NUM(m));
72
+ }
73
+
74
+ static VALUE
75
+ pcap_s_convert(self)
76
+ VALUE self;
77
+ {
78
+ return rbpcap_convert;
79
+ }
80
+
81
+ static VALUE
82
+ pcap_s_convert_set(self, val)
83
+ VALUE self;
84
+ {
85
+ rbpcap_convert = val;
86
+ return Qnil;
87
+ }
88
+
89
+ /*
90
+ * Capture object
91
+ */
92
+
93
+ struct capture_object {
94
+ pcap_t *pcap;
95
+ bpf_u_int32 netmask;
96
+ int dl_type; /* data-link type (DLT_*) */
97
+ };
98
+
99
+ static void
100
+ closed_capture()
101
+ {
102
+ rb_raise(rb_eRuntimeError, "device is already closed");
103
+ }
104
+
105
+ #define GetCapture(obj, cap) {\
106
+ Data_Get_Struct(obj, struct capture_object, cap);\
107
+ if (cap->pcap == NULL) closed_capture();\
108
+ }
109
+
110
+ /* called from GC */
111
+ static void
112
+ free_capture(cap)
113
+ struct capture_object *cap;
114
+ {
115
+ DEBUG_PRINT("free_capture");
116
+ if (cap->pcap != NULL) {
117
+ DEBUG_PRINT("closing capture");
118
+ rb_thread_fd_close(pcap_fileno(cap->pcap));
119
+ pcap_close(cap->pcap);
120
+ cap->pcap = NULL;
121
+ }
122
+ free(cap);
123
+ }
124
+
125
+ static VALUE
126
+ capture_open_live(argc, argv, class)
127
+ int argc;
128
+ VALUE *argv;
129
+ VALUE class;
130
+ {
131
+ VALUE v_device, v_snaplen, v_promisc, v_to_ms;
132
+ char *device;
133
+ int snaplen, promisc, to_ms;
134
+ int rs;
135
+ VALUE self;
136
+ struct capture_object *cap;
137
+ pcap_t *pcap;
138
+ bpf_u_int32 net, netmask;
139
+
140
+ DEBUG_PRINT("capture_open_live");
141
+
142
+ /* scan arg */
143
+ rs = rb_scan_args(argc, argv, "13", &v_device, &v_snaplen,
144
+ &v_promisc, &v_to_ms);
145
+
146
+ /* device */
147
+ Check_SafeStr(v_device);
148
+ device = RSTRING(v_device)->ptr;
149
+ /* snaplen */
150
+ if (rs >= 2) {
151
+ Check_Type(v_snaplen, T_FIXNUM);
152
+ snaplen = FIX2INT(v_snaplen);
153
+ } else {
154
+ snaplen = DEFAULT_SNAPLEN;
155
+ }
156
+ if (snaplen < 0)
157
+ rb_raise(rb_eArgError, "invalid snaplen");
158
+ /* promisc */
159
+ if (rs >= 3) {
160
+ promisc = RTEST(v_promisc);
161
+ } else {
162
+ promisc = DEFAULT_PROMISC;
163
+ }
164
+ /* to_ms */
165
+ if (rs >= 4) {
166
+ Check_Type(v_to_ms, T_FIXNUM);
167
+ to_ms = FIX2INT(v_to_ms);
168
+ } else
169
+ to_ms = DEFAULT_TO_MS;
170
+
171
+ /* open */
172
+ pcap = pcap_open_live(device, snaplen, promisc, to_ms, pcap_errbuf);
173
+ if (pcap == NULL) {
174
+ rb_raise(ePcapError, "%s", pcap_errbuf);
175
+ }
176
+ if (pcap_lookupnet(device, &net, &netmask, pcap_errbuf) == -1) {
177
+ netmask = 0;
178
+ rb_warning("cannot lookup net: %s\n", pcap_errbuf);
179
+ }
180
+
181
+ /* setup instance */
182
+ self = Data_Make_Struct(class, struct capture_object,
183
+ 0, free_capture, cap);
184
+ cap->pcap = pcap;
185
+ cap->netmask = netmask;
186
+ cap->dl_type = pcap_datalink(pcap);
187
+
188
+ return self;
189
+ }
190
+
191
+ static VALUE
192
+ capture_open_offline(class, fname)
193
+ VALUE class;
194
+ VALUE fname;
195
+ {
196
+ VALUE self;
197
+ struct capture_object *cap;
198
+ pcap_t *pcap;
199
+
200
+ DEBUG_PRINT("capture_open_offline");
201
+
202
+ /* open offline */
203
+ Check_SafeStr(fname);
204
+ pcap = pcap_open_offline(RSTRING(fname)->ptr, pcap_errbuf);
205
+ if (pcap == NULL) {
206
+ rb_raise(ePcapError, "%s", pcap_errbuf);
207
+ }
208
+
209
+ /* setup instance */
210
+ self = Data_Make_Struct(class, struct capture_object,
211
+ 0, free_capture, cap);
212
+ cap->pcap = pcap;
213
+ cap->netmask = 0;
214
+ cap->dl_type = pcap_datalink(pcap);
215
+
216
+ return self;
217
+ }
218
+
219
+ static VALUE
220
+ capture_close(self)
221
+ VALUE self;
222
+ {
223
+ struct capture_object *cap;
224
+
225
+ DEBUG_PRINT("capture_close");
226
+ GetCapture(self, cap);
227
+
228
+ rb_thread_fd_close(pcap_fileno(cap->pcap));
229
+ pcap_close(cap->pcap);
230
+ cap->pcap = NULL;
231
+ return Qnil;
232
+ }
233
+
234
+ static void
235
+ handler(cap, pkthdr, data)
236
+ struct capture_object *cap;
237
+ const struct pcap_pkthdr *pkthdr;
238
+ const u_char *data;
239
+ {
240
+ size_t offset = ftell(pcap_file(cap->pcap)) - pkthdr->caplen;
241
+ VALUE pkt = new_packet(data, pkthdr, cap->dl_type);
242
+ rb_yield_values(2, LONG2NUM(offset), pkt);
243
+ }
244
+
245
+ static VALUE
246
+ capture_dispatch(argc, argv, self)
247
+ int argc;
248
+ VALUE *argv;
249
+ VALUE self;
250
+ {
251
+ VALUE v_cnt;
252
+ int cnt;
253
+ struct capture_object *cap;
254
+ int ret;
255
+
256
+ DEBUG_PRINT("capture_dispatch");
257
+ GetCapture(self, cap);
258
+
259
+
260
+ /* scan arg */
261
+ if (rb_scan_args(argc, argv, "01", &v_cnt) >= 1) {
262
+ FIXNUM_P(v_cnt);
263
+ cnt = FIX2INT(v_cnt);
264
+ } else
265
+ cnt = -1;
266
+
267
+ TRAP_BEG;
268
+ ret = pcap_dispatch(cap->pcap, cnt, handler, (u_char *)cap);
269
+ TRAP_END;
270
+ if (ret == -1)
271
+ rb_raise(ePcapError, "dispatch: %s", pcap_geterr(cap->pcap));
272
+
273
+ return INT2FIX(ret);
274
+ }
275
+
276
+ int pcap_read(pcap_t *, int cnt, pcap_handler, u_char *); /* pcap-int.h */
277
+
278
+ static VALUE
279
+ capture_loop(argc, argv, self)
280
+ int argc;
281
+ VALUE *argv;
282
+ VALUE self;
283
+ {
284
+ VALUE v_cnt;
285
+ int cnt;
286
+ struct capture_object *cap;
287
+ int ret;
288
+
289
+ DEBUG_PRINT("capture_loop");
290
+ GetCapture(self, cap);
291
+
292
+
293
+ /* scan arg */
294
+ if (rb_scan_args(argc, argv, "01", &v_cnt) >= 1) {
295
+ FIXNUM_P(v_cnt);
296
+ cnt = FIX2INT(v_cnt);
297
+ } else
298
+ cnt = -1;
299
+
300
+ #if 0
301
+ TRAP_BEG;
302
+ ret = pcap_loop(cap->pcap, cnt, handler, (u_char *)cap);
303
+ TRAP_END;
304
+ #else
305
+ if (pcap_file(cap->pcap) != NULL) {
306
+ TRAP_BEG;
307
+ ret = pcap_loop(cap->pcap, cnt, handler, (u_char *)cap);
308
+ TRAP_END;
309
+ } else {
310
+ int fd = pcap_fileno(cap->pcap);
311
+ fd_set rset;
312
+ struct timeval tm;
313
+
314
+ FD_ZERO(&rset);
315
+ tm.tv_sec = 0;
316
+ tm.tv_usec = 0;
317
+ for (;;) {
318
+ do {
319
+ FD_SET(fd, &rset);
320
+ if (select(fd+1, &rset, NULL, NULL, &tm) == 0) {
321
+ rb_thread_wait_fd(fd);
322
+ }
323
+ TRAP_BEG;
324
+ ret = pcap_read(cap->pcap, 1, handler, (u_char *)cap);
325
+ TRAP_END;
326
+ } while (ret == 0);
327
+ if (ret <= 0)
328
+ break;
329
+ if (cnt > 0) {
330
+ cnt -= ret;
331
+ if (cnt <= 0)
332
+ break;
333
+ }
334
+ }
335
+ }
336
+ #endif
337
+ return INT2FIX(ret);
338
+ }
339
+
340
+ static VALUE
341
+ capture_setfilter(argc, argv, self)
342
+ int argc;
343
+ VALUE *argv;
344
+ VALUE self;
345
+ {
346
+ struct capture_object *cap;
347
+ VALUE vfilter, optimize;
348
+ char *filter;
349
+ int opt;
350
+ struct bpf_program program;
351
+
352
+ DEBUG_PRINT("capture_setfilter");
353
+ GetCapture(self, cap);
354
+
355
+ /* scan arg */
356
+ if (rb_scan_args(argc, argv, "11", &vfilter, &optimize) == 1) {
357
+ optimize = Qtrue;
358
+ }
359
+
360
+ /* check arg */
361
+ if (IsKindOf(vfilter, cFilter)) {
362
+ struct filter_object *f;
363
+ GetFilter(vfilter, f);
364
+ filter = f->expr;
365
+ } else {
366
+ Check_Type(vfilter, T_STRING);
367
+ filter = RSTRING(vfilter)->ptr;
368
+ }
369
+ opt = RTEST(optimize);
370
+
371
+ /* operation */
372
+ if (pcap_compile(cap->pcap, &program, filter,
373
+ opt, cap->netmask) < 0)
374
+ rb_raise(ePcapError, "setfilter: %s", pcap_geterr(cap->pcap));
375
+ if (pcap_setfilter(cap->pcap, &program) < 0)
376
+ rb_raise(ePcapError, "setfilter: %s", pcap_geterr(cap->pcap));
377
+
378
+ return Qnil;
379
+ }
380
+
381
+ static VALUE
382
+ capture_datalink(self)
383
+ VALUE self;
384
+ {
385
+ struct capture_object *cap;
386
+
387
+ DEBUG_PRINT("capture_datalink");
388
+ GetCapture(self, cap);
389
+
390
+ return INT2NUM(pcap_datalink(cap->pcap));
391
+ }
392
+
393
+ static VALUE
394
+ capture_snapshot(self)
395
+ VALUE self;
396
+ {
397
+ struct capture_object *cap;
398
+
399
+ DEBUG_PRINT("capture_snapshot");
400
+ GetCapture(self, cap);
401
+
402
+ return INT2NUM(pcap_snapshot(cap->pcap));
403
+ }
404
+
405
+ static VALUE
406
+ capture_stats(self)
407
+ VALUE self;
408
+ {
409
+ struct capture_object *cap;
410
+ struct pcap_stat stat;
411
+ VALUE v_stat;
412
+
413
+ DEBUG_PRINT("capture_stats");
414
+ GetCapture(self, cap);
415
+
416
+ if (pcap_stats(cap->pcap, &stat) == -1)
417
+ return Qnil;
418
+
419
+ v_stat = rb_funcall(cPcapStat, rb_intern("new"), 3,
420
+ UINT2NUM(stat.ps_recv),
421
+ UINT2NUM(stat.ps_drop),
422
+ UINT2NUM(stat.ps_ifdrop));
423
+
424
+ return v_stat;
425
+ }
426
+
427
+ /*
428
+ * Dumper object
429
+ */
430
+
431
+ struct dumper_object {
432
+ pcap_dumper_t *pcap_dumper;
433
+ int dl_type;
434
+ bpf_u_int32 snaplen;
435
+ };
436
+
437
+ static void
438
+ closed_dumper()
439
+ {
440
+ rb_raise(rb_eRuntimeError, "dumper is already closed");
441
+ }
442
+
443
+ #define GetDumper(obj, dumper) {\
444
+ Data_Get_Struct(obj, struct dumper_object, dumper);\
445
+ if (dumper->pcap_dumper == NULL) closed_dumper();\
446
+ }
447
+
448
+ /* called from GC */
449
+ static void
450
+ free_dumper(dumper)
451
+ struct dumper_object *dumper;
452
+ {
453
+ DEBUG_PRINT("free_dumper");
454
+ if (dumper->pcap_dumper != NULL) {
455
+ DEBUG_PRINT("closing dumper");
456
+ pcap_dump_close(dumper->pcap_dumper);
457
+ dumper->pcap_dumper = NULL;
458
+ }
459
+ free(dumper);
460
+ }
461
+
462
+ static VALUE
463
+ dumper_open(class, v_cap, v_fname)
464
+ VALUE class;
465
+ VALUE v_cap;
466
+ VALUE v_fname;
467
+ {
468
+ struct dumper_object *dumper;
469
+ struct capture_object *cap;
470
+ pcap_dumper_t *pcap_dumper;
471
+ VALUE self;
472
+
473
+ DEBUG_PRINT("dumper_open");
474
+
475
+ CheckClass(v_cap, cCapture);
476
+ GetCapture(v_cap, cap);
477
+ Check_SafeStr(v_fname);
478
+
479
+ pcap_dumper = pcap_dump_open(cap->pcap, RSTRING(v_fname)->ptr);
480
+ if (pcap_dumper == NULL) {
481
+ rb_raise(ePcapError, "dumper_open: %s", pcap_geterr(cap->pcap));
482
+ }
483
+
484
+ self = Data_Make_Struct(class, struct dumper_object, 0,
485
+ free_dumper, dumper);
486
+ dumper->pcap_dumper = pcap_dumper;
487
+ dumper->dl_type = cap->dl_type;
488
+ dumper->snaplen = pcap_snapshot(cap->pcap);
489
+
490
+ return self;
491
+ }
492
+
493
+ static VALUE
494
+ dumper_close(self)
495
+ VALUE self;
496
+ {
497
+ struct dumper_object *dumper;
498
+
499
+ DEBUG_PRINT("dumper_close");
500
+ GetDumper(self, dumper);
501
+
502
+ pcap_dump_close(dumper->pcap_dumper);
503
+ dumper->pcap_dumper = NULL;
504
+ return Qnil;
505
+ }
506
+
507
+ static VALUE
508
+ dumper_dump(self, v_pkt)
509
+ VALUE self;
510
+ VALUE v_pkt;
511
+ {
512
+ struct dumper_object *dumper;
513
+ struct packet_object *pkt;
514
+
515
+ DEBUG_PRINT("dumper_dump");
516
+ GetDumper(self, dumper);
517
+
518
+ CheckClass(v_pkt, cPacket);
519
+ GetPacket(v_pkt, pkt);
520
+ if (pkt->hdr.dl_type != dumper->dl_type)
521
+ rb_raise(rb_eArgError, "Cannot dump this packet: data-link type mismatch");
522
+ if (pkt->hdr.pkthdr.caplen > dumper->snaplen)
523
+ rb_raise(rb_eArgError, "Cannot dump this packet: too large caplen");
524
+
525
+ pcap_dump((u_char *)dumper->pcap_dumper, &pkt->hdr.pkthdr, pkt->data);
526
+ return Qnil;
527
+ }
528
+
529
+ /*
530
+ * Filter object
531
+ */
532
+
533
+ /* called from GC */
534
+ static void
535
+ mark_filter(filter)
536
+ struct filter_object *filter;
537
+ {
538
+ rb_gc_mark(filter->param);
539
+ rb_gc_mark(filter->optimize);
540
+ rb_gc_mark(filter->netmask);
541
+ }
542
+
543
+ static void
544
+ free_filter(filter)
545
+ struct filter_object *filter;
546
+ {
547
+ free(filter->expr);
548
+ free(filter);
549
+ /*
550
+ * This cause memory leak because filter->program hold some memory.
551
+ * We overlook it because libpcap does not implement pcap_freecode().
552
+ */
553
+ }
554
+
555
+ static VALUE
556
+ filter_new(argc, argv, class)
557
+ int argc;
558
+ VALUE *argv;
559
+ VALUE class;
560
+ {
561
+ VALUE self, v_expr, v_optimize, v_capture, v_netmask;
562
+ struct filter_object *filter;
563
+ struct capture_object *capture;
564
+ pcap_t *pcap;
565
+ char *expr;
566
+ int n, optimize, snaplen, linktype;
567
+ bpf_u_int32 netmask;
568
+
569
+ n = rb_scan_args(argc, argv, "13", &v_expr, &v_capture,
570
+ &v_optimize, &v_netmask);
571
+ /* filter expression */
572
+ Check_Type(v_expr, T_STRING);
573
+ expr = STR2CSTR(v_expr);
574
+ /* capture object */
575
+ if (IsKindOf(v_capture, cCapture)) {
576
+ CheckClass(v_capture, cCapture);
577
+ GetCapture(v_capture, capture);
578
+ pcap = capture->pcap;
579
+ } else if (NIL_P(v_capture)) {
580
+ /* assume most common case */
581
+ snaplen = DEFAULT_SNAPLEN;
582
+ linktype = DEFAULT_DATALINK;
583
+ pcap = 0;
584
+ } else {
585
+ snaplen = NUM2INT(rb_funcall(v_capture, rb_intern("[]"), 1, INT2FIX(0)));
586
+ linktype = NUM2INT(rb_funcall(v_capture, rb_intern("[]"), 1, INT2FIX(1)));
587
+ pcap = 0;
588
+ }
589
+ /* optimize flag */
590
+ optimize = 1;
591
+ if (n >= 3) {
592
+ optimize = RTEST(v_optimize);
593
+ }
594
+ /* netmask */
595
+ netmask = 0;
596
+ if (n >= 4) {
597
+ bpf_u_int32 mask = NUM2UINT(v_netmask);
598
+ netmask = htonl(mask);
599
+ }
600
+
601
+ filter = (struct filter_object *)xmalloc(sizeof(struct filter_object));
602
+ if (pcap) {
603
+ if (pcap_compile(pcap, &filter->program, expr, optimize, netmask) < 0)
604
+ rb_raise(ePcapError, "%s", pcap_geterr(pcap));
605
+ filter->datalink = pcap_datalink(pcap);
606
+ filter->snaplen = pcap_snapshot(pcap);
607
+ } else {
608
+ #ifdef HAVE_PCAP_COMPILE_NOPCAP
609
+ if (pcap_compile_nopcap(snaplen, linktype, &filter->program, expr, optimize, netmask) < 0)
610
+ /* libpcap-0.5 provides no error report for pcap_compile_nopcap */
611
+ rb_raise(ePcapError, "pcap_compile_nopcap error");
612
+ filter->datalink = linktype;
613
+ filter->snaplen = snaplen;
614
+ #else
615
+ rb_raise(rb_eArgError, "pcap_compile_nopcap needs libpcap-0.5 or later");
616
+ #endif
617
+ }
618
+ self = Data_Wrap_Struct(class, mark_filter, free_filter, filter);
619
+ filter->expr = strdup(expr);
620
+ filter->param = v_capture;
621
+ filter->optimize = optimize ? Qtrue : Qfalse;
622
+ filter->netmask = INT2NUM(ntohl(netmask));
623
+
624
+ return self;
625
+ }
626
+
627
+ VALUE
628
+ filter_match(self, v_pkt)
629
+ VALUE self, v_pkt;
630
+ {
631
+ struct filter_object *filter;
632
+ struct packet_object *pkt;
633
+ struct pcap_pkthdr *h;
634
+
635
+ GetFilter(self, filter);
636
+ CheckClass(v_pkt, cPacket);
637
+ GetPacket(v_pkt, pkt);
638
+ h = &pkt->hdr.pkthdr;
639
+
640
+ if (filter->datalink != pkt->hdr.dl_type)
641
+ rb_raise(rb_eRuntimeError, "Incompatible datalink type");
642
+ if (filter->snaplen < h->caplen)
643
+ rb_raise(rb_eRuntimeError, "Incompatible snaplen");
644
+
645
+ if (bpf_filter(filter->program.bf_insns, pkt->data, h->len, h->caplen))
646
+ return Qtrue;
647
+ else
648
+ return Qfalse;
649
+ }
650
+
651
+ static VALUE
652
+ filter_source(self)
653
+ VALUE self;
654
+ {
655
+ struct filter_object *filter;
656
+
657
+ GetFilter(self, filter);
658
+ return rb_str_new2(filter->expr);
659
+ }
660
+
661
+ static VALUE
662
+ new_filter(expr, param, optimize, netmask)
663
+ char *expr;
664
+ VALUE param, optimize, netmask;
665
+ {
666
+ return rb_funcall(cFilter,
667
+ rb_intern("new"), 4,
668
+ rb_str_new2(expr), param, optimize, netmask);
669
+ }
670
+
671
+ static VALUE
672
+ filter_or(self, other)
673
+ VALUE self, other;
674
+ {
675
+ struct filter_object *filter, *filter2;
676
+ char *expr;
677
+
678
+ CheckClass(other, cFilter);
679
+ GetFilter(self, filter);
680
+ GetFilter(other, filter2);
681
+
682
+ expr = ALLOCA_N(char, strlen(filter->expr) + strlen(filter2->expr) + 16);
683
+ sprintf(expr, "( %s ) or ( %s )", filter->expr, filter2->expr);
684
+ return new_filter(expr, filter->param, filter->optimize, filter->netmask);
685
+ }
686
+
687
+ static VALUE
688
+ filter_and(self, other)
689
+ VALUE self, other;
690
+ {
691
+ struct filter_object *filter, *filter2;
692
+ char *expr;
693
+
694
+ CheckClass(other, cFilter);
695
+ GetFilter(self, filter);
696
+ GetFilter(other, filter2);
697
+
698
+ expr = ALLOCA_N(char, strlen(filter->expr) + strlen(filter2->expr) + 16);
699
+ sprintf(expr, "( %s ) and ( %s )", filter->expr, filter2->expr);
700
+ return new_filter(expr, filter->param, filter->optimize, filter->netmask);
701
+ }
702
+
703
+ static VALUE
704
+ filter_not(self)
705
+ VALUE self;
706
+ {
707
+ struct filter_object *filter;
708
+ char *expr;
709
+
710
+ GetFilter(self, filter);
711
+ expr = ALLOCA_N(char, strlen(filter->expr) + 16);
712
+ sprintf(expr, "not ( %s )", filter->expr);
713
+ return new_filter(expr, filter->param, filter->optimize, filter->netmask);
714
+ }
715
+
716
+ /*
717
+ * Class definition
718
+ */
719
+
720
+ void
721
+ Init_pcap(void)
722
+ {
723
+ DEBUG_PRINT("Init_pcap");
724
+
725
+ /* define module Pcap */
726
+ mPcap = rb_define_module("Pcap");
727
+ rb_define_module_function(mPcap, "lookupdev", pcap_s_lookupdev, 0);
728
+ rb_define_module_function(mPcap, "lookupnet", pcap_s_lookupnet, 1);
729
+ rb_global_variable(&rbpcap_convert);
730
+ rb_define_singleton_method(mPcap, "convert?", pcap_s_convert, 0);
731
+ rb_define_singleton_method(mPcap, "convert=", pcap_s_convert_set, 1);
732
+ rb_define_const(mPcap, "DLT_NULL", INT2NUM(DLT_NULL));
733
+ rb_define_const(mPcap, "DLT_EN10MB", INT2NUM(DLT_EN10MB));
734
+ rb_define_const(mPcap, "DLT_EN3MB", INT2NUM(DLT_EN3MB));
735
+ rb_define_const(mPcap, "DLT_AX25", INT2NUM(DLT_AX25));
736
+ rb_define_const(mPcap, "DLT_PRONET", INT2NUM(DLT_PRONET));
737
+ rb_define_const(mPcap, "DLT_CHAOS", INT2NUM(DLT_CHAOS));
738
+ rb_define_const(mPcap, "DLT_IEEE802", INT2NUM(DLT_IEEE802));
739
+ rb_define_const(mPcap, "DLT_ARCNET", INT2NUM(DLT_ARCNET));
740
+ rb_define_const(mPcap, "DLT_SLIP", INT2NUM(DLT_SLIP));
741
+ rb_define_const(mPcap, "DLT_PPP", INT2NUM(DLT_PPP));
742
+ rb_define_const(mPcap, "DLT_FDDI", INT2NUM(DLT_FDDI));
743
+ rb_define_const(mPcap, "DLT_ATM_RFC1483", INT2NUM(DLT_ATM_RFC1483));
744
+ #ifdef DLT_RAW
745
+ rb_define_const(mPcap, "DLT_RAW", INT2NUM(DLT_RAW));
746
+ rb_define_const(mPcap, "DLT_SLIP_BSDOS", INT2NUM(DLT_SLIP_BSDOS));
747
+ rb_define_const(mPcap, "DLT_PPP_BSDOS", INT2NUM(DLT_PPP_BSDOS));
748
+ #endif
749
+
750
+ /* define class Capture */
751
+ cCapture = rb_define_class_under(mPcap, "Capture", rb_cObject);
752
+ rb_include_module(cCapture, rb_mEnumerable);
753
+ rb_define_singleton_method(cCapture, "open_live", capture_open_live, -1);
754
+ rb_define_singleton_method(cCapture, "open_offline", capture_open_offline, 1);
755
+ rb_define_method(cCapture, "close", capture_close, 0);
756
+ rb_define_method(cCapture, "dispatch", capture_dispatch, -1);
757
+ rb_define_method(cCapture, "loop", capture_loop, -1);
758
+ rb_define_method(cCapture, "each_packet", capture_loop, -1);
759
+ rb_define_method(cCapture, "each", capture_loop, -1);
760
+ rb_define_method(cCapture, "setfilter", capture_setfilter, -1);
761
+ rb_define_method(cCapture, "datalink", capture_datalink, 0);
762
+ rb_define_method(cCapture, "snapshot", capture_snapshot, 0);
763
+ rb_define_method(cCapture, "snaplen", capture_snapshot, 0);
764
+ rb_define_method(cCapture, "stats", capture_stats, 0);
765
+
766
+ /* define class Dumper */
767
+ cDumper = rb_define_class_under(mPcap, "Dumper", rb_cObject);
768
+ rb_define_singleton_method(cDumper, "open", dumper_open, 2);
769
+ rb_define_method(cDumper, "close", dumper_close, 0);
770
+ rb_define_method(cDumper, "dump", dumper_dump, 1);
771
+
772
+ /* define class Filter */
773
+ cFilter = rb_define_class_under(mPcap, "Filter", rb_cObject);
774
+ rb_define_singleton_method(cFilter, "new", filter_new, -1);
775
+ rb_define_singleton_method(cFilter, "compile", filter_new, -1);
776
+ rb_define_method(cFilter, "=~", filter_match, 1);
777
+ rb_define_method(cFilter, "===", filter_match, 1);
778
+ rb_define_method(cFilter, "source", filter_source, 0);
779
+ rb_define_method(cFilter, "|", filter_or, 1);
780
+ rb_define_method(cFilter, "&", filter_and, 1);
781
+ rb_define_method(cFilter, "~@", filter_not, 0);
782
+ /*rb_define_method(cFilter, "&", filter_and, 1);*/
783
+
784
+ /* define class PcapStat */
785
+ cPcapStat = rb_funcall(rb_cStruct, rb_intern("new"), 4,
786
+ Qnil,
787
+ INT2NUM(rb_intern("recv")),
788
+ INT2NUM(rb_intern("drop")),
789
+ INT2NUM(rb_intern("ifdrop")));
790
+ rb_define_const(mPcap, "Stat", cPcapStat);
791
+
792
+ /* define exception classes */
793
+ ePcapError = rb_define_class_under(mPcap, "PcapError", rb_eStandardError);
794
+ eTruncatedPacket = rb_define_class_under(mPcap, "TruncatedPacket", ePcapError);
795
+
796
+ Init_packet();
797
+ rb_f_require(Qnil, rb_str_new2("pcap_misc"));
798
+ }