pcaprub 0.10.0 → 0.11.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.
- data/README.rdoc +33 -6
- data/Rakefile +7 -6
- data/USAGE.rdoc +57 -3
- data/VERSION +1 -1
- data/examples/dead_cap.rb +12 -0
- data/examples/file_cap.rb +31 -0
- data/examples/simple_cap.rb +31 -0
- data/examples/telnet-raw.pcap +0 -0
- data/ext/pcaprub/extconf.rb +22 -1
- data/ext/pcaprub/pcaprub.c +668 -299
- data/lib/pcaprub.rb +9 -1
- data/lib/pcaprub/common.rb +17 -0
- data/lib/pcaprub/ext.rb +1 -0
- data/lib/pcaprub/version.rb +18 -0
- data/pcaprub.gemspec +9 -2
- metadata +9 -2
data/README.rdoc
CHANGED
@@ -3,9 +3,12 @@
|
|
3
3
|
This goal of this project is to provide a consistent interface
|
4
4
|
to LBL's libpcap packet capture library. This project was created
|
5
5
|
because the currently available ruby-pcap library is poorly designed
|
6
|
-
and has been unmaintained since 2000.
|
7
|
-
|
8
|
-
|
6
|
+
and has been unmaintained since 2000.
|
7
|
+
|
8
|
+
This does not provide packet processing functionality, it simply provides
|
9
|
+
the interface for capturing packets, and passing yielding those packets.
|
10
|
+
|
11
|
+
For true packet processing capability look at PCAPFU PCAPLET etc..
|
9
12
|
|
10
13
|
Requirements:
|
11
14
|
libpcap - http://www.tcpdump.org
|
@@ -14,19 +17,40 @@ Requirements:
|
|
14
17
|
|
15
18
|
gem install pcaprub
|
16
19
|
|
17
|
-
|
18
20
|
== Usage
|
19
21
|
|
20
22
|
require 'rubygems'
|
21
23
|
require 'pcaprub'
|
22
24
|
|
23
|
-
cap = Pcap.new
|
25
|
+
cap = PCAPRUB::Pcap.new
|
24
26
|
|
25
27
|
== Current Repository for Gemcutter source
|
26
28
|
|
27
29
|
The Git Repo on Github @shadowbq is forked from the Metasploit SVN repo
|
28
30
|
git clone git://github.com/shadowbq/pcaprub.git
|
29
31
|
|
32
|
+
== Notes on 11.x series and beyond.
|
33
|
+
|
34
|
+
The gem is now a module. The module is autoincluded, but this helps with name collisions and additional growth.
|
35
|
+
|
36
|
+
Some of the Error handling and basic intensive code is moving out the C base-extension (ext) and into native Ruby.
|
37
|
+
|
38
|
+
The file handling in dumper is now attached to the Capture Class and not the Module as an additional singleton.
|
39
|
+
|
40
|
+
capture = PCAPRUB::Pcap.open_live('eth0', SNAPLENGTH, true, 0)
|
41
|
+
capture.dump_open('./Example.pcap')
|
42
|
+
{ ... }
|
43
|
+
capture.dump_close
|
44
|
+
|
45
|
+
== Timstamps from the PCAP Header
|
46
|
+
|
47
|
+
Timestamps are now available when yeilding packets instead of strings
|
48
|
+
|
49
|
+
capture = PCAPRUB::Pcap.open_live('eth0', SNAPLENGTH, true, 0)
|
50
|
+
capture.each_packet do |packet|
|
51
|
+
puts Time.at(packet.time)
|
52
|
+
puts "micro => #{packet.microsec}"
|
53
|
+
end
|
30
54
|
|
31
55
|
=== Notes on other repositories
|
32
56
|
|
@@ -39,8 +63,11 @@ Packetfu Project also provides a listing (0.9-dev)
|
|
39
63
|
The Outdate RubyForge svn version can be obtained from Subversion: (0.7-dev)
|
40
64
|
svn checkout http://pcaprub.rubyforge.org/svn/trunk/
|
41
65
|
http download Public Rubyforge (0.6)
|
66
|
+
|
67
|
+
SourceForge Masaki Fukushima 2000 (0.6) -- Object Creation Heavy Implementation (PCAPLET integrated)
|
68
|
+
http://sourceforge.net/apps/trac/rubypcap/
|
42
69
|
|
43
70
|
Additonal Github Repos
|
44
71
|
github.com/dxoigmn/pcaprub (0.8-dev)
|
45
72
|
github.com/spox /pcaprub-spox (0.8-dev+)
|
46
|
-
|
73
|
+
|
data/Rakefile
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
3
|
require 'rake/clean'
|
4
|
+
require './lib/pcaprub/version'
|
4
5
|
|
5
6
|
desc "Build the extension:"
|
6
7
|
task :compile => %W[ext/pcaprub/Makefile ext/pcaprub/pcaprub.c]
|
@@ -43,8 +44,8 @@ rescue LoadError
|
|
43
44
|
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
44
45
|
end
|
45
46
|
|
46
|
-
require
|
47
|
-
|
47
|
+
require "rubygems/package_task"
|
48
|
+
Gem::PackageTask.new($gemspec) do |package|
|
48
49
|
package.need_zip = false
|
49
50
|
package.need_tar = false
|
50
51
|
end
|
@@ -74,10 +75,10 @@ task :test => :check_dependencies
|
|
74
75
|
|
75
76
|
task :default => %w[clean compile test]
|
76
77
|
|
77
|
-
require '
|
78
|
-
|
79
|
-
|
80
|
-
|
78
|
+
require 'rdoc/task'
|
79
|
+
RDoc::Task.new do |rdoc|
|
80
|
+
|
81
|
+
version = PCAPRUB::VERSION::STRING
|
81
82
|
rdoc.rdoc_dir = 'rdoc'
|
82
83
|
rdoc.title = "pcaprub #{version}"
|
83
84
|
rdoc.rdoc_files.include('README*')
|
data/USAGE.rdoc
CHANGED
@@ -11,12 +11,21 @@ Many of the methods require the Pcap instance to be "ready".
|
|
11
11
|
require "rubygems"
|
12
12
|
require "pcaprub"
|
13
13
|
|
14
|
-
mypcap = Pcap.new
|
14
|
+
mypcap = PCAPRUB::Pcap.new
|
15
|
+
|
16
|
+
== Backwards Compatibility
|
17
|
+
|
18
|
+
Pcaprub is included automatically upon load. This mixes in ::Pcap for backwards compatibility.
|
19
|
+
|
20
|
+
require "rubygems"
|
21
|
+
require "pcaprub"
|
22
|
+
|
23
|
+
mypcap = ::Pcap.new
|
15
24
|
|
16
25
|
|
17
26
|
== Setting up a live Capture
|
18
27
|
|
19
|
-
dev = ::Pcap.lookupdev
|
28
|
+
dev = PCAPRUB::Pcap.lookupdev
|
20
29
|
|
21
30
|
snaplength = 65535
|
22
31
|
promiscous_mode = true
|
@@ -81,6 +90,51 @@ Sniffing a set number of packets and also letting the user Interrupt Early
|
|
81
90
|
== Examining the DataLink
|
82
91
|
|
83
92
|
Ethernet or Linux loopback
|
84
|
-
if capture.datalink == Pcap::DLT_EN10MB
|
93
|
+
if capture.datalink == PCAPRUB::Pcap::DLT_EN10MB
|
85
94
|
puts "Ethernet 10MB Link detected"
|
86
95
|
end
|
96
|
+
|
97
|
+
== Examining Packet Internals
|
98
|
+
|
99
|
+
Sniffing and yielding Packet Objects using "each_packet"
|
100
|
+
|
101
|
+
require 'pcaprub'
|
102
|
+
SNAPLENGTH = 65535
|
103
|
+
capture = PCAPRUB::Pcap.open_live('wlan0', SNAPLENGTH, true, 0)
|
104
|
+
capture.setfilter('port 80')
|
105
|
+
|
106
|
+
capture_packets = 10
|
107
|
+
capture.each_packet do |packet|
|
108
|
+
puts packet.class
|
109
|
+
puts Time.at(packet.time)
|
110
|
+
puts "micro => #{packet.microsec}"
|
111
|
+
puts "Packet Length => #{packet.length}"
|
112
|
+
p packet.data
|
113
|
+
|
114
|
+
capture_packets -= 1
|
115
|
+
if capture_packets == 0
|
116
|
+
break
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
== Using the Packet Dump Capabilities
|
122
|
+
Write to file Example.pcap the first 10 packets on eth0.
|
123
|
+
|
124
|
+
require 'pcaprub'
|
125
|
+
SNAPLENGTH = 65535
|
126
|
+
capture = PCAPRUB::Pcap.open_live('eth0', SNAPLENGTH, true, 0)
|
127
|
+
dumper = capture.dump_open('./Example.pcap')
|
128
|
+
|
129
|
+
capture_packets = 10
|
130
|
+
capture.each do |packet|
|
131
|
+
capture.dump(packet.length, packet.length, packet)
|
132
|
+
capture_packets -= 1
|
133
|
+
if capture_packets == 0
|
134
|
+
break
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
capture.dump_close
|
139
|
+
|
140
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.11.0
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
3
|
+
#Example Output
|
4
|
+
#>> nohup sudo simple_cap.rb &
|
5
|
+
#>> ping www.google.com
|
6
|
+
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
7
|
+
#{"recv"=>0, "drop"=>0, "idrop"=>0}
|
8
|
+
#{"recv"=>0, "drop"=>0, "idrop"=>0}
|
9
|
+
#{"recv"=>0, "drop"=>0, "idrop"=>0}
|
10
|
+
#{"recv"=>2, "drop"=>0, "idrop"=>0}
|
11
|
+
#captured packet
|
12
|
+
#{"recv"=>4, "drop"=>0, "idrop"=>0}
|
13
|
+
#captured packet
|
14
|
+
#{"recv"=>6, "drop"=>0, "idrop"=>0}
|
15
|
+
#captured packet
|
16
|
+
#....^c
|
17
|
+
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
18
|
+
|
19
|
+
require 'rubygems'
|
20
|
+
require 'pcaprub'
|
21
|
+
require 'pp'
|
22
|
+
|
23
|
+
# Show me all SYN packets:
|
24
|
+
bpffilter = "tcp[13] & 2 != 0"
|
25
|
+
|
26
|
+
filename = './telnet-raw.pcap'
|
27
|
+
capture = PCAPRUB::Pcap.open_offline(filename)
|
28
|
+
puts "PCAP.h Version #{capture.pcap_major_version}.#{capture.pcap_minor_version}"
|
29
|
+
|
30
|
+
capture.setfilter(bpffilter)
|
31
|
+
pp capture
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
3
|
+
#Example Output
|
4
|
+
#>> nohup sudo simple_cap.rb &
|
5
|
+
#>> ping www.google.com
|
6
|
+
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
7
|
+
#{"recv"=>0, "drop"=>0, "idrop"=>0}
|
8
|
+
#{"recv"=>0, "drop"=>0, "idrop"=>0}
|
9
|
+
#{"recv"=>0, "drop"=>0, "idrop"=>0}
|
10
|
+
#{"recv"=>2, "drop"=>0, "idrop"=>0}
|
11
|
+
#captured packet
|
12
|
+
#{"recv"=>4, "drop"=>0, "idrop"=>0}
|
13
|
+
#captured packet
|
14
|
+
#{"recv"=>6, "drop"=>0, "idrop"=>0}
|
15
|
+
#captured packet
|
16
|
+
#....^c
|
17
|
+
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
18
|
+
|
19
|
+
require 'rubygems'
|
20
|
+
require 'pcaprub'
|
21
|
+
|
22
|
+
capture = PCAPRUB::Pcap.open_live('wlan0', 65535, true, 0)
|
23
|
+
capture.setfilter('icmp')
|
24
|
+
while 1==1
|
25
|
+
puts(capture.stats())
|
26
|
+
pkt = capture.next()
|
27
|
+
if pkt
|
28
|
+
puts "captured packet"
|
29
|
+
end
|
30
|
+
sleep(1)
|
31
|
+
end
|
Binary file
|
data/ext/pcaprub/extconf.rb
CHANGED
@@ -1,7 +1,28 @@
|
|
1
1
|
require 'mkmf'
|
2
2
|
extension_name = 'pcaprub'
|
3
3
|
|
4
|
-
|
4
|
+
puts "\n[*] Running checks for #{extension_name} code..."
|
5
|
+
puts("platform is #{RUBY_PLATFORM}")
|
6
|
+
|
7
|
+
if /i386-mingw32/ =~ RUBY_PLATFORM
|
8
|
+
|
9
|
+
unless have_library("ws2_32" ) and
|
10
|
+
have_library("iphlpapi") and
|
11
|
+
have_header("windows.h") and
|
12
|
+
have_header("winsock2.h") and
|
13
|
+
have_header("iphlpapi.h")
|
14
|
+
puts "\nNot all dependencies are satisfied for #{RUBY_PLATFORM} platform requirements"
|
15
|
+
exit
|
16
|
+
end
|
17
|
+
|
18
|
+
pcap_dir = with_config("pcap-dir", "C:/WpdPack")
|
19
|
+
pcap_includedir = with_config("pcap-includedir", pcap_dir + "/include")
|
20
|
+
pcap_libdir = with_config("pcap-libdir", pcap_dir + "/lib")
|
21
|
+
|
22
|
+
have_library("wpcap", "pcap_open_live")
|
23
|
+
have_library("wpcap", "pcap_setnonblock")
|
24
|
+
|
25
|
+
elsif /i386-mswin32/ =~ RUBY_PLATFORM
|
5
26
|
pcap_dir = with_config("pcap-dir", "C:\\WpdPack")
|
6
27
|
pcap_includedir = with_config("pcap-includedir", pcap_dir + "\\include")
|
7
28
|
pcap_libdir = with_config("pcap-libdir", pcap_dir + "\\lib")
|
data/ext/pcaprub/pcaprub.c
CHANGED
@@ -10,39 +10,37 @@
|
|
10
10
|
#if !defined(WIN32)
|
11
11
|
#include <netinet/in.h>
|
12
12
|
#include <arpa/inet.h>
|
13
|
+
#include <sys/time.h>
|
13
14
|
#endif
|
14
15
|
|
15
|
-
|
16
|
+
static VALUE mPCAP;
|
17
|
+
static VALUE rb_cPcap, rb_cPkt;
|
18
|
+
static VALUE ePCAPRUBError, eDumperError, eBindingError, eBPFilterError;
|
16
19
|
|
17
|
-
|
18
|
-
|
19
|
-
#define PCAPRUB_VERSION "0.9-dev"
|
20
|
+
// Now defined in Native Ruby
|
21
|
+
// #define PCAPRUB_VERSION "*.*.*"
|
20
22
|
|
21
23
|
#define OFFLINE 1
|
22
24
|
#define LIVE 2
|
23
25
|
|
24
26
|
typedef struct rbpcap {
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
pcap_t *pd;
|
28
|
+
pcap_dumper_t *pdt;
|
29
|
+
char iface[256];
|
30
|
+
char type;
|
29
31
|
} rbpcap_t;
|
30
32
|
|
31
33
|
|
32
34
|
typedef struct rbpcapjob {
|
33
35
|
struct pcap_pkthdr hdr;
|
34
|
-
|
36
|
+
unsigned char *pkt;
|
35
37
|
int wtf;
|
36
38
|
} rbpcapjob_t;
|
37
39
|
|
38
|
-
|
39
|
-
*
|
40
|
-
|
41
|
-
|
42
|
-
rbpcap_s_version(VALUE class)
|
43
|
-
{
|
44
|
-
return rb_str_new2(PCAPRUB_VERSION);
|
45
|
-
}
|
40
|
+
typedef struct rbpacket {
|
41
|
+
struct pcap_pkthdr* hdr;
|
42
|
+
u_char* pkt;
|
43
|
+
} rbpacket_t;
|
46
44
|
|
47
45
|
/*
|
48
46
|
* Return the name of a network device on the system.
|
@@ -52,40 +50,40 @@ rbpcap_s_version(VALUE class)
|
|
52
50
|
static VALUE
|
53
51
|
rbpcap_s_lookupdev(VALUE self)
|
54
52
|
{
|
55
|
-
|
56
|
-
|
57
|
-
|
53
|
+
char *dev = NULL;
|
54
|
+
char eb[PCAP_ERRBUF_SIZE];
|
55
|
+
VALUE ret_dev; /* device string to return */
|
58
56
|
#if defined(WIN32) /* pcap_lookupdev is broken on windows */
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
57
|
+
pcap_if_t *alldevs;
|
58
|
+
pcap_if_t *d;
|
59
|
+
|
60
|
+
/* Retrieve the device list from the local machine */
|
61
|
+
if (pcap_findalldevs(&alldevs,eb) == -1) {
|
62
|
+
rb_raise(eBindingError,"%s",eb);
|
63
|
+
}
|
64
|
+
|
65
|
+
/* Find the first interface with an address and not loopback */
|
66
|
+
for(d = alldevs; d != NULL; d= d->next) {
|
67
|
+
if(d->name && d->addresses && !(d->flags & PCAP_IF_LOOPBACK)) {
|
68
|
+
dev=d->name;
|
69
|
+
break;
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
if (dev == NULL) {
|
74
|
+
rb_raise(eBindingError,"%s","No valid interfaces found, Make sure WinPcap is installed.\n");
|
75
|
+
}
|
76
|
+
ret_dev = rb_str_new2(dev);
|
77
|
+
/* We don't need any more the device list. Free it */
|
78
|
+
pcap_freealldevs(alldevs);
|
81
79
|
#else
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
80
|
+
dev = pcap_lookupdev(eb);
|
81
|
+
if (dev == NULL) {
|
82
|
+
rb_raise(eBindingError, "%s", eb);
|
83
|
+
}
|
84
|
+
ret_dev = rb_str_new2(dev);
|
87
85
|
#endif
|
88
|
-
|
86
|
+
return ret_dev;
|
89
87
|
}
|
90
88
|
|
91
89
|
/*
|
@@ -94,33 +92,40 @@ rbpcap_s_lookupdev(VALUE self)
|
|
94
92
|
static VALUE
|
95
93
|
rbpcap_s_lookupnet(VALUE self, VALUE dev)
|
96
94
|
{
|
97
|
-
|
98
|
-
|
99
|
-
|
95
|
+
bpf_u_int32 net, mask, m;
|
96
|
+
struct in_addr addr;
|
97
|
+
char eb[PCAP_ERRBUF_SIZE];
|
100
98
|
VALUE list;
|
101
99
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
100
|
+
Check_Type(dev, T_STRING);
|
101
|
+
if (pcap_lookupnet(StringValuePtr(dev), &net, &mask, eb) == -1) {
|
102
|
+
rb_raise(rb_eRuntimeError, "%s", eb);
|
103
|
+
}
|
104
|
+
|
105
|
+
addr.s_addr = net;
|
106
|
+
m = ntohl(mask);
|
107
|
+
list = rb_ary_new();
|
110
108
|
rb_ary_push(list, rb_str_new2((char *) inet_ntoa(addr)));
|
111
109
|
rb_ary_push(list, UINT2NUM(m));
|
112
110
|
return(list);
|
113
111
|
}
|
114
112
|
|
115
|
-
|
113
|
+
/*
|
114
|
+
* Check if PCAP file or device is bound and loaded
|
115
|
+
*/
|
116
116
|
static int rbpcap_ready(rbpcap_t *rbp) {
|
117
117
|
if(! rbp->pd) {
|
118
|
-
rb_raise(
|
118
|
+
rb_raise(ePCAPRUBError, "a device or pcap file must be opened first");
|
119
119
|
return 0;
|
120
120
|
}
|
121
121
|
return 1;
|
122
122
|
}
|
123
123
|
|
124
|
+
|
125
|
+
|
126
|
+
/*
|
127
|
+
* Automated Garbage Collection for Pcap Class
|
128
|
+
*/
|
124
129
|
static void rbpcap_free(rbpcap_t *rbp) {
|
125
130
|
if (rbp->pd)
|
126
131
|
pcap_close(rbp->pd);
|
@@ -132,22 +137,58 @@ static void rbpcap_free(rbpcap_t *rbp) {
|
|
132
137
|
rbp->pdt = NULL;
|
133
138
|
free(rbp);
|
134
139
|
}
|
140
|
+
|
141
|
+
/*
|
142
|
+
* Automated Garbage Collection for Packet Class
|
143
|
+
*/
|
144
|
+
static void rbpacket_free(rbpacket_t *rbpacket)
|
145
|
+
{
|
146
|
+
|
147
|
+
if(rbpacket->hdr != NULL) {
|
148
|
+
rbpacket->hdr = NULL;
|
149
|
+
}
|
150
|
+
|
151
|
+
if(rbpacket->pkt != NULL) {
|
152
|
+
rbpacket->pkt = NULL;
|
153
|
+
}
|
154
|
+
|
155
|
+
free(rbpacket);
|
156
|
+
}
|
157
|
+
|
135
158
|
/*
|
136
159
|
* Creates a new Pcap instance and returns the object itself.
|
137
160
|
*/
|
138
161
|
static VALUE
|
139
162
|
rbpcap_new_s(VALUE class)
|
140
163
|
{
|
141
|
-
|
142
|
-
|
164
|
+
VALUE self;
|
165
|
+
rbpcap_t *rbp;
|
143
166
|
|
144
|
-
|
145
|
-
|
146
|
-
|
167
|
+
// need to make destructor do a pcap_close later
|
168
|
+
self = Data_Make_Struct(class, rbpcap_t, 0, rbpcap_free, rbp);
|
169
|
+
rb_obj_call_init(self, 0, 0);
|
147
170
|
|
148
|
-
|
149
|
-
|
150
|
-
|
171
|
+
memset(rbp, 0, sizeof(rbpcap_t));
|
172
|
+
|
173
|
+
return self;
|
174
|
+
}
|
175
|
+
|
176
|
+
/*
|
177
|
+
* Creates a new Packet instance and returns the object itself.
|
178
|
+
*/
|
179
|
+
static VALUE
|
180
|
+
rbpacket_new_s(VALUE class)
|
181
|
+
{
|
182
|
+
VALUE self;
|
183
|
+
rbpacket_t *rbpacket;
|
184
|
+
|
185
|
+
// need to make destructor do a pcap_close later
|
186
|
+
self = Data_Make_Struct(class, rbpacket_t, 0, rbpacket_free, rbpacket);
|
187
|
+
rb_obj_call_init(self, 0, 0);
|
188
|
+
|
189
|
+
memset(rbpacket, 0, sizeof(rbpacket_t));
|
190
|
+
|
191
|
+
return self;
|
151
192
|
}
|
152
193
|
|
153
194
|
/*
|
@@ -169,81 +210,81 @@ rbpcap_new_s(VALUE class)
|
|
169
210
|
static VALUE
|
170
211
|
rbpcap_setfilter(VALUE self, VALUE filter)
|
171
212
|
{
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
213
|
+
char eb[PCAP_ERRBUF_SIZE];
|
214
|
+
rbpcap_t *rbp;
|
215
|
+
u_int32_t mask = 0, netid = 0;
|
216
|
+
struct bpf_program bpf;
|
176
217
|
|
177
|
-
|
218
|
+
Data_Get_Struct(self, rbpcap_t, rbp);
|
178
219
|
|
179
|
-
|
180
|
-
|
220
|
+
if(TYPE(filter) != T_STRING)
|
221
|
+
rb_raise(eBPFilterError, "filter must be a string");
|
181
222
|
|
182
223
|
if(! rbpcap_ready(rbp)) return self;
|
183
224
|
|
184
|
-
|
185
|
-
|
186
|
-
|
225
|
+
if(rbp->type == LIVE)
|
226
|
+
if(pcap_lookupnet(rbp->iface, &netid, &mask, eb) < 0)
|
227
|
+
rb_raise(rb_eRuntimeError, "%s", eb);
|
187
228
|
|
188
|
-
|
189
|
-
|
229
|
+
if(pcap_compile(rbp->pd, &bpf, RSTRING_PTR(filter), 0, mask) < 0)
|
230
|
+
rb_raise(eBPFilterError, "invalid bpf filter");
|
190
231
|
|
191
|
-
|
192
|
-
|
232
|
+
if(pcap_setfilter(rbp->pd, &bpf) < 0)
|
233
|
+
rb_raise(eBPFilterError, "unable to set bpf filter");
|
193
234
|
|
194
|
-
|
235
|
+
return self;
|
195
236
|
}
|
196
237
|
|
197
238
|
// transparent method
|
198
239
|
static VALUE
|
199
240
|
rbpcap_open_live(VALUE self, VALUE iface,VALUE snaplen,VALUE promisc, VALUE timeout)
|
200
241
|
{
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
242
|
+
char eb[PCAP_ERRBUF_SIZE];
|
243
|
+
rbpcap_t *rbp;
|
244
|
+
int promisc_value = 0;
|
245
|
+
|
246
|
+
if(TYPE(iface) != T_STRING)
|
247
|
+
rb_raise(rb_eArgError, "interface must be a string");
|
248
|
+
if(TYPE(snaplen) != T_FIXNUM)
|
249
|
+
rb_raise(rb_eArgError, "snaplen must be a fixnum");
|
250
|
+
if(TYPE(timeout) != T_FIXNUM)
|
251
|
+
rb_raise(rb_eArgError, "timeout must be a fixnum");
|
252
|
+
|
253
|
+
switch(promisc) {
|
254
|
+
case Qtrue:
|
255
|
+
promisc_value = 1;
|
256
|
+
break;
|
257
|
+
case Qfalse:
|
258
|
+
promisc_value = 0;
|
259
|
+
break;
|
260
|
+
default:
|
261
|
+
rb_raise(ePCAPRUBError, "Promisc Argument not boolean");
|
262
|
+
}
|
263
|
+
|
264
|
+
Data_Get_Struct(self, rbpcap_t, rbp);
|
265
|
+
|
266
|
+
|
267
|
+
rbp->type = LIVE;
|
268
|
+
memset(rbp->iface, 0, sizeof(rbp->iface));
|
269
|
+
strncpy(rbp->iface, RSTRING_PTR(iface), sizeof(rbp->iface) - 1);
|
270
|
+
|
271
|
+
|
272
|
+
if(rbp->pd) {
|
273
|
+
pcap_close(rbp->pd);
|
274
|
+
}
|
275
|
+
|
276
|
+
rbp->pd = pcap_open_live(
|
277
|
+
RSTRING_PTR(iface),
|
278
|
+
NUM2INT(snaplen),
|
279
|
+
promisc_value,
|
280
|
+
NUM2INT(timeout),
|
281
|
+
eb
|
282
|
+
);
|
283
|
+
|
284
|
+
if(!rbp->pd)
|
285
|
+
rb_raise(rb_eRuntimeError, "%s", eb);
|
286
|
+
|
287
|
+
return self;
|
247
288
|
}
|
248
289
|
|
249
290
|
/*
|
@@ -258,34 +299,34 @@ rbpcap_open_live(VALUE self, VALUE iface,VALUE snaplen,VALUE promisc, VALUE time
|
|
258
299
|
static VALUE
|
259
300
|
rbpcap_open_live_s(VALUE class, VALUE iface, VALUE snaplen, VALUE promisc, VALUE timeout)
|
260
301
|
{
|
261
|
-
|
262
|
-
|
302
|
+
VALUE iPcap = rb_funcall(rb_cPcap, rb_intern("new"), 0);
|
303
|
+
return rbpcap_open_live(iPcap, iface, snaplen, promisc, timeout);
|
263
304
|
}
|
264
305
|
|
265
306
|
// transparent method
|
266
307
|
static VALUE
|
267
308
|
rbpcap_open_offline(VALUE self, VALUE filename)
|
268
309
|
{
|
269
|
-
|
270
|
-
|
310
|
+
char eb[PCAP_ERRBUF_SIZE];
|
311
|
+
rbpcap_t *rbp;
|
271
312
|
|
272
|
-
|
273
|
-
|
313
|
+
if(TYPE(filename) != T_STRING)
|
314
|
+
rb_raise(rb_eArgError, "filename must be a string");
|
274
315
|
|
275
|
-
|
316
|
+
Data_Get_Struct(self, rbpcap_t, rbp);
|
276
317
|
|
277
|
-
|
278
|
-
|
318
|
+
memset(rbp->iface, 0, sizeof(rbp->iface));
|
319
|
+
rbp->type = OFFLINE;
|
279
320
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
321
|
+
rbp->pd = pcap_open_offline(
|
322
|
+
RSTRING_PTR(filename),
|
323
|
+
eb
|
324
|
+
);
|
284
325
|
|
285
|
-
|
286
|
-
|
326
|
+
if(!rbp->pd)
|
327
|
+
rb_raise(rb_eRuntimeError, "%s", eb);
|
287
328
|
|
288
|
-
|
329
|
+
return self;
|
289
330
|
}
|
290
331
|
|
291
332
|
/*
|
@@ -300,36 +341,37 @@ rbpcap_open_offline(VALUE self, VALUE filename)
|
|
300
341
|
static VALUE
|
301
342
|
rbpcap_open_offline_s(VALUE class, VALUE filename)
|
302
343
|
{
|
303
|
-
|
344
|
+
VALUE iPcap = rb_funcall(rb_cPcap, rb_intern("new"), 0);
|
304
345
|
|
305
|
-
|
346
|
+
return rbpcap_open_offline(iPcap, filename);
|
306
347
|
}
|
307
348
|
|
308
349
|
// transparent method
|
309
350
|
static VALUE
|
310
351
|
rbpcap_open_dead(VALUE self, VALUE linktype, VALUE snaplen)
|
311
352
|
{
|
312
|
-
|
353
|
+
rbpcap_t *rbp;
|
313
354
|
|
314
355
|
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
356
|
+
if(TYPE(linktype) != T_FIXNUM)
|
357
|
+
rb_raise(rb_eArgError, "linktype must be a fixnum");
|
358
|
+
if(TYPE(snaplen) != T_FIXNUM)
|
359
|
+
rb_raise(rb_eArgError, "snaplen must be a fixnum");
|
319
360
|
|
320
|
-
|
361
|
+
Data_Get_Struct(self, rbpcap_t, rbp);
|
321
362
|
|
322
|
-
|
323
|
-
|
363
|
+
memset(rbp->iface, 0, sizeof(rbp->iface));
|
364
|
+
rbp->type = OFFLINE;
|
324
365
|
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
366
|
+
rbp->pd = pcap_open_dead(
|
367
|
+
NUM2INT(linktype),
|
368
|
+
NUM2INT(snaplen)
|
369
|
+
);
|
370
|
+
|
371
|
+
return self;
|
331
372
|
}
|
332
373
|
|
374
|
+
|
333
375
|
/*
|
334
376
|
*
|
335
377
|
* call-seq:
|
@@ -349,9 +391,9 @@ rbpcap_open_dead(VALUE self, VALUE linktype, VALUE snaplen)
|
|
349
391
|
static VALUE
|
350
392
|
rbpcap_open_dead_s(VALUE class, VALUE linktype, VALUE snaplen)
|
351
393
|
{
|
352
|
-
|
394
|
+
VALUE iPcap = rb_funcall(rb_cPcap, rb_intern("new"), 0);
|
353
395
|
|
354
|
-
|
396
|
+
return rbpcap_open_dead(iPcap, linktype, snaplen);
|
355
397
|
}
|
356
398
|
|
357
399
|
/*
|
@@ -363,18 +405,51 @@ rbpcap_open_dead_s(VALUE class, VALUE linktype, VALUE snaplen)
|
|
363
405
|
static VALUE
|
364
406
|
rbpcap_dump_open(VALUE self, VALUE filename)
|
365
407
|
{
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
408
|
+
rbpcap_t *rbp;
|
409
|
+
|
410
|
+
if(TYPE(filename) != T_STRING)
|
411
|
+
rb_raise(rb_eArgError, "filename must be a string");
|
412
|
+
|
413
|
+
Data_Get_Struct(self, rbpcap_t, rbp);
|
414
|
+
|
415
|
+
if(! rbpcap_ready(rbp)) return self;
|
416
|
+
|
417
|
+
rbp->pdt = pcap_dump_open(
|
418
|
+
rbp->pd,
|
419
|
+
RSTRING_PTR(filename)
|
420
|
+
);
|
421
|
+
|
422
|
+
if(!rbp->pdt)
|
423
|
+
rb_raise(eDumperError, "Stream could not be initialized or opened.");
|
424
|
+
|
425
|
+
return self;
|
426
|
+
}
|
370
427
|
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
428
|
+
/*
|
429
|
+
* call-seq:
|
430
|
+
* dump_close()
|
431
|
+
*
|
432
|
+
* dump_close() is called to manually close a "savefile"
|
433
|
+
*/
|
434
|
+
static VALUE
|
435
|
+
rbpcap_dump_close(VALUE self)
|
436
|
+
{
|
437
|
+
rbpcap_t *rbp;
|
438
|
+
|
439
|
+
Data_Get_Struct(self, rbpcap_t, rbp);
|
440
|
+
|
441
|
+
if(! rbpcap_ready(rbp)) return self;
|
442
|
+
|
443
|
+
if(!rbp->pdt)
|
444
|
+
rb_raise(eDumperError, "Stream is already closed.");
|
445
|
+
|
446
|
+
if (rbp->pdt)
|
447
|
+
pcap_dump_close(rbp->pdt);
|
448
|
+
|
449
|
+
rbp->pdt = NULL;
|
376
450
|
|
377
|
-
|
451
|
+
return self;
|
452
|
+
|
378
453
|
}
|
379
454
|
|
380
455
|
|
@@ -391,30 +466,36 @@ rbpcap_dump_open(VALUE self, VALUE filename)
|
|
391
466
|
static VALUE
|
392
467
|
rbpcap_dump(VALUE self, VALUE caplen, VALUE pktlen, VALUE packet)
|
393
468
|
{
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
469
|
+
rbpcap_t *rbp;
|
470
|
+
struct pcap_pkthdr pcap_hdr;
|
471
|
+
|
472
|
+
if(TYPE(packet) != T_STRING)
|
473
|
+
rb_raise(rb_eArgError, "packet data must be a string");
|
474
|
+
if(TYPE(caplen) != T_FIXNUM)
|
475
|
+
rb_raise(rb_eArgError, "caplen must be a fixnum");
|
476
|
+
if(TYPE(pktlen) != T_FIXNUM)
|
477
|
+
rb_raise(rb_eArgError, "pktlen must be a fixnum");
|
478
|
+
|
479
|
+
Data_Get_Struct(self, rbpcap_t, rbp);
|
480
|
+
|
481
|
+
gettimeofday(&pcap_hdr.ts, NULL);
|
482
|
+
pcap_hdr.caplen = NUM2UINT(caplen);
|
483
|
+
pcap_hdr.len = NUM2UINT(pktlen);
|
484
|
+
|
485
|
+
//capture.next is yeilding an 8Bit ASCII string
|
486
|
+
// -> return rb_str_new((char *) job.pkt, job.hdr.caplen);
|
487
|
+
//Call dump such that capture.next{|pk| capture.dump(pk.length, pk.length, pk)}
|
488
|
+
|
489
|
+
pcap_dump(
|
490
|
+
(u_char*)rbp->pdt,
|
491
|
+
&pcap_hdr,
|
492
|
+
(unsigned char *)RSTRING_PTR(packet)
|
493
|
+
);
|
494
|
+
|
495
|
+
return self;
|
496
|
+
}
|
403
497
|
|
404
|
-
Data_Get_Struct(self, rbpcap_t, rbp);
|
405
|
-
|
406
|
-
gettimeofday(&pcap_hdr.ts, NULL);
|
407
|
-
pcap_hdr.caplen = NUM2UINT(caplen);
|
408
|
-
pcap_hdr.len = NUM2UINT(pktlen);
|
409
498
|
|
410
|
-
pcap_dump(
|
411
|
-
(u_char*)rbp->pdt,
|
412
|
-
&pcap_hdr,
|
413
|
-
(unsigned char *)RSTRING_PTR(packet)
|
414
|
-
);
|
415
|
-
|
416
|
-
return self;
|
417
|
-
}
|
418
499
|
|
419
500
|
/*
|
420
501
|
* call-seq:
|
@@ -427,41 +508,49 @@ rbpcap_dump(VALUE self, VALUE caplen, VALUE pktlen, VALUE packet)
|
|
427
508
|
static VALUE
|
428
509
|
rbpcap_inject(VALUE self, VALUE payload)
|
429
510
|
{
|
430
|
-
|
511
|
+
rbpcap_t *rbp;
|
431
512
|
|
432
|
-
|
433
|
-
|
513
|
+
if(TYPE(payload) != T_STRING)
|
514
|
+
rb_raise(rb_eArgError, "payload must be a string");
|
434
515
|
|
435
|
-
|
516
|
+
Data_Get_Struct(self, rbpcap_t, rbp);
|
436
517
|
|
437
518
|
if(! rbpcap_ready(rbp)) return self;
|
438
519
|
#if defined(WIN32)
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
520
|
+
/* WinPcap does not have a pcap_inject call we use pcap_sendpacket, if it suceedes
|
521
|
+
* we simply return the amount of packets request to inject, else we fail.
|
522
|
+
*/
|
523
|
+
if(pcap_sendpacket(rbp->pd, RSTRING_PTR(payload), RSTRING_LEN(payload)) != 0) {
|
524
|
+
rb_raise(rb_eRuntimeError, "%s", pcap_geterr(rbp->pd));
|
525
|
+
}
|
526
|
+
return INT2NUM(RSTRING_LEN(payload));
|
446
527
|
#else
|
447
|
-
|
528
|
+
return INT2NUM(pcap_inject(rbp->pd, RSTRING_PTR(payload), RSTRING_LEN(payload)));
|
448
529
|
#endif
|
449
530
|
}
|
450
531
|
|
451
532
|
|
533
|
+
/*
|
534
|
+
*
|
535
|
+
* Packet Job Call back from pcap_dispatch
|
536
|
+
*
|
537
|
+
*/
|
538
|
+
|
452
539
|
static void rbpcap_handler(rbpcapjob_t *job, struct pcap_pkthdr *hdr, u_char *pkt){
|
453
540
|
job->pkt = (unsigned char *)pkt;
|
454
541
|
job->hdr = *hdr;
|
455
542
|
}
|
456
543
|
|
457
544
|
/*
|
458
|
-
|
545
|
+
**
|
459
546
|
* Returns the next packet from the packet capture device.
|
547
|
+
*
|
548
|
+
* Returns a string with the packet data.
|
460
549
|
*
|
461
|
-
* If the
|
550
|
+
* If the next_data() is unsuccessful, Null is returned.
|
462
551
|
*/
|
463
552
|
static VALUE
|
464
|
-
|
553
|
+
rbpcap_next_data(VALUE self)
|
465
554
|
{
|
466
555
|
rbpcap_t *rbp;
|
467
556
|
rbpcapjob_t job;
|
@@ -469,53 +558,147 @@ rbpcap_next(VALUE self)
|
|
469
558
|
int ret;
|
470
559
|
|
471
560
|
Data_Get_Struct(self, rbpcap_t, rbp);
|
561
|
+
|
472
562
|
if(! rbpcap_ready(rbp)) return self;
|
473
563
|
pcap_setnonblock(rbp->pd, 1, eb);
|
474
564
|
|
475
565
|
#ifdef MAKE_TRAP
|
476
566
|
TRAP_BEG;
|
477
567
|
#endif
|
568
|
+
|
569
|
+
// ret will contain the number of packets captured during the trap (ie one) since this is an iterator.
|
478
570
|
ret = pcap_dispatch(rbp->pd, 1, (pcap_handler) rbpcap_handler, (u_char *)&job);
|
571
|
+
|
479
572
|
#ifdef MAKE_TRAP
|
480
573
|
TRAP_END;
|
481
574
|
#endif
|
482
575
|
|
483
|
-
if(rbp->type == OFFLINE && ret <= 0)
|
576
|
+
if(rbp->type == OFFLINE && ret <= 0)
|
577
|
+
return Qnil;
|
484
578
|
|
485
579
|
if(ret > 0 && job.hdr.caplen > 0)
|
486
|
-
|
580
|
+
return rb_str_new((char *) job.pkt, job.hdr.caplen);
|
487
581
|
|
488
582
|
return Qnil;
|
489
583
|
}
|
490
584
|
|
585
|
+
|
586
|
+
/*
|
587
|
+
*
|
588
|
+
* Returns the next packet from the packet capture device.
|
589
|
+
*
|
590
|
+
* Returns a string with the packet data.
|
591
|
+
*
|
592
|
+
* If the next_packet() is unsuccessful, Null is returned.
|
593
|
+
*/
|
594
|
+
|
595
|
+
static VALUE
|
596
|
+
rbpcap_next_packet(VALUE self)
|
597
|
+
{
|
598
|
+
rbpcap_t *rbp;
|
599
|
+
rbpcapjob_t job;
|
600
|
+
char eb[PCAP_ERRBUF_SIZE];
|
601
|
+
int ret;
|
602
|
+
|
603
|
+
rbpacket_t* rbpacket;
|
604
|
+
|
605
|
+
Data_Get_Struct(self, rbpcap_t, rbp);
|
606
|
+
|
607
|
+
if(! rbpcap_ready(rbp)) return self;
|
608
|
+
|
609
|
+
pcap_setnonblock(rbp->pd, 1, eb);
|
610
|
+
|
611
|
+
#ifdef MAKE_TRAP
|
612
|
+
TRAP_BEG;
|
613
|
+
#endif
|
614
|
+
|
615
|
+
ret = pcap_dispatch(rbp->pd, 1, (pcap_handler) rbpcap_handler, (u_char *)&job);
|
616
|
+
|
617
|
+
#ifdef MAKE_TRAP
|
618
|
+
TRAP_END;
|
619
|
+
#endif
|
620
|
+
|
621
|
+
if(rbp->type == OFFLINE && ret <= 0)
|
622
|
+
return Qnil;
|
623
|
+
|
624
|
+
if(ret > 0 && job.hdr.caplen > 0)
|
625
|
+
{
|
626
|
+
rbpacket = ALLOC(rbpacket_t);
|
627
|
+
rbpacket->hdr = &job.hdr;
|
628
|
+
rbpacket->pkt = (u_char *)&job.pkt;
|
629
|
+
return Data_Wrap_Struct(rb_cPkt, 0, rbpacket_free, rbpacket);
|
630
|
+
}
|
631
|
+
|
632
|
+
return Qnil;
|
633
|
+
}
|
634
|
+
|
635
|
+
|
491
636
|
/*
|
492
637
|
* call-seq:
|
493
|
-
*
|
638
|
+
* each_data() { |packet| ... }
|
494
639
|
*
|
495
640
|
* Yields each packet from the capture to the passed-in block in turn.
|
496
641
|
*
|
497
642
|
*/
|
498
643
|
static VALUE
|
499
|
-
|
644
|
+
rbpcap_each_data(VALUE self)
|
500
645
|
{
|
501
|
-
|
646
|
+
rbpcap_t *rbp;
|
502
647
|
int fno = -1;
|
503
648
|
|
504
|
-
|
649
|
+
Data_Get_Struct(self, rbpcap_t, rbp);
|
505
650
|
|
506
651
|
if(! rbpcap_ready(rbp)) return self;
|
507
652
|
|
508
|
-
|
653
|
+
#if !defined(WIN32)
|
654
|
+
fno = pcap_get_selectable_fd(rbp->pd);
|
655
|
+
#else
|
656
|
+
fno = pcap_fileno(rbp->pd);
|
657
|
+
#endif
|
509
658
|
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
659
|
+
for(;;) {
|
660
|
+
VALUE packet = rbpcap_next_data(self);
|
661
|
+
if(packet == Qnil && rbp->type == OFFLINE) break;
|
662
|
+
packet == Qnil ? rb_thread_wait_fd(fno) : rb_yield(packet);
|
663
|
+
}
|
515
664
|
|
516
|
-
|
665
|
+
return self;
|
517
666
|
}
|
518
667
|
|
668
|
+
|
669
|
+
/*
|
670
|
+
* call-seq:
|
671
|
+
* each_packet() { |packet| ... }
|
672
|
+
*
|
673
|
+
* Yields a PCAP::Packet from the capture to the passed-in block in turn.
|
674
|
+
*
|
675
|
+
*/
|
676
|
+
static VALUE
|
677
|
+
rbpcap_each_packet(VALUE self)
|
678
|
+
{
|
679
|
+
rbpcap_t *rbp;
|
680
|
+
int fno = -1;
|
681
|
+
|
682
|
+
Data_Get_Struct(self, rbpcap_t, rbp);
|
683
|
+
|
684
|
+
if(! rbpcap_ready(rbp)) return self;
|
685
|
+
|
686
|
+
#if !defined(WIN32)
|
687
|
+
fno = pcap_get_selectable_fd(rbp->pd);
|
688
|
+
#else
|
689
|
+
fno = pcap_fileno(rbp->pd);
|
690
|
+
#endif
|
691
|
+
|
692
|
+
for(;;) {
|
693
|
+
VALUE packet = rbpcap_next_packet(self);
|
694
|
+
if(packet == Qnil && rbp->type == OFFLINE) break;
|
695
|
+
packet == Qnil ? rb_thread_wait_fd(fno) : rb_yield(packet);
|
696
|
+
}
|
697
|
+
|
698
|
+
return self;
|
699
|
+
}
|
700
|
+
|
701
|
+
|
519
702
|
/*
|
520
703
|
* call-seq:
|
521
704
|
* datalink()
|
@@ -527,13 +710,51 @@ rbpcap_capture(VALUE self)
|
|
527
710
|
static VALUE
|
528
711
|
rbpcap_datalink(VALUE self)
|
529
712
|
{
|
530
|
-
|
713
|
+
rbpcap_t *rbp;
|
714
|
+
|
715
|
+
Data_Get_Struct(self, rbpcap_t, rbp);
|
716
|
+
|
717
|
+
if(! rbpcap_ready(rbp)) return self;
|
718
|
+
|
719
|
+
return INT2NUM(pcap_datalink(rbp->pd));
|
720
|
+
}
|
721
|
+
|
722
|
+
/*
|
723
|
+
* call-seq:
|
724
|
+
* pcap_major_version()
|
725
|
+
*
|
726
|
+
* Returns the integer PCAP MAJOR LIBRARY value unless capture
|
727
|
+
*
|
728
|
+
*/
|
729
|
+
static VALUE
|
730
|
+
rbpcap_major_version(VALUE self)
|
731
|
+
{
|
732
|
+
rbpcap_t *rbp;
|
733
|
+
|
734
|
+
Data_Get_Struct(self, rbpcap_t, rbp);
|
735
|
+
|
736
|
+
if(! rbpcap_ready(rbp)) return self;
|
737
|
+
|
738
|
+
return INT2NUM(pcap_major_version(rbp->pd));
|
739
|
+
}
|
740
|
+
|
741
|
+
/*
|
742
|
+
* call-seq:
|
743
|
+
* pcap_minor_version()
|
744
|
+
*
|
745
|
+
* Returns the integer PCAP MINOR LIBRARY value unless capture
|
746
|
+
*
|
747
|
+
*/
|
748
|
+
static VALUE
|
749
|
+
rbpcap_minor_version(VALUE self)
|
750
|
+
{
|
751
|
+
rbpcap_t *rbp;
|
531
752
|
|
532
|
-
|
753
|
+
Data_Get_Struct(self, rbpcap_t, rbp);
|
533
754
|
|
534
755
|
if(! rbpcap_ready(rbp)) return self;
|
535
756
|
|
536
|
-
|
757
|
+
return INT2NUM(pcap_minor_version(rbp->pd));
|
537
758
|
}
|
538
759
|
|
539
760
|
/*
|
@@ -546,13 +767,13 @@ rbpcap_datalink(VALUE self)
|
|
546
767
|
static VALUE
|
547
768
|
rbpcap_snapshot(VALUE self)
|
548
769
|
{
|
549
|
-
|
770
|
+
rbpcap_t *rbp;
|
550
771
|
|
551
|
-
|
772
|
+
Data_Get_Struct(self, rbpcap_t, rbp);
|
552
773
|
|
553
774
|
if(! rbpcap_ready(rbp)) return self;
|
554
775
|
|
555
|
-
|
776
|
+
return INT2NUM(pcap_snapshot(rbp->pd));
|
556
777
|
}
|
557
778
|
|
558
779
|
/*
|
@@ -563,87 +784,235 @@ rbpcap_snapshot(VALUE self)
|
|
563
784
|
*
|
564
785
|
* - ["recv"] # number of packets received
|
565
786
|
* - ["drop"] # number of packets dropped
|
787
|
+
* - ["idrop"] # number of packets dropped by interface
|
566
788
|
*
|
567
789
|
*/
|
568
790
|
static VALUE
|
569
791
|
rbpcap_stats(VALUE self)
|
570
792
|
{
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
793
|
+
rbpcap_t *rbp;
|
794
|
+
struct pcap_stat stat;
|
795
|
+
VALUE hash;
|
796
|
+
|
797
|
+
Data_Get_Struct(self, rbpcap_t, rbp);
|
576
798
|
|
577
799
|
if(! rbpcap_ready(rbp)) return self;
|
578
800
|
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
801
|
+
if (pcap_stats(rbp->pd, &stat) == -1)
|
802
|
+
return Qnil;
|
803
|
+
|
804
|
+
hash = rb_hash_new();
|
805
|
+
rb_hash_aset(hash, rb_str_new2("recv"), UINT2NUM(stat.ps_recv));
|
806
|
+
rb_hash_aset(hash, rb_str_new2("drop"), UINT2NUM(stat.ps_drop));
|
807
|
+
rb_hash_aset(hash, rb_str_new2("idrop"), UINT2NUM(stat.ps_ifdrop));
|
808
|
+
// drops by interface XXX not yet supported under pcap.h 2.4
|
809
|
+
|
810
|
+
//#if defined(WIN32)
|
811
|
+
// rb_hash_aset(hash, rb_str_new2("bs_capt"), UINT2NUM(stat.bs_capt));
|
812
|
+
//#endif
|
813
|
+
|
814
|
+
return hash;
|
588
815
|
}
|
589
816
|
|
817
|
+
/*
|
818
|
+
*
|
819
|
+
* Returns the EPOCH integer from the ts.tv_sec record in the PCAP::Packet header
|
820
|
+
*
|
821
|
+
*/
|
822
|
+
static VALUE
|
823
|
+
rbpacket_time(VALUE self)
|
824
|
+
{
|
825
|
+
rbpacket_t* rbpacket;
|
826
|
+
Data_Get_Struct(self, rbpacket_t, rbpacket);
|
827
|
+
return INT2NUM(rbpacket->hdr->ts.tv_sec);
|
828
|
+
}
|
829
|
+
|
830
|
+
/*
|
831
|
+
*
|
832
|
+
* Returns the tv_usec integer from the ts.tv_usec record in the PCAP::Packet header
|
833
|
+
* timestamp microseconds
|
834
|
+
* the microseconds when this packet was captured, as an offset to ts_sec.
|
835
|
+
* Beware: this value shouldn't reach 1 second (1 000 000), in this case ts_sec must be increased instead!
|
836
|
+
*
|
837
|
+
* Ruby Microsecond Handling
|
838
|
+
* Time.at(946684800.2).usec #=> 200000
|
839
|
+
* Time.now.usec
|
840
|
+
*/
|
841
|
+
|
842
|
+
static VALUE
|
843
|
+
rbpacket_microsec(VALUE self)
|
844
|
+
{
|
845
|
+
rbpacket_t* rbpacket;
|
846
|
+
Data_Get_Struct(self, rbpacket_t, rbpacket);
|
847
|
+
return INT2NUM(rbpacket->hdr->ts.tv_usec);
|
848
|
+
}
|
849
|
+
|
850
|
+
|
851
|
+
/*
|
852
|
+
*
|
853
|
+
* Returns the integer length of packet length field from the in the PCAP::Packet header
|
854
|
+
*
|
855
|
+
*/
|
856
|
+
static VALUE
|
857
|
+
rbpacket_length(VALUE self)
|
858
|
+
{
|
859
|
+
rbpacket_t* rbpacket;
|
860
|
+
Data_Get_Struct(self, rbpacket_t, rbpacket);
|
861
|
+
return INT2NUM(rbpacket->hdr->len);
|
862
|
+
}
|
863
|
+
|
864
|
+
/*
|
865
|
+
*
|
866
|
+
* Returns the integer length of capture len from the in the PCAP::Packet header
|
867
|
+
*
|
868
|
+
*/
|
869
|
+
static VALUE
|
870
|
+
rbpacket_caplen(VALUE self)
|
871
|
+
{
|
872
|
+
rbpacket_t* rbpacket;
|
873
|
+
Data_Get_Struct(self, rbpacket_t, rbpacket);
|
874
|
+
return INT2NUM(rbpacket->hdr->caplen);
|
875
|
+
}
|
876
|
+
|
877
|
+
/*
|
878
|
+
*
|
879
|
+
* Returns the integer PCAP MINOR LIBRARY value unless capture
|
880
|
+
*
|
881
|
+
*/
|
882
|
+
static VALUE
|
883
|
+
rbpacket_data(VALUE self)
|
884
|
+
{
|
885
|
+
rbpacket_t* rbpacket;
|
886
|
+
Data_Get_Struct(self, rbpacket_t, rbpacket);
|
887
|
+
|
888
|
+
if(rbpacket->pkt == NULL)
|
889
|
+
return Qnil;
|
890
|
+
|
891
|
+
return rb_str_new((char *) rbpacket->pkt, rbpacket->hdr->caplen);
|
892
|
+
}
|
893
|
+
|
894
|
+
|
590
895
|
void
|
591
896
|
Init_pcaprub()
|
592
897
|
{
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
898
|
+
/*
|
899
|
+
* Document-class: Pcap
|
900
|
+
*
|
901
|
+
* Main class defined by the pcaprub extension.
|
902
|
+
*/
|
903
|
+
mPCAP = rb_define_module("PCAPRUB");
|
904
|
+
|
905
|
+
rb_cPcap = rb_define_class_under(mPCAP,"Pcap", rb_cObject);
|
906
|
+
rb_cPkt = rb_define_class_under(mPCAP,"Packet", rb_cObject);
|
907
|
+
|
908
|
+
ePCAPRUBError = rb_path2class("PCAPRUB::PCAPRUBError");
|
909
|
+
eBindingError = rb_path2class("PCAPRUB::BindingError");
|
910
|
+
eBPFilterError = rb_path2class("PCAPRUB::BPFError");
|
911
|
+
eDumperError = rb_path2class("PCAPRUB::DumperError");
|
912
|
+
|
913
|
+
rb_define_module_function(rb_cPcap, "lookupdev", rbpcap_s_lookupdev, 0);
|
914
|
+
rb_define_module_function(rb_cPcap, "lookupnet", rbpcap_s_lookupnet, 1);
|
915
|
+
|
916
|
+
rb_define_const(rb_cPcap, "DLT_NULL", INT2NUM(DLT_NULL));
|
917
|
+
rb_define_const(rb_cPcap, "DLT_EN10MB", INT2NUM(DLT_EN10MB));
|
918
|
+
rb_define_const(rb_cPcap, "DLT_EN3MB", INT2NUM(DLT_EN3MB));
|
919
|
+
rb_define_const(rb_cPcap, "DLT_AX25", INT2NUM(DLT_AX25));
|
920
|
+
rb_define_const(rb_cPcap, "DLT_PRONET", INT2NUM(DLT_PRONET));
|
921
|
+
rb_define_const(rb_cPcap, "DLT_CHAOS", INT2NUM(DLT_CHAOS));
|
922
|
+
rb_define_const(rb_cPcap, "DLT_IEEE802", INT2NUM(DLT_IEEE802));
|
923
|
+
rb_define_const(rb_cPcap, "DLT_ARCNET", INT2NUM(DLT_ARCNET));
|
924
|
+
rb_define_const(rb_cPcap, "DLT_SLIP", INT2NUM(DLT_SLIP));
|
925
|
+
rb_define_const(rb_cPcap, "DLT_PPP", INT2NUM(DLT_PPP));
|
926
|
+
rb_define_const(rb_cPcap, "DLT_FDDI", INT2NUM(DLT_FDDI));
|
927
|
+
rb_define_const(rb_cPcap, "DLT_ATM_RFC1483", INT2NUM(DLT_ATM_RFC1483));
|
928
|
+
rb_define_const(rb_cPcap, "DLT_RAW", INT2NUM(DLT_RAW));
|
929
|
+
rb_define_const(rb_cPcap, "DLT_SLIP_BSDOS", INT2NUM(DLT_SLIP_BSDOS));
|
930
|
+
rb_define_const(rb_cPcap, "DLT_PPP_BSDOS", INT2NUM(DLT_PPP_BSDOS));
|
931
|
+
rb_define_const(rb_cPcap, "DLT_IEEE802_11", INT2NUM(DLT_IEEE802_11));
|
932
|
+
rb_define_const(rb_cPcap, "DLT_IEEE802_11_RADIO", INT2NUM(DLT_IEEE802_11_RADIO));
|
933
|
+
rb_define_const(rb_cPcap, "DLT_IEEE802_11_RADIO_AVS", INT2NUM(DLT_IEEE802_11_RADIO_AVS));
|
934
|
+
rb_define_const(rb_cPcap, "DLT_LINUX_SLL", INT2NUM(DLT_LINUX_SLL));
|
935
|
+
rb_define_const(rb_cPcap, "DLT_PRISM_HEADER", INT2NUM(DLT_PRISM_HEADER));
|
936
|
+
rb_define_const(rb_cPcap, "DLT_AIRONET_HEADER", INT2NUM(DLT_AIRONET_HEADER));
|
937
|
+
/* Pcap Error Codes
|
938
|
+
* Error codes for the pcap API.
|
939
|
+
* These will all be negative, so you can check for the success or
|
940
|
+
* failure of a call that returns these codes by checking for a
|
941
|
+
* negative value.
|
942
|
+
*/
|
943
|
+
rb_define_const(rb_cPcap, "PCAP_ERROR", INT2NUM(PCAP_ERROR)); /* generic error code */
|
944
|
+
rb_define_const(rb_cPcap, "PCAP_ERROR_BREAK", INT2NUM(PCAP_ERROR_BREAK)); /* loop terminated by pcap_breakloop */
|
945
|
+
rb_define_const(rb_cPcap, "PCAP_ERROR_NOT_ACTIVATED", INT2NUM(PCAP_ERROR_NOT_ACTIVATED)); /* the capture needs to be activated */
|
946
|
+
rb_define_const(rb_cPcap, "PCAP_ERROR_ACTIVATED", INT2NUM(PCAP_ERROR_ACTIVATED)); /* the operation can't be performed on already activated captures */
|
947
|
+
rb_define_const(rb_cPcap, "PCAP_ERROR_NO_SUCH_DEVICE", INT2NUM(PCAP_ERROR_NO_SUCH_DEVICE)); /* no such device exists */
|
948
|
+
rb_define_const(rb_cPcap, "PCAP_ERROR_RFMON_NOTSUP", INT2NUM(PCAP_ERROR_RFMON_NOTSUP)); /* this device doesn't support rfmon (monitor) mode */
|
949
|
+
rb_define_const(rb_cPcap, "PCAP_ERROR_NOT_RFMON", INT2NUM(PCAP_ERROR_NOT_RFMON)); /* operation supported only in monitor mode */
|
950
|
+
rb_define_const(rb_cPcap, "PCAP_ERROR_PERM_DENIED", INT2NUM(PCAP_ERROR_PERM_DENIED)); /* no permission to open the device */
|
951
|
+
rb_define_const(rb_cPcap, "PCAP_ERROR_IFACE_NOT_UP", INT2NUM(PCAP_ERROR_IFACE_NOT_UP)); /* interface isn't up */
|
952
|
+
|
953
|
+
/*
|
954
|
+
* Warning codes for the pcap API.
|
955
|
+
* These will all be positive and non-zero, so they won't look like
|
956
|
+
* errors.
|
957
|
+
*/
|
958
|
+
rb_define_const(rb_cPcap, "PCAP_WARNING", INT2NUM(PCAP_WARNING)); /* generic warning code */
|
959
|
+
rb_define_const(rb_cPcap, "PCAP_WARNING_PROMISC_NOTSUP", INT2NUM(PCAP_WARNING_PROMISC_NOTSUP)); /* this device doesn't support promiscuous mode */
|
960
|
+
|
961
|
+
/*
|
962
|
+
* Value to pass to pcap_compile() as the netmask if you don't know what
|
963
|
+
* the netmask is.
|
964
|
+
*/
|
965
|
+
rb_define_const(rb_cPcap, "PCAP_NETMASK_UNKNOWN", INT2NUM(PCAP_NETMASK_UNKNOWN));
|
966
|
+
|
967
|
+
|
968
|
+
rb_define_singleton_method(rb_cPcap, "new", rbpcap_new_s, 0);
|
969
|
+
|
970
|
+
rb_define_singleton_method(rb_cPcap, "open_live", rbpcap_open_live_s, 4);
|
971
|
+
rb_define_singleton_method(rb_cPcap, "open_offline", rbpcap_open_offline_s, 1);
|
972
|
+
rb_define_singleton_method(rb_cPcap, "open_dead", rbpcap_open_dead_s, 2);
|
973
|
+
|
974
|
+
rb_define_method(rb_cPcap, "dump_open", rbpcap_dump_open, 1);
|
975
|
+
rb_define_method(rb_cPcap, "dump_close", rbpcap_dump_close, 0);
|
976
|
+
rb_define_method(rb_cPcap, "dump", rbpcap_dump, 3);
|
977
|
+
rb_define_method(rb_cPcap, "each_data", rbpcap_each_data, 0);
|
978
|
+
rb_define_method(rb_cPcap, "next_data", rbpcap_next_data, 0);
|
979
|
+
rb_define_method(rb_cPcap, "each_packet", rbpcap_each_packet, 0);
|
980
|
+
rb_define_method(rb_cPcap, "next_packet", rbpcap_next_packet, 0);
|
981
|
+
/*
|
982
|
+
* Document-method: each
|
983
|
+
* Alias of each_data
|
984
|
+
*/
|
985
|
+
rb_define_method(rb_cPcap, "each", rbpcap_each_data, 0);
|
986
|
+
/*
|
987
|
+
* Document-method: next
|
988
|
+
* Alias of next_data
|
989
|
+
*/
|
990
|
+
rb_define_method(rb_cPcap, "next", rbpcap_next_data, 0);
|
991
|
+
rb_define_method(rb_cPcap, "setfilter", rbpcap_setfilter, 1);
|
992
|
+
rb_define_method(rb_cPcap, "inject", rbpcap_inject, 1);
|
993
|
+
rb_define_method(rb_cPcap, "datalink", rbpcap_datalink, 0);
|
994
|
+
rb_define_method(rb_cPcap, "pcap_major_version", rbpcap_major_version, 0);
|
995
|
+
rb_define_method(rb_cPcap, "pcap_minor_version", rbpcap_minor_version, 0);
|
996
|
+
rb_define_method(rb_cPcap, "snapshot", rbpcap_snapshot, 0);
|
997
|
+
/*
|
998
|
+
* Document-method: snaplen
|
999
|
+
* Alias of snapshot
|
1000
|
+
*/
|
1001
|
+
rb_define_method(rb_cPcap, "snaplen", rbpcap_snapshot, 0);
|
1002
|
+
rb_define_method(rb_cPcap, "stats", rbpcap_stats, 0);
|
1003
|
+
|
1004
|
+
rb_define_singleton_method(rb_cPkt, "new", rbpacket_new_s, 0);
|
1005
|
+
|
1006
|
+
rb_define_method(rb_cPkt, "time", rbpacket_time, 0);
|
1007
|
+
rb_define_method(rb_cPkt, "microsec", rbpacket_microsec, 0);
|
1008
|
+
rb_define_method(rb_cPkt, "length", rbpacket_length, 0);
|
1009
|
+
rb_define_method(rb_cPkt, "caplen", rbpacket_caplen, 0);
|
1010
|
+
rb_define_method(rb_cPkt, "data", rbpacket_data, 0);
|
1011
|
+
/*
|
1012
|
+
* Document-method: to_s
|
1013
|
+
* Alias of data
|
1014
|
+
*/
|
1015
|
+
rb_define_method(rb_cPkt, "to_s", rbpacket_data, 0);
|
1016
|
+
|
642
1017
|
|
643
|
-
/*
|
644
|
-
* Document-method: snaplen
|
645
|
-
* Alias of snapshot
|
646
|
-
*/
|
647
|
-
rb_define_method(rb_cPcap, "snaplen", rbpcap_snapshot, 0);
|
648
|
-
rb_define_method(rb_cPcap, "stats", rbpcap_stats, 0);
|
649
1018
|
}
|