pcaprub 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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. This does not provide packet
7
- processing functionality, it simply provides the interface for
8
- capturing packets. For packet processing capability.
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 'rake/gempackagetask'
47
- Rake::GemPackageTask.new($gemspec) do |package|
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 'rake/rdoctask'
78
- Rake::RDocTask.new do |rdoc|
79
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
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.10.0
1
+ 0.11.0
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
4
+
5
+ require 'rubygems'
6
+ require 'pcaprub'
7
+
8
+
9
+ capture = PCAPRUB::Pcap.open_dead(Pcap::DLT_EN10MB, 65535)
10
+ puts capture.pcap_major_version()
11
+ puts capture.pcap_minor_version()
12
+
@@ -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
@@ -1,7 +1,28 @@
1
1
  require 'mkmf'
2
2
  extension_name = 'pcaprub'
3
3
 
4
- if /i386-mswin32/ =~ RUBY_PLATFORM
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")
@@ -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
- #include <sys/time.h>
16
+ static VALUE mPCAP;
17
+ static VALUE rb_cPcap, rb_cPkt;
18
+ static VALUE ePCAPRUBError, eDumperError, eBindingError, eBPFilterError;
16
19
 
17
- static VALUE rb_cPcap;
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
- pcap_t *pd;
26
- pcap_dumper_t *pdt;
27
- char iface[256];
28
- char type;
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
- unsigned char *pkt;
36
+ unsigned char *pkt;
35
37
  int wtf;
36
38
  } rbpcapjob_t;
37
39
 
38
- /*
39
- * returns the version of Pcaprub extension
40
- */
41
- static VALUE
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
- char *dev = NULL;
56
- char eb[PCAP_ERRBUF_SIZE];
57
- VALUE ret_dev; /* device string to return */
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
- pcap_if_t *alldevs;
60
- pcap_if_t *d;
61
-
62
- /* Retrieve the device list from the local machine */
63
- if (pcap_findalldevs(&alldevs,eb) == -1) {
64
- rb_raise(rb_eRuntimeError,"%s",eb);
65
- }
66
-
67
- /* Find the first interface with an address and not loopback */
68
- for(d = alldevs; d != NULL; d= d->next) {
69
- if(d->name && d->addresses && !(d->flags & PCAP_IF_LOOPBACK)) {
70
- dev=d->name;
71
- break;
72
- }
73
- }
74
-
75
- if (dev == NULL) {
76
- rb_raise(rb_eRuntimeError,"%s","No valid interfaces found, Make sure WinPcap is installed.\n");
77
- }
78
- ret_dev = rb_str_new2(dev);
79
- /* We don't need any more the device list. Free it */
80
- pcap_freealldevs(alldevs);
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
- dev = pcap_lookupdev(eb);
83
- if (dev == NULL) {
84
- rb_raise(rb_eRuntimeError, "%s", eb);
85
- }
86
- ret_dev = rb_str_new2(dev);
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
- return ret_dev;
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
- bpf_u_int32 net, mask, m;
98
- struct in_addr addr;
99
- char eb[PCAP_ERRBUF_SIZE];
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
- Check_Type(dev, T_STRING);
103
- if (pcap_lookupnet(StringValuePtr(dev), &net, &mask, eb) == -1) {
104
- rb_raise(rb_eRuntimeError, "%s", eb);
105
- }
106
-
107
- addr.s_addr = net;
108
- m = ntohl(mask);
109
- list = rb_ary_new();
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(rb_eArgError, "a device or pcap file must be opened first");
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
- VALUE self;
142
- rbpcap_t *rbp;
164
+ VALUE self;
165
+ rbpcap_t *rbp;
143
166
 
