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.
@@ -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
  }