pcaprub 0.6.2 → 0.8.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.
@@ -9,3 +9,18 @@ PacketRub project (http://packetrub.rubyforge.org).
9
9
 
10
10
  Requirements:
11
11
  libpcap - http://www.tcpdump.org
12
+
13
+ == Other Repositories
14
+
15
+ The latest community svn version can be obtained from Subversion:
16
+ svn checkout http://pcaprub.rubyforge.org/svn/trunk/
17
+
18
+ The Metasploit Project also provides a Subversion repository:
19
+ svn checkout http://metasploit.com/svn/framework3/trunk/external/pcaprub/
20
+
21
+ (credits: github.com/dxoigmn/pcaprub)
22
+
23
+ == Current Repository for Gemcutter source
24
+
25
+ The Git Repo on Github @shadowbq is forked from the Metasploit SVN repo
26
+ git clone git://github.com/shadowbq/pcaprub.git
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.2
1
+ 0.8.0
@@ -1,7 +1,19 @@
1
1
  require 'mkmf'
2
-
3
2
  extension_name = 'pcaprub'
4
- have_library("pcap", "pcap_open_live")
3
+
4
+ if /i386-mswin32/ =~ RUBY_PLATFORM
5
+ pcap_dir = with_config("pcap-dir", "C:\WpdPack")
6
+ pcap_includedir = with_config("pcap-includedir", pcap_dir + "\\include")
7
+ pcap_libdir = with_config("pcap-libdir", pcap_dir + "\\lib")
8
+
9
+ $CFLAGS = "-DWIN32 -I#{pcap_includedir}"
10
+ $LDFLAGS = "/link /LIBPATH:#{pcap_libdir}"
11
+ have_library("wpcap", "pcap_open_live")
12
+ have_library("wpcap", "pcap_setnonblock")
13
+ else
14
+ have_library("pcap", "pcap_open_live")
15
+ have_library("pcap", "pcap_setnonblock")
16
+ end
17
+
5
18
  dir_config(extension_name)
6
- #$CPPFLAGS += " -DRUBY_19" if RUBY_VERSION =~ /1.9/
7
19
  create_makefile(extension_name)
@@ -22,3 +22,27 @@ checked program was:
22
22
 
23
23
  --------------------
24
24
 
25
+ have_library: checking for pcap_setnonblock() in -lpcap... -------------------- yes
26
+
27
+ "cc -o conftest -I. -I/usr/local/lib/ruby/1.8/i386-freebsd7 -I. -O2 -fno-strict-aliasing -pipe -fPIC conftest.c -L. -L/usr/local/lib -Wl,-R/usr/local/lib -L. -rdynamic -lpcap -lruby18-static -lpcap -lpcap -lcrypt -lm -rpath=/usr/lib:/usr/local/lib -pthread -lc"
28
+ conftest.c: In function 't':
29
+ conftest.c:3: error: 'pcap_setnonblock' undeclared (first use in this function)
30
+ conftest.c:3: error: (Each undeclared identifier is reported only once
31
+ conftest.c:3: error: for each function it appears in.)
32
+ checked program was:
33
+ /* begin */
34
+ 1: /*top*/
35
+ 2: int main() { return 0; }
36
+ 3: int t() { void ((*volatile p)()); p = (void ((*)()))pcap_setnonblock; return 0; }
37
+ /* end */
38
+
39
+ "cc -o conftest -I. -I/usr/local/lib/ruby/1.8/i386-freebsd7 -I. -O2 -fno-strict-aliasing -pipe -fPIC conftest.c -L. -L/usr/local/lib -Wl,-R/usr/local/lib -L. -rdynamic -lpcap -lruby18-static -lpcap -lpcap -lcrypt -lm -rpath=/usr/lib:/usr/local/lib -pthread -lc"
40
+ checked program was:
41
+ /* begin */
42
+ 1: /*top*/
43
+ 2: int main() { return 0; }
44
+ 3: int t() { pcap_setnonblock(); return 0; }
45
+ /* end */
46
+
47
+ --------------------
48
+
@@ -3,8 +3,15 @@
3
3
 
4
4
  #include <pcap.h>
5
5
 
6
+ #if !defined(WIN32)
7
+ #include <netinet/in.h>
8
+ #include <arpa/inet.h>
9
+ #endif
10
+
6
11
  static VALUE rb_cPcap;
7
12
 
13
+ #define PCAPRUB_VERSION "0.8-dev"
14
+
8
15
  #define OFFLINE 1
9
16
  #define LIVE 2
10
17
 
@@ -14,6 +21,97 @@ typedef struct rbpcap {
14
21
  char type;
15
22
  } rbpcap_t;
16
23
 
24
+
25
+ typedef struct rbpcapjob {
26
+ struct pcap_pkthdr hdr;
27
+ char *pkt;
28
+ int wtf;
29
+ } rbpcapjob_t;
30
+
31
+ static VALUE
32
+ rbpcap_s_version(VALUE class)
33
+ {
34
+ return rb_str_new2(PCAPRUB_VERSION);
35
+ }
36
+
37
+
38
+ static VALUE
39
+ rbpcap_s_lookupdev(VALUE self)
40
+ {
41
+ char *dev = NULL;
42
+ char eb[PCAP_ERRBUF_SIZE];
43
+ VALUE ret_dev; /* device string to return */
44
+ #if defined(WIN32) /* pcap_lookupdev is broken on windows */
45
+ pcap_if_t *alldevs;
46
+ pcap_if_t *d;
47
+
48
+ /* Retrieve the device list from the local machine */
49
+ if (pcap_findalldevs(&alldevs,eb) == -1) {
50
+ rb_raise(rb_eRuntimeError,"%s",eb);
51
+ }
52
+
53
+ /* Find the first interface with an address and not loopback */
54
+ for(d = alldevs; d != NULL; d= d->next) {
55
+ if(d->name && d->addresses && !(d->flags & PCAP_IF_LOOPBACK)) {
56
+ dev=d->name;
57
+ break;
58
+ }
59
+ }
60
+
61
+ if (dev == NULL) {
62
+ rb_raise(rb_eRuntimeError,"%s","No valid interfaces found, Make sure WinPcap is installed.\n");
63
+ }
64
+ ret_dev = rb_str_new2(dev);
65
+ /* We don't need any more the device list. Free it */
66
+ pcap_freealldevs(alldevs);
67
+ #else
68
+ dev = pcap_lookupdev(eb);
69
+ if (dev == NULL) {
70
+ rb_raise(rb_eRuntimeError, "%s", eb);
71
+ }
72
+ ret_dev = rb_str_new2(dev);
73
+ #endif
74
+ return ret_dev;
75
+ }
76
+
77
+ static VALUE
78
+ rbpcap_s_lookupnet(VALUE self, VALUE dev)
79
+ {
80
+ bpf_u_int32 net, mask, m;
81
+ struct in_addr addr;
82
+ char eb[PCAP_ERRBUF_SIZE];
83
+ VALUE list;
84
+
85
+ Check_Type(dev, T_STRING);
86
+ if (pcap_lookupnet(STR2CSTR(dev), &net, &mask, eb) == -1) {
87
+ rb_raise(rb_eRuntimeError, "%s", eb);
88
+ }
89
+
90
+ addr.s_addr = net;
91
+ m = ntohl(mask);
92
+ list = rb_ary_new();
93
+ rb_ary_push(list, rb_str_new2((char *) inet_ntoa(addr)));
94
+ rb_ary_push(list, UINT2NUM(m));
95
+ return(list);
96
+ }
97
+
98
+
99
+ static int rbpcap_ready(rbpcap_t *rbp) {
100
+ if(! rbp->pd) {
101
+ rb_raise(rb_eArgError, "a device or pcap file must be opened first");
102
+ return 0;
103
+ }
104
+ return 1;
105
+ }
106
+
107
+ static void rbpcap_close(rbpcap_t *rbp) {
108
+ if (rbp->pd)
109
+ pcap_close(rbp->pd);
110
+
111
+ rbp->pd = NULL;
112
+ free(rbp);
113
+ }
114
+
17
115
  static VALUE
18
116
  rbpcap_new_s(VALUE class)
19
117
  {
@@ -21,101 +119,103 @@ rbpcap_new_s(VALUE class)
21
119
  rbpcap_t *rbp;
22
120
 
23
121
  // need to make destructor do a pcap_close later
24
- self = Data_Make_Struct(class, rbpcap_t, 0, free, rbp);
122
+ self = Data_Make_Struct(class, rbpcap_t, 0, rbpcap_close, rbp);
25
123
  rb_obj_call_init(self, 0, 0);
26
124
 
27
125
  memset(rbp, 0, sizeof(rbpcap_t));
28
-
126
+
29
127
  return self;
30
128
  }
31
129
 
32
130
  static VALUE
33
131
  rbpcap_setfilter(VALUE self, VALUE filter)
34
132
  {
35
- char eb[1024];
133
+ char eb[PCAP_ERRBUF_SIZE];
36
134
  rbpcap_t *rbp;
37
135
  u_int32_t mask = 0, netid = 0;
38
136
  struct bpf_program bpf;
39
137
 
40
138
  Data_Get_Struct(self, rbpcap_t, rbp);
41
139
 
42
- if(TYPE(filter) != T_STRING)
43
- rb_raise(rb_eArgError, "filter must be a string");
140
+ if(TYPE(filter) != T_STRING)
141
+ rb_raise(rb_eArgError, "filter must be a string");
44
142
 
143
+ if(! rbpcap_ready(rbp)) return self;
144
+
45
145
  if(rbp->type == LIVE)
46
- if(pcap_lookupnet(rbp->iface, &netid, &mask, eb) < 0)
47
- rb_raise(rb_eRuntimeError, "%s", eb);
146
+ if(pcap_lookupnet(rbp->iface, &netid, &mask, eb) < 0)
147
+ rb_raise(rb_eRuntimeError, "%s", eb);
48
148
 
49
149
  if(pcap_compile(rbp->pd, &bpf, RSTRING(filter)->ptr, 0, mask) < 0)
50
- rb_raise(rb_eRuntimeError, "invalid bpf filter");
150
+ rb_raise(rb_eRuntimeError, "invalid bpf filter");
51
151
 
52
152
  if(pcap_setfilter(rbp->pd, &bpf) < 0)
53
- rb_raise(rb_eRuntimeError, "unable to set bpf filter");
153
+ rb_raise(rb_eRuntimeError, "unable to set bpf filter");
54
154
 
55
155
  return self;
56
156
  }
57
157
 
158
+
58
159
  static VALUE
59
- rbpcap_open_live(VALUE self, VALUE interface, VALUE snaplen, VALUE promisc, VALUE timeout)
160
+ rbpcap_open_live(VALUE self, VALUE iface,VALUE snaplen,VALUE promisc, VALUE timeout)
60
161
  {
61
- char eb[1024];
162
+ char eb[PCAP_ERRBUF_SIZE];
62
163
  rbpcap_t *rbp;
63
164
  int promisc_value = 0;
64
165
 
65
- if(TYPE(interface) != T_STRING)
66
- rb_raise(rb_eArgError, "interface must be a string");
67
- if(TYPE(snaplen) != T_FIXNUM)
68
- rb_raise(rb_eArgError, "snaplen must be a fixnum");
69
- if(TYPE(timeout) != T_FIXNUM)
70
- rb_raise(rb_eArgError, "timeout must be a fixnum");
166
+ if(TYPE(iface) != T_STRING)
167
+ rb_raise(rb_eArgError, "interface must be a string");
168
+ if(TYPE(snaplen) != T_FIXNUM)
169
+ rb_raise(rb_eArgError, "snaplen must be a fixnum");
170
+ if(TYPE(timeout) != T_FIXNUM)
171
+ rb_raise(rb_eArgError, "timeout must be a fixnum");
71
172
 
72
173
  switch(promisc) {
73
- case Qtrue:
74
- promisc_value = 1;
75
- break;
76
- case Qfalse:
77
- promisc_value = 0;
78
- break;
79
- default:
80
- rb_raise(rb_eTypeError, "Argument not boolean");
174
+ case Qtrue:
175
+ promisc_value = 1;
176
+ break;
177
+ case Qfalse:
178
+ promisc_value = 0;
179
+ break;
180
+ default:
181
+ rb_raise(rb_eTypeError, "Argument not boolean");
81
182
  }
82
183
 
83
184
  Data_Get_Struct(self, rbpcap_t, rbp);
84
185
 
85
186
  rbp->type = LIVE;
86
187
  memset(rbp->iface, 0, sizeof(rbp->iface));
87
- strncpy(rbp->iface, RSTRING(interface)->ptr, sizeof(rbp->iface) - 1);
188
+ strncpy(rbp->iface, RSTRING(iface)->ptr, sizeof(rbp->iface) - 1);
88
189
 
89
190
  rbp->pd = pcap_open_live(
90
- RSTRING(interface)->ptr,
91
- NUM2INT(snaplen),
92
- promisc_value,
93
- NUM2INT(timeout),
94
- eb
191
+ RSTRING(iface)->ptr,
192
+ NUM2INT(snaplen),
193
+ promisc_value,
194
+ NUM2INT(timeout),
195
+ eb
95
196
  );
96
197
 
97
198
  if(!rbp->pd)
98
- rb_raise(rb_eRuntimeError, "%s", eb);
199
+ rb_raise(rb_eRuntimeError, "%s", eb);
99
200
 
100
201
  return self;
101
202
  }
102
203
 
103
204
  static VALUE
104
- rbpcap_open_live_s(VALUE class, VALUE interface, VALUE snaplen, VALUE promisc, VALUE timeout)
205
+ rbpcap_open_live_s(VALUE class, VALUE iface, VALUE snaplen, VALUE promisc, VALUE timeout)
105
206
  {
106
207
  VALUE iPcap = rb_funcall(rb_cPcap, rb_intern("new"), 0);
107
-
108
- return rbpcap_open_live(iPcap, interface, snaplen, promisc, timeout);
208
+ return rbpcap_open_live(iPcap, iface, snaplen, promisc, timeout);
109
209
  }
110
210
 
111
211
  static VALUE
112
212
  rbpcap_open_offline(VALUE self, VALUE filename)
113
213
  {
114
- char eb[1024];
214
+ char eb[PCAP_ERRBUF_SIZE];
115
215
  rbpcap_t *rbp;
116
216
 
117
- if(TYPE(filename) != T_STRING)
118
- rb_raise(rb_eArgError, "filename must be a string");
217
+ if(TYPE(filename) != T_STRING)
218
+ rb_raise(rb_eArgError, "filename must be a string");
119
219
 
120
220
  Data_Get_Struct(self, rbpcap_t, rbp);
121
221
 
@@ -123,12 +223,12 @@ rbpcap_open_offline(VALUE self, VALUE filename)
123
223
  rbp->type = OFFLINE;
124
224
 
125
225
  rbp->pd = pcap_open_offline(
126
- RSTRING(filename)->ptr,
127
- eb
226
+ RSTRING(filename)->ptr,
227
+ eb
128
228
  );
129
229
 
130
230
  if(!rbp->pd)
131
- rb_raise(rb_eRuntimeError, "%s", eb);
231
+ rb_raise(rb_eRuntimeError, "%s", eb);
132
232
 
133
233
  return self;
134
234
  }
@@ -147,32 +247,56 @@ rbpcap_inject(VALUE self, VALUE payload)
147
247
  {
148
248
  rbpcap_t *rbp;
149
249
 
150
- if(TYPE(payload) != T_STRING)
151
- rb_raise(rb_eArgError, "payload must be a string");
250
+ if(TYPE(payload) != T_STRING)
251
+ rb_raise(rb_eArgError, "payload must be a string");
152
252
 
153
253
  Data_Get_Struct(self, rbpcap_t, rbp);
154
254
 
255
+ if(! rbpcap_ready(rbp)) return self;
256
+ #if defined(WIN32)
257
+ /* WinPcap does not have a pcap_inject call we use pcap_sendpacket, if it suceedes
258
+ * we simply return the amount of packets request to inject, else we fail.
259
+ */
260
+ if(pcap_sendpacket(rbp->pd, RSTRING(payload)->ptr, RSTRING(payload)->len) != 0) {
261
+ rb_raise(rb_eRuntimeError, "%s", pcap_geterr(rbp->pd));
262
+ }
263
+ return INT2NUM(RSTRING(payload)->len);
264
+ #else
155
265
  return INT2NUM(pcap_inject(rbp->pd, RSTRING(payload)->ptr, RSTRING(payload)->len));
266
+ #endif
267
+ }
268
+
269
+
270
+ static void rbpcap_handler(rbpcapjob_t *job, struct pcap_pkthdr *hdr, u_char *pkt){
271
+ job->pkt = pkt;
272
+ job->hdr = *hdr;
156
273
  }
157
274
 
158
275
  static VALUE
159
276
  rbpcap_next(VALUE self)
160
277
  {
161
- int ret;
162
- char *pkt;
163
278
  rbpcap_t *rbp;
164
- struct pcap_pkthdr pkthdr;
165
-
279
+ rbpcapjob_t job;
280
+ char eb[PCAP_ERRBUF_SIZE];
281
+ int ret;
282
+
166
283
  Data_Get_Struct(self, rbpcap_t, rbp);
167
-
168
- memset(&pkthdr, 0, sizeof(pkthdr));
284
+ if(! rbpcap_ready(rbp)) return self;
285
+ pcap_setnonblock(rbp->pd, 1, eb);
169
286
 
170
287
  TRAP_BEG;
171
- pkt = (char *)pcap_next(rbp->pd, &pkthdr);
288
+
289
+ while(! (ret = pcap_dispatch(rbp->pd, 1, (pcap_handler) rbpcap_handler, (u_char *)&job))) {
290
+ if(rbp->type == OFFLINE) break;
291
+ rb_thread_schedule();
292
+ }
293
+
172
294
  TRAP_END;
173
295
 
174
- if(pkthdr.caplen > 0)
175
- return rb_str_new(pkt, pkthdr.caplen);
296
+ if(rbp->type = OFFLINE && ret <= 0) return Qnil;
297
+
298
+ if(job.hdr.caplen > 0)
299
+ return rb_str_new(job.pkt, job.hdr.caplen);
176
300
 
177
301
  return Qnil;
178
302
  }
@@ -180,22 +304,21 @@ rbpcap_next(VALUE self)
180
304
  static VALUE
181
305
  rbpcap_capture(VALUE self)
182
306
  {
183
- int ret;
184
- char *pkt;
185
307
  rbpcap_t *rbp;
186
- struct pcap_pkthdr pkthdr;
187
308
 
188
309
  Data_Get_Struct(self, rbpcap_t, rbp);
189
310
 
311
+ if(! rbpcap_ready(rbp)) return self;
312
+
190
313
  for(;;) {
191
314
 
192
- VALUE packet = rbpcap_next(self);
315
+ VALUE packet = rbpcap_next(self);
193
316
 
194
- if(packet == Qnil && rbp->type == OFFLINE)
195
- break;
317
+ if(packet == Qnil && rbp->type == OFFLINE)
318
+ break;
196
319
 
197
- if(packet != Qnil)
198
- rb_yield(packet);
320
+ if(packet != Qnil)
321
+ rb_yield(packet);
199
322
  }
200
323
 
201
324
  return self;
@@ -208,16 +331,54 @@ rbpcap_datalink(VALUE self)
208
331
  rbpcap_t *rbp;
209
332
 
210
333
  Data_Get_Struct(self, rbpcap_t, rbp);
211
-
334
+
335
+ if(! rbpcap_ready(rbp)) return self;
336
+
212
337
  return INT2NUM(pcap_datalink(rbp->pd));
213
338
  }
214
339
 
340
+ static VALUE
341
+ rbpcap_snapshot(VALUE self)
342
+ {
343
+ rbpcap_t *rbp;
344
+
345
+ Data_Get_Struct(self, rbpcap_t, rbp);
346
+
347
+ if(! rbpcap_ready(rbp)) return self;
348
+
349
+ return INT2NUM(pcap_snapshot(rbp->pd));
350
+ }
351
+
352
+ static VALUE
353
+ rbpcap_stats(VALUE self)
354
+ {
355
+ rbpcap_t *rbp;
356
+ struct pcap_stat stat;
357
+ VALUE hash;
358
+
359
+ Data_Get_Struct(self, rbpcap_t, rbp);
360
+
361
+ if(! rbpcap_ready(rbp)) return self;
362
+
363
+ if (pcap_stats(rbp->pd, &stat) == -1)
364
+ return Qnil;
365
+
366
+ hash = rb_hash_new();
367
+ rb_hash_aset(hash, rb_str_new2("recv"), UINT2NUM(stat.ps_recv));
368
+ rb_hash_aset(hash, rb_str_new2("drop"), UINT2NUM(stat.ps_drop));
369
+ rb_hash_aset(hash, rb_str_new2("idrop"), UINT2NUM(stat.ps_ifdrop));
370
+ return hash;
371
+ }
372
+
215
373
  void
216
374
  Init_pcaprub()
217
375
  {
218
376
  // Pcap
219
377
  rb_cPcap = rb_define_class("Pcap", rb_cObject);
220
-
378
+ rb_define_module_function(rb_cPcap, "version", rbpcap_s_version, 0);
379
+ rb_define_module_function(rb_cPcap, "lookupdev", rbpcap_s_lookupdev, 0);
380
+ rb_define_module_function(rb_cPcap, "lookupnet", rbpcap_s_lookupnet, 1);
381
+
221
382
  rb_define_const(rb_cPcap, "DLT_NULL", INT2NUM(DLT_NULL));
222
383
  rb_define_const(rb_cPcap, "DLT_EN10MB", INT2NUM(DLT_EN10MB));
223
384
  rb_define_const(rb_cPcap, "DLT_EN3MB", INT2NUM(DLT_EN3MB));
@@ -230,7 +391,15 @@ Init_pcaprub()
230
391
  rb_define_const(rb_cPcap, "DLT_PPP", INT2NUM(DLT_PPP));
231
392
  rb_define_const(rb_cPcap, "DLT_FDDI", INT2NUM(DLT_FDDI));
232
393
  rb_define_const(rb_cPcap, "DLT_ATM_RFC1483", INT2NUM(DLT_ATM_RFC1483));
233
-
394
+ rb_define_const(rb_cPcap, "DLT_RAW", INT2NUM(DLT_RAW));
395
+ rb_define_const(rb_cPcap, "DLT_SLIP_BSDOS", INT2NUM(DLT_SLIP_BSDOS));
396
+ rb_define_const(rb_cPcap, "DLT_PPP_BSDOS", INT2NUM(DLT_PPP_BSDOS));
397
+ rb_define_const(rb_cPcap, "DLT_IEEE802_11", INT2NUM(DLT_IEEE802_11));
398
+ rb_define_const(rb_cPcap, "DLT_IEEE802_11_RADIO", INT2NUM(DLT_IEEE802_11_RADIO));
399
+ rb_define_const(rb_cPcap, "DLT_IEEE802_11_RADIO_AVS", INT2NUM(DLT_IEEE802_11_RADIO_AVS));
400
+ rb_define_const(rb_cPcap, "DLT_LINUX_SLL", INT2NUM(DLT_LINUX_SLL));
401
+ rb_define_const(rb_cPcap, "DLT_PRISM_HEADER", INT2NUM(DLT_PRISM_HEADER));
402
+ rb_define_const(rb_cPcap, "DLT_AIRONET_HEADER", INT2NUM(DLT_AIRONET_HEADER));
234
403
 
235
404
  rb_define_singleton_method(rb_cPcap, "new", rbpcap_new_s, 0);
236
405
 
@@ -242,5 +411,9 @@ Init_pcaprub()
242
411
  rb_define_method(rb_cPcap, "setfilter", rbpcap_setfilter, 1);
243
412
  rb_define_method(rb_cPcap, "inject", rbpcap_inject, 1);
244
413
  rb_define_method(rb_cPcap, "datalink", rbpcap_datalink, 0);
245
-
414
+
415
+ rb_define_method(rb_cPcap, "snapshot", rbpcap_snapshot, 0);
416
+ rb_define_method(rb_cPcap, "snaplen", rbpcap_snapshot, 0);
417
+ rb_define_method(rb_cPcap, "stats", rbpcap_stats, 0);
246
418
  }
419
+
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{pcaprub}
8
- s.version = "0.6.2"
8
+ s.version = "0.8.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["shadowbq"]
12
- s.date = %q{2010-02-06}
12
+ s.date = %q{2010-02-08}
13
13
  s.description = %q{libpcap bindings for ruby}
14
14
  s.email = %q{shadowbq@gmail.com}
15
15
  s.extensions = ["ext/pcaprub/extconf.rb"]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pcaprub
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - shadowbq
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-02-06 00:00:00 -05:00
12
+ date: 2010-02-08 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies: []
15
15