pcaprub 0.8.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,17 +10,31 @@ PacketRub project (http://packetrub.rubyforge.org).
10
10
  Requirements:
11
11
  libpcap - http://www.tcpdump.org
12
12
 
13
- == Other Repositories
13
+ == Installation
14
14
 
15
- The latest community svn version can be obtained from Subversion:
16
- svn checkout http://pcaprub.rubyforge.org/svn/trunk/
15
+ gem install pcaprub
17
16
 
18
- The Metasploit Project also provides a Subversion repository:
19
- svn checkout http://metasploit.com/svn/framework3/trunk/external/pcaprub/
20
17
 
21
- (credits: github.com/dxoigmn/pcaprub)
18
+ == Usage
19
+
20
+ require 'rubygems'
21
+ require 'pcaprub'
22
+
23
+ cap = Pcap.new
22
24
 
23
25
  == Current Repository for Gemcutter source
24
26
 
25
27
  The Git Repo on Github @shadowbq is forked from the Metasploit SVN repo
26
28
  git clone git://github.com/shadowbq/pcaprub.git
29
+
30
+
31
+ === Notes on other repositories
32
+
33
+ The latest community svn version can be obtained from Subversion:
34
+ svn checkout http://pcaprub.rubyforge.org/svn/trunk/
35
+
36
+ The Metasploit Project also provides a Subversion repository:
37
+ svn checkout http://metasploit.com/svn/framework3/trunk/external/pcaprub/
38
+
39
+ (credits: github.com/dxoigmn/pcaprub)
40
+
data/Rakefile CHANGED
@@ -80,5 +80,7 @@ Rake::RDocTask.new do |rdoc|
80
80
  rdoc.rdoc_dir = 'rdoc'
81
81
  rdoc.title = "pcaprub #{version}"
82
82
  rdoc.rdoc_files.include('README*')
83
+ rdoc.rdoc_files.include('LICENSE*')
83
84
  rdoc.rdoc_files.include('lib/**/*.rb')
85
+ rdoc.rdoc_files.include('ext/**/*.c')
84
86
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.8.1
1
+ 0.9.0
@@ -15,5 +15,12 @@ else
15
15
  have_library("pcap", "pcap_setnonblock")
16
16
  end
17
17
 
18
+ if ( RUBY_VERSION =~ /^1\.9/ )
19
+ $CFLAGS += " -DRUBY_19"
20
+ end
21
+
22
+
18
23
  dir_config(extension_name)
19
24
  create_makefile(extension_name)
25
+
26
+
@@ -1,5 +1,9 @@
1
1
  #include "ruby.h"
2
+
3
+ #ifndef RUBY_19
2
4
  #include "rubysig.h"
5
+ #endif
6
+
3
7
 
4
8
  #include <pcap.h>
5
9
 
@@ -8,15 +12,18 @@
8
12
  #include <arpa/inet.h>
9
13
  #endif
10
14
 
15
+ #include <sys/time.h>
16
+
11
17
  static VALUE rb_cPcap;
12
18
 
13
- #define PCAPRUB_VERSION "0.8-dev"
19
+ #define PCAPRUB_VERSION "0.9-dev"
14
20
 
15
21
  #define OFFLINE 1
16
22
  #define LIVE 2
17
23
 
18
24
  typedef struct rbpcap {
19
25
  pcap_t *pd;
26
+ pcap_dumper_t *pdt;
20
27
  char iface[256];
21
28
  char type;
22
29
  } rbpcap_t;
@@ -24,7 +31,7 @@ typedef struct rbpcap {
24
31
 
25
32
  typedef struct rbpcapjob {
26
33
  struct pcap_pkthdr hdr;
27
- char *pkt;
34
+ unsigned char *pkt;
28
35
  int wtf;
29
36
  } rbpcapjob_t;
30
37
 
@@ -68,7 +75,7 @@ rbpcap_s_lookupdev(VALUE self)
68
75
  dev = pcap_lookupdev(eb);
69
76
  if (dev == NULL) {
70
77
  rb_raise(rb_eRuntimeError, "%s", eb);
71
- }
78
+ }
72
79
  ret_dev = rb_str_new2(dev);
73
80
  #endif
74
81
  return ret_dev;
@@ -104,11 +111,15 @@ static int rbpcap_ready(rbpcap_t *rbp) {
104
111
  return 1;
105
112
  }
106
113
 
107
- static void rbpcap_close(rbpcap_t *rbp) {
114
+ static void rbpcap_free(rbpcap_t *rbp) {
108
115
  if (rbp->pd)
109
116
  pcap_close(rbp->pd);
117
+
118
+ if (rbp->pdt)
119
+ pcap_dump_close(rbp->pdt);
110
120
 
111
121
  rbp->pd = NULL;
122
+ rbp->pdt = NULL;
112
123
  free(rbp);
113
124
  }
114
125
 
@@ -119,7 +130,7 @@ rbpcap_new_s(VALUE class)
119
130
  rbpcap_t *rbp;
120
131
 
121
132
  // need to make destructor do a pcap_close later
122
- self = Data_Make_Struct(class, rbpcap_t, 0, rbpcap_close, rbp);
133
+ self = Data_Make_Struct(class, rbpcap_t, 0, rbpcap_free, rbp);
123
134
  rb_obj_call_init(self, 0, 0);
124
135
 
125
136
  memset(rbp, 0, sizeof(rbpcap_t));
@@ -146,7 +157,7 @@ rbpcap_setfilter(VALUE self, VALUE filter)
146
157
  if(pcap_lookupnet(rbp->iface, &netid, &mask, eb) < 0)
147
158
  rb_raise(rb_eRuntimeError, "%s", eb);
148
159
 
149
- if(pcap_compile(rbp->pd, &bpf, RSTRING(filter)->ptr, 0, mask) < 0)
160
+ if(pcap_compile(rbp->pd, &bpf, RSTRING_PTR(filter), 0, mask) < 0)
150
161
  rb_raise(rb_eRuntimeError, "invalid bpf filter");
151
162
 
152
163
  if(pcap_setfilter(rbp->pd, &bpf) < 0)
@@ -183,12 +194,18 @@ rbpcap_open_live(VALUE self, VALUE iface,VALUE snaplen,VALUE promisc, VALUE time
183
194
 
184
195
  Data_Get_Struct(self, rbpcap_t, rbp);
185
196
 
197
+
186
198
  rbp->type = LIVE;
187
199
  memset(rbp->iface, 0, sizeof(rbp->iface));
188
- strncpy(rbp->iface, RSTRING(iface)->ptr, sizeof(rbp->iface) - 1);
200
+ strncpy(rbp->iface, RSTRING_PTR(iface), sizeof(rbp->iface) - 1);
189
201
 
202
+
203
+ if(rbp->pd) {
204
+ pcap_close(rbp->pd);
205
+ }
206
+
190
207
  rbp->pd = pcap_open_live(
191
- RSTRING(iface)->ptr,
208
+ RSTRING_PTR(iface),
192
209
  NUM2INT(snaplen),
193
210
  promisc_value,
194
211
  NUM2INT(timeout),
@@ -223,7 +240,7 @@ rbpcap_open_offline(VALUE self, VALUE filename)
223
240
  rbp->type = OFFLINE;
224
241
 
225
242
  rbp->pd = pcap_open_offline(
226
- RSTRING(filename)->ptr,
243
+ RSTRING_PTR(filename),
227
244
  eb
228
245
  );
229
246
 
@@ -242,6 +259,85 @@ rbpcap_open_offline_s(VALUE class, VALUE filename)
242
259
  return rbpcap_open_offline(iPcap, filename);
243
260
  }
244
261
 
262
+ static VALUE
263
+ rbpcap_open_dead(VALUE self, VALUE linktype, VALUE snaplen)
264
+ {
265
+ rbpcap_t *rbp;
266
+
267
+
268
+ if(TYPE(linktype) != T_FIXNUM)
269
+ rb_raise(rb_eArgError, "linktype must be a fixnum");
270
+ if(TYPE(snaplen) != T_FIXNUM)
271
+ rb_raise(rb_eArgError, "snaplen must be a fixnum");
272
+
273
+ Data_Get_Struct(self, rbpcap_t, rbp);
274
+
275
+ memset(rbp->iface, 0, sizeof(rbp->iface));
276
+ rbp->type = OFFLINE;
277
+
278
+ rbp->pd = pcap_open_dead(
279
+ NUM2INT(linktype),
280
+ NUM2INT(snaplen)
281
+ );
282
+
283
+ return self;
284
+ }
285
+
286
+ static VALUE
287
+ rbpcap_open_dead_s(VALUE class, VALUE linktype, VALUE snaplen)
288
+ {
289
+ VALUE iPcap = rb_funcall(rb_cPcap, rb_intern("new"), 0);
290
+
291
+ return rbpcap_open_dead(iPcap, linktype, snaplen);
292
+ }
293
+
294
+
295
+ static VALUE
296
+ rbpcap_dump_open(VALUE self, VALUE filename)
297
+ {
298
+ rbpcap_t *rbp;
299
+
300
+ if(TYPE(filename) != T_STRING)
301
+ rb_raise(rb_eArgError, "filename must be a string");
302
+
303
+ Data_Get_Struct(self, rbpcap_t, rbp);
304
+ rbp->pdt = pcap_dump_open(
305
+ rbp->pd,
306
+ RSTRING_PTR(filename)
307
+ );
308
+
309
+ return self;
310
+ }
311
+
312
+ //not sure if this deviates too much from the way the rest of this class works?
313
+ static VALUE
314
+ rbpcap_dump(VALUE self, VALUE caplen, VALUE pktlen, VALUE packet)
315
+ {
316
+ rbpcap_t *rbp;
317
+ struct pcap_pkthdr pcap_hdr;
318
+
319
+ if(TYPE(packet) != T_STRING)
320
+ rb_raise(rb_eArgError, "packet data must be a string");
321
+ if(TYPE(caplen) != T_FIXNUM)
322
+ rb_raise(rb_eArgError, "caplen must be a fixnum");
323
+ if(TYPE(pktlen) != T_FIXNUM)
324
+ rb_raise(rb_eArgError, "pktlen must be a fixnum");
325
+
326
+ Data_Get_Struct(self, rbpcap_t, rbp);
327
+
328
+ gettimeofday(&pcap_hdr.ts, NULL);
329
+ pcap_hdr.caplen = NUM2UINT(caplen);
330
+ pcap_hdr.len = NUM2UINT(pktlen);
331
+
332
+ pcap_dump(
333
+ (u_char*)rbp->pdt,
334
+ &pcap_hdr,
335
+ (unsigned char *)RSTRING_PTR(packet)
336
+ );
337
+
338
+ return self;
339
+ }
340
+
245
341
  static VALUE
246
342
  rbpcap_inject(VALUE self, VALUE payload)
247
343
  {
@@ -257,68 +353,65 @@ rbpcap_inject(VALUE self, VALUE payload)
257
353
  /* WinPcap does not have a pcap_inject call we use pcap_sendpacket, if it suceedes
258
354
  * we simply return the amount of packets request to inject, else we fail.
259
355
  */
260
- if(pcap_sendpacket(rbp->pd, RSTRING(payload)->ptr, RSTRING(payload)->len) != 0) {
356
+ if(pcap_sendpacket(rbp->pd, RSTRING_PTR(payload), RSTRING_LEN(payload)) != 0) {
261
357
  rb_raise(rb_eRuntimeError, "%s", pcap_geterr(rbp->pd));
262
358
  }
263
- return INT2NUM(RSTRING(payload)->len);
359
+ return INT2NUM(RSTRING_LEN(payload));
264
360
  #else
265
- return INT2NUM(pcap_inject(rbp->pd, RSTRING(payload)->ptr, RSTRING(payload)->len));
361
+ return INT2NUM(pcap_inject(rbp->pd, RSTRING_PTR(payload), RSTRING_LEN(payload)));
266
362
  #endif
267
363
  }
268
364
 
269
365
 
270
366
  static void rbpcap_handler(rbpcapjob_t *job, struct pcap_pkthdr *hdr, u_char *pkt){
271
- job->pkt = pkt;
367
+ job->pkt = (unsigned char *)pkt;
272
368
  job->hdr = *hdr;
273
369
  }
274
370
 
275
371
  static VALUE
276
372
  rbpcap_next(VALUE self)
277
373
  {
278
- rbpcap_t *rbp;
374
+ rbpcap_t *rbp;
279
375
  rbpcapjob_t job;
280
376
  char eb[PCAP_ERRBUF_SIZE];
281
377
  int ret;
282
378
 
283
- Data_Get_Struct(self, rbpcap_t, rbp);
379
+ Data_Get_Struct(self, rbpcap_t, rbp);
284
380
  if(! rbpcap_ready(rbp)) return self;
285
381
  pcap_setnonblock(rbp->pd, 1, eb);
286
382
 
287
- TRAP_BEG;
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
-
294
- TRAP_END;
383
+ #ifndef RUBY_19
384
+ TRAP_BEG;
385
+ #endif
386
+ ret = pcap_dispatch(rbp->pd, 1, (pcap_handler) rbpcap_handler, (u_char *)&job);
387
+ #ifndef RUBY_19
388
+ TRAP_END;
389
+ #endif
295
390
 
296
- if(rbp->type = OFFLINE && ret <= 0) return Qnil;
391
+ if(rbp->type == OFFLINE && ret <= 0) return Qnil;
297
392
 
298
- if(job.hdr.caplen > 0)
299
- return rb_str_new(job.pkt, job.hdr.caplen);
393
+ if(ret > 0 && job.hdr.caplen > 0)
394
+ return rb_str_new((char *) job.pkt, job.hdr.caplen);
300
395
 
301
- return Qnil;
396
+ return Qnil;
302
397
  }
303
398
 
304
399
  static VALUE
305
400
  rbpcap_capture(VALUE self)
306
401
  {
307
402
  rbpcap_t *rbp;
308
-
403
+ int fno = -1;
404
+
309
405
  Data_Get_Struct(self, rbpcap_t, rbp);
310
406
 
311
407
  if(! rbpcap_ready(rbp)) return self;
312
408
 
313
- for(;;) {
409
+ fno = pcap_get_selectable_fd(rbp->pd);
314
410
 
411
+ for(;;) {
315
412
  VALUE packet = rbpcap_next(self);
316
-
317
- if(packet == Qnil && rbp->type == OFFLINE)
318
- break;
319
-
320
- if(packet != Qnil)
321
- rb_yield(packet);
413
+ if(packet == Qnil && rbp->type == OFFLINE) break;
414
+ packet == Qnil ? rb_thread_wait_fd(fno) : rb_yield(packet);
322
415
  }
323
416
 
324
417
  return self;
@@ -349,6 +442,7 @@ rbpcap_snapshot(VALUE self)
349
442
  return INT2NUM(pcap_snapshot(rbp->pd));
350
443
  }
351
444
 
445
+ //returns a hash
352
446
  static VALUE
353
447
  rbpcap_stats(VALUE self)
354
448
  {
@@ -373,10 +467,27 @@ rbpcap_stats(VALUE self)
373
467
  void
374
468
  Init_pcaprub()
375
469
  {
376
- // Pcap
470
+ /*
471
+ * Document-class: Pcap
472
+ *
473
+ * Main class defined by the pcaprub extension.
474
+ */
377
475
  rb_cPcap = rb_define_class("Pcap", rb_cObject);
476
+
477
+ /*
478
+ * Document-module-function: Version
479
+ * return the version of Pcaprub extension
480
+ */
378
481
  rb_define_module_function(rb_cPcap, "version", rbpcap_s_version, 0);
482
+
483
+ /*
484
+ * return the device id
485
+ */
379
486
  rb_define_module_function(rb_cPcap, "lookupdev", rbpcap_s_lookupdev, 0);
487
+
488
+ /*
489
+ * return the net
490
+ */
380
491
  rb_define_module_function(rb_cPcap, "lookupnet", rbpcap_s_lookupnet, 1);
381
492
 
382
493
  rb_define_const(rb_cPcap, "DLT_NULL", INT2NUM(DLT_NULL));
@@ -405,15 +516,52 @@ Init_pcaprub()
405
516
 
406
517
  rb_define_singleton_method(rb_cPcap, "open_live", rbpcap_open_live_s, 4);
407
518
  rb_define_singleton_method(rb_cPcap, "open_offline", rbpcap_open_offline_s, 1);
408
-
519
+ rb_define_singleton_method(rb_cPcap, "open_dead", rbpcap_open_dead_s, 2);
520
+ rb_define_singleton_method(rb_cPcap, "dump_open", rbpcap_dump_open, 1);
521
+
522
+
523
+ /*
524
+ * Document-method: dump
525
+ */
526
+ rb_define_method(rb_cPcap, "dump", rbpcap_dump, 3);
527
+
528
+ /*
529
+ * Document-method: each
530
+ */
409
531
  rb_define_method(rb_cPcap, "each", rbpcap_capture, 0);
532
+
533
+ /*
534
+ * Document-method: next
535
+ */
410
536
  rb_define_method(rb_cPcap, "next", rbpcap_next, 0);
537
+
538
+ /*
539
+ * Document-method: setfilter
540
+ */
411
541
  rb_define_method(rb_cPcap, "setfilter", rbpcap_setfilter, 1);
542
+
543
+ /*
544
+ * Document-method: inject
545
+ */
412
546
  rb_define_method(rb_cPcap, "inject", rbpcap_inject, 1);
547
+
548
+ /*
549
+ * Document-method: datalink
550
+ */
413
551
  rb_define_method(rb_cPcap, "datalink", rbpcap_datalink, 0);
414
552
 
553
+ /*
554
+ * Document-method: snapshot
555
+ */
415
556
  rb_define_method(rb_cPcap, "snapshot", rbpcap_snapshot, 0);
557
+
558
+ /*
559
+ * Document-method: snaplen
560
+ */
416
561
  rb_define_method(rb_cPcap, "snaplen", rbpcap_snapshot, 0);
562
+
563
+ /*
564
+ * Document-method: stats
565
+ */
417
566
  rb_define_method(rb_cPcap, "stats", rbpcap_stats, 0);
418
567
  }
419
-
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{pcaprub}
8
- s.version = "0.8.1"
8
+ s.version = "0.9.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"]
@@ -81,15 +81,24 @@ class Pcap::UnitTest < Test::Unit::TestCase
81
81
  end
82
82
 
83
83
  def test_pcap_next
84
- =begin
85
84
  d = Pcap.lookupdev
86
85
  o = Pcap.open_live(d, 1344, true, 1)
86
+
87
87
  @c = 0
88
- t = Thread.new { while(true); @c += 1; end; }
89
- x = o.next
88
+ t = Thread.new { while(true); @c += 1; select(nil, nil, nil, 0.10); end; }
89
+
90
+ require 'timeout'
91
+ begin
92
+ Timeout.timeout(10) do
93
+ o.each do |pkt|
94
+ end
95
+ end
96
+ rescue ::Timeout::Error
97
+ end
98
+
90
99
  t.kill
91
- =end
100
+ puts "Background thread ticked #{@c} times while capture was running"
92
101
  true
93
102
  end
94
103
 
95
- enD
104
+ end
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.8.1
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - shadowbq