144
- // need to make destructor do a pcap_close later
145
- self = Data_Make_Struct(class, rbpcap_t, 0, rbpcap_free, rbp);
146
- rb_obj_call_init(self, 0, 0);
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
- memset(rbp, 0, sizeof(rbpcap_t));
149
-
150
- return self;
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
- char eb[PCAP_ERRBUF_SIZE];
173
- rbpcap_t *rbp;
174
- u_int32_t mask = 0, netid = 0;
175
- struct bpf_program bpf;
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
- Data_Get_Struct(self, rbpcap_t, rbp);
218
+ Data_Get_Struct(self, rbpcap_t, rbp);
178
219
 
179
- if(TYPE(filter) != T_STRING)
180
- rb_raise(rb_eArgError, "filter must be a string");
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
- if(rbp->type == LIVE)
185
- if(pcap_lookupnet(rbp->iface, &netid, &mask, eb) < 0)
186
- rb_raise(rb_eRuntimeError, "%s", eb);
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
- if(pcap_compile(rbp->pd, &bpf, RSTRING_PTR(filter), 0, mask) < 0)
189
- rb_raise(rb_eRuntimeError, "invalid bpf filter");
229
+ if(pcap_compile(rbp->pd, &bpf, RSTRING_PTR(filter), 0, mask) < 0)
230
+ rb_raise(eBPFilterError, "invalid bpf filter");
190
231
 
191
- if(pcap_setfilter(rbp->pd, &bpf) < 0)
192
- rb_raise(rb_eRuntimeError, "unable to set bpf filter");
232
+ if(pcap_setfilter(rbp->pd, &bpf) < 0)
233
+ rb_raise(eBPFilterError, "unable to set bpf filter");
193
234
 
194
- return self;
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
- char eb[PCAP_ERRBUF_SIZE];
202
- rbpcap_t *rbp;
203
- int promisc_value = 0;
204
-
205
- if(TYPE(iface) != T_STRING)
206
- rb_raise(rb_eArgError, "interface must be a string");
207
- if(TYPE(snaplen) != T_FIXNUM)
208
- rb_raise(rb_eArgError, "snaplen must be a fixnum");
209
- if(TYPE(timeout) != T_FIXNUM)
210
- rb_raise(rb_eArgError, "timeout must be a fixnum");
211
-
212
- switch(promisc) {
213
- case Qtrue:
214
- promisc_value = 1;
215
- break;
216
- case Qfalse:
217
- promisc_value = 0;
218
- break;
219
- default:
220
- rb_raise(rb_eTypeError, "Argument not boolean");
221
- }
222
-
223
- Data_Get_Struct(self, rbpcap_t, rbp);
224
-
225
-
226
- rbp->type = LIVE;
227
- memset(rbp->iface, 0, sizeof(rbp->iface));
228
- strncpy(rbp->iface, RSTRING_PTR(iface), sizeof(rbp->iface) - 1);
229
-
230
-
231
- if(rbp->pd) {
232
- pcap_close(rbp->pd);
233
- }
234
-
235
- rbp->pd = pcap_open_live(
236
- RSTRING_PTR(iface),
237
- NUM2INT(snaplen),
238
- promisc_value,
239
- NUM2INT(timeout),
240
- eb
241
- );
242
-
243
- if(!rbp->pd)
244
- rb_raise(rb_eRuntimeError, "%s", eb);
245
-
246
- return self;
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
- VALUE iPcap = rb_funcall(rb_cPcap, rb_intern("new"), 0);
262
- return rbpcap_open_live(iPcap, iface, snaplen, promisc, timeout);
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
- char eb[PCAP_ERRBUF_SIZE];
270
- rbpcap_t *rbp;
310
+ char eb[PCAP_ERRBUF_SIZE];
311
+ rbpcap_t *rbp;
271
312
 
272
- if(TYPE(filename) != T_STRING)
273
- rb_raise(rb_eArgError, "filename must be a string");
313
+ if(TYPE(filename) != T_STRING)
314
+ rb_raise(rb_eArgError, "filename must be a string");
274
315
 
275
- Data_Get_Struct(self, rbpcap_t, rbp);
316
+ Data_Get_Struct(self, rbpcap_t, rbp);
276
317
 
