ahobson-pcap 0.7.0

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