ahobson-pcap 0.7.0

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