pcaprub 0.8.1 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +20 -6
- data/Rakefile +2 -0
- data/VERSION +1 -1
- data/ext/pcaprub/extconf.rb +7 -0
- data/ext/pcaprub/pcaprub.c +186 -38
- data/pcaprub.gemspec +1 -1
- data/test/test_pcaprub_unit.rb +14 -5
- metadata +1 -1
data/README.rdoc
CHANGED
@@ -10,17 +10,31 @@ PacketRub project (http://packetrub.rubyforge.org).
|
|
10
10
|
Requirements:
|
11
11
|
libpcap - http://www.tcpdump.org
|
12
12
|
|
13
|
-
==
|
13
|
+
== Installation
|
14
14
|
|
15
|
-
|
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
|
-
|
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
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.9.0
|
data/ext/pcaprub/extconf.rb
CHANGED
data/ext/pcaprub/pcaprub.c
CHANGED
@@ -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.
|
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
|
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,
|
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,
|
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,
|
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
|
-
|
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
|
-
|
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,
|
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(
|
359
|
+
return INT2NUM(RSTRING_LEN(payload));
|
264
360
|
#else
|
265
|
-
return INT2NUM(pcap_inject(rbp->pd,
|
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
|
-
|
374
|
+
rbpcap_t *rbp;
|
279
375
|
rbpcapjob_t job;
|
280
376
|
char eb[PCAP_ERRBUF_SIZE];
|
281
377
|
int ret;
|
282
378
|
|
283
|
-
|
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
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
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
|
391
|
+
if(rbp->type == OFFLINE && ret <= 0) return Qnil;
|
297
392
|
|
298
|
-
|
299
|
-
|
393
|
+
if(ret > 0 && job.hdr.caplen > 0)
|
394
|
+
return rb_str_new((char *) job.pkt, job.hdr.caplen);
|
300
395
|
|
301
|
-
|
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
|
-
|
409
|
+
fno = pcap_get_selectable_fd(rbp->pd);
|
314
410
|
|
411
|
+
for(;;) {
|
315
412
|
VALUE packet = rbpcap_next(self);
|
316
|
-
|
317
|
-
|
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
|
-
|
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
|
-
|
data/pcaprub.gemspec
CHANGED
data/test/test_pcaprub_unit.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
100
|
+
puts "Background thread ticked #{@c} times while capture was running"
|
92
101
|
true
|
93
102
|
end
|
94
103
|
|
95
|
-
|
104
|
+
end
|