blackfoundry-pcap 0.1

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,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
+ }