277
- memset(rbp->iface, 0, sizeof(rbp->iface));
278
- rbp->type = OFFLINE;
318
+ memset(rbp->iface, 0, sizeof(rbp->iface));
319
+ rbp->type = OFFLINE;
279
320
 
280
- rbp->pd = pcap_open_offline(
281
- RSTRING_PTR(filename),
282
- eb
283
- );
321
+ rbp->pd = pcap_open_offline(
322
+ RSTRING_PTR(filename),
323
+ eb
324
+ );
284
325
 
285
- if(!rbp->pd)
286
- rb_raise(rb_eRuntimeError, "%s", eb);
326
+ if(!rbp->pd)
327
+ rb_raise(rb_eRuntimeError, "%s", eb);
287
328
 
288
- return self;
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
- VALUE iPcap = rb_funcall(rb_cPcap, rb_intern("new"), 0);
344
+ VALUE iPcap = rb_funcall(rb_cPcap, rb_intern("new"), 0);
304
345
 
305
- return rbpcap_open_offline(iPcap, filename);
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
- rbpcap_t *rbp;
353
+ rbpcap_t *rbp;
313
354
 
314
355
 
315
- if(TYPE(linktype) != T_FIXNUM)
316
- rb_raise(rb_eArgError, "linktype must be a fixnum");
317
- if(TYPE(snaplen) != T_FIXNUM)
318
- rb_raise(rb_eArgError, "snaplen must be a fixnum");
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
- Data_Get_Struct(self, rbpcap_t, rbp);
361
+ Data_Get_Struct(self, rbpcap_t, rbp);
321
362
 
322
- memset(rbp->iface, 0, sizeof(rbp->iface));
323
- rbp->type = OFFLINE;
363
+ memset(rbp->iface, 0, sizeof(rbp->iface));
364
+ rbp->type = OFFLINE;
324
365
 
325
- rbp->pd = pcap_open_dead(
326
- NUM2INT(linktype),
327
- NUM2INT(snaplen)
328
- );
329
-
330
- return self;
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
- VALUE iPcap = rb_funcall(rb_cPcap, rb_intern("new"), 0);
394
+ VALUE iPcap = rb_funcall(rb_cPcap, rb_intern("new"), 0);
353
395
 
354
- return rbpcap_open_dead(iPcap, linktype, snaplen);
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
- rbpcap_t *rbp;
367
-
368
- if(TYPE(filename) != T_STRING)
369
- rb_raise(rb_eArgError, "filename must be a string");
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
- Data_Get_Struct(self, rbpcap_t, rbp);
372
- rbp->pdt = pcap_dump_open(
373
- rbp->pd,
374
- RSTRING_PTR(filename)
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
- return self;
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
- rbpcap_t *rbp;
395
- struct pcap_pkthdr pcap_hdr;
396
-
397
- if(TYPE(packet) != T_STRING)
398
- rb_raise(rb_eArgError, "packet data must be a string");
399
- if(TYPE(caplen) != T_FIXNUM)
400
- rb_raise(rb_eArgError, "caplen must be a fixnum");
401
- if(TYPE(pktlen) != T_FIXNUM)
402
- rb_raise(rb_eArgError, "pktlen must be a fixnum");
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
- rbpcap_t *rbp;
511
+ rbpcap_t *rbp;
431
512
 
432
- if(TYPE(payload) != T_STRING)
433
- rb_raise(rb_eArgError, "payload must be a string");
513
+ if(TYPE(payload) != T_STRING)
514
+ rb_raise(rb_eArgError, "payload must be a string");
434
515
 
435
- Data_Get_Struct(self, rbpcap_t, rbp);
516
+ Data_Get_Struct(self, rbpcap_t, rbp);
436
517
 
437
518
  if(! rbpcap_ready(rbp)) return self;
438
519
  #if defined(WIN32)
439
- /* WinPcap does not have a pcap_inject call we use pcap_sendpacket, if it suceedes
440
- * we simply return the amount of packets request to inject, else we fail.
441
- */
442
- if(pcap_sendpacket(rbp->pd, RSTRING_PTR(payload), RSTRING_LEN(payload)) != 0) {
443
- rb_raise(rb_eRuntimeError, "%s", pcap_geterr(rbp->pd));
444
- }
445
- return INT2NUM(RSTRING_LEN(payload));
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
- return INT2NUM(pcap_inject(rbp->pd, RSTRING_PTR(payload), RSTRING_LEN(payload)));
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 next() is unsuccessful, Null is returned.
550
+ * If the next_data() is unsuccessful, Null is returned.
462
551
  */
463
552
  static VALUE
464
- rbpcap_next(VALUE self)
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) return Qnil;
576
+ if(rbp->type == OFFLINE && ret <= 0)
577
+ return Qnil;
484
578
 
485
579
  if(ret > 0 && job.hdr.caplen > 0)
486
- return rb_str_new((char *) job.pkt, job.hdr.caplen);
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
- * each() { |packet| ... }
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
- rbpcap_capture(VALUE self)
644
+ rbpcap_each_data(VALUE self)
500
645
  {
501
- rbpcap_t *rbp;
646
+ rbpcap_t *rbp;
502
647
  int fno = -1;
503
648
 
504
- Data_Get_Struct(self, rbpcap_t, rbp);
649
+ Data_Get_Struct(self, rbpcap_t, rbp);
505
650
 
506
651
  if(! rbpcap_ready(rbp)) return self;
507
652
 
508
- fno = pcap_get_selectable_fd(rbp->pd);
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
- for(;;) {
511
- VALUE packet = rbpcap_next(self);
512
- if(packet == Qnil && rbp->type == OFFLINE) break;
513
- packet == Qnil ? rb_thread_wait_fd(fno) : rb_yield(packet);
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
- return self;
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
- rbpcap_t *rbp;
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
- Data_Get_Struct(self, rbpcap_t, rbp);
753
+ Data_Get_Struct(self, rbpcap_t, rbp);
533
754
 
534
755
  if(! rbpcap_ready(rbp)) return self;
535
756
 
536
- return INT2NUM(pcap_datalink(rbp->pd));
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
- rbpcap_t *rbp;
770
+ rbpcap_t *rbp;
550
771
 
551
- Data_Get_Struct(self, rbpcap_t, rbp);
772
+ Data_Get_Struct(self, rbpcap_t, rbp);
552
773
 
553
774
  if(! rbpcap_ready(rbp)) return self;
554
775
 
555
- return INT2NUM(pcap_snapshot(rbp->pd));
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
- rbpcap_t *rbp;
572
- struct pcap_stat stat;
573
- VALUE hash;
574
-
575
- Data_Get_Struct(self, rbpcap_t, rbp);
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
- if (pcap_stats(rbp->pd, &stat) == -1)
580
- return Qnil;
581
-
582
- hash = rb_hash_new();
583
- rb_hash_aset(hash, rb_str_new2("recv"), UINT2NUM(stat.ps_recv));
584
- rb_hash_aset(hash, rb_str_new2("drop"), UINT2NUM(stat.ps_drop));
585
- // drops by interface XXX not yet supported under pcap.h 2.4
586
- // rb_hash_aset(hash, rb_str_new2("idrop"), UINT2NUM(stat.ps_ifdrop));
587
- return hash;
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
- * Document-class: Pcap
595
- *
596
- * Main class defined by the pcaprub extension.
597
- */
598
- rb_cPcap = rb_define_class("Pcap", rb_cObject);
599
-
600
- rb_define_module_function(rb_cPcap, "version", rbpcap_s_version, 0);
601
-
602
- rb_define_module_function(rb_cPcap, "lookupdev", rbpcap_s_lookupdev, 0);
603
- rb_define_module_function(rb_cPcap, "lookupnet", rbpcap_s_lookupnet, 1);
604
-
605
- rb_define_const(rb_cPcap, "DLT_NULL", INT2NUM(DLT_NULL));
606
- rb_define_const(rb_cPcap, "DLT_EN10MB", INT2NUM(DLT_EN10MB));
607
- rb_define_const(rb_cPcap, "DLT_EN3MB", INT2NUM(DLT_EN3MB));
608
- rb_define_const(rb_cPcap, "DLT_AX25", INT2NUM(DLT_AX25));
609
- rb_define_const(rb_cPcap, "DLT_PRONET", INT2NUM(DLT_PRONET));
610
- rb_define_const(rb_cPcap, "DLT_CHAOS", INT2NUM(DLT_CHAOS));
611
- rb_define_const(rb_cPcap, "DLT_IEEE802", INT2NUM(DLT_IEEE802));
612
- rb_define_const(rb_cPcap, "DLT_ARCNET", INT2NUM(DLT_ARCNET));
613
- rb_define_const(rb_cPcap, "DLT_SLIP", INT2NUM(DLT_SLIP));
614
- rb_define_const(rb_cPcap, "DLT_PPP", INT2NUM(DLT_PPP));
615
- rb_define_const(rb_cPcap, "DLT_FDDI", INT2NUM(DLT_FDDI));
616
- rb_define_const(rb_cPcap, "DLT_ATM_RFC1483", INT2NUM(DLT_ATM_RFC1483));
617
- rb_define_const(rb_cPcap, "DLT_RAW", INT2NUM(DLT_RAW));
618
- rb_define_const(rb_cPcap, "DLT_SLIP_BSDOS", INT2NUM(DLT_SLIP_BSDOS));
619
- rb_define_const(rb_cPcap, "DLT_PPP_BSDOS", INT2NUM(DLT_PPP_BSDOS));
620
- rb_define_const(rb_cPcap, "DLT_IEEE802_11", INT2NUM(DLT_IEEE802_11));
621
- rb_define_const(rb_cPcap, "DLT_IEEE802_11_RADIO", INT2NUM(DLT_IEEE802_11_RADIO));
622
- rb_define_const(rb_cPcap, "DLT_IEEE802_11_RADIO_AVS", INT2NUM(DLT_IEEE802_11_RADIO_AVS));
623
- rb_define_const(rb_cPcap, "DLT_LINUX_SLL", INT2NUM(DLT_LINUX_SLL));
624
- rb_define_const(rb_cPcap, "DLT_PRISM_HEADER", INT2NUM(DLT_PRISM_HEADER));
625
- rb_define_const(rb_cPcap, "DLT_AIRONET_HEADER", INT2NUM(DLT_AIRONET_HEADER));
626
-
627
- rb_define_singleton_method(rb_cPcap, "new", rbpcap_new_s, 0);
628
-
629
- rb_define_singleton_method(rb_cPcap, "open_live", rbpcap_open_live_s, 4);
630
- rb_define_singleton_method(rb_cPcap, "open_offline", rbpcap_open_offline_s, 1);
631
- rb_define_singleton_method(rb_cPcap, "open_dead", rbpcap_open_dead_s, 2);
632
- rb_define_singleton_method(rb_cPcap, "dump_open", rbpcap_dump_open, 1);
633
-
634
-
635
- rb_define_method(rb_cPcap, "dump", rbpcap_dump, 3);
636
- rb_define_method(rb_cPcap, "each", rbpcap_capture, 0);
637
- rb_define_method(rb_cPcap, "next", rbpcap_next, 0);
638
- rb_define_method(rb_cPcap, "setfilter", rbpcap_setfilter, 1);
639
- rb_define_method(rb_cPcap, "inject", rbpcap_inject, 1);
640
- rb_define_method(rb_cPcap, "datalink", rbpcap_datalink, 0);
641
- rb_define_method(rb_cPcap, "snapshot", rbpcap_snapshot, 0);
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
  }